diff options
Diffstat (limited to 'src/parser.zig')
| -rw-r--r-- | src/parser.zig | 128 |
1 files changed, 103 insertions, 25 deletions
diff --git a/src/parser.zig b/src/parser.zig index 422c9cb..18b2348 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -3,46 +3,112 @@ const tok = @import("tokenize.zig"); const Iterator = tok.Iterator; const Token = tok.Token; -const ParsingError = error{ InvalidExpression, ExpectedExit, ExpectedSemicolon }; +const ParsingError = error{ + InvalidExpression, + ExpectedExit, + ExpectedSemicolon, + ExpectedEqual, + ExpectedIdentifier, + InvalidStatement, +}; + +pub const NodeExpr = union(enum) { + intLit: NodeIntlit, + ident: NodeIdent, +}; -pub const NodeExpr = struct { - intLit: Token, +pub const NodeStmt = union(enum) { + exit: NodeExit, + value: NodeValue, +}; + +pub const NodeValue = struct { + ident: Token, + value: NodeExpr, + isConst: bool, }; pub const NodeExit = struct { expr: NodeExpr, }; +pub const NodeIntlit = struct { + intlit: Token, +}; + +pub const NodeIdent = struct { + ident: Token, +}; + pub const Parser = struct { tokens: Iterator(Token), + allocator: std.mem.Allocator, + nodes: std.ArrayList(NodeStmt), - pub fn init(tokens: []Token) Parser { + pub fn init(allocator: std.mem.Allocator, tokens: []Token) Parser { return .{ + .allocator = allocator, .tokens = Iterator(Token).init(tokens), + .nodes = std.ArrayList(NodeStmt).init(allocator), }; } - fn parseExpr(self: *Parser) !NodeExpr { - if (tok.checkType(self.tokens.peek().?, tok.TokenType.intLit)) - return NodeExpr{ .intLit = self.tokens.consume().? }; - return ParsingError.InvalidExpression; + pub fn deinit(self: *Parser) void { + self.nodes.deinit(); } - pub fn parse(self: *Parser) !NodeExit { - var root: NodeExit = undefined; - while (self.tokens.peek()) |token| { - switch (token) { - .exit => { - self.tokens.skip(); - root.expr = try self.parseExpr(); - if (!tok.checkType(self.tokens.peek().?, tok.TokenType.semiCol)) - return ParsingError.ExpectedSemicolon; - self.tokens.skip(); + fn parseExpr(self: *Parser) !NodeExpr { + return switch (self.tokens.peek().?) { + .intLit => NodeExpr{ + .intLit = NodeIntlit{ + .intlit = (try self.tokens.consume(.intLit)).?, + }, + }, + .ident => NodeExpr{ + .ident = NodeIdent{ + .ident = (try self.tokens.consume(.ident)).?, }, - else => return ParsingError.ExpectedExit, - } - } - return root; + }, + else => ParsingError.InvalidExpression, + }; + } + + fn parseStmt(self: *Parser) !NodeStmt { + return switch (self.tokens.peek().?) { + .exit => NodeStmt{ .exit = try self.parseExit() }, + .constant => NodeStmt{ .value = try self.parseValue(true) }, + .variable => NodeStmt{ .value = try self.parseValue(false) }, + else => ParsingError.InvalidStatement, + }; + } + + fn parseExit(self: *Parser) !NodeExit { + _ = try self.tokens.consume(.exit); + const expr = try self.parseExpr(); + _ = try self.tokens.consume(.semiCol); + return NodeExit{ + .expr = expr, + }; + } + + fn parseValue(self: *Parser, isConst: bool) !NodeValue { + self.tokens.skip(); + const ident = (try self.tokens.consume(.ident)).?; + _ = try self.tokens.consume(.equal); + const expr = try self.parseExpr(); + _ = try self.tokens.consume(.semiCol); + return NodeValue{ + .ident = ident, + .value = expr, + .isConst = isConst, + }; + } + + pub fn parse(self: *Parser) ![]const NodeStmt { + while (self.tokens.peek()) |_| + try self.nodes.append(try self.parseStmt()); + + return self.nodes.items; } }; @@ -52,8 +118,20 @@ test "Parser" { var tokenizer = tok.Tokenizer.init(std.testing.allocator, src); defer tokenizer.deinit(); const toks = try tokenizer.tokenize(); - var parser = Parser.init(toks); + var parser = Parser.init(std.testing.allocator, toks); + defer parser.deinit(); const parseTree = try parser.parse(); - const exp = NodeExit{ .expr = NodeExpr{ .intLit = Token{ .intLit = 120 } } }; - try expect(std.meta.eql(parseTree, exp)); + const exp: []const NodeStmt = &[_]NodeStmt{NodeStmt{ + .exit = NodeExit{ + .expr = NodeExpr{ + .intLit = NodeIntlit{ + .intlit = Token{ + .intLit = 120, + }, + }, + }, + }, + }}; + for (parseTree, exp) |stmt, expStmt| + try expect(std.meta.eql(stmt, expStmt)); } |
