summaryrefslogtreecommitdiff
path: root/src/js.rs
diff options
context:
space:
mode:
authorJesse Morgan <jesse@jesterpm.net>2024-01-01 19:41:30 -0800
committerJesse Morgan <jesse@jesterpm.net>2024-01-01 19:41:30 -0800
commit40ce26ce1e97cf46c598c7a510fa9c8a2162b5fa (patch)
tree05f78878174c7bf4fd1f26d61cc575713ef57c52 /src/js.rs
parent76420739e01cb925eca57845bb4704e97d6c816a (diff)
Add support for calling functions.HEADmaster
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.rs66
1 files changed, 60 insertions, 6 deletions
diff --git a/src/js.rs b/src/js.rs
index c0a96f8..bd7a36b 100644
--- a/src/js.rs
+++ b/src/js.rs
@@ -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!(),