diff --git a/ast/src/main/ast/pork.yml b/ast/src/main/ast/pork.yml index 774d842..87d1cac 100644 --- a/ast/src/main/ast/pork.yml +++ b/ast/src/main/ast/pork.yml @@ -64,6 +64,12 @@ types: - name: NotEquals values: token: "!=" + - name: EuclideanModulo + values: + token: "mod" + - name: Remainder + values: + token: "rem" InfixOperation: parent: Expression values: diff --git a/ast/src/main/kotlin/gay/pizza/pork/ast/InfixOperator.kt b/ast/src/main/kotlin/gay/pizza/pork/ast/InfixOperator.kt index 9c7a4b9..0425918 100644 --- a/ast/src/main/kotlin/gay/pizza/pork/ast/InfixOperator.kt +++ b/ast/src/main/kotlin/gay/pizza/pork/ast/InfixOperator.kt @@ -12,5 +12,7 @@ enum class InfixOperator(val token: String) { Multiply("*"), Divide("/"), Equals("=="), - NotEquals("!=") + NotEquals("!="), + EuclideanModulo("mod"), + Remainder("rem") } diff --git a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt index 2d569a4..a92d449 100644 --- a/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt +++ b/evaluator/src/main/kotlin/gay/pizza/pork/evaluator/EvaluationVisitor.kt @@ -1,6 +1,7 @@ package gay.pizza.pork.evaluator import gay.pizza.pork.ast.* +import kotlin.math.abs class EvaluationVisitor(root: Scope) : NodeVisitor { private var currentScope: Scope = root @@ -105,7 +106,9 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { add = { a, b -> a + b }, subtract = { a, b -> a - b }, multiply = { a, b -> a * b }, - divide = { a, b -> a / b } + divide = { a, b -> a / b }, + euclideanModulo = { a, b -> throw RuntimeException("Can't perform integer modulo between floating point types") }, + remainder = { a, b -> throw RuntimeException("Can't perform integer remainder between floating point types") } ) } @@ -118,7 +121,9 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { add = { a, b -> a + b }, subtract = { a, b -> a - b }, multiply = { a, b -> a * b }, - divide = { a, b -> a / b } + divide = { a, b -> a / b }, + euclideanModulo = { a, b -> throw RuntimeException("Can't perform integer modulo between floating point types") }, + remainder = { a, b -> throw RuntimeException("Can't perform integer remainder between floating point types") } ) } @@ -131,7 +136,9 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { add = { a, b -> a + b }, subtract = { a, b -> a - b }, multiply = { a, b -> a * b }, - divide = { a, b -> a / b } + divide = { a, b -> a / b }, + euclideanModulo = { x, d -> (x % d).let { q -> if (q < 0) q + abs(d) else q } }, + remainder = { x, d -> x % d } ) } @@ -144,7 +151,9 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { add = { a, b -> a + b }, subtract = { a, b -> a - b }, multiply = { a, b -> a * b }, - divide = { a, b -> a / b } + divide = { a, b -> a / b }, + euclideanModulo = { x, d -> (x % d).let { q -> if (q < 0) q + abs(d) else q } }, + remainder = { x, d -> x % d } ) } @@ -159,13 +168,17 @@ class EvaluationVisitor(root: Scope) : NodeVisitor { add: (T, T) -> T, subtract: (T, T) -> T, multiply: (T, T) -> T, - divide: (T, T) -> T + divide: (T, T) -> T, + euclideanModulo: (T, T) -> T, + remainder: (T, T) -> T ): T { return when (op) { InfixOperator.Plus -> add(convert(left), convert(right)) InfixOperator.Minus -> subtract(convert(left), convert(right)) InfixOperator.Multiply -> multiply(convert(left), convert(right)) InfixOperator.Divide -> divide(convert(left), convert(right)) + InfixOperator.EuclideanModulo -> euclideanModulo(convert(left), convert(right)) + InfixOperator.Remainder -> remainder(convert(left), convert(right)) else -> throw RuntimeException("Unable to handle operation $op") } } diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt index ee0b7ad..11d6661 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt @@ -167,7 +167,9 @@ class Parser(source: PeekableSource, val attribution: NodeAttribution) { TokenType.Multiply, TokenType.Divide, TokenType.Equality, - TokenType.Inequality + TokenType.Inequality, + TokenType.Mod, + TokenType.Rem ) ) { within { @@ -264,6 +266,8 @@ class Parser(source: PeekableSource, val attribution: NodeAttribution) { TokenType.Divide -> InfixOperator.Divide TokenType.Equality -> InfixOperator.Equals TokenType.Inequality -> InfixOperator.NotEquals + TokenType.Mod -> InfixOperator.EuclideanModulo + TokenType.Rem -> InfixOperator.Remainder else -> throw RuntimeException("Unknown Infix Operator") } diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt index 7dadcaf..709b78e 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt @@ -26,6 +26,8 @@ enum class TokenType(vararg properties: TokenTypeProperty) { LeftParentheses(SingleChar('(')), RightParentheses(SingleChar(')')), Negation(SingleChar('!'), Promotion('=', Inequality), OperatorFamily), + Mod(Keyword("mod"), OperatorFamily), + Rem(Keyword("rem"), OperatorFamily), Comma(SingleChar(',')), Period(SingleChar('.')), False(Keyword("false"), KeywordFamily),