feat: function calls
This commit is contained in:
parent
11d99fba38
commit
d08e753664
99 changed files with 881 additions and 148 deletions
113
src/AstGen.zig
113
src/AstGen.zig
|
|
@ -280,6 +280,13 @@ const GenIr = struct {
|
|||
self.instructions.items[self.instructions_top..];
|
||||
}
|
||||
|
||||
fn endsWithNoReturn(self: *GenIr) bool {
|
||||
if (self.isEmpty()) return false;
|
||||
const last_inst_index = self.instructions.items[self.instructions.items.len - 1];
|
||||
const last_inst = self.astgen.instructions.items[@intFromEnum(last_inst_index)];
|
||||
return last_inst.isNoReturn();
|
||||
}
|
||||
|
||||
fn makeSubBlock(self: *GenIr) GenIr {
|
||||
return .{
|
||||
.astgen = self.astgen,
|
||||
|
|
@ -730,7 +737,7 @@ fn expr(gi: *GenIr, scope: *Scope, optional_node: ?*const Ast.Node) InnerError!I
|
|||
.logical_greater_or_equal_expr => return binaryOp(gi, scope, node, .cmp_gte),
|
||||
.logical_lesser_expr => return binaryOp(gi, scope, node, .cmp_lt),
|
||||
.logical_lesser_or_equal_expr => return binaryOp(gi, scope, node, .cmp_lte),
|
||||
.call_expr => unreachable,
|
||||
.call_expr => return callExpr(gi, scope, node, .call),
|
||||
.choice_expr => unreachable,
|
||||
.choice_start_expr => unreachable,
|
||||
.choice_option_expr => unreachable,
|
||||
|
|
@ -1171,7 +1178,9 @@ fn callExpr(
|
|||
const scratch_top = astgen.scratch.items.len;
|
||||
defer astgen.scratch.shrinkRetainingCapacity(scratch_top);
|
||||
|
||||
const arguments: ?[]*Ast.Node = if (args_node) |n| n.data.list.items.? else null;
|
||||
// FIXME: List nodes should not have optional slices.
|
||||
// This hack is an abomination.
|
||||
const arguments: ?[]*Ast.Node = if (args_node) |n| if (n.data.list.items) |items| items else null else null;
|
||||
const args_count = if (arguments) |args| args.len else 0;
|
||||
|
||||
try astgen.scratch.resize(gpa, scratch_top + args_count);
|
||||
|
|
@ -1275,10 +1284,20 @@ fn divertExpr(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
|||
}
|
||||
|
||||
fn divertStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
||||
// TODO: Revisit this.
|
||||
const data = node.data.bin;
|
||||
return divertExpr(gi, scope, data.lhs.?);
|
||||
}
|
||||
|
||||
fn returnStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
||||
// TODO: Revisit this.
|
||||
const ret_arg = if (node.data.bin.lhs) |lhs| blk: {
|
||||
const arg_inst = try expr(gi, scope, lhs);
|
||||
break :blk arg_inst;
|
||||
} else .none;
|
||||
_ = try gi.addUnaryNode(.ret, ret_arg);
|
||||
}
|
||||
|
||||
fn tempDecl(gi: *GenIr, scope: *Scope, decl_node: *const Ast.Node) !void {
|
||||
const astgen = gi.astgen;
|
||||
const identifier_node = decl_node.data.bin.lhs.?;
|
||||
|
|
@ -1327,20 +1346,23 @@ fn blockInner(gi: *GenIr, parent_scope: *Scope, stmt_list: []*Ast.Node) !void {
|
|||
var child_scope = parent_scope.makeChild();
|
||||
defer child_scope.deinit();
|
||||
|
||||
for (stmt_list) |inner_node| {
|
||||
_ = switch (inner_node.tag) {
|
||||
.var_decl => try varDecl(gi, &child_scope, inner_node),
|
||||
.const_decl => try varDecl(gi, &child_scope, inner_node),
|
||||
.temp_decl => try tempDecl(gi, &child_scope, inner_node),
|
||||
.assign_stmt => try assignStmt(gi, &child_scope, inner_node),
|
||||
.content_stmt => try contentStmt(gi, &child_scope, inner_node),
|
||||
.choice_stmt => try choiceStmt(gi, &child_scope, inner_node),
|
||||
.expr_stmt => try exprStmt(gi, &child_scope, inner_node),
|
||||
.divert_stmt => try divertStmt(gi, &child_scope, inner_node),
|
||||
for (stmt_list) |node| {
|
||||
_ = switch (node.tag) {
|
||||
.var_decl => try varDecl(gi, &child_scope, node),
|
||||
.const_decl => try varDecl(gi, &child_scope, node),
|
||||
.temp_decl => try tempDecl(gi, &child_scope, node),
|
||||
.assign_stmt => try assignStmt(gi, &child_scope, node),
|
||||
.content_stmt => try contentStmt(gi, &child_scope, node),
|
||||
.choice_stmt => try choiceStmt(gi, &child_scope, node),
|
||||
.expr_stmt => try exprStmt(gi, &child_scope, node),
|
||||
.divert_stmt => try divertStmt(gi, &child_scope, node),
|
||||
.return_stmt => try returnStmt(gi, &child_scope, node),
|
||||
inline else => |e| @panic("Unexpected node: " ++ @tagName(e)),
|
||||
};
|
||||
}
|
||||
_ = try gi.addUnaryNode(.implicit_ret, .none);
|
||||
if (!gi.endsWithNoReturn()) {
|
||||
_ = try gi.addUnaryNode(.implicit_ret, .none);
|
||||
}
|
||||
}
|
||||
|
||||
fn blockStmt(block: *GenIr, scope: *Scope, stmt_node: *const Ast.Node) InnerError!void {
|
||||
|
|
@ -1415,9 +1437,10 @@ fn stitchDeclInner(
|
|||
}
|
||||
}
|
||||
if (body_node) |body| {
|
||||
try blockStmt(&decl_block, scope, body);
|
||||
const body_list = body.data.list.items.?;
|
||||
try blockInner(&decl_block, scope, body_list);
|
||||
} else {
|
||||
_ = try decl_block.addUnaryNode(.implicit_ret, .none);
|
||||
try blockInner(&decl_block, scope, &.{});
|
||||
}
|
||||
|
||||
const decl_str = try astgen.strFromNode(identifier_node);
|
||||
|
|
@ -1440,7 +1463,65 @@ fn stitchDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) Inne
|
|||
return stitchDeclInner(gi, &decl_scope, decl_node, prototype_node.?, body_node);
|
||||
}
|
||||
|
||||
fn functionDecl(_: *GenIr, _: *Scope, _: *const Ast.Node) InnerError!void {}
|
||||
fn functionDeclInner(
|
||||
gi: *GenIr,
|
||||
scope: *Scope,
|
||||
node: *const Ast.Node,
|
||||
prototype_node: *const Ast.Node,
|
||||
body_node: ?*const Ast.Node,
|
||||
) InnerError!void {
|
||||
const astgen = gi.astgen;
|
||||
const prototype_data = prototype_node.data.bin;
|
||||
const identifier_node = prototype_data.lhs.?;
|
||||
const decl_inst = try gi.addAsIndex(.{
|
||||
.tag = .declaration,
|
||||
.data = .{ .payload = undefined },
|
||||
});
|
||||
|
||||
var decl_block = gi.makeSubBlock();
|
||||
defer decl_block.unstack();
|
||||
|
||||
const stitch_inst = try decl_block.makePayloadNode(.decl_function);
|
||||
|
||||
if (prototype_data.rhs) |args_node| {
|
||||
const args_list = args_node.data.list.items.?;
|
||||
for (args_list) |arg| {
|
||||
assert(arg.tag == .parameter_decl);
|
||||
const arg_str = try astgen.strFromNode(arg);
|
||||
const arg_inst = try decl_block.addStrTok(.param, arg_str.index, arg.loc.start);
|
||||
|
||||
// TODO: Maybe make decl accept a ref?
|
||||
try scope.insert(arg_str.index, .{
|
||||
.decl_node = arg,
|
||||
.inst_index = arg_inst.toIndex().?,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (body_node) |body| {
|
||||
try blockStmt(&decl_block, scope, body);
|
||||
} else {
|
||||
_ = try decl_block.addUnaryNode(.implicit_ret, .none);
|
||||
}
|
||||
|
||||
const decl_str = try astgen.strFromNode(identifier_node);
|
||||
try setDeclStitchPayload(stitch_inst, &decl_block);
|
||||
try setDeclaration(decl_inst, .{
|
||||
.name = decl_str.index,
|
||||
.value = stitch_inst,
|
||||
.gi = gi,
|
||||
.node = node,
|
||||
});
|
||||
}
|
||||
|
||||
fn functionDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) InnerError!void {
|
||||
const knot_data = decl_node.data.bin;
|
||||
const prototype_node = knot_data.lhs;
|
||||
const body_node = knot_data.rhs;
|
||||
var decl_scope = parent_scope.makeChild();
|
||||
defer decl_scope.deinit();
|
||||
|
||||
return functionDeclInner(gi, &decl_scope, decl_node, prototype_node.?, body_node);
|
||||
}
|
||||
|
||||
fn knotDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) InnerError!void {
|
||||
const astgen = gi.astgen;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue