mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 21:21:33 +00:00
Implement token promotion.
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
class BooleanLiteral(val value: Boolean) : Expression {
|
class BooleanLiteral(val value: Boolean) : Expression() {
|
||||||
override val type: NodeType = NodeType.BooleanLiteral
|
override val type: NodeType = NodeType.BooleanLiteral
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package gay.pizza.pork.ast
|
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 val type: NodeType = NodeType.Define
|
||||||
|
|
||||||
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
interface Expression : Node
|
abstract class Expression : Node()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package gay.pizza.pork.ast
|
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 val type: NodeType = NodeType.FunctionCall
|
||||||
|
|
||||||
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
||||||
|
@ -4,6 +4,6 @@ class If(
|
|||||||
val condition: Expression,
|
val condition: Expression,
|
||||||
val thenExpression: Expression,
|
val thenExpression: Expression,
|
||||||
val elseExpression: Expression? = null
|
val elseExpression: Expression? = null
|
||||||
) : Expression {
|
) : Expression() {
|
||||||
override val type: NodeType = NodeType.If
|
override val type: NodeType = NodeType.If
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package gay.pizza.pork.ast
|
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 val type: NodeType = NodeType.InfixOperation
|
||||||
|
|
||||||
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
class IntLiteral(val value: Int) : Expression {
|
class IntLiteral(val value: Int) : Expression() {
|
||||||
override val type: NodeType = NodeType.IntLiteral
|
override val type: NodeType = NodeType.IntLiteral
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package gay.pizza.pork.ast
|
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 val type: NodeType = NodeType.Lambda
|
||||||
|
|
||||||
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package gay.pizza.pork.ast
|
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 val type: NodeType = NodeType.ListLiteral
|
||||||
|
|
||||||
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
interface Node {
|
abstract class Node {
|
||||||
val type: NodeType
|
abstract val type: NodeType
|
||||||
fun <T> visitChildren(visitor: Visitor<T>): List<T> = emptyList()
|
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
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
class Parentheses(val expression: Expression) : Expression {
|
class Parentheses(val expression: Expression) : Expression() {
|
||||||
override val type: NodeType = NodeType.Parentheses
|
override val type: NodeType = NodeType.Parentheses
|
||||||
|
|
||||||
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package gay.pizza.pork.ast
|
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 val type: NodeType = NodeType.Program
|
||||||
|
|
||||||
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
class Symbol(val id: String) : Node {
|
class Symbol(val id: String) : Node() {
|
||||||
override val type: NodeType = NodeType.Symbol
|
override val type: NodeType = NodeType.Symbol
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
class SymbolReference(val symbol: Symbol) : Expression {
|
class SymbolReference(val symbol: Symbol) : Expression() {
|
||||||
override val type: NodeType = NodeType.SymbolReference
|
override val type: NodeType = NodeType.SymbolReference
|
||||||
|
|
||||||
override fun <T> visitChildren(visitor: Visitor<T>): List<T> =
|
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 infixToken = source.next()
|
||||||
val infixOperator = convertInfixOperator(infixToken)
|
val infixOperator = convertInfixOperator(infixToken)
|
||||||
return InfixOperation(expression, infixOperator, readExpression())
|
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
|
return expression
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,12 +124,7 @@ class PorkParser(val source: PeekableSource<Token>) {
|
|||||||
TokenType.Minus -> InfixOperator.Minus
|
TokenType.Minus -> InfixOperator.Minus
|
||||||
TokenType.Multiply -> InfixOperator.Multiply
|
TokenType.Multiply -> InfixOperator.Multiply
|
||||||
TokenType.Divide -> InfixOperator.Divide
|
TokenType.Divide -> InfixOperator.Divide
|
||||||
else -> throw RuntimeException("Unknown Infix Operator")
|
TokenType.Equality -> InfixOperator.Equals
|
||||||
}
|
|
||||||
|
|
||||||
private fun convertWideInfixOperator(firstToken: Token, secondToken: Token): InfixOperator =
|
|
||||||
when (firstToken.type to secondToken.type) {
|
|
||||||
TokenType.Equals to TokenType.Equals -> InfixOperator.Equals
|
|
||||||
else -> throw RuntimeException("Unknown Infix Operator")
|
else -> throw RuntimeException("Unknown Infix Operator")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,10 +54,23 @@ class PorkTokenizer(val source: CharSource, val preserveWhitespace: Boolean = fa
|
|||||||
while (source.peek() != CharSource.NullChar) {
|
while (source.peek() != CharSource.NullChar) {
|
||||||
tokenStart = source.currentIndex
|
tokenStart = source.currentIndex
|
||||||
val char = source.next()
|
val char = source.next()
|
||||||
|
|
||||||
for (item in TokenType.SingleChars) {
|
for (item in TokenType.SingleChars) {
|
||||||
if (item.char == char) {
|
if (item.char != char) {
|
||||||
return Token(item, char.toString())
|
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)) {
|
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
|
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,
|
Symbol,
|
||||||
IntLiteral,
|
IntLiteral,
|
||||||
Equals(char = '='),
|
Equality,
|
||||||
|
Equals(char = '=', promotions = listOf(TokenPromotion('=', Equality))),
|
||||||
Plus(char = '+'),
|
Plus(char = '+'),
|
||||||
Minus(char = '-'),
|
Minus(char = '-'),
|
||||||
Multiply(char = '*'),
|
Multiply(char = '*'),
|
||||||
|
Reference in New Issue
Block a user