From 4534549f41aa012aaa4c409d7d9e3bb9105b0b46 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 25 Aug 2019 11:38:55 -0300 Subject: [PATCH] fix var declarations by making them expressions --- examples/hello.v | 4 +-- src/ast.zig | 60 ++++++++++++++++++++++------------------- src/parser.zig | 70 +++++++++++++++++++++++++++++++++--------------- 3 files changed, 83 insertions(+), 51 deletions(-) diff --git a/examples/hello.v b/examples/hello.v index 972d9f5..8685e38 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -9,6 +9,6 @@ fn main(a int) int { 1 + 2 + 3 + 4 1 + 1 * 1 3 / (51 + 2) - a := 1+2 - println(2 * 1956 + a) + mut a := 1+2 + a = 2 } diff --git a/src/ast.zig b/src/ast.zig index 7599921..2b52cf5 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -61,6 +61,10 @@ pub const AssignExpr = struct { pub const ExprType = enum { Assign, + + // vardecls as expressions is a hack + VarDecl, + Binary, Unary, Literal, @@ -68,8 +72,14 @@ pub const ExprType = enum { Grouping, }; +pub const VarDecl = struct { + assign: AssignExpr, + mutable: bool = false, +}; + pub const Expr = union(ExprType) { Assign: AssignExpr, + VarDecl: VarDecl, Binary: BinaryExpr, Unary: UnaryExpr, Literal: LiteralExpr, @@ -77,34 +87,25 @@ pub const Expr = union(ExprType) { Grouping: *Expr, }; -pub const VarDecl = struct { - name: Token, - initializer: *Expr, - mutable: bool = false, -}; +// TODO +//pub const IfStmt = struct { +// condition: *Expr, +// then_branch: *StmtList, +// else_branch: *StmtList, +//}; pub const Stmt = union(enum) { Expr: *Expr, Println: *Expr, - VarDecl: VarDecl, + + // TODO + //If: IfStmt, pub fn mkPrintln(allocator: *std.mem.Allocator, expr: *Expr) !*Stmt { var println = try allocator.create(Stmt); println.* = Stmt{ .Println = expr }; return println; } - - pub fn mkVarDecl(allocator: *std.mem.Allocator, name: Token, init: *Expr, mutable: bool) !*Stmt { - var vardecl = try allocator.create(Stmt); - vardecl.* = Stmt{ - .VarDecl = VarDecl{ - .name = name, - .initializer = init, - .mutable = mutable, - }, - }; - return vardecl; - } }; pub const Node = union(NodeType) { @@ -223,10 +224,23 @@ pub fn printExpr(expr: *Expr) void { .Variable => |token| std.debug.warn("{}", token.lexeme), + .VarDecl => |decl| { + if (decl.mutable) { + std.debug.warn("(mut "); + } else { + std.debug.warn("("); + } + + std.debug.warn("let {} ", decl.assign.name.lexeme); + printExpr(decl.assign.value); + std.debug.warn(")"); + }, + .Assign => |assign| { - std.debug.warn("(let "); + std.debug.warn("(set "); std.debug.warn("{} ", assign.name.lexeme); printExpr(assign.value); + std.debug.warn(")"); }, else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)), @@ -237,14 +251,6 @@ pub fn printStmt(stmt: *Stmt) void { switch (stmt.*) { .Println => |expr| parenthetize("println", &[_]*Expr{expr}), .Expr => |expr| printExpr(expr), - - .VarDecl => |decl| { - if (decl.mutable) - std.debug.warn("mut "); - std.debug.warn("assign {} := ", decl.name.lexeme); - printExpr(decl.initializer); - }, - else => std.debug.warn("UnknownStmt-{}", @tagName(stmt.*)), } } diff --git a/src/parser.zig b/src/parser.zig index 8dadcb1..7cd23e9 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -206,6 +206,21 @@ pub const Parser = struct { return expr; } + fn mkVarDecl(self: *@This(), name: Token, value: *Expr, mutable: bool) !*Expr { + var vardecl = try self.allocator.create(Expr); + vardecl.* = Expr{ + .VarDecl = ast.VarDecl{ + .assign = ast.AssignExpr{ + .name = name, + .value = value, + }, + .mutable = mutable, + }, + }; + + return vardecl; + } + fn mkBool(self: *Parser, val: bool) !*ast.Expr { var expr = try self.allocator.create(Expr); expr.* = Expr{ @@ -410,21 +425,7 @@ pub const Parser = struct { } fn parseDecl(self: *@This()) !*Stmt { - return switch (self.peek().ttype) { - .Mut => try self.parseMutVarDecl(), - else => try self.parseStmt(), - }; - } - - fn parseMutVarDecl(self: *@This()) !*Stmt { - _ = try self.consumeSingle(.Mut); - - var name = try self.consumeSingle(.Identifier); - - _ = try self.consumeSingle(.Equal); - var initializer = (try self.parseExpr()).Expr; - - return try Stmt.mkVarDecl(self.allocator, name, initializer, true); + return try self.parseStmt(); } fn parseStmt(self: *@This()) anyerror!*Stmt { @@ -457,18 +458,43 @@ pub const Parser = struct { } fn parseAssignment(self: *@This()) anyerror!*Expr { + // there can be two types coming out of this function: + // - a mutable/immutable variable declaration with := + // - an assignment to a variable with = + + // one is a statement, other is an expression. since the normal result + // of this is an Expr, we wrap variable assignments in an Expr as well. + var mutable: bool = false; + + std.debug.warn("start assignment pass with cur={}\n", self.peek()); + + if (self.check(.Mut)) { + _ = try self.consumeSingle(.Mut); + mutable = true; + } + var expr = try self.parseEquality(); + std.debug.warn("lvalue: {}, cur: {}\n", expr, self.peek()); - if (self.check(.ColonEqual)) { - var op = try self.consumeSingle(.ColonEqual); - var value = try self.parseAssignment(); + var value: *Expr = undefined; - if (ast.ExprType(expr.*) == .Variable) { - return try self.mkAssign(expr.Variable, value); + var op: Token = undefined; + + if (self.check(.ColonEqual) or self.check(.Equal)) { + op = self.peek(); + _ = try self.nextToken(); + value = try self.parseAssignment(); + + if (ast.ExprType(expr.*) != .Variable) { + self.doError("Invalid assignment target"); + return Result.CompileError; } - self.doError("Invalid assignment target"); - return Result.CompileError; + switch (op.ttype) { + .ColonEqual => return try self.mkVarDecl(expr.Variable, value, mutable), + .Equal => return try self.mkAssign(expr.Variable, value), + else => unreachable, + } } return expr;