mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 13:11:32 +00:00
parser: switch to char matcher interface
This commit is contained in:
@ -11,9 +11,14 @@ class IndentPrinter(
|
|||||||
append(indentLevelText)
|
append(indentLevelText)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun emitIndentedLine(line: String) {
|
||||||
|
emitIndent()
|
||||||
|
appendLine(line)
|
||||||
|
}
|
||||||
|
|
||||||
fun increaseIndent() {
|
fun increaseIndent() {
|
||||||
indentLevel++
|
indentLevel++
|
||||||
indentLevelText = indent.repeat(indentLevel)
|
indentLevelText += indent
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decreaseIndent() {
|
fun decreaseIndent() {
|
||||||
@ -21,5 +26,11 @@ class IndentPrinter(
|
|||||||
indentLevelText = indent.repeat(indentLevel)
|
indentLevelText = indent.repeat(indentLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun indented(block: IndentPrinter.() -> Unit) {
|
||||||
|
increaseIndent()
|
||||||
|
block(this)
|
||||||
|
decreaseIndent()
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String = buffer.toString()
|
override fun toString(): String = buffer.toString()
|
||||||
}
|
}
|
||||||
|
26
parser/src/main/kotlin/gay/pizza/pork/parser/CharMatcher.kt
Normal file
26
parser/src/main/kotlin/gay/pizza/pork/parser/CharMatcher.kt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package gay.pizza.pork.parser
|
||||||
|
|
||||||
|
fun interface CharMatcher {
|
||||||
|
fun valid(char: Char, index: Int): Boolean
|
||||||
|
|
||||||
|
class AnyOf(vararg val filters: CharMatcher) : CharMatcher {
|
||||||
|
override fun valid(char: Char, index: Int): Boolean =
|
||||||
|
filters.any { it.valid(char, index) }
|
||||||
|
}
|
||||||
|
|
||||||
|
class MatchSingle(val char: Char) : CharMatcher {
|
||||||
|
override fun valid(char: Char, index: Int): Boolean =
|
||||||
|
char == this.char
|
||||||
|
}
|
||||||
|
|
||||||
|
class MatchRange(val charRange: CharRange) : CharMatcher {
|
||||||
|
override fun valid(char: Char, index: Int): Boolean =
|
||||||
|
charRange.contains(char)
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotAtIndex(val index: Int, val matcher: CharMatcher) : CharMatcher {
|
||||||
|
override fun valid(char: Char, index: Int): Boolean {
|
||||||
|
return this.index != index && matcher.valid(char, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,21 @@
|
|||||||
package gay.pizza.pork.parser
|
package gay.pizza.pork.parser
|
||||||
|
|
||||||
|
import gay.pizza.pork.parser.CharMatcher.*
|
||||||
import gay.pizza.pork.parser.TokenTypeProperty.*
|
import gay.pizza.pork.parser.TokenTypeProperty.*
|
||||||
import gay.pizza.pork.parser.TokenFamily.*
|
import gay.pizza.pork.parser.TokenFamily.*
|
||||||
|
import gay.pizza.pork.parser.TokenTypeProperty.AnyOf
|
||||||
|
|
||||||
enum class TokenType(vararg properties: TokenTypeProperty) {
|
enum class TokenType(vararg properties: TokenTypeProperty) {
|
||||||
NumberLiteral(NumericLiteralFamily, CharIndexConsumer { it, index ->
|
NumberLiteral(NumericLiteralFamily, CharConsumer(CharMatcher.AnyOf(
|
||||||
(it in '0'..'9') || (index > 0 && it == '.') }),
|
MatchRange('0'..'9'),
|
||||||
Symbol(SymbolFamily, CharConsumer {
|
NotAtIndex(0, MatchSingle('.'))
|
||||||
(it in 'a'..'z') ||
|
))),
|
||||||
(it in 'A'..'Z') ||
|
Symbol(SymbolFamily, CharConsumer(CharMatcher.AnyOf(
|
||||||
(it == '_') ||
|
MatchRange('a'..'z'),
|
||||||
(it in '0' .. '9')}, KeywordUpgrader),
|
MatchRange('A'..'Z'),
|
||||||
|
MatchRange('0' .. '9'),
|
||||||
|
MatchSingle('_')
|
||||||
|
)), KeywordUpgrader),
|
||||||
StringLiteral(StringLiteralFamily),
|
StringLiteral(StringLiteralFamily),
|
||||||
Equality(OperatorFamily),
|
Equality(OperatorFamily),
|
||||||
Inequality(ManyChars("!="), OperatorFamily),
|
Inequality(ManyChars("!="), OperatorFamily),
|
||||||
@ -61,7 +66,12 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
|
|||||||
Native(ManyChars("native"), KeywordFamily),
|
Native(ManyChars("native"), KeywordFamily),
|
||||||
Let(ManyChars("let"), KeywordFamily),
|
Let(ManyChars("let"), KeywordFamily),
|
||||||
Var(ManyChars("var"), KeywordFamily),
|
Var(ManyChars("var"), KeywordFamily),
|
||||||
Whitespace(CharConsumer { it == ' ' || it == '\r' || it == '\n' || it == '\t' }),
|
Whitespace(CharConsumer(CharMatcher.AnyOf(
|
||||||
|
MatchSingle(' '),
|
||||||
|
MatchSingle('\r'),
|
||||||
|
MatchSingle('\n'),
|
||||||
|
MatchSingle('\t')
|
||||||
|
))),
|
||||||
BlockComment(CommentFamily),
|
BlockComment(CommentFamily),
|
||||||
LineComment(CommentFamily),
|
LineComment(CommentFamily),
|
||||||
EndOfFile;
|
EndOfFile;
|
||||||
@ -77,8 +87,6 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
|
|||||||
val family: TokenFamily =
|
val family: TokenFamily =
|
||||||
properties.filterIsInstance<TokenFamily>().singleOrNull() ?: OtherFamily
|
properties.filterIsInstance<TokenFamily>().singleOrNull() ?: OtherFamily
|
||||||
val charConsumer: CharConsumer? = properties.filterIsInstance<CharConsumer>().singleOrNull()
|
val charConsumer: CharConsumer? = properties.filterIsInstance<CharConsumer>().singleOrNull()
|
||||||
val charIndexConsumer: CharIndexConsumer? =
|
|
||||||
properties.filterIsInstance<CharIndexConsumer>().singleOrNull()
|
|
||||||
val tokenUpgrader: TokenUpgrader? =
|
val tokenUpgrader: TokenUpgrader? =
|
||||||
properties.filterIsInstance<TokenUpgrader>().singleOrNull()
|
properties.filterIsInstance<TokenUpgrader>().singleOrNull()
|
||||||
|
|
||||||
@ -89,7 +97,7 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
|
|||||||
val ManyChars = entries.filter { item -> item.manyChars != null }
|
val ManyChars = entries.filter { item -> item.manyChars != null }
|
||||||
val SingleChars = entries.filter { item -> item.singleChar != null }
|
val SingleChars = entries.filter { item -> item.singleChar != null }
|
||||||
val CharConsumers = entries.filter { item ->
|
val CharConsumers = entries.filter { item ->
|
||||||
item.charConsumer != null || item.charIndexConsumer != null }
|
item.charConsumer != null }
|
||||||
|
|
||||||
val ParserIgnoredTypes: Array<TokenType> = arrayOf(
|
val ParserIgnoredTypes: Array<TokenType> = arrayOf(
|
||||||
Whitespace,
|
Whitespace,
|
||||||
|
@ -5,8 +5,7 @@ interface TokenTypeProperty {
|
|||||||
class Promotion(val nextChar: Char, val type: TokenType) : TokenTypeProperty
|
class Promotion(val nextChar: Char, val type: TokenType) : TokenTypeProperty
|
||||||
class ManyChars(val text: String) : TokenTypeProperty
|
class ManyChars(val text: String) : TokenTypeProperty
|
||||||
class AnyOf(vararg val strings: String): TokenTypeProperty
|
class AnyOf(vararg val strings: String): TokenTypeProperty
|
||||||
class CharConsumer(val isValid: (Char) -> Boolean) : TokenTypeProperty
|
open class CharConsumer(val matcher: CharMatcher) : TokenTypeProperty
|
||||||
class CharIndexConsumer(val isValid: (Char, Int) -> Boolean) : TokenTypeProperty
|
|
||||||
open class TokenUpgrader(val maybeUpgrade: (Token) -> Token?) : TokenTypeProperty
|
open class TokenUpgrader(val maybeUpgrade: (Token) -> Token?) : TokenTypeProperty
|
||||||
|
|
||||||
object KeywordUpgrader : TokenUpgrader({ token ->
|
object KeywordUpgrader : TokenUpgrader({ token ->
|
||||||
|
@ -102,27 +102,14 @@ class Tokenizer(val source: CharSource) {
|
|||||||
|
|
||||||
var index = 0
|
var index = 0
|
||||||
for (item in TokenType.CharConsumers) {
|
for (item in TokenType.CharConsumers) {
|
||||||
if (item.charConsumer != null) {
|
if (!item.charConsumer!!.matcher.valid(char, index)) {
|
||||||
if (!item.charConsumer.isValid(char)) {
|
continue
|
||||||
continue
|
|
||||||
}
|
|
||||||
} else if (item.charIndexConsumer != null) {
|
|
||||||
if (!item.charIndexConsumer.isValid(char, index)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw ParseError("Unknown Char Consumer")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val text = buildString {
|
val text = buildString {
|
||||||
append(char)
|
append(char)
|
||||||
|
|
||||||
while (
|
while (item.charConsumer.matcher.valid(source.peek(), ++index)) {
|
||||||
if (item.charConsumer != null)
|
|
||||||
item.charConsumer.isValid(source.peek())
|
|
||||||
else
|
|
||||||
item.charIndexConsumer!!.isValid(source.peek(), ++index)
|
|
||||||
) {
|
|
||||||
append(nextChar())
|
append(nextChar())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,5 +155,6 @@ class Tokenizer(val source: CharSource) {
|
|||||||
return char
|
return char
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun currentSourceIndex(): SourceIndex = SourceIndex(source.currentIndex, currentLineIndex, currentLineColumn)
|
private fun currentSourceIndex(): SourceIndex =
|
||||||
|
SourceIndex(source.currentIndex, currentLineIndex, currentLineColumn)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import gay.pizza.pork.buildext.AstCodegenType
|
import gay.pizza.pork.buildext.AstCodegenType
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("org.jetbrains.intellij") version "1.15.0"
|
id("org.jetbrains.intellij") version "1.16.0"
|
||||||
id("gay.pizza.pork.module")
|
id("gay.pizza.pork.module")
|
||||||
id("gay.pizza.pork.ast")
|
id("gay.pizza.pork.ast")
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,8 @@ import gay.pizza.pork.idea.psi.gen.PorkElement
|
|||||||
class PorkSymbolDeclaration(val element: PorkElement) : PsiSymbolDeclaration {
|
class PorkSymbolDeclaration(val element: PorkElement) : PsiSymbolDeclaration {
|
||||||
override fun getDeclaringElement(): PsiElement = element
|
override fun getDeclaringElement(): PsiElement = element
|
||||||
override fun getRangeInDeclaringElement(): TextRange {
|
override fun getRangeInDeclaringElement(): TextRange {
|
||||||
val textRangeOfSymbol = PorkElementHelpers.symbolElementOf(element)?.psi?.textRangeInParent
|
return PorkElementHelpers.symbolElementOf(element)?.psi?.textRangeInParent
|
||||||
?: throw RuntimeException("Unable to get symbol of element: $element")
|
?: throw RuntimeException("Unable to get symbol of element: $element")
|
||||||
return textRangeOfSymbol
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSymbol(): Symbol = PorkElementHelpers.psiSymbolFor(element) ?:
|
override fun getSymbol(): Symbol = PorkElementHelpers.psiSymbolFor(element) ?:
|
||||||
|
Reference in New Issue
Block a user