From 19fd9daebf2ddc267862742e9dbbd644662b12e7 Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 26 Aug 2019 10:49:43 -0300 Subject: [PATCH 1/2] add structs --- examples/hello.v | 8 ++++---- src/ast.zig | 40 ++++++++++++++++++++++++++++++++++------ src/ast_printer.zig | 21 ++++++++++++++++++++- src/parser.zig | 30 ++++++++++++++++++++++++++++-- 4 files changed, 86 insertions(+), 13 deletions(-) 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); From c2499f96c90786c97ca324509ba659f61d8b08dd Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 26 Aug 2019 11:59:32 -0300 Subject: [PATCH 2/2] add struct intialization --- README.md | 3 +++ examples/hello.v | 10 +++++---- src/ast.zig | 15 ++++++++++++++ src/ast_printer.zig | 12 +++++++++++ src/parser.zig | 50 ++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 85 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 054b284..95aa47f 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ because i can - `for` is split between `for` and `loop` because my fucking god i cant stand having *four* different variations of `for`. + - struct initialization is with `Struct.{}`, not `Struct{}`, to remove parsing + ambiguities + ## how ``` diff --git a/examples/hello.v b/examples/hello.v index 85f2989..af539b5 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -18,6 +18,7 @@ fn main(a int) int { println(50) } + a && b a || b @@ -35,10 +36,11 @@ fn main(a int) int { return 23 - //p := Point{ - // x: 10 - // y: 20 - //} + p := Point.{ + x: 10 + y: 20 + } + //println(p.x) } diff --git a/src/ast.zig b/src/ast.zig index 52cb582..c031733 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -77,6 +77,8 @@ pub const ExprType = enum { Literal, Variable, Call, + Struct, + Grouping, }; @@ -91,6 +93,18 @@ pub const CallExpr = struct { arguments: ExprList, }; +pub const StructInit = struct { + field: Token, + expr: *Expr, +}; + +pub const StructInitList = std.ArrayList(StructInit); + +pub const StructExpr = struct { + name: Token, + inits: StructInitList, +}; + pub const Expr = union(ExprType) { Assign: AssignExpr, VarDecl: VarDecl, @@ -99,6 +113,7 @@ pub const Expr = union(ExprType) { Unary: UnaryExpr, Logical: LogicalExpr, Literal: LiteralExpr, + Struct: StructExpr, Variable: Token, Grouping: *Expr, diff --git a/src/ast_printer.zig b/src/ast_printer.zig index 46fceb7..a44aa33 100644 --- a/src/ast_printer.zig +++ b/src/ast_printer.zig @@ -165,6 +165,18 @@ pub fn printExpr(expr: *Expr) void { std.debug.warn(")"); }, + .Struct => |val| { + std.debug.warn("({} (", val.name.lexeme); + + for (val.inits.toSlice()) |init| { + std.debug.warn(" ({} ", init.field.lexeme); + printExpr(init.expr); + std.debug.warn(")"); + } + + std.debug.warn("))"); + }, + else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)), } } diff --git a/src/parser.zig b/src/parser.zig index 083c1d9..f300ddc 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -259,6 +259,18 @@ pub const Parser = struct { return expr; } + fn mkStructExpr(self: *@This(), name: Token, args: ast.StructInitList) !*Expr { + var expr = try self.allocator.create(Expr); + expr.* = Expr{ + .Struct = ast.StructExpr{ + .name = name, + .inits = args, + }, + }; + + return expr; + } + fn mkBool(self: *Parser, val: bool) !*ast.Expr { var expr = try self.allocator.create(Expr); expr.* = Expr{ @@ -699,14 +711,21 @@ pub const Parser = struct { var expr = try self.parsePrimary(); while (true) { + std.debug.warn("maybe fncall / struct: {}\n", self.peek().ttype); + printer.printExpr(expr); + if (self.check(.LeftParen)) { if (ast.ExprType(expr.*) != .Variable) { - self.doError("cannot call non-variable{}", ast.ExprType(expr.*)); + self.doError("cannot call non-variable {}", ast.ExprType(expr.*)); return Result.CompileError; } _ = try self.consumeSingle(.LeftParen); expr = try self.finishCall(expr); + } else if (self.check(.Dot)) { + _ = try self.consumeSingle(.Dot); + _ = try self.consumeSingle(.LeftBrace); + expr = try self.finishStructVal(expr); } else { break; } @@ -738,6 +757,35 @@ pub const Parser = struct { return self.mkCall(callee, paren, args); } + fn finishStructVal(self: *@This(), expr: *Expr) !*Expr { + // {a: 10 b: 10} + // for this to work properly, must be Variable, since its a type. + if (ast.ExprType(expr.*) != .Variable) { + self.doError("Expected variable for struct type, got {}", ast.ExprType(expr.*)); + return Result.CompileError; + } + + var inits = ast.StructInitList.init(self.allocator); + errdefer inits.deinit(); + + while (!self.check(.RightBrace)) { + const field_name = try self.consumeSingle(.Identifier); + // TODO check .Comma for the quick initialization {val,val,val} + + _ = try self.consumeSingle(.Colon); + const field_value = (try self.parseExpr()).Expr; + + try inits.append(ast.StructInit{ + .field = field_name, + .expr = field_value, + }); + } + + _ = try self.consumeSingle(.RightBrace); + + return try self.mkStructExpr(expr.Variable, inits); + } + fn parsePrimary(self: *@This()) !*Expr { const curtype = self.peek().ttype; const lexeme = self.peek().lexeme;