language: prelude and internal functions, and varargs support

This commit is contained in:
2023-09-10 19:27:59 -04:00
parent 1cfb197a7f
commit e8c984f2dc
24 changed files with 166 additions and 104 deletions

View File

@ -217,7 +217,7 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
private fun readImportDeclaration(): ImportDeclaration = within {
expect(TokenType.Import)
val form = readSymbolRaw()
val components = oneAndContinuedBy(TokenType.Period) { readSymbolRaw() }
val components = oneAndContinuedBy(TokenType.Dot) { readSymbolRaw() }
ImportDeclaration(form, components)
}
@ -237,7 +237,12 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
val name = readSymbolRaw()
expect(TokenType.LeftParentheses)
val arguments = collect(TokenType.RightParentheses, TokenType.Comma) {
readSymbolRaw()
val symbol = readSymbolRaw()
var multiple: Boolean = false
if (next(TokenType.DotDotDot)) {
multiple = true
}
ArgumentSpec(symbol, multiple)
}
expect(TokenType.RightParentheses)

View File

@ -155,7 +155,10 @@ class Printer(buffer: StringBuilder) : NodeVisitor<Unit> {
visit(node.symbol)
append("(")
for ((index, argument) in node.arguments.withIndex()) {
visit(argument)
visit(argument.symbol)
if (argument.multiple) {
append("...")
}
if (index + 1 != node.arguments.size) {
append(", ")
}

View File

@ -30,23 +30,25 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
LeftParentheses(SingleChar('(')),
RightParentheses(SingleChar(')')),
Negation(SingleChar('!'), Promotion('=', Inequality), OperatorFamily),
Mod(Keyword("mod"), OperatorFamily),
Rem(Keyword("rem"), OperatorFamily),
Mod(ManyChars("mod"), OperatorFamily),
Rem(ManyChars("rem"), OperatorFamily),
Comma(SingleChar(',')),
Period(SingleChar('.')),
False(Keyword("false"), KeywordFamily),
True(Keyword("true"), KeywordFamily),
If(Keyword("if"), KeywordFamily),
Else(Keyword("else"), KeywordFamily),
While(Keyword("while"), KeywordFamily),
Continue(Keyword("continue"), KeywordFamily),
Break(Keyword("break"), KeywordFamily),
Import(Keyword("import"), KeywordFamily),
Export(Keyword("export"), KeywordFamily),
Func(Keyword("func"), KeywordFamily),
Native(Keyword("native"), KeywordFamily),
Let(Keyword("let"), KeywordFamily),
Var(Keyword("var"), KeywordFamily),
DotDotDot(ManyChars("...")),
DotDot(ManyChars(".."), Promotion('.', DotDotDot)),
Dot(SingleChar('.'), Promotion('.', DotDot)),
False(ManyChars("false"), KeywordFamily),
True(ManyChars("true"), KeywordFamily),
If(ManyChars("if"), KeywordFamily),
Else(ManyChars("else"), KeywordFamily),
While(ManyChars("while"), KeywordFamily),
Continue(ManyChars("continue"), KeywordFamily),
Break(ManyChars("break"), KeywordFamily),
Import(ManyChars("import"), KeywordFamily),
Export(ManyChars("export"), KeywordFamily),
Func(ManyChars("func"), KeywordFamily),
Native(ManyChars("native"), KeywordFamily),
Let(ManyChars("let"), KeywordFamily),
Var(ManyChars("var"), KeywordFamily),
Whitespace(CharConsumer { it == ' ' || it == '\r' || it == '\n' || it == '\t' }),
BlockComment(CommentFamily),
LineComment(CommentFamily),
@ -54,8 +56,8 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
val promotions: List<Promotion> =
properties.filterIsInstance<Promotion>()
val keyword: Keyword? =
properties.filterIsInstance<Keyword>().singleOrNull()
val manyChars: ManyChars? =
properties.filterIsInstance<ManyChars>().singleOrNull()
val singleChar: SingleChar? =
properties.filterIsInstance<SingleChar>().singleOrNull()
val family: TokenFamily =
@ -67,7 +69,7 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
properties.filterIsInstance<TokenUpgrader>().singleOrNull()
companion object {
val Keywords = entries.filter { item -> item.keyword != null }
val ManyChars = entries.filter { item -> item.manyChars != null }
val SingleChars = entries.filter { item -> item.singleChar != null }
val CharConsumers = entries.filter { item ->
item.charConsumer != null || item.charIndexConsumer != null }

View File

@ -3,15 +3,15 @@ package gay.pizza.pork.parser
interface TokenTypeProperty {
class SingleChar(val char: Char) : TokenTypeProperty
class Promotion(val nextChar: Char, val type: TokenType) : TokenTypeProperty
class Keyword(val text: String) : TokenTypeProperty
class ManyChars(val text: String) : TokenTypeProperty
class CharConsumer(val isValid: (Char) -> Boolean) : TokenTypeProperty
class CharIndexConsumer(val isValid: (Char, Int) -> Boolean) : TokenTypeProperty
open class TokenUpgrader(val maybeUpgrade: (Token) -> Token?) : TokenTypeProperty
object KeywordUpgrader : TokenUpgrader({ token ->
var upgraded: Token? = null
for (item in TokenType.Keywords) {
if (item.keyword != null && token.text == item.keyword.text) {
for (item in TokenType.ManyChars) {
if (item.manyChars != null && token.text == item.manyChars.text) {
upgraded = Token(item, token.start, token.text)
break
}

View File

@ -79,13 +79,18 @@ class Tokenizer(val source: CharSource) {
var type = item
var text = itemChar.toString()
for (promotion in item.promotions) {
if (source.peek() != promotion.nextChar) {
continue
var promoted = true
while (promoted) {
promoted = false
for (promotion in type.promotions) {
if (source.peek() != promotion.nextChar) {
continue
}
val nextChar = source.next()
type = promotion.type
text += nextChar
promoted = true
}
val nextChar = source.next()
type = promotion.type
text += nextChar
}
return Token(type, tokenStart, text)
}