summary refs log tree commit diff
diff options
context:
space:
mode:
authorBaitinq <manuelpalenzuelamerino@gmail.com>2025-01-12 13:10:52 +0100
committerBaitinq <manuelpalenzuelamerino@gmail.com>2025-01-12 13:10:52 +0100
commit3b97c7c9f1094bbf7704f58f64b70118a5dda6dc (patch)
tree649092f2824a4dbbf0de5acc99e41384b3f6a782
parentEvaluator: Add simple test (diff)
downloadinterpreter-3b97c7c9f1094bbf7704f58f64b70118a5dda6dc.tar.gz
interpreter-3b97c7c9f1094bbf7704f58f64b70118a5dda6dc.tar.bz2
interpreter-3b97c7c9f1094bbf7704f58f64b70118a5dda6dc.zip
Misc: Improve error messages and add todos
-rw-r--r--examples/3.src5
-rw-r--r--examples/4.src3
-rw-r--r--src/evaluator.zig21
-rw-r--r--src/parser.zig7
-rw-r--r--src/tokenizer.zig1
-rw-r--r--todo/1.src1
-rw-r--r--todo/2.src1
7 files changed, 34 insertions, 5 deletions
diff --git a/examples/3.src b/examples/3.src
new file mode 100644
index 0000000..736ab61
--- /dev/null
+++ b/examples/3.src
@@ -0,0 +1,5 @@
+let ten = 10;
+
+let twelve = ten + 2;
+
+print(twelve);
diff --git a/examples/4.src b/examples/4.src
new file mode 100644
index 0000000..7e6662e
--- /dev/null
+++ b/examples/4.src
@@ -0,0 +1,3 @@
+let hello = "hello";
+
+print(hello + " world!");
diff --git a/src/evaluator.zig b/src/evaluator.zig
index fb129b5..e8e1bc5 100644
--- a/src/evaluator.zig
+++ b/src/evaluator.zig
@@ -3,6 +3,7 @@ const parser = @import("parser.zig");
 
 const EvaluatorError = error{
     EvaluationError,
+    OutOfMemory,
 };
 
 pub const Evaluator = struct {
@@ -37,6 +38,7 @@ pub const Evaluator = struct {
     }
 
     fn evaluate_statement(self: *Evaluator, statement: *parser.Node) !void {
+        errdefer std.debug.print("Error evaluating statement\n", .{});
         std.debug.assert(statement.* == parser.Node.STATEMENT);
 
         return switch (statement.STATEMENT.statement.*) {
@@ -47,20 +49,29 @@ pub const Evaluator = struct {
     }
 
     fn evaluate_variable_statement(self: *Evaluator, node: *parser.Node) !void {
+        errdefer std.debug.print("Error evaluating variable statement\n", .{});
         std.debug.assert(node.* == parser.Node.VARIABLE_STATEMENT);
 
         const variable_statement = node.VARIABLE_STATEMENT;
 
+        //TODO: We should lowercase keys no?
         if (variable_statement.is_declaration) {
             try self.variables.put(variable_statement.name, null);
         }
 
-        std.debug.assert(self.variables.contains(variable_statement.name));
+        // Make sure identifier exists
+        _ = try self.get_expression_value(node.VARIABLE_STATEMENT.expression);
 
-        try self.variables.put(variable_statement.name, node.VARIABLE_STATEMENT.expression); //TODO: We really should enforce this at the compiler level
+        if (!self.variables.contains(variable_statement.name)) {
+            std.debug.print("Variable not found: {s}\n", .{variable_statement.name});
+            return EvaluatorError.EvaluationError;
+        }
+
+        try self.variables.put(variable_statement.name, node.VARIABLE_STATEMENT.expression); //TODO: We really should enforce this at the compiler level.
     }
 
     fn evaluate_print_statement(self: *Evaluator, print_statement: *parser.Node) !void {
+        errdefer std.debug.print("Error evaluating print statement\n", .{});
         std.debug.assert(print_statement.* == parser.Node.PRINT_STATEMENT);
 
         const print_value = try self.get_expression_value(print_statement.PRINT_STATEMENT.expression);
@@ -69,12 +80,16 @@ pub const Evaluator = struct {
     }
 
     fn get_expression_value(self: *Evaluator, node: *parser.Node) !i64 {
+        errdefer std.debug.print("Error getting statement value\n", .{});
         std.debug.assert(node.* == parser.Node.EXPRESSION);
 
         return switch (node.EXPRESSION) {
             .NUMBER => |number| number.value,
             .IDENTIFIER => |identifier| {
-                const expression = self.variables.get(identifier.name) orelse return EvaluatorError.EvaluationError;
+                const expression = self.variables.get(identifier.name) orelse {
+                    std.debug.print("Identifier {any} not found\n", .{identifier.name});
+                    return EvaluatorError.EvaluationError;
+                };
                 return try self.get_expression_value(expression.?);
             },
         };
diff --git a/src/parser.zig b/src/parser.zig
index 2b75165..9e27d65 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -68,6 +68,7 @@ pub const Parser = struct {
 
     // Statement ::= (VariableStatement | PrintStatement) SEMICOLON
     fn parse_statement(self: *Parser) ParserError!*Node {
+        errdefer std.debug.print("Error parsing statement\n", .{});
         const token = self.peek_token() orelse return ParserError.ParsingError;
 
         const statement = switch (token) {
@@ -86,6 +87,7 @@ pub const Parser = struct {
 
     // VariableStatement ::= ("let" IDENTIFIER | IDENTIFIER) EQUALS Expression
     fn parse_variable_statement(self: *Parser) ParserError!*Node {
+        errdefer std.debug.print("Error parsing variable statement\n", .{});
         const token = self.peek_token() orelse return ParserError.ParsingError;
 
         var is_declaration: bool = false;
@@ -111,6 +113,7 @@ pub const Parser = struct {
 
     // PrintStatement :== PRINT LPAREN Expression RPAREN
     fn parse_print_statement(self: *Parser) ParserError!*Node {
+        errdefer std.debug.print("Error parsing print statement\n", .{});
         _ = try self.accept_token(tokenizer.TokenType.PRINT);
 
         _ = try self.accept_token(tokenizer.TokenType.LPAREN);
@@ -128,6 +131,7 @@ pub const Parser = struct {
 
     // Expression :== NUMBER | IDENTIFIER
     fn parse_expression(self: *Parser) ParserError!*Node {
+        errdefer std.debug.print("Error parsing expression\n", .{});
         const token = self.consume_token() orelse return ParserError.ParsingError;
 
         return switch (token) {
@@ -145,11 +149,12 @@ pub const Parser = struct {
                     },
                 },
             }),
-            else => unreachable,
+            else => return ParserError.ParsingError,
         };
     }
 
     fn accept_token(self: *Parser, expected_token: tokenizer.TokenType) ParserError!tokenizer.Token {
+        errdefer std.debug.print("Error accepting token: {any}\n", .{expected_token});
         const token = self.peek_token() orelse return ParserError.ParsingError;
 
         if (token != expected_token) return ParserError.ParsingError;
diff --git a/src/tokenizer.zig b/src/tokenizer.zig
index 1d28f72..73a90e8 100644
--- a/src/tokenizer.zig
+++ b/src/tokenizer.zig
@@ -87,7 +87,6 @@ pub const Token = union(TokenType) {
 };
 
 test "simple" {
-    // TODO: Add invalid src test
     const tests = [_]struct {
         buf: []u8,
         tokens: []const Token,
diff --git a/todo/1.src b/todo/1.src
new file mode 100644
index 0000000..e17f230
--- /dev/null
+++ b/todo/1.src
@@ -0,0 +1 @@
+let x = -;
diff --git a/todo/2.src b/todo/2.src
new file mode 100644
index 0000000..31354ec
--- /dev/null
+++ b/todo/2.src
@@ -0,0 +1 @@
+_