Implement constants that refer to other constants

This commit is contained in:
Andrew Morris
2023-07-07 17:46:29 +10:00
parent 48fd851fb7
commit 24438aecb7
6 changed files with 85 additions and 36 deletions

View File

@@ -0,0 +1,8 @@
//! test_output(-4)
export default function () {
return y;
}
const x = 3;
const y = ~x;

View File

@@ -8,7 +8,7 @@ use crate::{
pub use crate::instruction::{Instruction, InstructionFieldMut};
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct Module {
pub export_default: Value,
pub export_star: Object,
@@ -24,16 +24,6 @@ impl Module {
}
}
impl Default for Module {
fn default() -> Self {
Module {
export_default: Value::Void,
export_star: Object::default(),
definitions: Vec::default(),
}
}
}
impl std::fmt::Display for Module {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if self.export_star.properties.is_empty() {

View File

@@ -1,7 +1,9 @@
use std::collections::HashMap;
use swc_common::Spanned;
use crate::{
asm::{Number, Object, Value},
asm::{Number, Object, Pointer, Value},
scope_analysis::ScopeAnalysis,
static_eval_expr::static_eval_expr,
Diagnostic, DiagnosticLevel,
@@ -9,6 +11,7 @@ use crate::{
pub fn compile_enum_value(
sa: &ScopeAnalysis,
cm: &HashMap<Pointer, Value>,
ts_enum: &swc_ecma_ast::TsEnumDecl,
diagnostics: &mut Vec<Diagnostic>,
) -> Value {
@@ -22,7 +25,7 @@ pub fn compile_enum_value(
};
let init_value = match &member.init {
Some(init) => match static_eval_expr(sa, init) {
Some(init) => match static_eval_expr(sa, cm, init) {
Some(init_value) => match init_value {
Value::Number(Number(n)) => {
next_default_id = Some(n + 1.0);

View File

@@ -1,6 +1,6 @@
use queues::*;
use std::cell::RefCell;
use std::collections::BTreeSet;
use std::collections::{BTreeSet, HashMap};
use std::mem::take;
use std::rc::Rc;
@@ -66,6 +66,7 @@ pub struct FunctionCompiler {
pub definitions: Vec<Definition>,
pub owner_id: OwnerId,
pub scope_analysis: Rc<ScopeAnalysis>,
pub constants_map: Rc<RefCell<HashMap<Pointer, Value>>>,
pub definition_allocator: Rc<RefCell<NameAllocator>>,
pub reg_allocator: RegAllocator,
pub label_allocator: NameAllocator,
@@ -82,6 +83,7 @@ pub struct FunctionCompiler {
impl FunctionCompiler {
pub fn new(
scope_analysis: &Rc<ScopeAnalysis>,
constants_map: &Rc<RefCell<HashMap<Pointer, Value>>>,
owner_id: OwnerId,
definition_allocator: Rc<RefCell<NameAllocator>>,
) -> FunctionCompiler {
@@ -95,6 +97,7 @@ impl FunctionCompiler {
definitions: vec![],
owner_id,
scope_analysis: scope_analysis.clone(),
constants_map: constants_map.clone(),
definition_allocator,
reg_allocator,
label_allocator: NameAllocator::default(),
@@ -240,10 +243,15 @@ impl FunctionCompiler {
fn_name: Option<String>,
functionish: Functionish,
scope_analysis: &Rc<ScopeAnalysis>,
constants_map: &Rc<RefCell<HashMap<Pointer, Value>>>,
definition_allocator: Rc<RefCell<NameAllocator>>,
) -> (Vec<Definition>, Vec<Diagnostic>) {
let mut self_ =
FunctionCompiler::new(scope_analysis, functionish.owner_id(), definition_allocator);
let mut self_ = FunctionCompiler::new(
scope_analysis,
constants_map,
functionish.owner_id(),
definition_allocator,
);
self_
.queue
@@ -1253,7 +1261,12 @@ impl FunctionCompiler {
}
};
let enum_value = compile_enum_value(&self.scope_analysis, ts_enum, &mut self.diagnostics);
let enum_value = compile_enum_value(
&self.scope_analysis,
&self.constants_map.borrow(),
ts_enum,
&mut self.diagnostics,
);
self.definitions.push(Definition {
pointer,

View File

@@ -1,4 +1,5 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
@@ -98,6 +99,7 @@ struct ModuleCompiler {
diagnostics: Vec<Diagnostic>,
definition_allocator: Rc<RefCell<NameAllocator>>,
scope_analysis: Rc<ScopeAnalysis>,
constants_map: Rc<RefCell<HashMap<Pointer, Value>>>,
module: Module,
}
@@ -205,7 +207,7 @@ impl ModuleCompiler {
.scope_analysis
.lookup(ident)
.map(|name| name.value.clone()),
expr => static_eval_expr(&self.scope_analysis, expr),
expr => static_eval_expr(&self.scope_analysis, &self.constants_map.borrow(), expr),
};
match value {
@@ -298,7 +300,10 @@ impl ModuleCompiler {
};
if let (Some(ident), Some(init)) = (ident, init) {
let value = match static_eval_expr(&self.scope_analysis, init) {
let value_opt =
static_eval_expr(&self.scope_analysis, &self.constants_map.borrow(), init);
let value = match value_opt {
Some(value) => value,
None => {
self.todo(
@@ -334,6 +339,11 @@ impl ModuleCompiler {
}
};
self
.constants_map
.borrow_mut()
.insert(pointer.clone(), value.clone());
self.module.definitions.push(Definition {
pointer,
content: DefinitionContent::Value(value),
@@ -407,7 +417,12 @@ impl ModuleCompiler {
));
}
let enum_value = compile_enum_value(&self.scope_analysis, ts_enum, &mut self.diagnostics);
let enum_value = compile_enum_value(
&self.scope_analysis,
&self.constants_map.borrow(),
ts_enum,
&mut self.diagnostics,
);
self.module.definitions.push(Definition {
pointer,
@@ -783,6 +798,7 @@ impl ModuleCompiler {
fn_name,
functionish,
&self.scope_analysis,
&self.constants_map,
self.definition_allocator.clone(),
);
@@ -827,6 +843,7 @@ impl ModuleCompiler {
let mut member_initializers_fnc = FunctionCompiler::new(
&self.scope_analysis,
&self.constants_map,
OwnerId::Span(class.span),
self.definition_allocator.clone(),
);
@@ -919,7 +936,13 @@ 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) => {
match static_eval_expr(&self.scope_analysis, &computed.expr) {
let value_opt = static_eval_expr(
&self.scope_analysis,
&self.constants_map.borrow(),
&computed.expr,
);
match value_opt {
None => {
self.todo(
computed.span,

View File

@@ -1,12 +1,18 @@
use std::collections::HashMap;
use valuescript_vm::operations::to_i32;
use crate::{
asm::{Array, Builtin, Number, Object, Value},
asm::{Array, Builtin, Number, Object, Pointer, Value},
expression_compiler::value_from_literal,
scope_analysis::ScopeAnalysis,
};
pub fn static_eval_expr(sa: &ScopeAnalysis, expr: &swc_ecma_ast::Expr) -> Option<Value> {
pub fn static_eval_expr(
sa: &ScopeAnalysis,
cm: &HashMap<Pointer, Value>,
expr: &swc_ecma_ast::Expr,
) -> Option<Value> {
let symbol_iterator_opt = as_symbol_iterator(expr);
if symbol_iterator_opt.is_some() {
@@ -28,7 +34,7 @@ pub fn static_eval_expr(sa: &ScopeAnalysis, expr: &swc_ecma_ast::Expr) -> Option
return None;
}
static_eval_expr(sa, &item.expr)?
static_eval_expr(sa, cm, &item.expr)?
}
None => Value::Void,
});
@@ -49,11 +55,13 @@ pub fn static_eval_expr(sa: &ScopeAnalysis, expr: &swc_ecma_ast::Expr) -> Option
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(sa, &computed.expr)?,
swc_ecma_ast::PropName::Computed(computed) => {
static_eval_expr(sa, cm, &computed.expr)?
}
swc_ecma_ast::PropName::BigInt(bi) => Value::BigInt(bi.value.clone()),
};
let value = static_eval_expr(sa, &kv.value)?;
let value = static_eval_expr(sa, cm, &kv.value)?;
(key, value)
}
@@ -76,7 +84,11 @@ pub fn static_eval_expr(sa: &ScopeAnalysis, expr: &swc_ecma_ast::Expr) -> Option
swc_ecma_ast::Expr::SuperProp(_) => None,
swc_ecma_ast::Expr::Call(_) => None,
swc_ecma_ast::Expr::New(_) => None,
swc_ecma_ast::Expr::Ident(ident) => sa.lookup(ident).map(|name| name.value.clone()),
swc_ecma_ast::Expr::Ident(ident) => match sa.lookup(ident).map(|name| name.value.clone()) {
Some(Value::Pointer(p)) => cm.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,
@@ -95,18 +107,18 @@ pub fn static_eval_expr(sa: &ScopeAnalysis, expr: &swc_ecma_ast::Expr) -> Option
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(sa, &unary.arg)? {
swc_ecma_ast::UnaryOp::Minus => match static_eval_expr(sa, cm, &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(sa, &unary.arg)? {
swc_ecma_ast::UnaryOp::Plus => match static_eval_expr(sa, cm, &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(sa, &unary.arg)? {
swc_ecma_ast::UnaryOp::Tilde => match static_eval_expr(sa, cm, &unary.arg)? {
Value::Number(Number(x)) => Some(Value::Number(Number(!to_i32(x) as f64))),
Value::BigInt(bi) => Some(Value::BigInt(!bi)),
_ => None,
@@ -120,7 +132,7 @@ pub fn static_eval_expr(sa: &ScopeAnalysis, expr: &swc_ecma_ast::Expr) -> Option
let mut last = Value::Void;
for expr in &seq.exprs {
last = static_eval_expr(sa, expr)?;
last = static_eval_expr(sa, cm, expr)?;
}
Some(last)
@@ -135,11 +147,11 @@ pub fn static_eval_expr(sa: &ScopeAnalysis, expr: &swc_ecma_ast::Expr) -> Option
None // TODO
}
swc_ecma_ast::Expr::Paren(paren) => static_eval_expr(sa, &paren.expr),
swc_ecma_ast::Expr::TsTypeAssertion(tta) => static_eval_expr(sa, &tta.expr),
swc_ecma_ast::Expr::TsConstAssertion(tca) => static_eval_expr(sa, &tca.expr),
swc_ecma_ast::Expr::TsNonNull(tnn) => static_eval_expr(sa, &tnn.expr),
swc_ecma_ast::Expr::TsAs(ta) => static_eval_expr(sa, &ta.expr),
swc_ecma_ast::Expr::Paren(paren) => static_eval_expr(sa, cm, &paren.expr),
swc_ecma_ast::Expr::TsTypeAssertion(tta) => static_eval_expr(sa, cm, &tta.expr),
swc_ecma_ast::Expr::TsConstAssertion(tca) => static_eval_expr(sa, cm, &tca.expr),
swc_ecma_ast::Expr::TsNonNull(tnn) => static_eval_expr(sa, cm, &tnn.expr),
swc_ecma_ast::Expr::TsAs(ta) => static_eval_expr(sa, cm, &ta.expr),
}
}