Implement token promotion.

This commit is contained in:
Alex Zenla 2023-08-20 00:48:10 -07:00
parent 77329541fa
commit 72163a2aa6
Signed by: alex
GPG Key ID: C0780728420EBFE5
18 changed files with 41 additions and 33 deletions

View File

@ -1,5 +1,5 @@
package gay.pizza.pork.ast
class BooleanLiteral(val value: Boolean) : Expression {
class BooleanLiteral(val value: Boolean) : Expression() {
override val type: NodeType = NodeType.BooleanLiteral
}

View File

@ -1,6 +1,6 @@
package gay.pizza.pork.ast
class Define(val symbol: Symbol, val value: Expression) : Expression {
class Define(val symbol: Symbol, val value: Expression) : Expression() {
override val type: NodeType = NodeType.Define
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =

View File

@ -1,3 +1,3 @@
package gay.pizza.pork.ast
interface Expression : Node
abstract class Expression : Node()

View File

@ -1,6 +1,6 @@
package gay.pizza.pork.ast
class FunctionCall(val symbol: Symbol, val arguments: List<Expression>) : Expression {
class FunctionCall(val symbol: Symbol, val arguments: List<Expression>) : Expression() {
override val type: NodeType = NodeType.FunctionCall
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =

View File

@ -4,6 +4,6 @@ class If(
val condition: Expression,
val thenExpression: Expression,
val elseExpression: Expression? = null
) : Expression {
) : Expression() {
override val type: NodeType = NodeType.If
}

View File

@ -1,6 +1,6 @@
package gay.pizza.pork.ast
class InfixOperation(val left: Expression, val op: InfixOperator, val right: Expression) : Expression {
class InfixOperation(val left: Expression, val op: InfixOperator, val right: Expression) : Expression() {
override val type: NodeType = NodeType.InfixOperation
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =

View File

@ -1,5 +1,5 @@
package gay.pizza.pork.ast
class IntLiteral(val value: Int) : Expression {
class IntLiteral(val value: Int) : Expression() {
override val type: NodeType = NodeType.IntLiteral
}

View File

@ -1,6 +1,6 @@
package gay.pizza.pork.ast
class Lambda(val arguments: List<Symbol>, val expressions: List<Expression>) : Expression {
class Lambda(val arguments: List<Symbol>, val expressions: List<Expression>) : Expression() {
override val type: NodeType = NodeType.Lambda
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =

View File

@ -1,6 +1,6 @@
package gay.pizza.pork.ast
class ListLiteral(val items: List<Expression>) : Expression {
class ListLiteral(val items: List<Expression>) : Expression() {
override val type: NodeType = NodeType.ListLiteral
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =

View File

@ -1,6 +1,8 @@
package gay.pizza.pork.ast
interface Node {
val type: NodeType
fun <T> visitChildren(visitor: Visitor<T>): List<T> = emptyList()
abstract class Node {
abstract val type: NodeType
open fun <T> visitChildren(visitor: Visitor<T>): List<T> = emptyList()
override fun toString(): String = let { node -> buildString { Printer(this).visit(node) } }
}

View File

@ -1,6 +1,6 @@
package gay.pizza.pork.ast
class Parentheses(val expression: Expression) : Expression {
class Parentheses(val expression: Expression) : Expression() {
override val type: NodeType = NodeType.Parentheses
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =

View File

@ -1,6 +1,6 @@
package gay.pizza.pork.ast
class Program(val expressions: List<Expression>) : Node {
class Program(val expressions: List<Expression>) : Node() {
override val type: NodeType = NodeType.Program
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =

View File

@ -1,5 +1,5 @@
package gay.pizza.pork.ast
class Symbol(val id: String) : Node {
class Symbol(val id: String) : Node() {
override val type: NodeType = NodeType.Symbol
}

View File

@ -1,6 +1,6 @@
package gay.pizza.pork.ast
class SymbolReference(val symbol: Symbol) : Expression {
class SymbolReference(val symbol: Symbol) : Expression() {
override val type: NodeType = NodeType.SymbolReference
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =

View File

@ -109,18 +109,12 @@ class PorkParser(val source: PeekableSource<Token>) {
}
}
if (peekType(TokenType.Plus, TokenType.Minus, TokenType.Multiply, TokenType.Divide)) {
if (peekType(TokenType.Plus, TokenType.Minus, TokenType.Multiply, TokenType.Divide, TokenType.Equality)) {
val infixToken = source.next()
val infixOperator = convertInfixOperator(infixToken)
return InfixOperation(expression, infixOperator, readExpression())
}
if (peekType(TokenType.Equals)) {
val twoWideInfix = source.next()
val secondToken = expect(twoWideInfix.type)
return InfixOperation(expression, convertWideInfixOperator(twoWideInfix, secondToken), readExpression())
}
return expression
}
@ -130,12 +124,7 @@ class PorkParser(val source: PeekableSource<Token>) {
TokenType.Minus -> InfixOperator.Minus
TokenType.Multiply -> InfixOperator.Multiply
TokenType.Divide -> InfixOperator.Divide
else -> throw RuntimeException("Unknown Infix Operator")
}
private fun convertWideInfixOperator(firstToken: Token, secondToken: Token): InfixOperator =
when (firstToken.type to secondToken.type) {
TokenType.Equals to TokenType.Equals -> InfixOperator.Equals
TokenType.Equality -> InfixOperator.Equals
else -> throw RuntimeException("Unknown Infix Operator")
}

View File

@ -54,10 +54,23 @@ class PorkTokenizer(val source: CharSource, val preserveWhitespace: Boolean = fa
while (source.peek() != CharSource.NullChar) {
tokenStart = source.currentIndex
val char = source.next()
for (item in TokenType.SingleChars) {
if (item.char == char) {
return Token(item, char.toString())
if (item.char != char) {
continue
}
var type = item
var text = item.char.toString()
for (promotion in item.promotions) {
if (source.peek() != promotion.nextChar) {
continue
}
val nextChar = source.next()
type = promotion.type
text += nextChar
}
return Token(type, text)
}
if (isWhitespace(char)) {

View File

@ -0,0 +1,3 @@
package gay.pizza.pork.parse
class TokenPromotion(val nextChar: Char, val type: TokenType)

View File

@ -1,9 +1,10 @@
package gay.pizza.pork.parse
enum class TokenType(val char: Char? = null, val keyword: String? = null) {
enum class TokenType(val char: Char? = null, val keyword: String? = null, val promotions: List<TokenPromotion> = emptyList()) {
Symbol,
IntLiteral,
Equals(char = '='),
Equality,
Equals(char = '=', promotions = listOf(TokenPromotion('=', Equality))),
Plus(char = '+'),
Minus(char = '-'),
Multiply(char = '*'),