diff --git a/src/ast.zig b/src/ast.zig index 5886e8a..7588cc7 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -1,27 +1,63 @@ -pub const AstNodeType = enum { - Program, - BinOp, +const tokens = @import("tokens.zig"); +const Token = tokens.Token; + +pub const ExprType = enum { + Unary, + Binary, + Grouping, Number, }; -pub const AstNode = union(AstNodeType) { - Program: []AstNode, - BinOp: AstBinOp, - Number: AstNumber, +pub const Expr = union(ExprType) { + Unary: UnaryExpr, + Binary: BinaryExpr, + Grouping: Grouping, + Number: Number, }; -pub const BinOpType = enum { - Equality, +pub const UnaryExpr = struct { + operator: Token, + right: *Expr, }; -pub const AstBinOp = struct { - optype: BinOpType, +pub fn mkUnary(operator: Token, right: *Expr) Expr { + return Expr{ + .Unary = UnaryExpr{ + .operator = operator, + .right = right, + }, + }; +} - // TODO expression - left: *AstNode, - right: *AstNode, +pub const BinaryExpr = struct { + left: *Expr, + operator: Token, + right: *Expr, }; +pub fn mkBinary(left: *Expr, operator: Token, right: *Expr) Expr { + return Expr{ + .Binary = BinaryExpr{ + .left = left, + .operator = operator, + .right = right, + }, + }; +} + +pub const Grouping = struct { + expression: *Expr, +}; + +pub fn mkGrouping(expression: *Expr) Expr { + return Expr{ + .Grouping = Grouping{ + .expression = expression, + }, + }; +} + +/// Represents the default number literals in V. pub const NumberType = enum { Integer32, Integer64, @@ -31,7 +67,9 @@ pub const NumberType = enum { Float64, }; -pub const AstNumber = union(NumberType) { +/// "translation" of V number types to Zig number types for nicer +/// representation. +pub const Number = union(NumberType) { Integer32: i32, Integer64: i64, Unsigned32: u32, @@ -40,41 +78,16 @@ pub const AstNumber = union(NumberType) { Float64: f64, }; -pub fn printNode(stdout: var, node: AstNode) anyerror!void { - switch (node) { - .Program => |children| try printNodes(stdout, children), - .BinOp => |bin_op| blk: { - try stdout.print("("); - switch (bin_op.optype) { - .Equality => try stdout.write("=="), - } +pub fn mkNum(comptime T: type, num: T) Expr { + var expr = switch (T) { + i32 => Expr{ .Number = Number{ .Integer32 = num } }, + i64 => Expr{ .Number = Number{ .Integer64 = num } }, + u32 => Expr{ .Number = Number{ .Unsigned32 = num } }, + u64 => Expr{ .Number = Number{ .Unsigned64 = num } }, + f32 => Expr{ .Number = Number{ .Float32 = num } }, + f64 => Expr{ .Number = Number{ .Float64 = num } }, + else => unreachable, + }; - try stdout.write(" "); - try printNode(stdout, bin_op.left.*); - try stdout.write(" "); - try printNode(stdout, bin_op.right.*); - try stdout.print(")"); - }, - .Number => |ast_num| { - switch (ast_num) { - .Integer32 => |num| try stdout.print("{}", num), - .Integer64 => |num| try stdout.print("{}", num), - .Unsigned32 => |num| try stdout.print("{}", num), - .Unsigned64 => |num| try stdout.print("{}", num), - .Float32 => |num| try stdout.print("{}", num), - .Float64 => |num| try stdout.print("{}", num), - } - }, - } -} - -fn printNodes(stdout: var, nodes: []AstNode) anyerror!void { - try stdout.print("("); - - for (nodes) |node| { - try stdout.print(" "); - try printNode(stdout, node); - } - - try stdout.print(")"); + return expr; } diff --git a/src/ast_printer.zig b/src/ast_printer.zig new file mode 100644 index 0000000..ae1a9b7 --- /dev/null +++ b/src/ast_printer.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const ast = @import("ast.zig"); + +fn parenthesize(name: []const u8, exprs: []*ast.Expr) void { + std.debug.warn("({}", name); + + for (exprs) |expr| { + std.debug.warn(" "); + printAst(expr); + } + + std.debug.warn(")"); +} + +pub fn printAst(ast_expr: *ast.Expr) void { + switch (ast_expr.*) { + .Binary => |expr| parenthesize(expr.operator.lexeme, &[]*ast.Expr{ expr.left, expr.right }), + .Grouping => |expr| parenthesize("group", &[]*ast.Expr{expr.expression}), + .Unary => |expr| parenthesize(expr.operator.lexeme, &[]*ast.Expr{expr.right}), + .Number => |ast_num| { + switch (ast_num) { + .Integer32 => |num| std.debug.warn("{}", num), + .Integer64 => |num| std.debug.warn("{}", num), + .Unsigned32 => |num| std.debug.warn("{}", num), + .Unsigned64 => |num| std.debug.warn("{}", num), + .Float32 => |num| std.debug.warn("{}", num), + .Float64 => |num| std.debug.warn("{}", num), + } + }, + else => unreachable, + } +} diff --git a/src/runner.zig b/src/runner.zig index 5e0bb1b..209842d 100644 --- a/src/runner.zig +++ b/src/runner.zig @@ -4,6 +4,9 @@ const parsers = @import("parser.zig"); const main = @import("main.zig"); const ast = @import("ast.zig"); +const tokens = @import("tokens.zig"); +const printer = @import("ast_printer.zig"); + const Allocator = std.mem.Allocator; const Result = main.Result; const Parser = parsers.Parser; @@ -42,24 +45,18 @@ pub const Runner = struct { scanner = scanners.Scanner.init(self.allocator, code); //var parser = Parser.init(self.allocator, &scanner); //var tree = try parser.parse(); - try ast.printNode(self.stdout, ast.AstNode{ - .Program = &[]ast.AstNode{ast.AstNode{ - .BinOp = ast.AstBinOp{ - .optype = ast.BinOpType.Equality, - .left = &ast.AstNode{ - .Number = ast.AstNumber{ - .Integer32 = 30, - }, - }, - .right = &ast.AstNode{ - .Number = ast.AstNumber{ - .Integer32 = 30, - }, - }, - }, - }}, - }); - try self.stdout.print("\n"); + + var expr = ast.mkBinary( + &ast.mkUnary( + tokens.Token{ .ttype = .Minus, .lexeme = "-", .line = 1 }, + &ast.mkNum(i32, 123), + ), + tokens.Token{ .ttype = .Star, .lexeme = "*", .line = 1 }, + &ast.mkGrouping(&ast.mkNum(f32, 45.67)), + ); + + printer.printAst(&expr); + std.debug.warn("\n"); return Result.Ok; }