Make compile_enum_value and static_eval_expr methods of ModuleCompiler

This commit is contained in:
Andrew Morris
2023-07-24 14:10:15 +10:00
parent 870c9eed2a
commit ff47617862
5 changed files with 239 additions and 258 deletions

View File

@@ -1,63 +0,0 @@
use swc_common::Spanned;
use crate::{
asm::{Number, Object, Value},
diagnostic::DiagnosticReporter,
module_compiler::ModuleCompiler,
static_eval_expr::static_eval_expr,
};
pub fn compile_enum_value(mc: &mut ModuleCompiler, ts_enum: &swc_ecma_ast::TsEnumDecl) -> Value {
let mut properties = Vec::<(Value, Value)>::new();
let mut next_default_id: Option<f64> = Some(0.0);
for member in &ts_enum.members {
let key = match &member.id {
swc_ecma_ast::TsEnumMemberId::Ident(ident) => ident.sym.to_string(),
swc_ecma_ast::TsEnumMemberId::Str(str) => str.value.to_string(),
};
let init_value = match &member.init {
Some(init) => match static_eval_expr(mc, init) {
Some(init_value) => match init_value {
Value::Number(Number(n)) => {
next_default_id = Some(n + 1.0);
Some(Value::Number(Number(n)))
}
Value::String(_) => Some(init_value),
_ => None,
},
None => {
mc.internal_error(init.span(), "Static eval failed");
None
}
},
None => None,
};
let value = match init_value {
Some(value) => value,
None => {
let id = match next_default_id {
Some(id) => id,
None => {
mc.error(member.span, "Missing required initializer");
0.0
}
};
let value = Value::Number(Number(id));
next_default_id = Some(id + 1.0);
value
}
};
properties.push((Value::String(key.clone()), value.clone()));
properties.push((value, Value::String(key)));
}
Value::Object(Box::new(Object { properties }))
}

View File

