summaryrefslogtreecommitdiff
path: root/src/js.rs
diff options
context:
space:
mode:
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!(),