feat: assignment operations
This commit is contained in:
parent
ecd6017673
commit
f82b361005
9 changed files with 79 additions and 48 deletions
|
|
@ -51,6 +51,8 @@ pub const Node = struct {
|
|||
divert_expr,
|
||||
selector_expr,
|
||||
assign_stmt,
|
||||
assign_add_stmt,
|
||||
assign_sub_stmt,
|
||||
block_stmt,
|
||||
content_stmt,
|
||||
divert_stmt,
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ fn nodeTagToString(tag: Ast.Node.Tag) []const u8 {
|
|||
.call_expr => "CallExpr",
|
||||
.choice_expr => "ChoiceContentExpr",
|
||||
.assign_stmt => "AssignStmt",
|
||||
.assign_add_stmt => "AssignAddStmt",
|
||||
.assign_sub_stmt => "AssignSubStmt",
|
||||
.block_stmt => "BlockStmt",
|
||||
.content_stmt => "ContentStmt",
|
||||
.divert_stmt => "DivertStmt",
|
||||
|
|
@ -396,6 +398,8 @@ fn renderAstWalk(
|
|||
.logical_lesser_or_equal_expr,
|
||||
.logical_lesser_expr,
|
||||
.assign_stmt,
|
||||
.assign_add_stmt,
|
||||
.assign_sub_stmt,
|
||||
.divert_stmt,
|
||||
.return_stmt,
|
||||
.expr_stmt,
|
||||
|
|
|
|||
|
|
@ -783,44 +783,8 @@ fn expr(gi: *GenIr, scope: *Scope, optional_node: ?*const Ast.Node) InnerError!I
|
|||
.logical_lesser_expr => return binaryOp(gi, scope, node, .cmp_lt),
|
||||
.logical_lesser_or_equal_expr => return binaryOp(gi, scope, node, .cmp_lte),
|
||||
.call_expr => return callExpr(gi, scope, node, .call),
|
||||
.choice_expr => unreachable,
|
||||
.divert_expr => unreachable,
|
||||
.selector_expr => return fieldAccess(gi, scope, node),
|
||||
.assign_stmt => unreachable,
|
||||
.block_stmt => unreachable,
|
||||
.content_stmt => unreachable,
|
||||
.divert_stmt => unreachable,
|
||||
.return_stmt => unreachable,
|
||||
.expr_stmt => unreachable,
|
||||
.choice_stmt => unreachable,
|
||||
.choice_star_stmt => unreachable,
|
||||
.choice_plus_stmt => unreachable,
|
||||
.gather_point_stmt => unreachable,
|
||||
.gathered_stmt => unreachable,
|
||||
.function_prototype => unreachable,
|
||||
.stitch_prototype => unreachable,
|
||||
.knot_prototype => unreachable,
|
||||
.function_decl => unreachable,
|
||||
.stitch_decl => unreachable,
|
||||
.knot_decl => unreachable,
|
||||
.const_decl => unreachable,
|
||||
.var_decl => unreachable,
|
||||
.list_decl => unreachable,
|
||||
.temp_decl => unreachable,
|
||||
.parameter_decl => unreachable,
|
||||
.ref_parameter_decl => unreachable,
|
||||
.argument_list => unreachable,
|
||||
.parameter_list => unreachable,
|
||||
.switch_stmt => unreachable, // Handled in switchStmt
|
||||
.switch_case => unreachable, // Handled in switchStmt
|
||||
.if_stmt => unreachable, // Handled in ifStmt
|
||||
.multi_if_stmt => unreachable, // Handled in multiIfStmt
|
||||
.if_branch => unreachable, // Handled in ifStmt and multiIfStmt
|
||||
.else_branch => unreachable, // Handled in switchStmt, multiIfStmt, and ifStmt
|
||||
.content => unreachable,
|
||||
.inline_logic_expr => unreachable,
|
||||
.inline_if_stmt => unreachable,
|
||||
.invalid => unreachable,
|
||||
inline else => |_| unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1164,7 +1128,7 @@ fn contentStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
|||
}
|
||||
}
|
||||
|
||||
fn assignStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void {
|
||||
fn assign(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void {
|
||||
const astgen = gi.astgen;
|
||||
const identifier_node = node.data.bin.lhs.?;
|
||||
const expr_node = node.data.bin.rhs.?;
|
||||
|
|
@ -1178,6 +1142,32 @@ fn assignStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void
|
|||
return fail(astgen, identifier_node, "unknown identifier", .{});
|
||||
}
|
||||
|
||||
fn assignOp(
|
||||
gi: *GenIr,
|
||||
scope: *Scope,
|
||||
node: *const Ast.Node,
|
||||
op_inst_tag: Ir.Inst.Tag,
|
||||
) InnerError!void {
|
||||
const astgen = gi.astgen;
|
||||
const identifier_node = node.data.bin.lhs.?;
|
||||
const expr_node = node.data.bin.rhs.?;
|
||||
const name_str = try astgen.strFromNode(identifier_node);
|
||||
|
||||
if (scope.lookup(name_str.index)) |decl| {
|
||||
const lhs = try gi.addUnaryNode(.load, decl.inst_index.toRef());
|
||||
const rhs = try expr(gi, scope, expr_node);
|
||||
|
||||
const result = switch (op_inst_tag) {
|
||||
.add => try gi.addBinaryNode(.add, lhs, rhs),
|
||||
.sub => try gi.addBinaryNode(.sub, lhs, rhs),
|
||||
else => unreachable,
|
||||
};
|
||||
_ = try gi.addBinaryNode(.store, decl.inst_index.toRef(), result);
|
||||
return;
|
||||
}
|
||||
return fail(astgen, identifier_node, "unknown identifier", .{});
|
||||
}
|
||||
|
||||
fn choiceStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void {
|
||||
const astgen = gi.astgen;
|
||||
const gpa = astgen.gpa;
|
||||
|
|
@ -1540,7 +1530,9 @@ fn blockInner(gi: *GenIr, parent_scope: *Scope, stmt_list: []*Ast.Node) !void {
|
|||
.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),
|
||||
.assign_stmt => try assign(gi, &child_scope, node),
|
||||
.assign_add_stmt => try assignOp(gi, &child_scope, node, .add),
|
||||
.assign_sub_stmt => try assignOp(gi, &child_scope, node, .sub),
|
||||
.content_stmt => try contentStmt(gi, &child_scope, node),
|
||||
.choice_stmt => try choiceStmt(gi, &child_scope, node),
|
||||
.expr_stmt => try exprStmt(gi, &child_scope, node),
|
||||
|
|
|
|||
|
|
@ -111,6 +111,15 @@ fn getTokenInfixType(tag: Token.Tag) Ast.Node.Tag {
|
|||
};
|
||||
}
|
||||
|
||||
fn getTokenAssignType(tag: Token.Tag) ?Ast.Node.Tag {
|
||||
return switch (tag) {
|
||||
.equal => .assign_stmt,
|
||||
.plus_equal => .assign_add_stmt,
|
||||
.minus_equal => .assign_sub_stmt,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
fn getBindingPower(tag: Token.Tag) Precedence {
|
||||
return switch (tag) {
|
||||
.ampersand_ampersand, .keyword_and => .logical_and,
|
||||
|
|
@ -703,16 +712,18 @@ fn parseAssignStmt(p: *Parse) Error!*Ast.Node {
|
|||
const main_token = p.token;
|
||||
const lhs = try parseIdentifierExpr(p);
|
||||
|
||||
if (!p.checkToken(.equal)) return parseExprStmt(p, lhs);
|
||||
_ = p.nextToken();
|
||||
if (getTokenAssignType(p.token.tag)) |op| {
|
||||
_ = p.nextToken();
|
||||
|
||||
const rhs = try p.expectExpr();
|
||||
_ = try p.expectNewline();
|
||||
const rhs = try p.expectExpr();
|
||||
_ = try p.expectNewline();
|
||||
|
||||
return .createBinary(p.arena, .assign_stmt, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, lhs, rhs);
|
||||
return .createBinary(p.arena, op, .{
|
||||
.start = main_token.loc.start,
|
||||
.end = p.token.loc.start,
|
||||
}, lhs, rhs);
|
||||
}
|
||||
return parseExprStmt(p, lhs);
|
||||
}
|
||||
|
||||
fn parseTempDecl(p: *Parse) Error!*Ast.Node {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ test "fixture - variable arithmetic" {
|
|||
try testRuntimeFixture("variable-arithmetic");
|
||||
}
|
||||
|
||||
test "fixture - assignment op" {
|
||||
try testRuntimeFixture("assignment-op");
|
||||
}
|
||||
|
||||
test "fixture - constant folding" {
|
||||
try testRuntimeFixture("constant-folding");
|
||||
}
|
||||
|
|
|
|||
0
src/Story/testdata/assignment-op/input.txt
vendored
Normal file
0
src/Story/testdata/assignment-op/input.txt
vendored
Normal file
5
src/Story/testdata/assignment-op/story.ink
vendored
Normal file
5
src/Story/testdata/assignment-op/story.ink
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
~ temp foo = 0
|
||||
~ foo = 1
|
||||
~ foo += 4
|
||||
~ foo -= 2
|
||||
{foo}
|
||||
1
src/Story/testdata/assignment-op/transcript.txt
vendored
Normal file
1
src/Story/testdata/assignment-op/transcript.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
3
|
||||
|
|
@ -119,6 +119,7 @@ pub const Tokenizer = struct {
|
|||
slash,
|
||||
equal,
|
||||
bang,
|
||||
plus,
|
||||
pipe,
|
||||
less_than,
|
||||
greater_than,
|
||||
|
|
@ -197,7 +198,7 @@ pub const Tokenizer = struct {
|
|||
},
|
||||
'+' => {
|
||||
self.index += 1;
|
||||
result.tag = .plus;
|
||||
continue :state .plus;
|
||||
},
|
||||
'-' => {
|
||||
self.index += 1;
|
||||
|
|
@ -284,6 +285,13 @@ pub const Tokenizer = struct {
|
|||
}
|
||||
},
|
||||
},
|
||||
.plus => switch (self.buffer[self.index]) {
|
||||
'=' => {
|
||||
self.index += 1;
|
||||
result.tag = .plus_equal;
|
||||
},
|
||||
else => result.tag = .plus,
|
||||
},
|
||||
.pipe => switch (self.buffer[self.index]) {
|
||||
'|' => {
|
||||
self.index += 1;
|
||||
|
|
@ -296,6 +304,10 @@ pub const Tokenizer = struct {
|
|||
self.index += 1;
|
||||
result.tag = .right_arrow;
|
||||
},
|
||||
'=' => {
|
||||
self.index += 1;
|
||||
result.tag = .minus_equal;
|
||||
},
|
||||
else => result.tag = .minus,
|
||||
},
|
||||
.slash => switch (self.buffer[self.index]) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue