language: euclidean modulo and remainder infix operators (#3)

This commit is contained in:
a dinosaur 2023-09-10 12:41:20 +10:00 committed by GitHub
parent 03c278f5b1
commit 0024a8b141
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 34 additions and 7 deletions

View File

@ -64,6 +64,12 @@ types:
- name: NotEquals
values:
token: "!="
- name: EuclideanModulo
values:
token: "mod"
- name: Remainder
values:
token: "rem"
InfixOperation:
parent: Expression
values:

View File

@ -12,5 +12,7 @@ enum class InfixOperator(val token: String) {
Multiply("*"),
Divide("/"),
Equals("=="),
NotEquals("!=")
NotEquals("!="),
EuclideanModulo("mod"),
Remainder("rem")
}

View File

@ -1,6 +1,7 @@
package gay.pizza.pork.evaluator
import gay.pizza.pork.ast.*
import kotlin.math.abs
class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
private var currentScope: Scope = root
@ -105,7 +106,9 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
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<Any> {
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<Any> {
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<Any> {
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<Any> {
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")
}
}

View File

@ -167,7 +167,9 @@ class Parser(source: PeekableSource<Token>, 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<Token>, 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")
}

View File

@ -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),