diff options
Diffstat (limited to 'src/js.rs')
-rw-r--r-- | src/js.rs | 66 |
1 files changed, 60 insertions, 6 deletions
@@ -38,6 +38,13 @@ pub struct JsCompiler { max_var: Vec<usize>, bytecode: Vec<u8>, functions: Vec<Function>, + identifiers: Vec<BTreeMap<Sym, IdentifierType>>, +} + +#[derive(Clone)] +enum IdentifierType { + Variable(IonValue), + Function(usize), } impl JsCompiler { @@ -50,6 +57,7 @@ impl JsCompiler { max_var: vec![0], bytecode: Vec::new(), functions: Vec::new(), + identifiers: Vec::new(), }; compiler.enter_block(); compiler @@ -63,6 +71,13 @@ impl JsCompiler { }; vars.insert("this".to_string(), 0); self.vars.push(vars); + + let identifiers = if let Some(identifiers) = self.identifiers.last() { + identifiers.clone() + } else { + BTreeMap::new() + }; + self.identifiers.push(identifiers); } fn exit_block(&mut self) { @@ -109,6 +124,15 @@ impl JsCompiler { self.bytecode.push(OpCode::SwapPop.into()); } + fn push_invoke(&mut self, function_id: usize) { + self.bytecode.push(OpCode::Invoke.into()); + self.push_varuint(function_id); + } + + fn push_invoke_dynamic(&mut self) { + self.bytecode.push(OpCode::InvokeDynamic.into()); + } + fn push_yield(&mut self) { self.bytecode.push(OpCode::Yield.into()); } @@ -233,7 +257,9 @@ impl JsCompiler { self.exit_block(); let name_symbol = if let Some(name) = func.name() { - self.to_symbol_id(name.sym()) + let id = self.to_symbol_id(name.sym()); + self.identifiers.last_mut().unwrap().insert(name.sym(), IdentifierType::Function(id)); + id } else { self.new_symbol_id(format!("anonFunction{}", self.functions.len())) }; @@ -255,12 +281,20 @@ impl JsCompiler { match v.binding() { Binding::Pattern(_) => todo!(), Binding::Identifier(ident) => { - let varid = self.get_or_create_variable(ident.sym()); if let Some(init) = v.init() { + if decl.is_const() { + if let Some(value) = self.get_static_expression(init) { + self.identifiers.last_mut() + .unwrap() + .insert(ident.sym(), IdentifierType::Variable(value)); + continue; + } + } self.compile_expression(init); } else { self.push_push(&IonValue::new_null()); } + let varid = self.get_or_create_variable(ident.sym()); self.push_store(varid); } } @@ -387,6 +421,13 @@ impl JsCompiler { fn get_static_expression(&mut self, expression: &Expression) -> Option<IonValue> { match expression { + Expression::Identifier(ident) => { + match self.identifiers.last().unwrap().get(&ident.sym()) { + Some(IdentifierType::Function(id)) => Some(IonValue::new_symbol(*id)), + Some(IdentifierType::Variable(value)) => Some(value.clone()), + None => None, + } + }, Expression::Literal(lit) => Some(self.literal_to_ion(lit)), Expression::ArrayLiteral(alit) => { let mut list = Vec::with_capacity(alit.as_ref().len()); @@ -482,7 +523,6 @@ impl JsCompiler { // I don't expect it will make sense to evaluate these statically. Expression::This => None, - Expression::Identifier(_) => None, Expression::New(_) => None, Expression::Optional(_) => None, @@ -495,8 +535,12 @@ impl JsCompiler { match expression { Expression::This => self.push_load(0), Expression::Identifier(ident) => { - let varid = self.get_or_create_variable(ident.sym()); - self.push_load(varid); + if let Some(value) = self.get_static_expression(expression) { + self.push_push(&value); + } else { + let varid = self.get_or_create_variable(ident.sym()); + self.push_load(varid); + } }, Expression::Literal(lit) => { let value = self.literal_to_ion(lit); @@ -602,7 +646,17 @@ impl JsCompiler { } }, Expression::New(_) => todo!(), - Expression::Call(_) => todo!(), + Expression::Call(call) => { + for arg in call.args() { + self.compile_expression(arg); + } + if let Some(value) = self.get_static_expression(call.function()) { + self.push_invoke(value.to_symbol_id()); + } else { + self.compile_expression(call.function()); + self.push_invoke_dynamic(); + } + }, Expression::SuperCall(_) => todo!(), Expression::ImportCall(_) => todo!(), Expression::Optional(_) => todo!(), |