fix var declarations by making them expressions

This commit is contained in:
Luna 2019-08-25 11:38:55 -03:00
parent 72bc932d23
commit 4534549f41
3 changed files with 83 additions and 51 deletions

View file

@ -9,6 +9,6 @@ fn main(a int) int {
1 + 2 + 3 + 4 1 + 2 + 3 + 4
1 + 1 * 1 1 + 1 * 1
3 / (51 + 2) 3 / (51 + 2)
a := 1+2 mut a := 1+2
println(2 * 1956 + a) a = 2
} }

View file

@ -61,6 +61,10 @@ pub const AssignExpr = struct {
pub const ExprType = enum { pub const ExprType = enum {
Assign, Assign,
// vardecls as expressions is a hack
VarDecl,
Binary, Binary,
Unary, Unary,
Literal, Literal,
@ -68,8 +72,14 @@ pub const ExprType = enum {
Grouping, Grouping,
}; };
pub const VarDecl = struct {
assign: AssignExpr,
mutable: bool = false,
};
pub const Expr = union(ExprType) { pub const Expr = union(ExprType) {
Assign: AssignExpr, Assign: AssignExpr,
VarDecl: VarDecl,
Binary: BinaryExpr, Binary: BinaryExpr,
Unary: UnaryExpr, Unary: UnaryExpr,
Literal: LiteralExpr, Literal: LiteralExpr,
@ -77,34 +87,25 @@ pub const Expr = union(ExprType) {
Grouping: *Expr, Grouping: *Expr,
}; };
pub const VarDecl = struct { // TODO
name: Token, //pub const IfStmt = struct {
initializer: *Expr, // condition: *Expr,
mutable: bool = false, // then_branch: *StmtList,
}; // else_branch: *StmtList,
//};
pub const Stmt = union(enum) { pub const Stmt = union(enum) {
Expr: *Expr, Expr: *Expr,
Println: *Expr, Println: *Expr,
VarDecl: VarDecl,
// TODO
//If: IfStmt,
pub fn mkPrintln(allocator: *std.mem.Allocator, expr: *Expr) !*Stmt { pub fn mkPrintln(allocator: *std.mem.Allocator, expr: *Expr) !*Stmt {
var println = try allocator.create(Stmt); var println = try allocator.create(Stmt);
println.* = Stmt{ .Println = expr }; println.* = Stmt{ .Println = expr };
return println; 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) { pub const Node = union(NodeType) {
@ -223,10 +224,23 @@ pub fn printExpr(expr: *Expr) void {
.Variable => |token| std.debug.warn("{}", token.lexeme), .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| { .Assign => |assign| {
std.debug.warn("(let "); std.debug.warn("(set ");
std.debug.warn("{} ", assign.name.lexeme); std.debug.warn("{} ", assign.name.lexeme);
printExpr(assign.value); printExpr(assign.value);
std.debug.warn(")");
}, },
else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)), else => std.debug.warn("UnknownExpr-{}", @tagName(expr.*)),
@ -237,14 +251,6 @@ pub fn printStmt(stmt: *Stmt) void {
switch (stmt.*) { switch (stmt.*) {
.Println => |expr| parenthetize("println", &[_]*Expr{expr}), .Println => |expr| parenthetize("println", &[_]*Expr{expr}),
.Expr => |expr| printExpr(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.*)), else => std.debug.warn("UnknownStmt-{}", @tagName(stmt.*)),
} }
} }

View file

@ -206,6 +206,21 @@ pub const Parser = struct {
return expr; 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 { fn mkBool(self: *Parser, val: bool) !*ast.Expr {
var expr = try self.allocator.create(Expr); var expr = try self.allocator.create(Expr);
expr.* = Expr{ expr.* = Expr{
@ -410,21 +425,7 @@ pub const Parser = struct {
} }
fn parseDecl(self: *@This()) !*Stmt { fn parseDecl(self: *@This()) !*Stmt {
return switch (self.peek().ttype) { return try self.parseStmt();
.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);
} }
fn parseStmt(self: *@This()) anyerror!*Stmt { fn parseStmt(self: *@This()) anyerror!*Stmt {
@ -457,18 +458,43 @@ pub const Parser = struct {
} }
fn parseAssignment(self: *@This()) anyerror!*Expr { 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(); var expr = try self.parseEquality();
std.debug.warn("lvalue: {}, cur: {}\n", expr, self.peek());
if (self.check(.ColonEqual)) { var value: *Expr = undefined;
var op = try self.consumeSingle(.ColonEqual);
var value = try self.parseAssignment();
if (ast.ExprType(expr.*) == .Variable) { var op: Token = undefined;
return try self.mkAssign(expr.Variable, value);
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"); switch (op.ttype) {
return Result.CompileError; .ColonEqual => return try self.mkVarDecl(expr.Variable, value, mutable),
.Equal => return try self.mkAssign(expr.Variable, value),
else => unreachable,
}
} }
return expr; return expr;