mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 21:00:56 +00:00
If Statement Support
This commit is contained in:
parent
f1645d0924
commit
cccea9c2ca
8
examples/fib.pork
Normal file
8
examples/fib.pork
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fib = { n in
|
||||||
|
if n == 0
|
||||||
|
then 0
|
||||||
|
else if n == 1
|
||||||
|
then 1
|
||||||
|
else fib(n - 1) + fib(n - 2)
|
||||||
|
}
|
||||||
|
main = { in fib(20) }
|
@ -1,14 +1,18 @@
|
|||||||
main = {
|
main = { in
|
||||||
three = 3
|
three = 3
|
||||||
two = 2
|
two = 2
|
||||||
calculateSimple = {
|
calculateSimple = { in
|
||||||
(50 + three) * two
|
(50 + three) * two
|
||||||
}
|
}
|
||||||
calculateComplex = {
|
calculateComplex = { in
|
||||||
three + two + 50
|
three + two + 50
|
||||||
}
|
}
|
||||||
|
multiply = { a, b in
|
||||||
|
a * b
|
||||||
|
}
|
||||||
calculateSimpleResult = calculateSimple()
|
calculateSimpleResult = calculateSimple()
|
||||||
calculateComplexResult = calculateComplex()
|
calculateComplexResult = calculateComplex()
|
||||||
|
multiplyResult = multiply(50, 50)
|
||||||
|
|
||||||
list = [10, 20, 30]
|
list = [10, 20, 30]
|
||||||
trueValue = true
|
trueValue = true
|
||||||
@ -17,6 +21,7 @@ main = {
|
|||||||
[
|
[
|
||||||
calculateSimpleResult,
|
calculateSimpleResult,
|
||||||
calculateComplexResult,
|
calculateComplexResult,
|
||||||
|
multiplyResult,
|
||||||
list,
|
list,
|
||||||
trueValue,
|
trueValue,
|
||||||
falseValue
|
falseValue
|
||||||
|
@ -4,5 +4,5 @@ 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> =
|
||||||
listOf(visitor.visit(symbol), visitor.visit(value))
|
visitor.visitNodes(symbol, value)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
class FunctionCall(val symbol: Symbol) : 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> =
|
||||||
listOf(visitor.visit(symbol))
|
visitor.visitAll(listOf(symbol), arguments)
|
||||||
}
|
}
|
||||||
|
9
src/main/kotlin/gay/pizza/pork/ast/If.kt
Normal file
9
src/main/kotlin/gay/pizza/pork/ast/If.kt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
|
class If(
|
||||||
|
val condition: Expression,
|
||||||
|
val thenExpression: Expression,
|
||||||
|
val elseExpression: Expression
|
||||||
|
) : Expression {
|
||||||
|
override val type: NodeType = NodeType.If
|
||||||
|
}
|
@ -4,5 +4,5 @@ class InfixOperation(val left: Expression, val op: InfixOperator, val right: Exp
|
|||||||
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> =
|
||||||
listOf(visitor.visit(left), visitor.visit(right))
|
visitor.visitNodes(left, right)
|
||||||
}
|
}
|
||||||
|
@ -4,5 +4,6 @@ enum class InfixOperator(val token: String) {
|
|||||||
Plus("+"),
|
Plus("+"),
|
||||||
Minus("-"),
|
Minus("-"),
|
||||||
Multiply("*"),
|
Multiply("*"),
|
||||||
Divide("/")
|
Divide("/"),
|
||||||
|
Equals("==")
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
class Lambda(val expressions: List<Expression>) : Expression {
|
class Lambda(val arguments: List<Symbol>, val expressions: List<Expression>) : Expression {
|
||||||
constructor(vararg expressions: Expression) : this(listOf(*expressions))
|
|
||||||
|
|
||||||
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> =
|
||||||
expressions.map { expression -> visitor.visit(expression) }
|
visitor.visitAll(arguments, expressions)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
class ListLiteral(val items: List<Expression>) : Expression {
|
class ListLiteral(val items: List<Expression>) : Expression {
|
||||||
constructor(vararg items: Expression) : this(listOf(*items))
|
|
||||||
|
|
||||||
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> =
|
||||||
items.map { visitor.visit(it) }
|
visitor.visitAll(items)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,8 @@ enum class NodeType(val parent: NodeType? = null, vararg traits: NodeTypeTrait)
|
|||||||
Lambda(Expression),
|
Lambda(Expression),
|
||||||
InfixOperation(Expression),
|
InfixOperation(Expression),
|
||||||
SymbolReference(Expression),
|
SymbolReference(Expression),
|
||||||
FunctionCall(Expression);
|
FunctionCall(Expression),
|
||||||
|
If(Expression);
|
||||||
|
|
||||||
val parents: Set<NodeType>
|
val parents: Set<NodeType>
|
||||||
|
|
||||||
|
@ -4,5 +4,5 @@ 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> =
|
||||||
listOf(visitor.visit(expression))
|
visitor.visitNodes(expression)
|
||||||
}
|
}
|
||||||
|
@ -25,19 +25,46 @@ class Printer(private val buffer: StringBuilder) : Visitor<Unit> {
|
|||||||
|
|
||||||
override fun visitFunctionCall(node: FunctionCall) {
|
override fun visitFunctionCall(node: FunctionCall) {
|
||||||
visit(node.symbol)
|
visit(node.symbol)
|
||||||
append("()")
|
append("(")
|
||||||
|
for ((index, argument) in node.arguments.withIndex()) {
|
||||||
|
visit(argument)
|
||||||
|
if (index + 1 != node.arguments.size) {
|
||||||
|
append(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
append(")")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitReference(node: SymbolReference) {
|
override fun visitReference(node: SymbolReference) {
|
||||||
visit(node.symbol)
|
visit(node.symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitIf(node: If) {
|
||||||
|
append("if ")
|
||||||
|
visit(node.condition)
|
||||||
|
append(" then ")
|
||||||
|
visit(node.thenExpression)
|
||||||
|
append(" else ")
|
||||||
|
visit(node.elseExpression)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitSymbol(node: Symbol) {
|
override fun visitSymbol(node: Symbol) {
|
||||||
append(node.id)
|
append(node.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLambda(node: Lambda) {
|
override fun visitLambda(node: Lambda) {
|
||||||
append("{")
|
append("{")
|
||||||
|
if (node.arguments.isNotEmpty()) {
|
||||||
|
append(" ")
|
||||||
|
for ((index, argument) in node.arguments.withIndex()) {
|
||||||
|
visit(argument)
|
||||||
|
if (index + 1 != node.arguments.size) {
|
||||||
|
append(",")
|
||||||
|
}
|
||||||
|
append(" ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
append("in")
|
||||||
indent++
|
indent++
|
||||||
for (expression in node.expressions) {
|
for (expression in node.expressions) {
|
||||||
appendLine()
|
appendLine()
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
package gay.pizza.pork.ast
|
package gay.pizza.pork.ast
|
||||||
|
|
||||||
class Program(val expressions: List<Expression>) : Node {
|
class Program(val expressions: List<Expression>) : Node {
|
||||||
constructor(vararg expressions: Expression) : this(listOf(*expressions))
|
|
||||||
|
|
||||||
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> =
|
||||||
expressions.map { visitor.visit(it) }
|
visitor.visitAll(expressions)
|
||||||
}
|
}
|
||||||
|
@ -4,5 +4,5 @@ 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> =
|
||||||
listOf(visitor.visit(symbol))
|
visitor.visitNodes(symbol)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ interface Visitor<T> {
|
|||||||
fun visitDefine(node: Define): T
|
fun visitDefine(node: Define): T
|
||||||
fun visitFunctionCall(node: FunctionCall): T
|
fun visitFunctionCall(node: FunctionCall): T
|
||||||
fun visitReference(node: SymbolReference): T
|
fun visitReference(node: SymbolReference): T
|
||||||
|
fun visitIf(node: If): T
|
||||||
fun visitSymbol(node: Symbol): T
|
fun visitSymbol(node: Symbol): T
|
||||||
fun visitLambda(node: Lambda): T
|
fun visitLambda(node: Lambda): T
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ interface Visitor<T> {
|
|||||||
is Lambda -> visitLambda(node)
|
is Lambda -> visitLambda(node)
|
||||||
is FunctionCall -> visitFunctionCall(node)
|
is FunctionCall -> visitFunctionCall(node)
|
||||||
is SymbolReference -> visitReference(node)
|
is SymbolReference -> visitReference(node)
|
||||||
|
is If -> visitIf(node)
|
||||||
else -> throw RuntimeException("Unknown Expression")
|
else -> throw RuntimeException("Unknown Expression")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,4 +37,10 @@ interface Visitor<T> {
|
|||||||
is Program -> visitProgram(node)
|
is Program -> visitProgram(node)
|
||||||
else -> throw RuntimeException("Unknown Node")
|
else -> throw RuntimeException("Unknown Node")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun visitNodes(vararg nodes: Node): List<T> =
|
||||||
|
nodes.map { visit(it) }
|
||||||
|
|
||||||
|
fun visitAll(vararg nodeLists: List<Node>): List<T> =
|
||||||
|
nodeLists.asSequence().flatten().map { visit(it) }.toList()
|
||||||
}
|
}
|
||||||
|
7
src/main/kotlin/gay/pizza/pork/eval/Arguments.kt
Normal file
7
src/main/kotlin/gay/pizza/pork/eval/Arguments.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.eval
|
||||||
|
|
||||||
|
class Arguments(val values: List<Any>) {
|
||||||
|
companion object {
|
||||||
|
val Zero = Arguments(emptyList())
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
package gay.pizza.pork.eval
|
package gay.pizza.pork.eval
|
||||||
|
|
||||||
fun interface CallableFunction {
|
fun interface CallableFunction {
|
||||||
fun call(argument: Any): Any
|
fun call(arguments: Arguments): Any
|
||||||
}
|
}
|
||||||
|
@ -11,18 +11,33 @@ class PorkEvaluator(root: Scope) : Visitor<Any> {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionCall(node: FunctionCall): Any = currentScope.call(node.symbol.id)
|
override fun visitFunctionCall(node: FunctionCall): Any {
|
||||||
|
val arguments = node.arguments.map { visit(it) }
|
||||||
|
return currentScope.call(node.symbol.id, Arguments(arguments))
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitReference(node: SymbolReference): Any =
|
override fun visitReference(node: SymbolReference): Any =
|
||||||
currentScope.value(node.symbol.id)
|
currentScope.value(node.symbol.id)
|
||||||
|
|
||||||
|
override fun visitIf(node: If): Any {
|
||||||
|
val condition = visit(node.condition)
|
||||||
|
return if (condition == true) {
|
||||||
|
visit(node.thenExpression)
|
||||||
|
} else {
|
||||||
|
visit(node.elseExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitSymbol(node: Symbol): Any {
|
override fun visitSymbol(node: Symbol): Any {
|
||||||
return Unit
|
return Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLambda(node: Lambda): CallableFunction {
|
override fun visitLambda(node: Lambda): CallableFunction {
|
||||||
return CallableFunction { _ ->
|
return CallableFunction { arguments ->
|
||||||
currentScope = currentScope.fork()
|
currentScope = currentScope.fork()
|
||||||
|
for ((index, argumentSymbol) in node.arguments.withIndex()) {
|
||||||
|
currentScope.define(argumentSymbol.id, arguments.values[index])
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
var value: Any? = null
|
var value: Any? = null
|
||||||
for (expression in node.expressions) {
|
for (expression in node.expressions) {
|
||||||
@ -45,6 +60,13 @@ class PorkEvaluator(root: Scope) : Visitor<Any> {
|
|||||||
val left = visit(node.left)
|
val left = visit(node.left)
|
||||||
val right = visit(node.right)
|
val right = visit(node.right)
|
||||||
|
|
||||||
|
when (node.op) {
|
||||||
|
InfixOperator.Equals -> {
|
||||||
|
return left == right
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
|
||||||
if (left !is Number || right !is Number) {
|
if (left !is Number || right !is Number) {
|
||||||
throw RuntimeException("Failed to evaluate infix operation, bad types.")
|
throw RuntimeException("Failed to evaluate infix operation, bad types.")
|
||||||
}
|
}
|
||||||
@ -57,6 +79,7 @@ class PorkEvaluator(root: Scope) : Visitor<Any> {
|
|||||||
InfixOperator.Minus -> leftInt - rightInt
|
InfixOperator.Minus -> leftInt - rightInt
|
||||||
InfixOperator.Multiply -> leftInt * rightInt
|
InfixOperator.Multiply -> leftInt * rightInt
|
||||||
InfixOperator.Divide -> leftInt / rightInt
|
InfixOperator.Divide -> leftInt / rightInt
|
||||||
|
else -> throw RuntimeException("Unable to handle operation ${node.op}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,13 +21,12 @@ class Scope(val parent: Scope? = null) {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun call(name: String, argument: Any = Unit): Any {
|
fun call(name: String, arguments: Arguments): Any {
|
||||||
val value = value(name)
|
val value = value(name)
|
||||||
if (value !is CallableFunction) {
|
if (value !is CallableFunction) {
|
||||||
throw RuntimeException("$value is not callable.")
|
throw RuntimeException("$value is not callable.")
|
||||||
}
|
}
|
||||||
val function = value as CallableFunction
|
return value.call(arguments)
|
||||||
return function.call(argument)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fork(): Scope {
|
fun fork(): Scope {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package gay.pizza.pork
|
package gay.pizza.pork
|
||||||
|
|
||||||
import gay.pizza.pork.ast.*
|
import gay.pizza.pork.ast.*
|
||||||
|
import gay.pizza.pork.eval.Arguments
|
||||||
import gay.pizza.pork.eval.Scope
|
import gay.pizza.pork.eval.Scope
|
||||||
import gay.pizza.pork.eval.PorkEvaluator
|
import gay.pizza.pork.eval.PorkEvaluator
|
||||||
import gay.pizza.pork.parse.*
|
import gay.pizza.pork.parse.*
|
||||||
@ -12,7 +13,7 @@ fun main(args: Array<String>) {
|
|||||||
val scope = Scope()
|
val scope = Scope()
|
||||||
val evaluator = PorkEvaluator(scope)
|
val evaluator = PorkEvaluator(scope)
|
||||||
evaluator.visit(ast)
|
evaluator.visit(ast)
|
||||||
println("> ${scope.call("main")}")
|
println("> ${scope.call("main", Arguments.Zero)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val code = Path(args[0]).readText()
|
val code = Path(args[0]).readText()
|
||||||
|
@ -2,6 +2,7 @@ package gay.pizza.pork.parse
|
|||||||
|
|
||||||
interface PeekableSource<T> {
|
interface PeekableSource<T> {
|
||||||
val currentIndex: Int
|
val currentIndex: Int
|
||||||
|
fun back()
|
||||||
fun next(): T
|
fun next(): T
|
||||||
fun peek(): T
|
fun peek(): T
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,29 @@ class PorkParser(val source: PeekableSource<Token>) {
|
|||||||
return Symbol(token.text)
|
return Symbol(token.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun readIf(): If {
|
||||||
|
expect(TokenType.If)
|
||||||
|
val condition = readExpression()
|
||||||
|
expect(TokenType.Then)
|
||||||
|
val thenExpression = readExpression()
|
||||||
|
expect(TokenType.Else)
|
||||||
|
val elseExpression = readExpression()
|
||||||
|
return If(condition, thenExpression, elseExpression)
|
||||||
|
}
|
||||||
|
|
||||||
private fun readSymbolCases(): Expression {
|
private fun readSymbolCases(): Expression {
|
||||||
val symbol = readSymbol()
|
val symbol = readSymbol()
|
||||||
return if (peekType(TokenType.LeftParentheses)) {
|
return if (peekType(TokenType.LeftParentheses)) {
|
||||||
expect(TokenType.LeftParentheses)
|
expect(TokenType.LeftParentheses)
|
||||||
|
val arguments = collectExpressions(TokenType.RightParentheses, TokenType.Comma)
|
||||||
expect(TokenType.RightParentheses)
|
expect(TokenType.RightParentheses)
|
||||||
FunctionCall(symbol)
|
FunctionCall(symbol, arguments)
|
||||||
} else if (peekType(TokenType.Equals)) {
|
} else if (peekType(TokenType.Equals)) {
|
||||||
expect(TokenType.Equals)
|
expect(TokenType.Equals)
|
||||||
|
if (peekType(TokenType.Equals)) {
|
||||||
|
source.back()
|
||||||
|
return SymbolReference(symbol)
|
||||||
|
}
|
||||||
Define(symbol, readExpression())
|
Define(symbol, readExpression())
|
||||||
} else {
|
} else {
|
||||||
SymbolReference(symbol)
|
SymbolReference(symbol)
|
||||||
@ -29,9 +44,21 @@ class PorkParser(val source: PeekableSource<Token>) {
|
|||||||
|
|
||||||
fun readLambda(): Lambda {
|
fun readLambda(): Lambda {
|
||||||
expect(TokenType.LeftCurly)
|
expect(TokenType.LeftCurly)
|
||||||
|
val arguments = mutableListOf<Symbol>()
|
||||||
|
while (!peekType(TokenType.In)) {
|
||||||
|
val symbol = readSymbol()
|
||||||
|
arguments.add(symbol)
|
||||||
|
if (peekType(TokenType.Comma)) {
|
||||||
|
expect(TokenType.Comma)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(TokenType.In)
|
||||||
val items = collectExpressions(TokenType.RightCurly)
|
val items = collectExpressions(TokenType.RightCurly)
|
||||||
expect(TokenType.RightCurly)
|
expect(TokenType.RightCurly)
|
||||||
return Lambda(items)
|
return Lambda(arguments, items)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readExpression(): Expression {
|
fun readExpression(): Expression {
|
||||||
@ -40,31 +67,42 @@ class PorkParser(val source: PeekableSource<Token>) {
|
|||||||
TokenType.IntLiteral -> {
|
TokenType.IntLiteral -> {
|
||||||
readIntLiteral()
|
readIntLiteral()
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenType.LeftBracket -> {
|
TokenType.LeftBracket -> {
|
||||||
readListLiteral()
|
readListLiteral()
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenType.Symbol -> {
|
TokenType.Symbol -> {
|
||||||
readSymbolCases()
|
readSymbolCases()
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenType.LeftCurly -> {
|
TokenType.LeftCurly -> {
|
||||||
readLambda()
|
readLambda()
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenType.LeftParentheses -> {
|
TokenType.LeftParentheses -> {
|
||||||
expect(TokenType.LeftParentheses)
|
expect(TokenType.LeftParentheses)
|
||||||
val expression = readExpression()
|
val expression = readExpression()
|
||||||
expect(TokenType.RightParentheses)
|
expect(TokenType.RightParentheses)
|
||||||
Parentheses(expression)
|
Parentheses(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenType.True -> {
|
TokenType.True -> {
|
||||||
expect(TokenType.True)
|
expect(TokenType.True)
|
||||||
return BooleanLiteral(true)
|
return BooleanLiteral(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenType.False -> {
|
TokenType.False -> {
|
||||||
expect(TokenType.False)
|
expect(TokenType.False)
|
||||||
return BooleanLiteral(false)
|
return BooleanLiteral(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TokenType.If -> {
|
||||||
|
return readIf()
|
||||||
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
throw RuntimeException("Failed to parse token: ${token.type} '${token.text}' as expression.")
|
throw RuntimeException("Failed to parse token: ${token.type} '${token.text}' as expression")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +111,13 @@ class PorkParser(val source: PeekableSource<Token>) {
|
|||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +130,12 @@ class PorkParser(val source: PeekableSource<Token>) {
|
|||||||
else -> throw RuntimeException("Unknown Infix Operator")
|
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
|
||||||
|
else -> throw RuntimeException("Unknown Infix Operator")
|
||||||
|
}
|
||||||
|
|
||||||
fun readListLiteral(): ListLiteral {
|
fun readListLiteral(): ListLiteral {
|
||||||
expect(TokenType.LeftBracket)
|
expect(TokenType.LeftBracket)
|
||||||
val items = collectExpressions(TokenType.RightBracket, TokenType.Comma)
|
val items = collectExpressions(TokenType.RightBracket, TokenType.Comma)
|
||||||
|
@ -3,6 +3,9 @@ package gay.pizza.pork.parse
|
|||||||
class StringCharSource(val input: String) : CharSource {
|
class StringCharSource(val input: String) : CharSource {
|
||||||
private var index = 0
|
private var index = 0
|
||||||
override val currentIndex: Int = index
|
override val currentIndex: Int = index
|
||||||
|
override fun back() {
|
||||||
|
index--
|
||||||
|
}
|
||||||
|
|
||||||
override fun next(): Char {
|
override fun next(): Char {
|
||||||
if (index == input.length) {
|
if (index == input.length) {
|
||||||
|
@ -3,6 +3,9 @@ package gay.pizza.pork.parse
|
|||||||
class TokenStreamSource(val stream: TokenStream) : TokenSource {
|
class TokenStreamSource(val stream: TokenStream) : TokenSource {
|
||||||
private var index = 0
|
private var index = 0
|
||||||
override val currentIndex: Int = index
|
override val currentIndex: Int = index
|
||||||
|
override fun back() {
|
||||||
|
index--
|
||||||
|
}
|
||||||
|
|
||||||
override fun next(): Token {
|
override fun next(): Token {
|
||||||
if (index == stream.tokens.size) {
|
if (index == stream.tokens.size) {
|
||||||
|
@ -18,6 +18,9 @@ enum class TokenType(val char: Char? = null, val keyword: String? = null) {
|
|||||||
False(keyword = "false"),
|
False(keyword = "false"),
|
||||||
True(keyword = "true"),
|
True(keyword = "true"),
|
||||||
In(keyword = "in"),
|
In(keyword = "in"),
|
||||||
|
If(keyword = "if"),
|
||||||
|
Then(keyword = "then"),
|
||||||
|
Else(keyword = "else"),
|
||||||
EndOfFile;
|
EndOfFile;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
Loading…
Reference in New Issue
Block a user