feat: 支持复合运算符

This commit is contained in:
爱特每羊队
2026-06-06 20:20:05 +08:00
parent e245ab347a
commit 3c728686fc
8 changed files with 177 additions and 8 deletions
+1 -1
View File
@@ -223,7 +223,7 @@ impl Compiler {
} else {
self.count_expression(&assign.right, ctx);
ctx.alloc_reg();
ctx.projected_pc += 1; // STORE_VAR
ctx.projected_pc += 1;
}
}
Expression::ConditionalExpression(cond) => {
+20 -6
View File
@@ -630,13 +630,27 @@ impl Compiler {
&assign.left
{
if assign.operator != AssignmentOperator::Assign {
return Err("compound assignment not yet supported".into());
let rhs = self.emit_expression(&assign.right, ctx)?;
let name = id_ref.name.as_str();
let var_reg = ctx.lookup_or_global(name);
let op = match assign.operator {
AssignmentOperator::Addition => OpCode::COMPOUND_ADD,
AssignmentOperator::Subtraction => OpCode::COMPOUND_SUB,
AssignmentOperator::Multiplication => OpCode::COMPOUND_MUL,
AssignmentOperator::Division => OpCode::COMPOUND_DIV,
AssignmentOperator::Remainder => OpCode::COMPOUND_MOD,
AssignmentOperator::Exponential => OpCode::COMPOUND_EXP,
_ => unreachable!(),
};
ctx.emit(opcode::encode(op, var_reg, rhs, 0));
Ok(var_reg)
} else {
let val_reg = self.emit_expression(&assign.right, ctx)?;
let name = id_ref.name.as_str();
let var_reg = ctx.lookup_or_global(name);
ctx.emit(opcode::encode(OpCode::STORE_VAR, var_reg, val_reg, 0));
Ok(val_reg)
}
let val_reg = self.emit_expression(&assign.right, ctx)?;
let name = id_ref.name.as_str();
let var_reg = ctx.lookup_or_global(name);
ctx.emit(opcode::encode(OpCode::STORE_VAR, var_reg, val_reg, 0));
Ok(val_reg)
} else {
Err("assignment target not supported".into())
}
+5
View File
@@ -155,6 +155,11 @@ fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher) {
8u8.hash(h);
b.value.hash(h);
}
Expression::AssignmentExpression(assign) => {
11u8.hash(h);
std::mem::discriminant(&assign.operator).hash(h);
hash_expression(&assign.right, h);
}
_ => {
std::mem::discriminant(expr).hash(h);
}
+19 -1
View File
@@ -16,8 +16,14 @@ pub enum OpCode {
DIV = 0x03,
MOD = 0x04,
NEG = 0x05,
COMPOUND_ADD = 0x06,
COMPOUND_SUB = 0x07,
COMPOUND_MUL = 0x08,
COMPOUND_DIV = 0x09,
COMPOUND_MOD = 0x0A,
COMPOUND_EXP = 0x0B,
// ── Comparison (0x10-0x1F) ──
// -- Comparison (0x10-0x1F) --
EQ = 0x10,
NEQ = 0x11,
LT = 0x12,
@@ -104,6 +110,12 @@ impl TryFrom<u8> for OpCode {
0x03 => Ok(OpCode::DIV),
0x04 => Ok(OpCode::MOD),
0x05 => Ok(OpCode::NEG),
0x06 => Ok(OpCode::COMPOUND_ADD),
0x07 => Ok(OpCode::COMPOUND_SUB),
0x08 => Ok(OpCode::COMPOUND_MUL),
0x09 => Ok(OpCode::COMPOUND_DIV),
0x0A => Ok(OpCode::COMPOUND_MOD),
0x0B => Ok(OpCode::COMPOUND_EXP),
0x10 => Ok(OpCode::EQ),
0x11 => Ok(OpCode::NEQ),
0x12 => Ok(OpCode::LT),
@@ -163,6 +175,12 @@ impl fmt::Display for OpCode {
OpCode::DIV => "DIV",
OpCode::MOD => "MOD",
OpCode::NEG => "NEG",
OpCode::COMPOUND_ADD => "COMPOUND_ADD",
OpCode::COMPOUND_SUB => "COMPOUND_SUB",
OpCode::COMPOUND_MUL => "COMPOUND_MUL",
OpCode::COMPOUND_DIV => "COMPOUND_DIV",
OpCode::COMPOUND_MOD => "COMPOUND_MOD",
OpCode::COMPOUND_EXP => "COMPOUND_EXP",
OpCode::EQ => "EQ",
OpCode::NEQ => "NEQ",
OpCode::LT => "LT",
@@ -202,3 +202,43 @@ fn compile_unary_plus_no_error() {
});
assert!(result.is_ok(), "+'hello' should compile without error");
}
#[test]
fn compile_compound_add() {
let module = compile_source("var x=0; x+=1");
assert!(
module
.bytecode
.iter()
.any(|&i| opcode::opcode(i) == OpCode::COMPOUND_ADD),
"x+=1 should emit COMPOUND_ADD opcode"
);
}
#[test]
fn compile_compound_exp() {
let module = compile_source("var x=0; x**=2");
assert!(
module
.bytecode
.iter()
.any(|&i| opcode::opcode(i) == OpCode::COMPOUND_EXP),
"x**=2 should emit COMPOUND_EXP opcode"
);
}
#[test]
fn compile_compound_assign_no_error() {
let result = std::panic::catch_unwind(|| {
compile_source("x+=1");
});
assert!(result.is_ok(), "x+=1 should compile without error");
}
#[test]
fn compile_compound_exp_no_error() {
let result = std::panic::catch_unwind(|| {
compile_source("x**=2");
});
assert!(result.is_ok(), "x**=2 should compile without error");
}
@@ -97,3 +97,10 @@ fn regression_conditionalexpression_hash() {
"different expression types with same test must produce different hashes"
);
}
#[test]
fn hash_compound_vs_simple_assign() {
let hash_a = parse_to_hash("x=1");
let hash_b = parse_to_hash("x+=1");
assert_ne!(hash_a, hash_b, "x=1 and x+=1 must produce different hashes");
}