Compare commits

...

3 commits

Author SHA1 Message Date
9b3e9e8139 add if statements 2019-08-25 13:02:40 -03:00
83910811fa ast: add IfStmt and IfBranch 2019-08-25 12:31:57 -03:00
f9f6362c91 ast: add return type to FnDecl
- ast: make FnDecl and Const print better as s-expressions
2019-08-25 12:24:34 -03:00
3 changed files with 129 additions and 35 deletions

View file

@ -11,4 +11,10 @@ fn main(a int) int {
3 / (51 + 2) 3 / (51 + 2)
mut a := 1+2 mut a := 1+2
a = 2 a = 2
if a {
println(30)
} else {
println(50)
}
} }

View file

@ -20,14 +20,13 @@ pub const NodeType = enum {
pub const ParamDecl = struct { pub const ParamDecl = struct {
name: Token, name: Token,
// TODO types
typ: Token, typ: Token,
}; };
pub const FnDecl = struct { pub const FnDecl = struct {
func_name: Token, func_name: Token,
params: ParamList, params: ParamList,
return_type: Token,
body: StmtList, body: StmtList,
}; };
@ -80,32 +79,51 @@ pub const VarDecl = struct {
pub const Expr = union(ExprType) { pub const Expr = union(ExprType) {
Assign: AssignExpr, Assign: AssignExpr,
VarDecl: VarDecl, VarDecl: VarDecl,
Binary: BinaryExpr, Binary: BinaryExpr,
Unary: UnaryExpr, Unary: UnaryExpr,
Literal: LiteralExpr, Literal: LiteralExpr,
Variable: Token, Variable: Token,
Grouping: *Expr, Grouping: *Expr,
}; };
// TODO pub const IfBranch = std.ArrayList(*Stmt);
//pub const IfStmt = struct {
// condition: *Expr, pub const IfStmt = struct {
// then_branch: *StmtList, condition: *Expr,
// else_branch: *StmtList, then_branch: IfBranch,
//}; else_branch: ?IfBranch,
};
pub const Stmt = union(enum) { pub const Stmt = union(enum) {
Expr: *Expr, Expr: *Expr,
Println: *Expr, Println: *Expr,
// TODO If: IfStmt,
//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 mkIfStmt(
allocator: *std.mem.Allocator,
condition: *Expr,
then: IfBranch,
else_branch: ?IfBranch,
) !*Stmt {
var println = try allocator.create(Stmt);
println.* = Stmt{
.If = IfStmt{
.condition = condition,
.then_branch = then,
.else_branch = else_branch,
},
};
return println;
}
}; };
pub const Node = union(NodeType) { pub const Node = union(NodeType) {
@ -137,39 +155,50 @@ fn print(ident: usize, comptime fmt: []const u8, args: ...) void {
std.debug.warn(fmt, args); std.debug.warn(fmt, args);
} }
fn printBlock(ident: usize, block: var, endNewline: bool) void {
std.debug.warn("(\n");
for (block.toSlice()) |stmt| {
printIdent(ident);
printStmt(ident, stmt);
std.debug.warn("\n");
}
if (endNewline) {
print(ident - 1, ")\n");
} else {
print(ident - 1, ")");
}
}
pub fn printNode(node: *Node, ident: usize) void { pub fn printNode(node: *Node, ident: usize) void {
switch (node.*) { switch (node.*) {
.FnDecl => |decl| { .FnDecl => |decl| {
print(ident, "FnDecl name='{}'\n", decl.func_name.lexeme); print(ident, "(fn {} (", decl.func_name.lexeme);
for (decl.params.toSlice()) |param| { for (decl.params.toSlice()) |param| {
print( std.debug.warn("({} {}) ", param.name.lexeme, param.typ.lexeme);
ident + 1,
"param: '{}' {}\n",
param.name.lexeme,
param.typ.lexeme,
);
} }
for (decl.body.toSlice()) |stmt| { printBlock(ident + 1, decl.body, false);
printIdent(ident + 1); std.debug.warn(")\n");
printStmt(stmt);
std.debug.warn("\n");
}
}, },
.ConstDecl => |consts| { .ConstDecl => |consts| {
print(ident, "ConstDecl ({} consts)\n", consts.len); print(ident, "(const (\n");
for (consts.toSlice()) |const_decl| { for (consts.toSlice()) |const_decl| {
print( print(
ident + 1, ident + 1,
"{} = ", "({} ",
const_decl.name.lexeme, const_decl.name.lexeme,
); );
printExpr(const_decl.expr); printExpr(const_decl.expr);
std.debug.warn("\n"); std.debug.warn(")\n");
} }
print(ident, "))\n");
}, },
.Root => { .Root => {
@ -186,7 +215,7 @@ pub fn printNode(node: *Node, ident: usize) void {
.Stmt => |stmt| blk: { .Stmt => |stmt| blk: {
printIdent(ident); printIdent(ident);
printStmt(stmt); printStmt(ident, stmt);
std.debug.warn("\n"); std.debug.warn("\n");
}, },
@ -247,10 +276,24 @@ pub fn printExpr(expr: *Expr) void {
} }
} }
pub fn printStmt(stmt: *Stmt) void { pub fn printStmt(ident: usize, 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),
.If => |ifstmt| {
std.debug.warn("(if ");
printExpr(ifstmt.condition);
std.debug.warn(" ");
printBlock(ident + 1, ifstmt.then_branch, false);
if (ifstmt.else_branch) |else_branch| {
std.debug.warn(" else ");
printBlock(ident + 1, else_branch, false);
}
std.debug.warn(")\n");
},
else => std.debug.warn("UnknownStmt-{}", @tagName(stmt.*)), else => std.debug.warn("UnknownStmt-{}", @tagName(stmt.*)),
} }
} }

View file

@ -120,12 +120,19 @@ pub const Parser = struct {
return false; return false;
} }
fn mkFnDecl(self: *Parser, name: Token, params: ast.ParamList, block: ast.StmtList) !*ast.Node { fn mkFnDecl(
self: *Parser,
name: Token,
params: ast.ParamList,
return_type: Token,
block: ast.StmtList,
) !*ast.Node {
var node = try self.allocator.create(Node); var node = try self.allocator.create(Node);
node.* = Node{ node.* = Node{
.FnDecl = ast.FnDecl{ .FnDecl = ast.FnDecl{
.func_name = name, .func_name = name,
.params = params, .params = params,
.return_type = return_type,
.body = block, .body = block,
}, },
}; };
@ -348,6 +355,8 @@ pub const Parser = struct {
while (self.peek().ttype != .RightParen) { while (self.peek().ttype != .RightParen) {
const param_name = try self.consumeSingle(.Identifier); const param_name = try self.consumeSingle(.Identifier);
// TODO dedicated function to consume a type
const param_type = try self.consumeSingle(.Identifier); const param_type = try self.consumeSingle(.Identifier);
try param_list.append(ast.ParamDecl{ try param_list.append(ast.ParamDecl{
@ -358,13 +367,10 @@ pub const Parser = struct {
_ = try self.consumeSingle(.RightParen); _ = try self.consumeSingle(.RightParen);
// TODO return type // TODO dedicated function to consume a type
const return_type = try self.consumeSingle(.Identifier); const return_type = try self.consumeSingle(.Identifier);
var block_node = try self.parseBlock();
var block = try self.parseBlock(); return try self.mkFnDecl(name, param_list, return_type, block_node.Block);
std.debug.warn("!fn name: {}\n", name);
return try self.mkFnDecl(name, param_list, block.Block);
} }
fn parseConstDecl(self: *@This()) !?*Node { fn parseConstDecl(self: *@This()) !?*Node {
@ -413,7 +419,6 @@ pub const Parser = struct {
_ = try self.consumeSingle(.LeftBrace); _ = try self.consumeSingle(.LeftBrace);
while (self.peek().ttype != .RightBrace) { while (self.peek().ttype != .RightBrace) {
std.debug.warn("get smt with cur {}\n", self.peek().ttype);
var stmt = try self.parseDecl(); var stmt = try self.parseDecl();
ast.printNode(try self.mkStmt(stmt), 0); ast.printNode(try self.mkStmt(stmt), 0);
try stmts.append(stmt); try stmts.append(stmt);
@ -430,6 +435,7 @@ pub const Parser = struct {
fn parseStmt(self: *@This()) anyerror!*Stmt { fn parseStmt(self: *@This()) anyerror!*Stmt {
return switch (self.peek().ttype) { return switch (self.peek().ttype) {
.If => try self.parseIfStmt(),
.Println => try self.parsePrintln(), .Println => try self.parsePrintln(),
// TODO make newlines tokens and consume newline? // TODO make newlines tokens and consume newline?
@ -437,6 +443,45 @@ pub const Parser = struct {
}; };
} }
/// Copy of parseBlock for if branches
fn parseIfBranch(self: *@This()) !ast.IfBranch {
var branch = ast.IfBranch.init(self.allocator);
errdefer branch.deinit();
_ = try self.consumeSingle(.LeftBrace);
while (self.peek().ttype != .RightBrace) {
var stmt = try self.parseDecl();
ast.printNode(try self.mkStmt(stmt), 0);
try branch.append(stmt);
}
_ = try self.consumeSingle(.RightBrace);
return branch;
}
fn parseIfStmt(self: *@This()) !*Stmt {
_ = try self.consumeSingle(.If);
var condition = (try self.parseExpr()).Expr;
const then_branch = try self.parseIfBranch();
var else_branch: ?ast.IfBranch = null;
if (self.check(.Else)) {
_ = try self.consumeSingle(.Else);
else_branch = try self.parseIfBranch();
}
return try Stmt.mkIfStmt(
self.allocator,
condition,
then_branch,
else_branch,
);
}
fn parsePrintln(self: *@This()) !*Stmt { fn parsePrintln(self: *@This()) !*Stmt {
_ = try self.consumeSingle(.Println); _ = try self.consumeSingle(.Println);