mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
Implement token promotion.
This commit is contained in:
parent
77329541fa
commit
72163a2aa6
@ -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
|
||||
}
|
||||
|
@ -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> =
|
||||
|
@ -1,3 +1,3 @@
|
||||
package gay.pizza.pork.ast
|
||||
|
||||
interface Expression : Node
|
||||
abstract class Expression : Node()
|
||||
|
@ -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> =
|
||||
|
@ -4,6 +4,6 @@ class If(
|
||||
val condition: Expression,
|
||||
val thenExpression: Expression,
|
||||
val elseExpression: Expression? = null
|
||||
) : Expression {
|
||||
) : Expression() {
|
||||
override val type: NodeType = NodeType.If
|
||||
}
|
||||
|
@ -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> =
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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> =
|
||||
|
@ -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> =
|
||||
|
@ -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) } }
|
||||
}
|
||||
|
@ -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> =
|
||||
|
@ -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> =
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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> =
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
|
@ -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)) {
|
||||
|
3
src/main/kotlin/gay/pizza/pork/parse/TokenPromotion.kt
Normal file
3
src/main/kotlin/gay/pizza/pork/parse/TokenPromotion.kt
Normal file
@ -0,0 +1,3 @@
|
||||
package gay.pizza.pork.parse
|
||||
|
||||
class TokenPromotion(val nextChar: Char, val type: TokenType)
|
@ -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 = '*'),
|
||||
|
Loading…
Reference in New Issue
Block a user