@@ -8,7 +8,6 @@ use crate::asm::{
Builtin, Definition, DefinitionContent, FnLine, Function, Instruction, Label, Pointer, Register,
Value,
};
use crate::compile_enum_value::compile_enum_value;
use crate::diagnostic::{Diagnostic, DiagnosticContainer, DiagnosticLevel, DiagnosticReporter};
use crate::expression_compiler::CompiledExpression;
use crate::expression_compiler::ExpressionCompiler;
@@ -1203,7 +1202,7 @@ impl<'a> FunctionCompiler<'a> {
}
};
let enum_value = compile_enum_value(self.mc, ts_enum);
let enum_value = self.mc.compile_enum_value(ts_enum);
self.definitions.push(Definition {
pointer,

View File

@@ -2,7 +2,6 @@ pub mod asm;
mod assembler;
pub mod assembly_parser;
mod compile;
mod compile_enum_value;
mod constants;
mod diagnostic;
mod expression_compiler;
@@ -18,7 +17,6 @@ mod optimization;
mod resolve_path;
mod scope;
mod scope_analysis;
mod static_eval_expr;
mod target_accessor;
mod visit_pointers;

View File

@@ -5,20 +5,19 @@ use swc_common::errors::{DiagnosticBuilder, Emitter};
use swc_common::{errors::Handler, FileName, SourceMap, Spanned};
use swc_ecma_ast::EsVersion;
use swc_ecma_parser::{Syntax, TsConfig};
use valuescript_vm::operations::to_i32;
use crate::asm::{
Class, Definition, DefinitionContent, FnLine, Function, Instruction, Lazy, Module, Object,
Pointer, Register, Value,
Array, Builtin, Class, Definition, DefinitionContent, FnLine, Function, Instruction, Lazy,
Module, Number, Object, Pointer, Register, Value,
};
use crate::compile_enum_value::compile_enum_value;
use crate::diagnostic::{Diagnostic, DiagnosticContainer, DiagnosticReporter};
use crate::expression_compiler::{CompiledExpression, ExpressionCompiler};
use crate::expression_compiler::{value_from_literal, CompiledExpression, ExpressionCompiler};
use crate::function_compiler::{FunctionCompiler, Functionish};
use crate::ident::Ident;
use crate::name_allocator::{ident_from_str, NameAllocator};
use crate::scope::OwnerId;
use crate::scope_analysis::ScopeAnalysis;
use crate::static_eval_expr::static_eval_expr;
struct DiagnosticCollector {
diagnostics: Arc<Mutex<Vec<Diagnostic>>>,
@@ -181,11 +180,12 @@ impl ModuleCompiler {
ExportDefaultDecl(edd) => self.compile_export_default_decl(edd),
ExportDefaultExpr(ede) => {
let value = match &*ede.expr {
// TODO: Just do identifiers in compile_expr
swc_ecma_ast::Expr::Ident(ident) => self
.scope_analysis
.lookup(&Ident::from_swc_ident(ident))
.map(|name| name.value.clone()),
expr => static_eval_expr(self, expr),
expr => self.compile_expr(expr),
};
match value {
@@ -284,7 +284,7 @@ impl ModuleCompiler {
};
if let (Some(ident), Some(init)) = (ident, init) {
let value_opt = static_eval_expr(self, init);
let value_opt = self.compile_expr(init);
let value = match value_opt {
Some(value) => value,
@@ -386,7 +386,7 @@ impl ModuleCompiler {
));
}
let enum_value = compile_enum_value(self, ts_enum);
let enum_value = self.compile_enum_value(ts_enum);
self.module.definitions.push(Definition {
pointer,
@@ -869,7 +869,7 @@ impl ModuleCompiler {
let name = match &method.key {
swc_ecma_ast::PropName::Ident(ident) => Value::String(ident.sym.to_string()),
swc_ecma_ast::PropName::Computed(computed) => {
let value_opt = static_eval_expr(self, &computed.expr);
let value_opt = self.compile_expr(&computed.expr);
match value_opt {
None => {
@@ -938,4 +938,233 @@ impl ModuleCompiler {
defn_name
}
pub fn compile_enum_value(&mut self, ts_enum: &swc_ecma_ast::TsEnumDecl) -> Value {
let mut properties = Vec::<(Value, Value)>::new();
let mut next_default_id: Option<f64> = Some(0.0);
for member in &ts_enum.members {
let key = match &member.id {
swc_ecma_ast::TsEnumMemberId::Ident(ident) => ident.sym.to_string(),
swc_ecma_ast::TsEnumMemberId::Str(str) => str.value.to_string(),
};
let init_value = match &member.init {
Some(init) => match self.compile_expr(init) {
Some(init_value) => match init_value {
Value::Number(Number(n)) => {
next_default_id = Some(n + 1.0);
Some(Value::Number(Number(n)))
}
Value::String(_) => Some(init_value),
_ => None,
},
None => {
self.internal_error(init.span(), "Static eval failed");
None
}
},
None => None,
};
let value = match init_value {
Some(value) => value,
None => {
let id = match next_default_id {
Some(id) => id,
None => {
self.error(member.span, "Missing required initializer");
0.0
}
};
let value = Value::Number(Number(id));
next_default_id = Some(id + 1.0);
value
}
};
properties.push((Value::String(key.clone()), value.clone()));
properties.push((value, Value::String(key)));
}
Value::Object(Box::new(Object { properties }))
}
pub fn compile_expr(&mut self, expr: &swc_ecma_ast::Expr) -> Option<Value> {
let symbol_iterator_opt = as_symbol_iterator(expr);
if symbol_iterator_opt.is_some() {
return symbol_iterator_opt;
}
match expr {
swc_ecma_ast::Expr::Lit(lit) => match value_from_literal(lit) {
Ok(value) => Some(value),
_ => None,
},
swc_ecma_ast::Expr::Array(array) => {
let mut values = Vec::<Value>::new();
for item in &array.elems {
values.push(match item {
Some(item) => {
if item.spread.is_some() {
return None;
}
self.compile_expr(&item.expr)?
}
None => Value::Void,
});
}
Some(Value::Array(Box::new(Array { values })))
}
swc_ecma_ast::Expr::Object(object) => {
let mut properties = Vec::<(Value, Value)>::new();
for prop in &object.props {
let (key, value) = match prop {
swc_ecma_ast::PropOrSpread::Spread(_) => return None,
swc_ecma_ast::PropOrSpread::Prop(prop) => match &**prop {
swc_ecma_ast::Prop::Shorthand(_) => return None,
swc_ecma_ast::Prop::KeyValue(kv) => {
let key = match &kv.key {
swc_ecma_ast::PropName::Ident(ident) => Value::String(ident.sym.to_string()),
swc_ecma_ast::PropName::Str(str) => Value::String(str.value.to_string()),
swc_ecma_ast::PropName::Num(num) => Value::Number(Number(num.value)),
swc_ecma_ast::PropName::Computed(computed) => {
self.compile_expr(&computed.expr)?
}
swc_ecma_ast::PropName::BigInt(bi) => Value::BigInt(bi.value.clone()),
};
let value = self.compile_expr(&kv.value)?;
(key, value)
}
swc_ecma_ast::Prop::Assign(_) => return None,
swc_ecma_ast::Prop::Getter(_) => return None,
swc_ecma_ast::Prop::Setter(_) => return None,
swc_ecma_ast::Prop::Method(_) => return None,
},
};
properties.push((key, value));
}
Some(Value::Object(Box::new(Object { properties })))
}
swc_ecma_ast::Expr::This(_) => None,
swc_ecma_ast::Expr::Fn(_) => None,
swc_ecma_ast::Expr::Update(_) => None,
swc_ecma_ast::Expr::Assign(_) => None,
swc_ecma_ast::Expr::SuperProp(_) => None,
swc_ecma_ast::Expr::Call(_) => None,
swc_ecma_ast::Expr::New(_) => None,
swc_ecma_ast::Expr::Ident(ident) => match self
.scope_analysis
.lookup(&Ident::from_swc_ident(ident))
.map(|name| name.value.clone())
{
Some(Value::Pointer(p)) => self.constants_map.get(&p).cloned(),
Some(value) => Some(value),
None => None,
},
swc_ecma_ast::Expr::TaggedTpl(_) => None,
swc_ecma_ast::Expr::Arrow(_) => None,
swc_ecma_ast::Expr::Class(_) => None,
swc_ecma_ast::Expr::Yield(_) => None,
swc_ecma_ast::Expr::MetaProp(_) => None,
swc_ecma_ast::Expr::Await(_) => None,
swc_ecma_ast::Expr::JSXMember(_) => None,
swc_ecma_ast::Expr::JSXNamespacedName(_) => None,
swc_ecma_ast::Expr::JSXEmpty(_) => None,
swc_ecma_ast::Expr::JSXElement(_) => None,
swc_ecma_ast::Expr::JSXFragment(_) => None,
swc_ecma_ast::Expr::TsInstantiation(_) => None,
swc_ecma_ast::Expr::PrivateName(_) => None,
swc_ecma_ast::Expr::OptChain(_) => None,
swc_ecma_ast::Expr::Invalid(_) => None,
swc_ecma_ast::Expr::Member(_) => None,
swc_ecma_ast::Expr::Cond(_) => None,
swc_ecma_ast::Expr::Unary(unary) => match unary.op {
swc_ecma_ast::UnaryOp::Minus => match self.compile_expr(&unary.arg)? {
Value::Number(Number(x)) => Some(Value::Number(Number(-x))),
Value::BigInt(bi) => Some(Value::BigInt(-bi)),
_ => None,
},
swc_ecma_ast::UnaryOp::Plus => match self.compile_expr(&unary.arg)? {
Value::Number(Number(x)) => Some(Value::Number(Number(x))),
Value::BigInt(bi) => Some(Value::BigInt(bi)),
_ => None,
},
swc_ecma_ast::UnaryOp::Bang => None,
swc_ecma_ast::UnaryOp::Tilde => match self.compile_expr(&unary.arg)? {
Value::Number(Number(x)) => Some(Value::Number(Number(!to_i32(x) as f64))),
Value::BigInt(bi) => Some(Value::BigInt(!bi)),
_ => None,
},
swc_ecma_ast::UnaryOp::TypeOf => None,
swc_ecma_ast::UnaryOp::Void => None,
swc_ecma_ast::UnaryOp::Delete => None,
},
swc_ecma_ast::Expr::Bin(_) => None,
swc_ecma_ast::Expr::Seq(seq) => {
let mut last = Value::Void;
for expr in &seq.exprs {
last = self.compile_expr(expr)?;
}
Some(last)
}
swc_ecma_ast::Expr::Tpl(tpl) => 'b: {
let len = tpl.exprs.len();
assert_eq!(tpl.quasis.len(), len + 1);
if len == 0 {
break 'b Some(Value::String(tpl.quasis[0].raw.to_string()));
}
None // TODO
}
swc_ecma_ast::Expr::Paren(paren) => self.compile_expr(&paren.expr),
swc_ecma_ast::Expr::TsTypeAssertion(tta) => self.compile_expr(&tta.expr),
swc_ecma_ast::Expr::TsConstAssertion(tca) => self.compile_expr(&tca.expr),
swc_ecma_ast::Expr::TsNonNull(tnn) => self.compile_expr(&tnn.expr),
swc_ecma_ast::Expr::TsAs(ta) => self.compile_expr(&ta.expr),
}
}
}
fn as_symbol_iterator(expr: &swc_ecma_ast::Expr) -> Option<Value> {
let member_expr = match expr {
swc_ecma_ast::Expr::Member(member_expr) => member_expr,
_ => return None,
};
match &*member_expr.obj {
swc_ecma_ast::Expr::Ident(ident) => {
if ident.sym.to_string() != "Symbol" {
return None;
}
}
_ => return None,
};
match &member_expr.prop {
swc_ecma_ast::MemberProp::Ident(ident) => {
if ident.sym.to_string() != "iterator" {
return None;
}
}
_ => return None,
}
Some(Value::Builtin(Builtin {
name: "SymbolIterator".to_string(),
}))
}

View File

@@ -1,182 +0,0 @@
use valuescript_vm::operations::to_i32;
use crate::{
asm::{Array, Builtin, Number, Object, Value},
expression_compiler::value_from_literal,
ident::Ident,
module_compiler::ModuleCompiler,
};
pub fn static_eval_expr(mc: &ModuleCompiler, expr: &swc_ecma_ast::Expr) -> Option<Value> {
let symbol_iterator_opt = as_symbol_iterator(expr);
if symbol_iterator_opt.is_some() {
return symbol_iterator_opt;
}
match expr {
swc_ecma_ast::Expr::Lit(lit) => match value_from_literal(lit) {
Ok(value) => Some(value),
_ => None,
},
swc_ecma_ast::Expr::Array(array) => {
let mut values = Vec::<Value>::new();
for item in &array.elems {
values.push(match item {
Some(item) => {
if item.spread.is_some() {
return None;
}
static_eval_expr(mc, &item.expr)?
}
None => Value::Void,
});
}
Some(Value::Array(Box::new(Array { values })))
}
swc_ecma_ast::Expr::Object(object) => {
let mut properties = Vec::<(Value, Value)>::new();
for prop in &object.props {
let (key, value) = match prop {
swc_ecma_ast::PropOrSpread::Spread(_) => return None,
swc_ecma_ast::PropOrSpread::Prop(prop) => match &**prop {
swc_ecma_ast::Prop::Shorthand(_) => return None,
swc_ecma_ast::Prop::KeyValue(kv) => {
let key = match &kv.key {
swc_ecma_ast::PropName::Ident(ident) => Value::String(ident.sym.to_string()),
swc_ecma_ast::PropName::Str(str) => Value::String(str.value.to_string()),
swc_ecma_ast::PropName::Num(num) => Value::Number(Number(num.value)),
swc_ecma_ast::PropName::Computed(computed) => static_eval_expr(mc, &computed.expr)?,
swc_ecma_ast::PropName::BigInt(bi) => Value::BigInt(bi.value.clone()),
};
let value = static_eval_expr(mc, &kv.value)?;
(key, value)
}
swc_ecma_ast::Prop::Assign(_) => return None,
swc_ecma_ast::Prop::Getter(_) => return None,
swc_ecma_ast::Prop::Setter(_) => return None,
swc_ecma_ast::Prop::Method(_) => return None,
},
};
properties.push((key, value));
}
Some(Value::Object(Box::new(Object { properties })))
}
swc_ecma_ast::Expr::This(_) => None,
swc_ecma_ast::Expr::Fn(_) => None,
swc_ecma_ast::Expr::Update(_) => None,
swc_ecma_ast::Expr::Assign(_) => None,
swc_ecma_ast::Expr::SuperProp(_) => None,
swc_ecma_ast::Expr::Call(_) => None,
swc_ecma_ast::Expr::New(_) => None,
swc_ecma_ast::Expr::Ident(ident) => match mc
.scope_analysis
.lookup(&Ident::from_swc_ident(ident))
.map(|name| name.value.clone())
{
Some(Value::Pointer(p)) => mc.constants_map.get(&p).cloned(),
Some(value) => Some(value),
None => None,
},
swc_ecma_ast::Expr::TaggedTpl(_) => None,
swc_ecma_ast::Expr::Arrow(_) => None,
swc_ecma_ast::Expr::Class(_) => None,
swc_ecma_ast::Expr::Yield(_) => None,
swc_ecma_ast::Expr::MetaProp(_) => None,
swc_ecma_ast::Expr::Await(_) => None,
swc_ecma_ast::Expr::JSXMember(_) => None,
swc_ecma_ast::Expr::JSXNamespacedName(_) => None,
swc_ecma_ast::Expr::JSXEmpty(_) => None,
swc_ecma_ast::Expr::JSXElement(_) => None,
swc_ecma_ast::Expr::JSXFragment(_) => None,
swc_ecma_ast::Expr::TsInstantiation(_) => None,
swc_ecma_ast::Expr::PrivateName(_) => None,
swc_ecma_ast::Expr::OptChain(_) => None,
swc_ecma_ast::Expr::Invalid(_) => None,
swc_ecma_ast::Expr::Member(_) => None,
swc_ecma_ast::Expr::Cond(_) => None,
swc_ecma_ast::Expr::Unary(unary) => match unary.op {
swc_ecma_ast::UnaryOp::Minus => match static_eval_expr(mc, &unary.arg)? {
Value::Number(Number(x)) => Some(Value::Number(Number(-x))),
Value::BigInt(bi) => Some(Value::BigInt(-bi)),
_ => None,
},
swc_ecma_ast::UnaryOp::Plus => match static_eval_expr(mc, &unary.arg)? {
Value::Number(Number(x)) => Some(Value::Number(Number(x))),
Value::BigInt(bi) => Some(Value::BigInt(bi)),
_ => None,
},
swc_ecma_ast::UnaryOp::Bang => None,
swc_ecma_ast::UnaryOp::Tilde => match static_eval_expr(mc, &unary.arg)? {
Value::Number(Number(x)) => Some(Value::Number(Number(!to_i32(x) as f64))),
Value::BigInt(bi) => Some(Value::BigInt(!bi)),
_ => None,
},
swc_ecma_ast::UnaryOp::TypeOf => None,
swc_ecma_ast::UnaryOp::Void => None,
swc_ecma_ast::UnaryOp::Delete => None,
},
swc_ecma_ast::Expr::Bin(_) => None,
swc_ecma_ast::Expr::Seq(seq) => {
let mut last = Value::Void;
for expr in &seq.exprs {
last = static_eval_expr(mc, expr)?;
}
Some(last)
}
swc_ecma_ast::Expr::Tpl(tpl) => 'b: {
let len = tpl.exprs.len();
assert_eq!(tpl.quasis.len(), len + 1);
if len == 0 {
break 'b Some(Value::String(tpl.quasis[0].raw.to_string()));
}
None // TODO
}
swc_ecma_ast::Expr::Paren(paren) => static_eval_expr(mc, &paren.expr),
swc_ecma_ast::Expr::TsTypeAssertion(tta) => static_eval_expr(mc, &tta.expr),
swc_ecma_ast::Expr::TsConstAssertion(tca) => static_eval_expr(mc, &tca.expr),
swc_ecma_ast::Expr::TsNonNull(tnn) => static_eval_expr(mc, &tnn.expr),
swc_ecma_ast::Expr::TsAs(ta) => static_eval_expr(mc, &ta.expr),
}
}
fn as_symbol_iterator(expr: &swc_ecma_ast::Expr) -> Option<Value> {
let member_expr = match expr {
swc_ecma_ast::Expr::Member(member_expr) => member_expr,
_ => return None,
};
match &*member_expr.obj {
swc_ecma_ast::Expr::Ident(ident) => {
if ident.sym.to_string() != "Symbol" {
return None;
}
}
_ => return None,
};
match &member_expr.prop {
swc_ecma_ast::MemberProp::Ident(ident) => {
if ident.sym.to_string() != "iterator" {
return None;
}
}
_ => return None,
}
Some(Value::Builtin(Builtin {
name: "SymbolIterator".to_string(),
}))
}