summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--build.zig1
-rw-r--r--examples/7.src2
-rw-r--r--grammar.ebnf2
-rw-r--r--src/evaluator.zig5
-rw-r--r--src/parser.zig43
-rw-r--r--src/tokenizer.zig113
6 files changed, 72 insertions, 94 deletions
diff --git a/build.zig b/build.zig
index b7e63d6..ea79181 100644
--- a/build.zig
+++ b/build.zig
@@ -102,6 +102,7 @@ pub fn build(b: *std.Build) !void {
             const run_example = b.addSystemCommand(&.{ "zig", "build", "run", "--", example_path });
             run_example.setName(b.fmt("{s}", .{example_path}));
             run_example.expectExitCode(0);
+            run_example.has_side_effects = true;
             examples_step.dependOn(&run_example.step);
         }
     }
diff --git a/examples/7.src b/examples/7.src
index 9bb3c73..9846af5 100644
--- a/examples/7.src
+++ b/examples/7.src
@@ -1,7 +1,7 @@
 let main = () => {
 	let i = 4;
 	
-	if (1 - 1 * 2) == 5 - (10 / 2) - 1 {
+	if (1 - -1 * 2) == 5 - (10 / 2) + 3 {
 		print(i);
 		return i;
 	};
diff --git a/grammar.ebnf b/grammar.ebnf
index 700147e..af2d9ec 100644
--- a/grammar.ebnf
+++ b/grammar.ebnf
@@ -22,7 +22,7 @@ AdditiveExpression ::= MultiplicativeExpression (("+" | "-") MultiplicativeExpre
 
 MultiplicativeExpression ::= UnaryExpression (("*" | "/") UnaryExpression)*
 
-UnaryExpression ::= "!" UnaryExpression | PrimaryExpression
+UnaryExpression ::= ("!" | "-") UnaryExpression | PrimaryExpression
 
 PrimaryExpression ::= NUMBER | BOOLEAN | IDENTIFIER | FunctionCallStatement | LPAREN Expression RPAREN
 
diff --git a/src/evaluator.zig b/src/evaluator.zig
index 9f8b61f..798d66c 100644
--- a/src/evaluator.zig
+++ b/src/evaluator.zig
@@ -174,6 +174,10 @@ pub const Evaluator = struct {
             },
             .UNARY_EXPRESSION => |x| {
                 const val = try self.get_expression_value(x.expression) orelse return EvaluatorError.EvaluationError;
+                if (!x.negation) {
+                    std.debug.assert(val.* == .NUMBER);
+                    return try self.create_variable(.{ .NUMBER = -val.NUMBER });
+                }
                 std.debug.assert(val.* == .BOOLEAN);
                 return try self.create_variable(.{ .BOOLEAN = !val.BOOLEAN });
             },
@@ -268,7 +272,6 @@ const Environment = struct {
             .allocator = allocator,
         };
 
-        //TODO: Add more scopes when evaluating functions
         // Create global scope
         try self.create_scope();
 
diff --git a/src/parser.zig b/src/parser.zig
index 966cad3..a13f1cc 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -6,23 +6,7 @@ const ParserError = error{
     OutOfMemory,
 };
 
-const NodeType = enum {
-    PROGRAM,
-    STATEMENT,
-    ASSIGNMENT_STATEMENT,
-    FUNCTION_CALL_STATEMENT,
-    IF_STATEMENT,
-    WHILE_STATEMENT,
-    EQUALITY_EXPRESSION,
-    ADDITIVE_EXPRESSION,
-    MULTIPLICATIVE_EXPRESSION,
-    UNARY_EXPRESSION,
-    PRIMARY_EXPRESSION,
-    FUNCTION_DEFINITION,
-    RETURN_STATEMENT,
-};
-
-pub const Node = union(NodeType) {
+pub const Node = union(enum) {
     PROGRAM: struct {
         statements: []*Node,
     },
@@ -159,7 +143,7 @@ pub const Parser = struct {
         return self.create_node(.{
             .ASSIGNMENT_STATEMENT = .{
                 .is_declaration = is_declaration,
-                .name = try self.allocator.dupe(u8, identifier.IDENTIFIER),
+                .name = try self.allocator.dupe(u8, identifier.type.IDENTIFIER),
                 .expression = @constCast(expression),
             },
         });
@@ -178,7 +162,7 @@ pub const Parser = struct {
         _ = try self.parse_token(tokenizer.TokenType.RPAREN);
 
         return self.create_node(.{ .FUNCTION_CALL_STATEMENT = .{
-            .name = try self.allocator.dupe(u8, identifier.IDENTIFIER),
+            .name = try self.allocator.dupe(u8, identifier.type.IDENTIFIER),
             .arguments = arguments,
         } });
     }
@@ -322,18 +306,19 @@ pub const Parser = struct {
         return lhs;
     }
 
-    // UnaryExpression ::= "!" UnaryExpression | PrimaryExpression
+    // 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.BANG) != null;
+        const not = self.accept_token(tokenizer.TokenType.BANG) != null;
+        const minus = self.accept_token(tokenizer.TokenType.MINUS) != null;
 
-        if (!negation) {
+        if (!not and !minus) {
             return try self.parse_primary_expression();
         }
 
         return self.create_node(.{ .UNARY_EXPRESSION = .{
-            .negation = negation,
+            .negation = not,
             .expression = try self.parse_unary_expression(),
         } });
     }
@@ -352,7 +337,7 @@ pub const Parser = struct {
 
         const token = self.consume_token() orelse return ParserError.ParsingError;
 
-        return switch (token) {
+        return switch (token.type) {
             .NUMBER => |number_token| try self.create_node(.{
                 .PRIMARY_EXPRESSION = .{
                     .NUMBER = .{
@@ -420,7 +405,7 @@ pub const Parser = struct {
             try node_list.append(try self.create_node(.{
                 .PRIMARY_EXPRESSION = .{
                     .IDENTIFIER = .{
-                        .name = try self.allocator.dupe(u8, ident.IDENTIFIER),
+                        .name = try self.allocator.dupe(u8, ident.type.IDENTIFIER),
                     },
                 },
             }));
@@ -443,11 +428,11 @@ pub const Parser = struct {
         });
     }
 
-    fn parse_token(self: *Parser, expected_token: tokenizer.TokenType) ParserError!tokenizer.Token {
+    fn parse_token(self: *Parser, expected_token: std.meta.Tag(tokenizer.TokenType)) ParserError!tokenizer.Token {
         errdefer if (!self.try_context) std.debug.print("Error accepting token: {any}\n", .{expected_token});
         const token = self.peek_token() orelse return ParserError.ParsingError;
 
-        if (token != expected_token) {
+        if (expected_token != std.meta.activeTag(token.type)) {
             if (!self.try_context) std.debug.print("Expected {any} - found {any}\n", .{ expected_token, token });
             return ParserError.ParsingError;
         }
@@ -468,9 +453,9 @@ pub const Parser = struct {
         return node;
     }
 
-    fn accept_token(self: *Parser, token: tokenizer.TokenType) ?tokenizer.Token {
+    fn accept_token(self: *Parser, token_type: std.meta.Tag(tokenizer.TokenType)) ?tokenizer.Token {
         const curr_token = self.peek_token() orelse return null;
-        if (curr_token == token) {
+        if (std.meta.activeTag(curr_token.type) == token_type) {
             return self.consume_token();
         }
         return null;
diff --git a/src/tokenizer.zig b/src/tokenizer.zig
index e125110..f028d74 100644
--- a/src/tokenizer.zig
+++ b/src/tokenizer.zig
@@ -4,53 +4,30 @@ const TokenizerError = error{
     TokenizingError,
 };
 
-pub const TokenType = enum {
+pub const TokenType = union(enum) {
     // Keywords
-    LET,
-    IF,
-    WHILE,
-    RETURN,
-    ARROW,
-
-    // Identifiers
-    IDENTIFIER,
-
-    // Literals
-    NUMBER,
-    BOOLEAN,
-
-    // Operators
-    EQUALS,
-    PLUS,
-    MINUS,
-    MUL,
-    DIV,
-    BANG,
-
-    // Punctuation
-    SEMICOLON,
-    COMMA,
-    LPAREN,
-    RPAREN,
-    LBRACE,
-    RBRACE,
-};
-
-pub const Token = union(TokenType) {
     LET: void,
     IF: void,
     WHILE: void,
     RETURN: void,
     ARROW: void,
+
+    // Identifiers
     IDENTIFIER: []u8,
+
+    // Literals
     NUMBER: i64,
     BOOLEAN: bool,
+
+    // Operators
     EQUALS: void,
     PLUS: void,
     MINUS: void,
     MUL: void,
     DIV: void,
     BANG: void,
+
+    // Punctuation
     SEMICOLON: void,
     COMMA: void,
     LPAREN: void,
@@ -59,6 +36,14 @@ pub const Token = union(TokenType) {
     RBRACE: void,
 };
 
+pub const Token = struct {
+    //TODO: Add source code info
+    col: u64,
+    row: u64,
+
+    type: TokenType,
+};
+
 pub const Tokenizer = struct {
     buf: []u8,
     offset: u64,
@@ -68,48 +53,45 @@ pub const Tokenizer = struct {
     }
 
     pub fn next(self: *Tokenizer) TokenizerError!?Token {
-        defer self.offset += 1;
         self.skip_whitespace();
         self.skip_comments();
         self.skip_whitespace();
 
         if (self.offset >= self.buf.len) return null;
 
-        const c = self.buf[self.offset];
-
-        if (self.accept_substr("let")) return Token{ .LET = void{} };
-        if (self.accept_substr("if")) return Token{ .IF = void{} };
-        if (self.accept_substr("while")) return Token{ .WHILE = void{} };
-        if (self.accept_substr("return")) return Token{ .RETURN = void{} };
-        if (self.accept_substr("true")) return Token{ .BOOLEAN = true };
-        if (self.accept_substr("false")) return Token{ .BOOLEAN = false };
-
-        if (self.accept_substr("=>")) return Token{ .ARROW = void{} };
-        if (c == ';') return Token{ .SEMICOLON = void{} };
-        if (c == ',') return Token{ .COMMA = void{} };
-        if (c == '(') return Token{ .LPAREN = void{} };
-        if (c == ')') return Token{ .RPAREN = void{} };
-        if (c == '{') return Token{ .LBRACE = void{} };
-        if (c == '}') return Token{ .RBRACE = void{} };
-        if (c == '=') return Token{ .EQUALS = void{} };
-        if (c == '+') return Token{ .PLUS = void{} };
-        if (c == '-') return Token{ .MINUS = void{} };
-        if (c == '*') return Token{ .MUL = void{} };
-        if (c == '/') return Token{ .DIV = void{} };
-        if (c == '!') return Token{ .BANG = void{} };
+        if (self.accept_string("let")) return self.create_token(.{ .LET = void{} });
+        if (self.accept_string("if")) return self.create_token(.{ .IF = void{} });
+        if (self.accept_string("while")) return self.create_token(.{ .WHILE = void{} });
+        if (self.accept_string("return")) return self.create_token(.{ .RETURN = void{} });
+        if (self.accept_string("true")) return self.create_token(.{ .BOOLEAN = true });
+        if (self.accept_string("false")) return self.create_token(.{ .BOOLEAN = false });
+
+        if (self.accept_string("=>")) return self.create_token(.{ .ARROW = void{} });
+        if (self.accept_string(";")) return self.create_token(.{ .SEMICOLON = void{} });
+        if (self.accept_string(",")) return self.create_token(.{ .COMMA = void{} });
+        if (self.accept_string("(")) return self.create_token(.{ .LPAREN = void{} });
+        if (self.accept_string(")")) return self.create_token(.{ .RPAREN = void{} });
+        if (self.accept_string("{")) return self.create_token(.{ .LBRACE = void{} });
+        if (self.accept_string("}")) return self.create_token(.{ .RBRACE = void{} });
+        if (self.accept_string("=")) return self.create_token(.{ .EQUALS = void{} });
+        if (self.accept_string("+")) return self.create_token(.{ .PLUS = void{} });
+        if (self.accept_string("-")) return self.create_token(.{ .MINUS = void{} });
+        if (self.accept_string("*")) return self.create_token(.{ .MUL = void{} });
+        if (self.accept_string("/")) return self.create_token(.{ .DIV = void{} });
+        if (self.accept_string("!")) return self.create_token(.{ .BANG = void{} });
 
         const string = self.consume_string();
         if (string.len == 0) return TokenizerError.TokenizingError;
 
-        if (std.fmt.parseInt(i32, string, 10) catch null) |i| return Token{ .NUMBER = i };
+        if (std.fmt.parseInt(i32, string, 10) catch null) |i| return self.create_token(.{ .NUMBER = i });
 
-        return Token{ .IDENTIFIER = string };
+        return self.create_token(.{ .IDENTIFIER = string });
     }
 
     fn skip_comments(self: *Tokenizer) void {
-        if (!self.accept_substr("/*")) return;
+        if (!self.accept_string("/*")) return;
 
-        while (!self.accept_substr("*/")) {
+        while (!self.accept_string("*/")) {
             self.offset += 1;
         }
     }
@@ -127,17 +109,16 @@ pub const Tokenizer = struct {
         defer self.offset = if (self.offset > 0) self.offset - 1 else self.offset;
         const start = self.offset;
         while (true) {
+            defer self.offset += 1;
             if (self.offset >= self.buf.len) return self.buf[start..self.offset];
 
             const c = self.buf[self.offset];
 
             if (!std.ascii.isAlphanumeric(c) and c != '_') return self.buf[start..self.offset];
-
-            self.offset += 1;
         }
     }
 
-    fn accept_substr(self: *Tokenizer, substr: []const u8) bool {
+    fn accept_string(self: *Tokenizer, substr: []const u8) bool {
         if (self.offset + substr.len > self.buf.len) return false;
         if (std.mem.eql(u8, self.buf[self.offset .. self.offset + substr.len], substr)) {
             self.offset += substr.len;
@@ -145,6 +126,14 @@ pub const Tokenizer = struct {
         }
         return false;
     }
+
+    fn create_token(self: *Tokenizer, token_type: TokenType) Token {
+        return Token{
+            .col = self.offset,
+            .row = self.offset,
+            .type = token_type,
+        };
+    }
 };
 
 test "simple" {