diff options
author | Jesse Morgan <jesse@jesterpm.net> | 2024-01-01 19:41:30 -0800 |
---|---|---|
committer | Jesse Morgan <jesse@jesterpm.net> | 2024-01-01 19:41:30 -0800 |
commit | 40ce26ce1e97cf46c598c7a510fa9c8a2162b5fa (patch) | |
tree | 05f78878174c7bf4fd1f26d61cc575713ef57c52 /src/js.rs | |
parent | 76420739e01cb925eca57845bb4704e97d6c816a (diff) |
So far this only works if the function is defined before it is called.
Otherwise, it fails in confusing ways. The problem is that I currently
assume identifiers are always variables, but functions are currently
never variables. Functions are currently treated as special case when
they are declared. I'll need to rethink that...
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!(), |