diff options
-rw-r--r-- | build.zig | 1 | ||||
-rw-r--r-- | examples/7.src | 2 | ||||
-rw-r--r-- | grammar.ebnf | 2 | ||||
-rw-r--r-- | src/evaluator.zig | 5 | ||||
-rw-r--r-- | src/parser.zig | 43 | ||||
-rw-r--r-- | src/tokenizer.zig | 113 |
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" { |