From 1ee2bc30da74269bfcfbccaec2ff6c6708e8fd2a Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Wed, 31 May 2023 11:33:12 +1000 Subject: [PATCH] Implement spreading for calls, news, and methods --- inputs/passing/spread.ts | 32 +- .../src/expression_compiler.rs | 339 ++++++++---------- 2 files changed, 170 insertions(+), 201 deletions(-) diff --git a/inputs/passing/spread.ts b/inputs/passing/spread.ts index b3d86d2..c634757 100644 --- a/inputs/passing/spread.ts +++ b/inputs/passing/spread.ts @@ -1,6 +1,32 @@ -// test_output! [".","a","b","c","."] +// test_output! [".abc.",".abc.",".abc.",".abc."] export default function () { - const middle = ["a", "b", "c"]; - return [".", ...middle, "."]; + const middle = ["a", "b", "c"] as const; + const arr = [".", ...middle, "."]; + const call = foo(".", ...middle, "."); + + let bar = new Bar(".", ...middle, "."); + bar.method(".", ...middle, "."); + + const new_ = bar.value; + const method = bar.method_value; + + return [arr, call, new_, method].map((x) => x.join("")); +} + +function foo(a: string, b: string, c: string, d: string, e: string) { + return [a, b, c, d, e]; +} + +class Bar { + value: string[]; + method_value: string[] = []; + + constructor(a: string, b: string, c: string, d: string, e: string) { + this.value = [a, b, c, d, e]; + } + + method(a: string, b: string, c: string, d: string, e: string) { + this.method_value = [a, b, c, d, e]; + } } diff --git a/valuescript_compiler/src/expression_compiler.rs b/valuescript_compiler/src/expression_compiler.rs index 16e936f..d0e3b06 100644 --- a/valuescript_compiler/src/expression_compiler.rs +++ b/valuescript_compiler/src/expression_compiler.rs @@ -213,11 +213,7 @@ impl<'a> ExpressionCompiler<'a> { return CompiledExpression::empty(); } TsConstAssertion(ts_const_assertion) => { - self - .fnc - .todo(ts_const_assertion.span, "TsConstAssertion expression"); - - return CompiledExpression::empty(); + return self.compile(&ts_const_assertion.expr, target_register); } TsNonNull(ts_non_null_exp) => { return self.compile(&ts_non_null_exp.expr, target_register); @@ -529,82 +525,9 @@ impl<'a> ExpressionCompiler<'a> { array_exp: &swc_ecma_ast::ArrayLit, target_register: Option, ) -> CompiledExpression { - let mut segments = Vec::::new(); - let mut current = Vec::::new(); - let mut sub_nested_registers = Vec::::new(); + let args = array_exp.elems.iter().map(|x| x.as_ref()); - for i in 0..array_exp.elems.len() { - match &array_exp.elems[i] { - None => { - current.push(Value::Void); - } - Some(elem) => { - if elem.spread.is_some() && !current.is_empty() { - segments.push(Value::Array(Box::new(Array { - values: take(&mut current), - }))); - } - - let mut compiled_elem = self.compile(&*elem.expr, None); - - if elem.spread.is_some() { - segments.push(compiled_elem.value); - } else { - current.push(compiled_elem.value); - } - - sub_nested_registers.append(&mut compiled_elem.nested_registers); - compiled_elem.release_checker.has_unreleased_registers = false; - } - } - } - - if segments.is_empty() { - return match target_register { - None => CompiledExpression::new( - Value::Array(Box::new(Array { values: current })), - sub_nested_registers, - ), - Some(tr) => { - self.fnc.push(Instruction::Mov( - Value::Array(Box::new(Array { values: current })), - tr.clone(), - )); - - for reg in sub_nested_registers { - self.fnc.release_reg(®); - } - - CompiledExpression::new(Value::Register(tr), vec![]) - } - }; - } - - for reg in sub_nested_registers { - self.fnc.release_reg(®); - } - - if !current.is_empty() { - segments.push(Value::Array(Box::new(Array { values: current }))); - } - - let mut nested_registers = Vec::::new(); - - let res_reg = match target_register { - Some(target_register) => target_register, - None => { - let tmp = self.fnc.allocate_tmp(); - nested_registers.push(tmp.clone()); - tmp - } - }; - - self.fnc.push(Instruction::Cat( - Value::Array(Box::new(Array { values: segments })), - res_reg.clone(), - )); - - CompiledExpression::new(Value::Register(res_reg), nested_registers) + self.args(args, target_register) } pub fn object_expression( @@ -855,9 +778,8 @@ impl<'a> ExpressionCompiler<'a> { target_register: Option, ) -> CompiledExpression { let mut nested_registers = Vec::::new(); - let mut sub_nested_registers = Vec::::new(); - let mut callee = match &call_exp.callee { + let callee = match &call_exp.callee { swc_ecma_ast::Callee::Expr(expr) => self.compile(&*expr, None), _ => { self @@ -868,48 +790,27 @@ impl<'a> ExpressionCompiler<'a> { } }; - callee.release_checker.has_unreleased_registers = false; - sub_nested_registers.append(&mut callee.nested_registers); + let args = call_exp.args.iter().map(|x| Some(x)); + let compiled_args = self.args(args, None); - let mut args = Array::default(); - - for i in 0..call_exp.args.len() { - let arg = &call_exp.args[i]; - - if arg.spread.is_some() { - self.fnc.todo(arg.spread.span(), "argument spreading"); - } - - let mut compiled_arg = self.compile(&*arg.expr, None); - compiled_arg.release_checker.has_unreleased_registers = false; - sub_nested_registers.append(&mut compiled_arg.nested_registers); - - args.values.push(compiled_arg.value); - } - - let tmp_dest: Register; - - let dest = match &target_register { + let dest = match target_register { Some(tr) => tr, None => { - tmp_dest = self.fnc.allocate_tmp(); - nested_registers.push(tmp_dest.clone()); + let tmp = self.fnc.allocate_tmp(); + nested_registers.push(tmp.clone()); - &tmp_dest + tmp } }; - self.fnc.push(Instruction::Call( - callee.value, - Value::Array(Box::new(args)), - dest.clone(), - )); + let args_value = self.fnc.use_(compiled_args); + let callee_value = self.fnc.use_(callee); - for reg in sub_nested_registers { - self.fnc.release_reg(®); - } + self + .fnc + .push(Instruction::Call(callee_value, args_value, dest.clone())); - CompiledExpression::new(Value::Register(dest.clone()), nested_registers) + CompiledExpression::new(Value::Register(dest), nested_registers) } pub fn new_expression( @@ -920,57 +821,35 @@ impl<'a> ExpressionCompiler<'a> { // TODO: Try to deduplicate with call_expression let mut nested_registers = Vec::::new(); - let mut sub_nested_registers = Vec::::new(); - let mut callee = self.compile(&new_exp.callee, None); + let callee = self.compile(&new_exp.callee, None); - callee.release_checker.has_unreleased_registers = false; - sub_nested_registers.append(&mut callee.nested_registers); - - // let mut instr = " new ".to_string(); - // instr += &callee.value.to_string(); - // instr += " "; - - let mut args = Array::default(); - - for new_args in &new_exp.args { - for i in 0..new_args.len() { - let arg = &new_args[i]; - - if arg.spread.is_some() { - self.fnc.todo(arg.spread.span(), "argument spreading"); - } - - let mut compiled_arg = self.compile(&*arg.expr, None); - sub_nested_registers.append(&mut compiled_arg.nested_registers); - - args.values.push(self.fnc.use_(compiled_arg)); - } - } - - let tmp_dest: Register; - - let dest = match &target_register { - Some(tr) => tr, - None => { - tmp_dest = self.fnc.allocate_tmp(); - nested_registers.push(tmp_dest.clone()); - - &tmp_dest + let compiled_args = match &new_exp.args { + None => CompiledExpression::new(Value::Array(Box::new(Array::default())), vec![]), + Some(new_exp_args) => { + let args = new_exp_args.iter().map(|x| Some(x)); + self.args(args, None) } }; - self.fnc.push(Instruction::New( - callee.value, - Value::Array(Box::new(args)), - dest.clone(), - )); + let dest = match target_register { + Some(tr) => tr, + None => { + let tmp = self.fnc.allocate_tmp(); + nested_registers.push(tmp.clone()); - for reg in sub_nested_registers { - self.fnc.release_reg(®); - } + tmp + } + }; - CompiledExpression::new(Value::Register(dest.clone()), nested_registers) + let callee_value = self.fnc.use_(callee); + let args_value = self.fnc.use_(compiled_args); + + self + .fnc + .push(Instruction::New(callee_value, args_value, dest.clone())); + + CompiledExpression::new(Value::Register(dest), nested_registers) } pub fn method_call_expression( @@ -1008,31 +887,18 @@ impl<'a> ExpressionCompiler<'a> { prop.release_checker.has_unreleased_registers = false; sub_nested_registers.append(&mut prop.nested_registers); - let mut asm_args = Array::default(); + let compiled_args = { + let args_iter = args.iter().map(|x| Some(x)); + self.args(args_iter, None) + }; - for i in 0..args.len() { - let arg = &args[i]; - - if arg.spread.is_some() { - self.fnc.todo(arg.spread.span(), "argument spreading"); - } - - let mut compiled_arg = self.compile(&*arg.expr, None); - compiled_arg.release_checker.has_unreleased_registers = false; - sub_nested_registers.append(&mut compiled_arg.nested_registers); - - asm_args.values.push(compiled_arg.value); - } - - let tmp_dest: Register; - - let dest = match &target_register { + let dest = match target_register { Some(tr) => tr, None => { - tmp_dest = self.fnc.allocate_tmp(); - nested_registers.push(tmp_dest.clone()); + let tmp = self.fnc.allocate_tmp(); + nested_registers.push(tmp.clone()); - &tmp_dest + tmp } }; @@ -1040,31 +906,21 @@ impl<'a> ExpressionCompiler<'a> { TargetAccessorOrCompiledExpression::TargetAccessor(mut ta) => { let targets_this = ta.targets_this(); + let args_value = self.fnc.use_(compiled_args); + let instr = match targets_this { - false => Instruction::SubCall( - obj_value.clone(), - prop.value, - Value::Array(Box::new(asm_args)), - dest.clone(), - ), - true => Instruction::ThisSubCall( - obj_value.clone(), - prop.value, - Value::Array(Box::new(asm_args)), - dest.clone(), - ), + false => Instruction::SubCall(obj_value.clone(), prop.value, args_value, dest.clone()), + true => Instruction::ThisSubCall(obj_value.clone(), prop.value, args_value, dest.clone()), }; self.fnc.push(instr); ta.assign_and_packup(self, &obj_value, targets_this); } TargetAccessorOrCompiledExpression::CompiledExpression(ce) => { - let instr = Instruction::ConstSubCall( - obj_value.clone(), - prop.value, - Value::Array(Box::new(asm_args)), - dest.clone(), - ); + let args_value = self.fnc.use_(compiled_args); + + let instr = + Instruction::ConstSubCall(obj_value.clone(), prop.value, args_value, dest.clone()); self.fnc.push(instr); self.fnc.use_(ce); @@ -1620,6 +1476,93 @@ impl<'a> ExpressionCompiler<'a> { self.fnc.label(initialized_label); } + + fn args<'b, IterT>( + &mut self, + arg_list: IterT, + target_register: Option, + ) -> CompiledExpression + where + IterT: Iterator>, + { + let mut segments = Vec::::new(); + let mut current = Vec::::new(); + let mut sub_nested_registers = Vec::::new(); + + for arg in arg_list { + let arg = match arg { + None => { + current.push(Value::Void); + continue; + } + Some(arg) => arg, + }; + + if arg.spread.is_some() && !current.is_empty() { + segments.push(Value::Array(Box::new(Array { + values: take(&mut current), + }))); + } + + let mut compiled_elem = self.compile(&*arg.expr, None); + + if arg.spread.is_some() { + segments.push(compiled_elem.value); + } else { + current.push(compiled_elem.value); + } + + sub_nested_registers.append(&mut compiled_elem.nested_registers); + compiled_elem.release_checker.has_unreleased_registers = false; + } + + if segments.is_empty() { + return match target_register { + None => CompiledExpression::new( + Value::Array(Box::new(Array { values: current })), + sub_nested_registers, + ), + Some(tr) => { + self.fnc.push(Instruction::Mov( + Value::Array(Box::new(Array { values: current })), + tr.clone(), + )); + + for reg in sub_nested_registers { + self.fnc.release_reg(®); + } + + CompiledExpression::new(Value::Register(tr), vec![]) + } + }; + } + + for reg in sub_nested_registers { + self.fnc.release_reg(®); + } + + if !current.is_empty() { + segments.push(Value::Array(Box::new(Array { values: current }))); + } + + let mut nested_registers = Vec::::new(); + + let res_reg = match target_register { + Some(target_register) => target_register, + None => { + let tmp = self.fnc.allocate_tmp(); + nested_registers.push(tmp.clone()); + tmp + } + }; + + self.fnc.push(Instruction::Cat( + Value::Array(Box::new(Array { values: segments })), + res_reg.clone(), + )); + + CompiledExpression::new(Value::Register(res_reg), nested_registers) + } } pub fn make_unary_op(op: swc_ecma_ast::UnaryOp, arg: Value, dst: Register) -> Option {