diff --git a/examples/syntax.pork b/examples/syntax.pork index 729ef6e..5461f6a 100644 --- a/examples/syntax.pork +++ b/examples/syntax.pork @@ -19,7 +19,7 @@ main = { in falseValue = false invert = { value in - if value then false else true + !value } [ diff --git a/src/main/kotlin/gay/pizza/pork/ast/NodeType.kt b/src/main/kotlin/gay/pizza/pork/ast/NodeType.kt index ff8f282..b1dae8d 100644 --- a/src/main/kotlin/gay/pizza/pork/ast/NodeType.kt +++ b/src/main/kotlin/gay/pizza/pork/ast/NodeType.kt @@ -13,7 +13,8 @@ enum class NodeType(val parent: NodeType? = null, vararg traits: NodeTypeTrait) Parentheses(Expression), Define(Expression), Lambda(Expression), - InfixOperation(Expression), + PrefixOperation(Expression, Operation), + InfixOperation(Expression, Operation), SymbolReference(Expression), FunctionCall(Expression), If(Expression); diff --git a/src/main/kotlin/gay/pizza/pork/ast/NodeTypeTrait.kt b/src/main/kotlin/gay/pizza/pork/ast/NodeTypeTrait.kt index b031749..3e1d4d6 100644 --- a/src/main/kotlin/gay/pizza/pork/ast/NodeTypeTrait.kt +++ b/src/main/kotlin/gay/pizza/pork/ast/NodeTypeTrait.kt @@ -2,5 +2,6 @@ package gay.pizza.pork.ast enum class NodeTypeTrait { Intermediate, + Operation, Literal } diff --git a/src/main/kotlin/gay/pizza/pork/ast/PrefixOperation.kt b/src/main/kotlin/gay/pizza/pork/ast/PrefixOperation.kt new file mode 100644 index 0000000..f184d4a --- /dev/null +++ b/src/main/kotlin/gay/pizza/pork/ast/PrefixOperation.kt @@ -0,0 +1,5 @@ +package gay.pizza.pork.ast + +class PrefixOperation(val op: PrefixOperator, val expression: Expression) : Expression() { + override val type: NodeType = NodeType.PrefixOperation +} diff --git a/src/main/kotlin/gay/pizza/pork/ast/PrefixOperator.kt b/src/main/kotlin/gay/pizza/pork/ast/PrefixOperator.kt new file mode 100644 index 0000000..5da19e5 --- /dev/null +++ b/src/main/kotlin/gay/pizza/pork/ast/PrefixOperator.kt @@ -0,0 +1,5 @@ +package gay.pizza.pork.ast + +enum class PrefixOperator(val token: String) { + Negate("!") +} diff --git a/src/main/kotlin/gay/pizza/pork/ast/Printer.kt b/src/main/kotlin/gay/pizza/pork/ast/Printer.kt index cfdf3e6..824c8e0 100644 --- a/src/main/kotlin/gay/pizza/pork/ast/Printer.kt +++ b/src/main/kotlin/gay/pizza/pork/ast/Printer.kt @@ -111,6 +111,11 @@ class Printer(private val buffer: StringBuilder) : Visitor { append(")") } + override fun visitPrefixOperation(node: PrefixOperation) { + append(node.op.token) + visit(node.expression) + } + override fun visitInfixOperation(node: InfixOperation) { visit(node.left) append(" ") diff --git a/src/main/kotlin/gay/pizza/pork/ast/Visitor.kt b/src/main/kotlin/gay/pizza/pork/ast/Visitor.kt index d2e166f..6e4fdfe 100644 --- a/src/main/kotlin/gay/pizza/pork/ast/Visitor.kt +++ b/src/main/kotlin/gay/pizza/pork/ast/Visitor.kt @@ -13,6 +13,7 @@ interface Visitor { fun visitListLiteral(node: ListLiteral): T fun visitParentheses(node: Parentheses): T + fun visitPrefixOperation(node: PrefixOperation): T fun visitInfixOperation(node: InfixOperation): T fun visitProgram(node: Program): T @@ -23,6 +24,7 @@ interface Visitor { is ListLiteral -> visitListLiteral(node) is Parentheses -> visitParentheses(node) is InfixOperation -> visitInfixOperation(node) + is PrefixOperation -> visitPrefixOperation(node) is Define -> visitDefine(node) is Lambda -> visitLambda(node) is FunctionCall -> visitFunctionCall(node) diff --git a/src/main/kotlin/gay/pizza/pork/compiler/KotlinCompiler.kt b/src/main/kotlin/gay/pizza/pork/compiler/KotlinCompiler.kt index 107c306..311019f 100644 --- a/src/main/kotlin/gay/pizza/pork/compiler/KotlinCompiler.kt +++ b/src/main/kotlin/gay/pizza/pork/compiler/KotlinCompiler.kt @@ -57,6 +57,9 @@ class KotlinCompiler : Visitor { override fun visitParentheses(node: Parentheses): String = "(${visit(node.expression)})" + override fun visitPrefixOperation(node: PrefixOperation): String = + "${node.op.token}${visit(node.expression)}" + override fun visitInfixOperation(node: InfixOperation): String = "${visit(node.left)} ${node.op.token} ${visit(node.right)}" diff --git a/src/main/kotlin/gay/pizza/pork/eval/PorkEvaluator.kt b/src/main/kotlin/gay/pizza/pork/eval/PorkEvaluator.kt index a86f03e..ff2a668 100644 --- a/src/main/kotlin/gay/pizza/pork/eval/PorkEvaluator.kt +++ b/src/main/kotlin/gay/pizza/pork/eval/PorkEvaluator.kt @@ -60,6 +60,18 @@ class PorkEvaluator(root: Scope) : Visitor { override fun visitParentheses(node: Parentheses): Any = visit(node.expression) + override fun visitPrefixOperation(node: PrefixOperation): Any { + val value = visit(node.expression) + return when (node.op) { + PrefixOperator.Negate -> { + if (value !is Boolean) { + throw RuntimeException("Cannot negate a value which is not a boolean.") + } + !value + } + } + } + override fun visitInfixOperation(node: InfixOperation): Any { val left = visit(node.left) val right = visit(node.right) diff --git a/src/main/kotlin/gay/pizza/pork/parse/PorkParser.kt b/src/main/kotlin/gay/pizza/pork/parse/PorkParser.kt index 828e395..98fcce6 100644 --- a/src/main/kotlin/gay/pizza/pork/parse/PorkParser.kt +++ b/src/main/kotlin/gay/pizza/pork/parse/PorkParser.kt @@ -96,6 +96,11 @@ class PorkParser(val source: PeekableSource) { return BooleanLiteral(false) } + TokenType.Negation -> { + expect(TokenType.Negation) + return PrefixOperation(PrefixOperator.Negate, readExpression()) + } + TokenType.If -> { return readIf() } diff --git a/src/main/kotlin/gay/pizza/pork/parse/TokenType.kt b/src/main/kotlin/gay/pizza/pork/parse/TokenType.kt index 3b6f443..a3ace9d 100644 --- a/src/main/kotlin/gay/pizza/pork/parse/TokenType.kt +++ b/src/main/kotlin/gay/pizza/pork/parse/TokenType.kt @@ -15,6 +15,7 @@ enum class TokenType(val char: Char? = null, val keyword: String? = null, val pr RightBracket(char = ']'), LeftParentheses(char = '('), RightParentheses(char = ')'), + Negation(char = '!'), Comma(char = ','), False(keyword = "false"), True(keyword = "true"),