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;