summaryrefslogtreecommitdiff
path: root/src/js.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/js.rs')
-rw-r--r--src/js.rs174
1 files changed, 143 insertions, 31 deletions
diff --git a/src/js.rs b/src/js.rs
index 9249d30..d924969 100644
--- a/src/js.rs
+++ b/src/js.rs
@@ -384,47 +384,40 @@ impl JsCompiler {
}
}
- fn compile_expression(&mut self, expression: &Expression) {
+ fn get_static_expression(&mut self, expression: &Expression) -> Option<IonValue> {
match expression {
- Expression::This => self.push_load(0),
- Expression::Identifier(ident) => {
- let varid = self.get_or_create_variable(ident.sym());
- self.push_load(varid);
- },
- Expression::Literal(lit) => {
- let value = self.literal_to_ion(lit);
- self.push_push(&value);
- },
+ Expression::Literal(lit) => Some(self.literal_to_ion(lit)),
Expression::ArrayLiteral(alit) => {
- // TODO: there's an opportunity here inject static arrays into the bytecode.
+ let mut list = Vec::with_capacity(alit.as_ref().len());
for exprmaybe in alit.as_ref() {
if let Some(expr) = exprmaybe {
- self.compile_expression(expr);
+ if let Some(item) = self.get_static_expression(expr) {
+ list.push(item)
+ } else {
+ return None;
+ }
} else {
- self.push_push(&IonValue::new_null());
+ list.push(IonValue::new_null())
}
}
- self.push_push(&alit.as_ref().len().into());
- self.push_newlist();
+ Some(IonValue::from(list))
},
Expression::ObjectLiteral(olit) => {
- // TODO: there's an opportunity here inject static objects into the bytecode.
+ let mut fields = Vec::with_capacity(olit.properties().len());
for propdef in olit.properties() {
match propdef {
- PropertyDefinition::IdentifierReference(ident) => {
- let varid = self.get_or_create_variable(ident.sym());
- self.push_load(varid);
- let symb = self.to_ion_symbol(ident.sym());
- self.push_push(&symb);
- },
+ PropertyDefinition::IdentifierReference(ident) => return None,
PropertyDefinition::Property(name, expr) => {
- self.compile_expression(expr);
- match name {
- PropertyName::Literal(sym) => {
- let symb = self.to_ion_symbol(*sym);
- self.push_push(&symb);
- },
- PropertyName::Computed(_) => todo!(),
+ if let Some(value) = self.get_static_expression(expr) {
+ match name {
+ PropertyName::Literal(sym) => {
+ let symb = self.to_symbol_id(*sym);
+ fields.push((symb, value));
+ },
+ PropertyName::Computed(_) => return None,
+ }
+ } else {
+ return None;
}
},
PropertyDefinition::MethodDefinition(_, _) => todo!(),
@@ -432,8 +425,127 @@ impl JsCompiler {
PropertyDefinition::CoverInitializedName(_, _) => todo!(),
}
}
- self.push_push(&olit.properties().len().into());
- self.push_newstruct();
+ Some(IonValue::from(fields))
+ },
+ Expression::Spread(_) => None,
+ Expression::Function(_) => None,
+ Expression::ArrowFunction(_) => None,
+ Expression::AsyncArrowFunction(_) => None,
+ Expression::Generator(_) => None,
+ Expression::AsyncFunction(_) => None,
+ Expression::AsyncGenerator(_) => None,
+ Expression::Class(_) => None,
+ Expression::TemplateLiteral(_) => None,
+ Expression::PropertyAccess(atype) => {
+ match atype {
+ PropertyAccess::Simple(access) => {
+ if let Some(target) = self.get_static_expression(access.target()) {
+ let field = match access.field() {
+ PropertyAccessField::Const(sym) => {
+ Some(self.to_ion_symbol(*sym))
+ },
+ PropertyAccessField::Expr(expr) => {
+ self.get_static_expression(expr)
+ },
+ };
+ if let Some(field) = field {
+ return target.get_field(field.to_symbol_id());
+ }
+ }
+ None
+ },
+ PropertyAccess::Private(_) => todo!(),
+ PropertyAccess::Super(_) => todo!(),
+ }
+ },
+
+ Expression::Parenthesized(expr) => self.get_static_expression(expr.expression()),
+
+ // TODO: Add static evaluation to these.
+ Expression::Assign(assignment) => None,
+ Expression::Unary(_) => None,
+ Expression::Update(_) => None,
+ Expression::Binary(binary) => None,
+ Expression::BinaryInPrivate(_) => None,
+ Expression::Conditional(_) => None,
+ Expression::Call(_) => None,
+ Expression::SuperCall(_) => None,
+ Expression::ImportCall(_) => None,
+
+ // These probably don't make sense to evaluate statically.
+ Expression::TaggedTemplate(_) => None,
+ Expression::NewTarget => None,
+ Expression::ImportMeta => None,
+ Expression::Await(_) => None,
+ Expression::Yield(_) => None,
+
+ // I don't expect it will make sense to evaluate these statically.
+ Expression::This => None,
+ Expression::Identifier(_) => None,
+ Expression::New(_) => None,
+ Expression::Optional(_) => None,
+
+ _ => todo!(),
+ }
+
+ }
+
+ fn compile_expression(&mut self, expression: &Expression) {
+ match expression {
+ Expression::This => self.push_load(0),
+ Expression::Identifier(ident) => {
+ let varid = self.get_or_create_variable(ident.sym());
+ self.push_load(varid);
+ },
+ Expression::Literal(lit) => {
+ let value = self.literal_to_ion(lit);
+ self.push_push(&value);
+ },
+ Expression::ArrayLiteral(alit) => {
+ if let Some(value) = self.get_static_expression(expression) {
+ self.push_push(&value);
+ } else {
+ for exprmaybe in alit.as_ref() {
+ if let Some(expr) = exprmaybe {
+ self.compile_expression(expr);
+ } else {
+ self.push_push(&IonValue::new_null());
+ }
+ }
+ self.push_push(&alit.as_ref().len().into());
+ self.push_newlist();
+ }
+ },
+ Expression::ObjectLiteral(olit) => {
+ if let Some(value) = self.get_static_expression(expression) {
+ self.push_push(&value);
+ } else {
+ for propdef in olit.properties() {
+ match propdef {
+ PropertyDefinition::IdentifierReference(ident) => {
+ let varid = self.get_or_create_variable(ident.sym());
+ self.push_load(varid);
+ let symb = self.to_ion_symbol(ident.sym());
+ self.push_push(&symb);
+ },
+ PropertyDefinition::Property(name, expr) => {
+ self.compile_expression(expr);
+ match name {
+ PropertyName::Literal(sym) => {
+ let symb = self.to_ion_symbol(*sym);
+ self.push_push(&symb);
+ },
+ PropertyName::Computed(_) => todo!(),
+ }
+ },
+ PropertyDefinition::MethodDefinition(_, _) => todo!(),
+ PropertyDefinition::SpreadObject(_) => todo!(),
+ PropertyDefinition::CoverInitializedName(_, _) => todo!(),
+ }
+ }
+ self.push_push(&olit.properties().len().into());
+ self.push_newstruct();
+ }
},
Expression::Spread(_) => todo!(),
Expression::Function(_) => todo!(),