Skip to content

Commit

Permalink
language: add boolean and/or operators, change negation syntax (#7)
Browse files Browse the repository at this point in the history
* language: add boolean and/or operators, change negation syntax

* examples: simplify row builder using arrays
  • Loading branch information
ScrelliCopter authored Sep 11, 2023
1 parent 0aab450 commit a07e0fe
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 11 deletions.
10 changes: 8 additions & 2 deletions ast/src/main/ast/pork.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ types:
- name: LesserEqual
values:
token: "<="
- name: BooleanAnd
values:
token: "and"
- name: BooleanOr
values:
token: "or"
- name: BinaryAnd
values:
token: "&"
Expand Down Expand Up @@ -196,9 +202,9 @@ types:
- name: token
type: String
enums:
- name: Negate
- name: BooleanNot
values:
token: "!"
token: "not"
- name: UnaryPlus
values:
token: "+"
Expand Down
2 changes: 2 additions & 0 deletions ast/src/main/kotlin/gay/pizza/pork/ast/InfixOperator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ enum class InfixOperator(val token: String) {
Greater(">"),
GreaterEqual(">="),
LesserEqual("<="),
BooleanAnd("and"),
BooleanOr("or"),
BinaryAnd("&"),
BinaryOr("|"),
BinaryExclusiveOr("^")
Expand Down
2 changes: 1 addition & 1 deletion ast/src/main/kotlin/gay/pizza/pork/ast/PrefixOperator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import kotlinx.serialization.Serializable
@Serializable
@SerialName("prefixOperator")
enum class PrefixOperator(val token: String) {
Negate("!"),
BooleanNot("not"),
UnaryPlus("+"),
UnaryMinus("-"),
BinaryNot("~")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
override fun visitPrefixOperation(node: PrefixOperation): Any {
val value = node.expression.visit(this)
return when (node.op) {
PrefixOperator.Negate -> {
PrefixOperator.BooleanNot -> {
if (value !is Boolean) {
throw RuntimeException("Cannot negate a value which is not a boolean.")
}
Expand Down Expand Up @@ -192,6 +192,14 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
else -> {}
}

if (left is Boolean && right is Boolean) {
when (node.op) {
InfixOperator.BooleanAnd -> return left && right
InfixOperator.BooleanOr -> return left || right
else -> {}
}
}

if (left !is Number || right !is Number) {
throw RuntimeException("Failed to evaluate infix operation, bad types.")
}
Expand Down Expand Up @@ -311,7 +319,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
InfixOperator.Minus -> subtract(convert(left), convert(right))
InfixOperator.Multiply -> multiply(convert(left), convert(right))
InfixOperator.Divide -> divide(convert(left), convert(right))
InfixOperator.Equals, InfixOperator.NotEquals -> throw RuntimeException("Unable to handle operation $op")
InfixOperator.Equals, InfixOperator.NotEquals, InfixOperator.BooleanAnd, InfixOperator.BooleanOr -> throw RuntimeException("Unable to handle operation $op")
InfixOperator.BinaryAnd -> binaryAnd(convert(left), convert(right))
InfixOperator.BinaryOr -> binaryOr(convert(left), convert(right))
InfixOperator.BinaryExclusiveOr -> binaryExclusiveOr(convert(left), convert(right))
Expand All @@ -333,7 +341,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
binaryNot: (T) -> T
): Any {
return when (op) {
PrefixOperator.Negate -> throw RuntimeException("Unable to handle operation $op")
PrefixOperator.BooleanNot -> throw RuntimeException("Unable to handle operation $op")
PrefixOperator.UnaryPlus -> plus(convert(value))
PrefixOperator.UnaryMinus -> minus(convert(value))
PrefixOperator.BinaryNot -> binaryNot(convert(value))
Expand Down
30 changes: 30 additions & 0 deletions examples/boolean.pork
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
func buildRow(str, a, b, c, d) {
let checkSeparator = " "
print("|", str, "| ")
for i in [a, b, c, d] {
print(checkSeparator)
if a { print("✅|") } else { print("🚫|") }
}
println()
}

export func main() {
println("| | a=🚫 b=🚫| a=✅b=🚫| a=🚫b=✅| a=✅b=✅|")
buildRow(" a == b", false == false, true == false, false == true, true == true)
buildRow("!a == b", (not false) == false, (not true) == false, (not false) == true, (not true) == true)
buildRow(" a == !b", false == (not false), true == (not false), false == (not true), true == (not true))
buildRow("!a == !b", (not false) == (not false), (not true) == (not false), (not false) == (not true), (not true) == (not true))
buildRow(" a != b", false != false, true != false, false != true, true != true)
buildRow("!a != b", (not false) != false, (not true) != false, (not false) != true, (not true) != true)
buildRow(" a != !b", false != (not false), true != (not false), false != (not true), true != (not true))
buildRow("!a != !b", (not false) != (not false), (not true) != (not false), (not false) != (not true), (not true) != (not true))
buildRow(" a && b", false and false, true and false, false and true, true and true)
buildRow("!a && b", (not false) and false, (not true) and false, (not false) and true, (not true) and true)
buildRow(" a && !b", false and (not false), true and (not false), false and (not true), true and (not true))
buildRow("!a && !b", (not false) and (not false), (not true) and (not false), (not false) and (not true), (not true) and (not true))
buildRow(" a || b", false or false, true or false, false or true, true or true)
buildRow("!a || b", (not false) or false, (not true) or false, (not false) or true, (not true) or true)
buildRow(" a || !b", false or (not false), true or (not false), false or (not true), true or (not true))
buildRow("!a || !b", (not false) or (not false), (not true) or (not false), (not false) or (not true), (not true) or (not true))
println("|------------------------------------------------------|")
}
11 changes: 8 additions & 3 deletions parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
}

private fun readPrefixOperation(): PrefixOperation = within {
expect(TokenType.Negation, TokenType.Plus, TokenType.Minus, TokenType.Tilde) {
expect(TokenType.Not, TokenType.Plus, TokenType.Minus, TokenType.Tilde) {
PrefixOperation(convertPrefixOperator(it), readExpression())
}
}
Expand Down Expand Up @@ -157,7 +157,7 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
readParentheses()
}

TokenType.Negation, TokenType.Plus, TokenType.Minus, TokenType.Tilde -> {
TokenType.Not, TokenType.Plus, TokenType.Minus, TokenType.Tilde -> {
readPrefixOperation()
}

Expand Down Expand Up @@ -215,7 +215,9 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
TokenType.Lesser,
TokenType.Greater,
TokenType.LesserEqual,
TokenType.GreaterEqual
TokenType.GreaterEqual,
TokenType.And,
TokenType.Or
)
) {
within {
Expand Down Expand Up @@ -338,10 +340,13 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
TokenType.Greater -> InfixOperator.Greater
TokenType.LesserEqual -> InfixOperator.LesserEqual
TokenType.GreaterEqual -> InfixOperator.GreaterEqual
TokenType.And -> InfixOperator.BooleanAnd
TokenType.Or -> InfixOperator.BooleanOr
else -> throw RuntimeException("Unknown Infix Operator")
}

private fun convertPrefixOperator(token: Token): PrefixOperator = when (token.type) {
TokenType.Not -> PrefixOperator.BooleanNot
TokenType.Plus -> PrefixOperator.UnaryPlus
TokenType.Minus -> PrefixOperator.UnaryMinus
TokenType.Tilde -> PrefixOperator.BinaryNot
Expand Down
7 changes: 5 additions & 2 deletions parser/src/main/kotlin/gay/pizza/pork/parser/TokenType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
(it in '0' .. '9')}, KeywordUpgrader),
StringLiteral(StringLiteralFamily),
Equality(OperatorFamily),
Inequality(OperatorFamily),
Inequality(ManyChars("!="), OperatorFamily),
ExclaimationPoint(SingleChar('!'), Promotion('=', Inequality)),
Equals(SingleChar('='), Promotion('=', Equality)),
PlusPlus(ManyChars("++"), OperatorFamily),
MinusMinus(ManyChars("--"), OperatorFamily),
Plus(SingleChar('+'), OperatorFamily, Promotion('+', PlusPlus)),
Minus(SingleChar('-'), OperatorFamily, Promotion('-', MinusMinus)),
Multiply(SingleChar('*'), OperatorFamily),
Divide(SingleChar('/'), OperatorFamily),
And(ManyChars("and"), OperatorFamily),
Or(ManyChars("or"), OperatorFamily),
Tilde(SingleChar('~'), OperatorFamily),
Ampersand(SingleChar('&'), OperatorFamily),
Pipe(SingleChar('|'), OperatorFamily),
Expand All @@ -35,7 +38,7 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
RightBracket(SingleChar(']')),
LeftParentheses(SingleChar('(')),
RightParentheses(SingleChar(')')),
Negation(SingleChar('!'), Promotion('=', Inequality), OperatorFamily),
Not(ManyChars("not"), OperatorFamily),
Mod(ManyChars("mod"), OperatorFamily),
Rem(ManyChars("rem"), OperatorFamily),
Comma(SingleChar(',')),
Expand Down

0 comments on commit a07e0fe

Please sign in to comment.