summary refs log tree commit diff
diff options
context:
space:
mode:
authorBaitinq <manuelpalenzuelamerino@gmail.com>2025-01-21 00:32:14 +0100
committerBaitinq <manuelpalenzuelamerino@gmail.com>2025-01-21 00:32:14 +0100
commit967dc36c30abbab9e2983568feab9bb514ab58df (patch)
treedd038d87758bfe17edba4c1ba5457b1ebbde9184
parentParser: Add support for parenthesis grouping (diff)
downloadinterpreter-967dc36c30abbab9e2983568feab9bb514ab58df.tar.gz
interpreter-967dc36c30abbab9e2983568feab9bb514ab58df.tar.bz2
interpreter-967dc36c30abbab9e2983568feab9bb514ab58df.zip
Feature: Add support for NOT unary expression
-rw-r--r--examples/9.src3
-rw-r--r--grammar.ebnf4
-rw-r--r--src/evaluator.zig5
-rw-r--r--src/parser.zig27
-rw-r--r--src/tokenizer.zig3
5 files changed, 37 insertions, 5 deletions
diff --git a/examples/9.src b/examples/9.src
index d21ae71..f3ab389 100644
--- a/examples/9.src
+++ b/examples/9.src
@@ -1,7 +1,8 @@
 let main = () => {
 	let i = true;
+	i = !i;
 
-	if i {
+	if !i {
 		print(i);
 		return 1;
 	};
diff --git a/grammar.ebnf b/grammar.ebnf
index a251f26..33a6574 100644
--- a/grammar.ebnf
+++ b/grammar.ebnf
@@ -16,7 +16,9 @@ Expression   ::= EqualityExpression | AdditiveExpression | FunctionDefinition
 
 EqualityExpression ::= AdditiveExpression "==" AdditiveExpression
 
-AdditiveExpression ::= PrimaryExpression (("+" | "-") PrimaryExpression)*
+AdditiveExpression ::= UnaryExpression (("+" | "-") UnaryExpression)*
+
+UnaryExpression ::= "!" UnaryExpression | PrimaryExpression
 
 PrimaryExpression ::= NUMBER | BOOLEAN | IDENTIFIER | FunctionCallStatement | LPAREN Expression RPAREN
 
diff --git a/src/evaluator.zig b/src/evaluator.zig
index f35956a..c1997f3 100644
--- a/src/evaluator.zig
+++ b/src/evaluator.zig
@@ -144,6 +144,11 @@ pub const Evaluator = struct {
                 if (x.addition) return try self.create_variable(.{ .NUMBER = lhs.NUMBER + rhs.NUMBER });
                 return try self.create_variable(.{ .NUMBER = lhs.NUMBER - rhs.NUMBER });
             },
+            .UNARY_EXPRESSION => |x| {
+                const val = try self.get_expression_value(x.expression) orelse return EvaluatorError.EvaluationError;
+                std.debug.assert(val.* == .BOOLEAN);
+                return try self.create_variable(.{ .BOOLEAN = !val.BOOLEAN });
+            },
             .EQUALITY_EXPRESSION => |x| {
                 const lhs = try self.get_expression_value(x.lhs) orelse return EvaluatorError.EvaluationError;
                 const rhs = try self.get_expression_value(x.rhs) orelse return EvaluatorError.EvaluationError;
diff --git a/src/parser.zig b/src/parser.zig
index ce5522d..f574161 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -15,6 +15,7 @@ const NodeType = enum {
     EXPRESSION,
     EQUALITY_EXPRESSION,
     ADDITIVE_EXPRESSION,
+    UNARY_EXPRESSION,
     PRIMARY_EXPRESSION,
     FUNCTION_DEFINITION,
     RETURN_STATEMENT,
@@ -58,6 +59,10 @@ pub const Node = union(NodeType) {
         lhs: *Node,
         rhs: *Node,
     },
+    UNARY_EXPRESSION: struct {
+        negation: bool,
+        expression: *Node,
+    },
     PRIMARY_EXPRESSION: union(enum) {
         NUMBER: struct {
             value: i64,
@@ -244,11 +249,11 @@ pub const Parser = struct {
         } });
     }
 
-    // AdditiveExpression ::= PrimaryExpression (("+" | "-") PrimaryExpression)*
+    // AdditiveExpression ::= UnaryExpression (("+" | "-") UnaryExpression)*
     fn parse_additive_expression(self: *Parser) ParserError!*Node {
         errdefer if (!self.try_context) std.debug.print("Error parsing additive expression\n", .{});
 
-        var lhs = try self.parse_primary_expression();
+        var lhs = try self.parse_unary_expression();
 
         while (true) {
             const plus = self.accept_token(tokenizer.TokenType.PLUS);
@@ -256,7 +261,7 @@ pub const Parser = struct {
 
             if (plus == null and minus == null) break;
 
-            const rhs = try self.parse_primary_expression();
+            const rhs = try self.parse_unary_expression();
 
             lhs = try self.create_node(.{ .ADDITIVE_EXPRESSION = .{
                 .addition = plus != null,
@@ -268,6 +273,22 @@ pub const Parser = struct {
         return lhs;
     }
 
+    // UnaryExpression ::= "!" UnaryExpression | PrimaryExpression
+    fn parse_unary_expression(self: *Parser) ParserError!*Node {
+        errdefer if (!self.try_context) std.debug.print("Error parsing unary expression\n", .{});
+
+        const negation = self.accept_token(tokenizer.TokenType.NOT) != null;
+
+        if (!negation) {
+            return try self.parse_primary_expression();
+        }
+
+        return self.create_node(.{ .UNARY_EXPRESSION = .{
+            .negation = negation,
+            .expression = try self.parse_unary_expression(),
+        } });
+    }
+
     // PrimaryExpression ::= NUMBER | BOOLEAN | IDENTIFIER | FunctionCallStatement | LPAREN Expression RPAREN
     fn parse_primary_expression(self: *Parser) ParserError!*Node {
         errdefer if (!self.try_context) std.debug.print("Error parsing primary expression\n", .{});
diff --git a/src/tokenizer.zig b/src/tokenizer.zig
index 6765ea9..d137763 100644
--- a/src/tokenizer.zig
+++ b/src/tokenizer.zig
@@ -22,6 +22,7 @@ pub const TokenType = enum {
     EQUALS,
     PLUS,
     MINUS,
+    NOT,
 
     // Punctuation
     SEMICOLON,
@@ -43,6 +44,7 @@ pub const Token = union(TokenType) {
     EQUALS: void,
     PLUS: void,
     MINUS: void,
+    NOT: void,
     SEMICOLON: void,
     COMMA: void,
     LPAREN: void,
@@ -79,6 +81,7 @@ pub const Tokenizer = struct {
         if (c == '=') return Token{ .EQUALS = void{} };
         if (c == '+') return Token{ .PLUS = void{} };
         if (c == '-') return Token{ .MINUS = void{} };
+        if (c == '!') return Token{ .NOT = void{} };
 
         const string = self.consume_string();
         if (string.len == 0) return TokenizerError.TokenizingError;