diff --git a/src/ast.zig b/src/ast.zig index b08c4f7..ce9c60e 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -3,6 +3,7 @@ const tokens = @import("tokens.zig"); const Token = tokens.Token; pub const NodeList = std.ArrayList(*Node); +pub const StmtList = std.ArrayList(*Stmt); pub const ExprList = std.ArrayList(*Expr); pub const ParamList = std.ArrayList(ParamDecl); pub const ConstList = std.ArrayList(SingleConst); @@ -14,6 +15,7 @@ pub const NodeType = enum { ConstDecl, Block, Expr, + Stmt, }; pub const ParamDecl = struct { @@ -26,14 +28,12 @@ pub const ParamDecl = struct { pub const FnDecl = struct { func_name: Token, params: ParamList, - body: ExprList, + body: StmtList, }; pub const SingleConst = struct { name: Token, - - // TODO expr - value: Token, + expr: *Expr, }; pub const BinaryExpr = struct { @@ -61,14 +61,26 @@ pub const Expr = union(enum) { Grouping: *Expr, }; +pub const Stmt = union(enum) { + Expr: *Expr, + Println: *Expr, + + pub fn mkPrintln(allocator: *std.mem.Allocator, expr: *Expr) !*Stmt { + var println = try allocator.create(Stmt); + println.* = Stmt{ .Println = expr }; + return println; + } +}; + pub const Node = union(NodeType) { Root: NodeList, FnDecl: FnDecl, ConstDecl: ConstList, - // TODO StmtList - Block: ExprList, + Block: StmtList, + Expr: *Expr, + Stmt: *Stmt, }; pub fn mkRoot(allocator: *std.mem.Allocator) !*Node { @@ -103,9 +115,9 @@ pub fn printNode(node: *Node, ident: usize) void { ); } - for (decl.body.toSlice()) |expr| { + for (decl.body.toSlice()) |stmt| { printIdent(ident + 1); - printExpr(expr); + printStmt(stmt); std.debug.warn("\n"); } }, @@ -115,10 +127,12 @@ pub fn printNode(node: *Node, ident: usize) void { for (consts.toSlice()) |const_decl| { print( ident + 1, - "'{}' = '{}'\n", + "{} = ", const_decl.name.lexeme, - const_decl.value.lexeme, ); + + printExpr(const_decl.expr); + std.debug.warn("\n"); } }, @@ -165,3 +179,10 @@ pub fn printExpr(expr: *Expr) void { else => std.debug.warn("unknown"), } } + +pub fn printStmt(stmt: *Stmt) void { + switch (stmt.*) { + .Println => |expr| parenthetize("println", &[_]*Expr{expr}), + .Expr => |expr| printExpr(expr), + } +} diff --git a/src/parser.zig b/src/parser.zig index 1c8da47..f0f8a70 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -13,6 +13,7 @@ const Result = main.Result; const Node = ast.Node; const Expr = ast.Expr; +const Stmt = ast.Stmt; pub const Parser = struct { allocator: *Allocator, @@ -117,14 +118,12 @@ pub const Parser = struct { return false; } - fn mkFnDecl(self: *Parser, name: Token, params: ast.ParamList, block: ast.ExprList) !*ast.Node { + fn mkFnDecl(self: *Parser, name: Token, params: ast.ParamList, block: ast.StmtList) !*ast.Node { var node = try self.allocator.create(Node); node.* = Node{ .FnDecl = ast.FnDecl{ .func_name = name, .params = params, - - // TODO stmt .body = block, }, }; @@ -137,9 +136,9 @@ pub const Parser = struct { return node; } - fn mkBlock(self: *Parser, exprs: ast.ExprList) !*ast.Node { + fn mkBlock(self: *Parser, stmts: ast.StmtList) !*ast.Node { var node = try self.allocator.create(Node); - node.* = Node{ .Block = exprs }; + node.* = Node{ .Block = stmts }; return node; } @@ -149,6 +148,18 @@ pub const Parser = struct { return node; } + fn mkStmt(self: *Parser, stmt: *Stmt) !*ast.Node { + var node = try self.allocator.create(Node); + node.* = Node{ .Stmt = stmt }; + return node; + } + + fn mkStmtExpr(self: *Parser, expr: *Expr) !*Stmt { + var stmt = try self.allocator.create(Stmt); + stmt.* = Stmt{ .Expr = expr }; + return stmt; + } + fn mkGrouping(self: *Parser, expr: *Expr) !*ast.Expr { var grouping = try self.allocator.create(Expr); grouping.* = Expr{ .Grouping = expr }; @@ -334,12 +345,14 @@ pub const Parser = struct { const const_name = try self.consumeSingle(.Identifier); _ = try self.consumeSingle(.Equal); - // TODO expr - const const_value = self.peek(); - _ = try self.nextToken(); + var expr = try self.parseExpr(); + // _ = try self.nextToken(); //const const_value = try self.consumeSingle(.Identifier); - try consts.append(ast.SingleConst{ .name = const_name, .value = const_value }); + try consts.append(ast.SingleConst{ + .name = const_name, + .expr = expr.Expr, + }); } _ = try self.consumeSingle(.RightParen); @@ -360,20 +373,42 @@ pub const Parser = struct { } fn parseBlock(self: *@This()) !*Node { - var exprs = ast.ExprList.init(self.allocator); - errdefer exprs.deinit(); + var stmts = ast.StmtList.init(self.allocator); + errdefer stmts.deinit(); _ = try self.consumeSingle(.LeftBrace); while (self.peek().ttype != .RightBrace) { - var node = try self.parseExpr(); + var node = try self.parseStmt(); ast.printNode(node, 0); - try exprs.append(node.Expr); - //_ = try self.nextToken(); + try stmts.append(node.Stmt); } + _ = try self.consumeSingle(.RightBrace); - return try self.mkBlock(exprs); + return try self.mkBlock(stmts); + } + + fn parseStmt(self: *@This()) anyerror!*Node { + var stmt = switch (self.peek().ttype) { + .Println => try self.parsePrintln(), + + // TODO make newlines tokens and consume newline? + else => try self.parseStmtExpr(), + }; + + return try self.mkStmt(stmt); + } + + fn parsePrintln(self: *@This()) !*Stmt { + _ = try self.consumeSingle(.Println); + var expr = try self.parseExpr(); + return try Stmt.mkPrintln(self.allocator, expr.Expr); + } + + fn parseStmtExpr(self: *@This()) !*Stmt { + var expr = (try self.parseExpr()).Expr; + return try self.mkStmtExpr(expr); } fn parseExpr(self: *@This()) anyerror!*Node { diff --git a/src/scanner.zig b/src/scanner.zig index 613b096..811c1c9 100644 --- a/src/scanner.zig +++ b/src/scanner.zig @@ -49,6 +49,7 @@ const keywords = [_][]const u8{ "true", "false", "None", + "println", }; const keyword_ttypes = [_]TokenType{ @@ -76,6 +77,7 @@ const keyword_ttypes = [_]TokenType{ .True, .False, .None, + .Println, }; fn getKeyword(keyword: []const u8) ?TokenType { diff --git a/src/tokens.zig b/src/tokens.zig index 57973de..7579028 100644 --- a/src/tokens.zig +++ b/src/tokens.zig @@ -71,6 +71,8 @@ pub const TokenType = enum { False, None, + Println, + EOF, };