fix var declarations by making them expressions
This commit is contained in:
parent
72bc932d23
commit
4534549f41
3 changed files with 83 additions and 51 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
60
src/ast.zig
60
src/ast.zig
|
@ -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.*)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue