diff --git a/examples/hello.v b/examples/hello.v index 13de5a8..85f2989 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -42,7 +42,7 @@ fn main(a int) int { //println(p.x) } -//struct Point { -// x int -// y int -//} +struct Point { + x int + y int +} diff --git a/src/ast.zig b/src/ast.zig index 1bd9a81..52cb582 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -12,6 +12,7 @@ pub const NodeType = enum { Root, FnDecl, ConstDecl, + Struct, Block, Expr, Stmt, @@ -184,19 +185,46 @@ pub const Stmt = union(enum) { } }; +pub const FieldList = std.ArrayList(StructField); + +pub const StructField = struct { + name: Token, + typ: Token, + mutable: bool = true, + public: bool = true, +}; + +pub const Struct = struct { + name: Token, + fields: FieldList, +}; + pub const Node = union(NodeType) { Root: NodeList, FnDecl: FnDecl, ConstDecl: ConstList, + Struct: Struct, Block: StmtList, Expr: *Expr, Stmt: *Stmt, -}; -pub fn mkRoot(allocator: *std.mem.Allocator) !*Node { - var node = try allocator.create(Node); - node.* = Node{ .Root = NodeList.init(allocator) }; - return node; -} + pub fn mkRoot(allocator: *std.mem.Allocator) !*Node { + var node = try allocator.create(Node); + node.* = Node{ .Root = NodeList.init(allocator) }; + return node; + } + + pub fn mkStructDecl(allocator: *std.mem.Allocator, name: Token, fields: FieldList) !*Node { + var node = try allocator.create(Node); + node.* = Node{ + .Struct = Struct{ + .name = name, + .fields = fields, + }, + }; + + return node; + } +}; diff --git a/src/ast_printer.zig b/src/ast_printer.zig index 3bedd68..46fceb7 100644 --- a/src/ast_printer.zig +++ b/src/ast_printer.zig @@ -74,12 +74,31 @@ pub fn printNode(node: *Node, ident: usize) void { std.debug.warn("\n"); }, - .Stmt => |stmt| blk: { + .Stmt => |stmt| { printIdent(ident); printStmt(ident, stmt); std.debug.warn("\n"); }, + .Struct => |struc| { + print(ident, "(struct {} (\n", struc.name.lexeme); + for (struc.fields.toSlice()) |field| { + printIdent(ident + 1); + if (field.mutable) { + std.debug.warn("(mut "); + } else { + std.debug.warn("("); + } + + if (field.public) { + std.debug.warn("pub "); + } + + std.debug.warn("{} {})\n", field.name.lexeme, field.typ.lexeme); + } + print(ident, "))\n"); + }, + else => { print(ident, "unknown node: {}\n", node); }, diff --git a/src/parser.zig b/src/parser.zig index ea42dcf..083c1d9 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -311,7 +311,7 @@ pub const Parser = struct { } pub fn parse(self: *Parser) !*ast.Node { - var root = try ast.mkRoot(self.allocator); + var root = try Node.mkRoot(self.allocator); var token_opt: ?Token = null; @@ -389,11 +389,37 @@ pub const Parser = struct { return self.mkConstDecl(consts); } + fn parseStructDecl(self: *@This()) !*Node { + var fields = ast.FieldList.init(self.allocator); + errdefer fields.deinit(); + + _ = try self.consumeSingle(.Struct); + + var name = try self.consumeSingle(.Identifier); + + _ = try self.consumeSingle(.LeftBrace); + + while (!self.check(.RightBrace)) { + // TODO mut and pub + const field_name = try self.consumeSingle(.Identifier); + const field_type = try self.consumeSingle(.Identifier); + + try fields.append(ast.StructField{ + .name = field_name, + .typ = field_type, + }); + } + + _ = try self.consumeSingle(.RightBrace); + + return Node.mkStructDecl(self.allocator, name, fields); + } + fn parseTopDecl(self: *@This()) !*Node { return switch (self.peek().ttype) { .Fn => try self.parseFnDecl(), .Const => try self.parseConstDecl(), - // TODO .Struct => try self.parseStructDecl(), + .Struct => try self.parseStructDecl(), else => |ttype| blk: { self.doError("(basic) expected fn/const, got {}\n", ttype);