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,
|
divert_expr,
|
||||||
selector_expr,
|
selector_expr,
|
||||||
assign_stmt,
|
assign_stmt,
|
||||||
|
assign_add_stmt,
|
||||||
|
assign_sub_stmt,
|
||||||
block_stmt,
|
block_stmt,
|
||||||
content_stmt,
|
content_stmt,
|
||||||
divert_stmt,
|
divert_stmt,
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ fn nodeTagToString(tag: Ast.Node.Tag) []const u8 {
|
||||||
.call_expr => "CallExpr",
|
.call_expr => "CallExpr",
|
||||||
.choice_expr => "ChoiceContentExpr",
|
.choice_expr => "ChoiceContentExpr",
|
||||||
.assign_stmt => "AssignStmt",
|
.assign_stmt => "AssignStmt",
|
||||||
|
.assign_add_stmt => "AssignAddStmt",
|
||||||
|
.assign_sub_stmt => "AssignSubStmt",
|
||||||
.block_stmt => "BlockStmt",
|
.block_stmt => "BlockStmt",
|
||||||
.content_stmt => "ContentStmt",
|
.content_stmt => "ContentStmt",
|
||||||
.divert_stmt => "DivertStmt",
|
.divert_stmt => "DivertStmt",
|
||||||
|
|
@ -396,6 +398,8 @@ fn renderAstWalk(
|
||||||
.logical_lesser_or_equal_expr,
|
.logical_lesser_or_equal_expr,
|
||||||
.logical_lesser_expr,
|
.logical_lesser_expr,
|
||||||
.assign_stmt,
|
.assign_stmt,
|
||||||
|
.assign_add_stmt,
|
||||||
|
.assign_sub_stmt,
|
||||||
.divert_stmt,
|
.divert_stmt,
|
||||||
.return_stmt,
|
.return_stmt,
|
||||||
.expr_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_expr => return binaryOp(gi, scope, node, .cmp_lt),
|
||||||
.logical_lesser_or_equal_expr => return binaryOp(gi, scope, node, .cmp_lte),
|
.logical_lesser_or_equal_expr => return binaryOp(gi, scope, node, .cmp_lte),
|
||||||
.call_expr => return callExpr(gi, scope, node, .call),
|
.call_expr => return callExpr(gi, scope, node, .call),
|
||||||
.choice_expr => unreachable,
|
|
||||||
.divert_expr => unreachable,
|
|
||||||
.selector_expr => return fieldAccess(gi, scope, node),
|
.selector_expr => return fieldAccess(gi, scope, node),
|
||||||
.assign_stmt => unreachable,
|
inline else => |_| 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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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 astgen = gi.astgen;
|
||||||
const identifier_node = node.data.bin.lhs.?;
|
const identifier_node = node.data.bin.lhs.?;
|
||||||
const expr_node = node.data.bin.rhs.?;
|
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", .{});
|
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 {
|
fn choiceStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void {
|
||||||
const astgen = gi.astgen;
|
const astgen = gi.astgen;
|
||||||
const gpa = astgen.gpa;
|
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),
|
.var_decl => try varDecl(gi, &child_scope, node),
|
||||||
.const_decl => try varDecl(gi, &child_scope, node),
|
.const_decl => try varDecl(gi, &child_scope, node),
|
||||||
.temp_decl => try tempDecl(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),
|
.content_stmt => try contentStmt(gi, &child_scope, node),
|
||||||
.choice_stmt => try choiceStmt(gi, &child_scope, node),
|
.choice_stmt => try choiceStmt(gi, &child_scope, node),
|
||||||
.expr_stmt => try exprStmt(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 {
|
fn getBindingPower(tag: Token.Tag) Precedence {
|
||||||
return switch (tag) {
|
return switch (tag) {
|
||||||
.ampersand_ampersand, .keyword_and => .logical_and,
|
.ampersand_ampersand, .keyword_and => .logical_and,
|
||||||
|
|
@ -703,16 +712,18 @@ fn parseAssignStmt(p: *Parse) Error!*Ast.Node {
|
||||||
const main_token = p.token;
|
const main_token = p.token;
|
||||||
const lhs = try parseIdentifierExpr(p);
|
const lhs = try parseIdentifierExpr(p);
|
||||||
|
|
||||||
if (!p.checkToken(.equal)) return parseExprStmt(p, lhs);
|
if (getTokenAssignType(p.token.tag)) |op| {
|
||||||
_ = p.nextToken();
|
_ = p.nextToken();
|
||||||
|
|
||||||
const rhs = try p.expectExpr();
|
const rhs = try p.expectExpr();
|
||||||
_ = try p.expectNewline();
|
_ = try p.expectNewline();
|
||||||
|
|
||||||
return .createBinary(p.arena, .assign_stmt, .{
|
return .createBinary(p.arena, op, .{
|
||||||
.start = main_token.loc.start,
|
.start = main_token.loc.start,
|
||||||
.end = p.token.loc.start,
|
.end = p.token.loc.start,
|
||||||
}, lhs, rhs);
|
}, lhs, rhs);
|
||||||
|
}
|
||||||
|
return parseExprStmt(p, lhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseTempDecl(p: *Parse) Error!*Ast.Node {
|
fn parseTempDecl(p: *Parse) Error!*Ast.Node {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ test "fixture - variable arithmetic" {
|
||||||
try testRuntimeFixture("variable-arithmetic");
|
try testRuntimeFixture("variable-arithmetic");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "fixture - assignment op" {
|
||||||
|
try testRuntimeFixture("assignment-op");
|
||||||
|
}
|
||||||
|
|
||||||
test "fixture - constant folding" {
|
test "fixture - constant folding" {
|
||||||
try testRuntimeFixture("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,
|
slash,
|
||||||
equal,
|
equal,
|
||||||
bang,
|
bang,
|
||||||
|
plus,
|
||||||
pipe,
|
pipe,
|
||||||
less_than,
|
less_than,
|
||||||
greater_than,
|
greater_than,
|
||||||
|
|
@ -197,7 +198,7 @@ pub const Tokenizer = struct {
|
||||||
},
|
},
|
||||||
'+' => {
|
'+' => {
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
result.tag = .plus;
|
continue :state .plus;
|
||||||
},
|
},
|
||||||
'-' => {
|
'-' => {
|
||||||
self.index += 1;
|
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]) {
|
.pipe => switch (self.buffer[self.index]) {
|
||||||
'|' => {
|
'|' => {
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
|
|
@ -296,6 +304,10 @@ pub const Tokenizer = struct {
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
result.tag = .right_arrow;
|
result.tag = .right_arrow;
|
||||||
},
|
},
|
||||||
|
'=' => {
|
||||||
|
self.index += 1;
|
||||||
|
result.tag = .minus_equal;
|
||||||
|
},
|
||||||
else => result.tag = .minus,
|
else => result.tag = .minus,
|
||||||
},
|
},
|
||||||
.slash => switch (self.buffer[self.index]) {
|
.slash => switch (self.buffer[self.index]) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue