language: add boolean and/or operators, change negation syntax

This commit is contained in:
a dinosaur 2023-09-11 20:44:33 +10:00
parent 0aab45094a
commit b0fbf3ee53
7 changed files with 68 additions and 11 deletions

View File

@ -96,6 +96,12 @@ types:
- name: LesserEqual - name: LesserEqual
values: values:
token: "<=" token: "<="
- name: BooleanAnd
values:
token: "and"
- name: BooleanOr
values:
token: "or"
- name: BinaryAnd - name: BinaryAnd
values: values:
token: "&" token: "&"
@ -196,9 +202,9 @@ types:
- name: token - name: token
type: String type: String
enums: enums:
- name: Negate - name: BooleanNot
values: values:
token: "!" token: "not"
- name: UnaryPlus - name: UnaryPlus
values: values:
token: "+" token: "+"

View File

@ -19,6 +19,8 @@ enum class InfixOperator(val token: String) {
Greater(">"), Greater(">"),
GreaterEqual(">="), GreaterEqual(">="),
LesserEqual("<="), LesserEqual("<="),
BooleanAnd("and"),
BooleanOr("or"),
BinaryAnd("&"), BinaryAnd("&"),
BinaryOr("|"), BinaryOr("|"),
BinaryExclusiveOr("^") BinaryExclusiveOr("^")

View File

@ -7,7 +7,7 @@ import kotlinx.serialization.Serializable
@Serializable @Serializable
@SerialName("prefixOperator") @SerialName("prefixOperator")
enum class PrefixOperator(val token: String) { enum class PrefixOperator(val token: String) {
Negate("!"), BooleanNot("not"),
UnaryPlus("+"), UnaryPlus("+"),
UnaryMinus("-"), UnaryMinus("-"),
BinaryNot("~") BinaryNot("~")

View File

@ -92,7 +92,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
override fun visitPrefixOperation(node: PrefixOperation): Any { override fun visitPrefixOperation(node: PrefixOperation): Any {
val value = node.expression.visit(this) val value = node.expression.visit(this)
return when (node.op) { return when (node.op) {
PrefixOperator.Negate -> { PrefixOperator.BooleanNot -> {
if (value !is Boolean) { if (value !is Boolean) {
throw RuntimeException("Cannot negate a value which is not a boolean.") throw RuntimeException("Cannot negate a value which is not a boolean.")
} }
@ -192,6 +192,14 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
else -> {} 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) { 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.")
} }
@ -311,7 +319,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
InfixOperator.Minus -> subtract(convert(left), convert(right)) InfixOperator.Minus -> subtract(convert(left), convert(right))
InfixOperator.Multiply -> multiply(convert(left), convert(right)) InfixOperator.Multiply -> multiply(convert(left), convert(right))
InfixOperator.Divide -> divide(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.BinaryAnd -> binaryAnd(convert(left), convert(right))
InfixOperator.BinaryOr -> binaryOr(convert(left), convert(right)) InfixOperator.BinaryOr -> binaryOr(convert(left), convert(right))
InfixOperator.BinaryExclusiveOr -> binaryExclusiveOr(convert(left), convert(right)) InfixOperator.BinaryExclusiveOr -> binaryExclusiveOr(convert(left), convert(right))
@ -333,7 +341,7 @@ class EvaluationVisitor(root: Scope) : NodeVisitor<Any> {
binaryNot: (T) -> T binaryNot: (T) -> T
): Any { ): Any {
return when (op) { 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.UnaryPlus -> plus(convert(value))
PrefixOperator.UnaryMinus -> minus(convert(value)) PrefixOperator.UnaryMinus -> minus(convert(value))
PrefixOperator.BinaryNot -> binaryNot(convert(value)) PrefixOperator.BinaryNot -> binaryNot(convert(value))

33
examples/boolean.pork Normal file
View File

@ -0,0 +1,33 @@
func buildRow(str, a, b, c, d) {
let checkSeparator = "| "
print("|", str, checkSeparator)
if a { print("✅") } else { print("🚫") }
print(checkSeparator)
if b { print("✅") } else { print("🚫") }
print(checkSeparator)
if c { print("✅") } else { print("🚫") }
print(checkSeparator)
if d { 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("|-----------------------------------------------------|")
}

View File

@ -83,7 +83,7 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
} }
private fun readPrefixOperation(): PrefixOperation = within { 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()) PrefixOperation(convertPrefixOperator(it), readExpression())
} }
} }
@ -157,7 +157,7 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
readParentheses() readParentheses()
} }
TokenType.Negation, TokenType.Plus, TokenType.Minus, TokenType.Tilde -> { TokenType.Not, TokenType.Plus, TokenType.Minus, TokenType.Tilde -> {
readPrefixOperation() readPrefixOperation()
} }
@ -215,7 +215,9 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
TokenType.Lesser, TokenType.Lesser,
TokenType.Greater, TokenType.Greater,
TokenType.LesserEqual, TokenType.LesserEqual,
TokenType.GreaterEqual TokenType.GreaterEqual,
TokenType.And,
TokenType.Or
) )
) { ) {
within { within {
@ -338,10 +340,13 @@ class Parser(source: PeekableSource<Token>, val attribution: NodeAttribution) {
TokenType.Greater -> InfixOperator.Greater TokenType.Greater -> InfixOperator.Greater
TokenType.LesserEqual -> InfixOperator.LesserEqual TokenType.LesserEqual -> InfixOperator.LesserEqual
TokenType.GreaterEqual -> InfixOperator.GreaterEqual TokenType.GreaterEqual -> InfixOperator.GreaterEqual
TokenType.And -> InfixOperator.BooleanAnd
TokenType.Or -> InfixOperator.BooleanOr
else -> throw RuntimeException("Unknown Infix Operator") else -> throw RuntimeException("Unknown Infix Operator")
} }
private fun convertPrefixOperator(token: Token): PrefixOperator = when (token.type) { private fun convertPrefixOperator(token: Token): PrefixOperator = when (token.type) {
TokenType.Not -> PrefixOperator.BooleanNot
TokenType.Plus -> PrefixOperator.UnaryPlus TokenType.Plus -> PrefixOperator.UnaryPlus
TokenType.Minus -> PrefixOperator.UnaryMinus TokenType.Minus -> PrefixOperator.UnaryMinus
TokenType.Tilde -> PrefixOperator.BinaryNot TokenType.Tilde -> PrefixOperator.BinaryNot

View File

@ -13,7 +13,8 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
(it in '0' .. '9')}, KeywordUpgrader), (it in '0' .. '9')}, KeywordUpgrader),
StringLiteral(StringLiteralFamily), StringLiteral(StringLiteralFamily),
Equality(OperatorFamily), Equality(OperatorFamily),
Inequality(OperatorFamily), Inequality(ManyChars("!="), OperatorFamily),
ExclaimationPoint(SingleChar('!'), Promotion('=', Inequality)),
Equals(SingleChar('='), Promotion('=', Equality)), Equals(SingleChar('='), Promotion('=', Equality)),
PlusPlus(ManyChars("++"), OperatorFamily), PlusPlus(ManyChars("++"), OperatorFamily),
MinusMinus(ManyChars("--"), OperatorFamily), MinusMinus(ManyChars("--"), OperatorFamily),
@ -21,6 +22,8 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
Minus(SingleChar('-'), OperatorFamily, Promotion('-', MinusMinus)), Minus(SingleChar('-'), OperatorFamily, Promotion('-', MinusMinus)),
Multiply(SingleChar('*'), OperatorFamily), Multiply(SingleChar('*'), OperatorFamily),
Divide(SingleChar('/'), OperatorFamily), Divide(SingleChar('/'), OperatorFamily),
And(ManyChars("and"), OperatorFamily),
Or(ManyChars("or"), OperatorFamily),
Tilde(SingleChar('~'), OperatorFamily), Tilde(SingleChar('~'), OperatorFamily),
Ampersand(SingleChar('&'), OperatorFamily), Ampersand(SingleChar('&'), OperatorFamily),
Pipe(SingleChar('|'), OperatorFamily), Pipe(SingleChar('|'), OperatorFamily),
@ -35,7 +38,7 @@ enum class TokenType(vararg properties: TokenTypeProperty) {
RightBracket(SingleChar(']')), RightBracket(SingleChar(']')),
LeftParentheses(SingleChar('(')), LeftParentheses(SingleChar('(')),
RightParentheses(SingleChar(')')), RightParentheses(SingleChar(')')),
Negation(SingleChar('!'), Promotion('=', Inequality), OperatorFamily), Not(ManyChars("not"), OperatorFamily),
Mod(ManyChars("mod"), OperatorFamily), Mod(ManyChars("mod"), OperatorFamily),
Rem(ManyChars("rem"), OperatorFamily), Rem(ManyChars("rem"), OperatorFamily),
Comma(SingleChar(',')), Comma(SingleChar(',')),