mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-04-18 03:00:27 -04:00
Replace capture_finder with scope_analysis data
This commit is contained in:
@@ -1,470 +0,0 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{asm::Pointer, scope::scope_reg};
|
||||
|
||||
use super::scope::{MappedName, Scope};
|
||||
|
||||
pub struct CaptureFinder {
|
||||
outside_scope: Scope,
|
||||
pub ordered_names: Vec<String>,
|
||||
names: HashSet<String>,
|
||||
}
|
||||
|
||||
impl CaptureFinder {
|
||||
pub fn new(outside_scope: Scope) -> CaptureFinder {
|
||||
return CaptureFinder {
|
||||
outside_scope: outside_scope,
|
||||
ordered_names: Default::default(),
|
||||
names: Default::default(),
|
||||
};
|
||||
}
|
||||
|
||||
fn ref_(&mut self, scope: &Scope, name: String) {
|
||||
if name == "undefined" {
|
||||
return;
|
||||
}
|
||||
|
||||
if scope.get(&name).is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut insert = |n: &String| {
|
||||
let inserted = self.names.insert(n.clone());
|
||||
|
||||
if inserted {
|
||||
self.ordered_names.push(n.clone());
|
||||
}
|
||||
};
|
||||
|
||||
match self.outside_scope.get(&name) {
|
||||
None => std::panic!("Unresolved name {}", name),
|
||||
Some(MappedName::Definition(_)) => {} // Not capture - just definition
|
||||
Some(MappedName::Register(_)) => insert(&name),
|
||||
Some(MappedName::QueuedFunction(qfn)) => {
|
||||
for cap in &qfn.capture_params {
|
||||
if scope.get(cap).is_some() {
|
||||
std::panic!("Not implemented: Nested capture edge case");
|
||||
}
|
||||
|
||||
insert(cap);
|
||||
}
|
||||
}
|
||||
Some(MappedName::Builtin(_)) => {}
|
||||
Some(MappedName::Constant(_)) => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fn_decl(&mut self, parent_scope: &Scope, decl: &swc_ecma_ast::FnDecl) {
|
||||
let scope = parent_scope.nest();
|
||||
|
||||
scope.set(decl.ident.sym.to_string(), scope_reg("".to_string()));
|
||||
|
||||
self.function(&scope, &decl.function);
|
||||
}
|
||||
|
||||
pub fn fn_expr(&mut self, parent_scope: &Scope, expr: &swc_ecma_ast::FnExpr) {
|
||||
let scope = parent_scope.nest();
|
||||
|
||||
for ident in &expr.ident {
|
||||
scope.set(ident.sym.to_string(), scope_reg("".to_string()));
|
||||
}
|
||||
|
||||
self.function(&scope, &expr.function);
|
||||
}
|
||||
|
||||
pub fn arrow_expr(&mut self, parent_scope: &Scope, arrow: &swc_ecma_ast::ArrowExpr) {
|
||||
let scope = parent_scope.nest();
|
||||
|
||||
for param in &arrow.params {
|
||||
match ¶m {
|
||||
swc_ecma_ast::Pat::Ident(ident) => {
|
||||
scope.set(ident.id.sym.to_string(), scope_reg("".to_string()))
|
||||
}
|
||||
_ => std::panic!("Not implemented: destructuring"),
|
||||
}
|
||||
}
|
||||
|
||||
match &arrow.body {
|
||||
swc_ecma_ast::BlockStmtOrExpr::BlockStmt(block_stmt) => {
|
||||
self.populate_fn_scope(&scope, block_stmt);
|
||||
self.block(&scope, block_stmt);
|
||||
}
|
||||
swc_ecma_ast::BlockStmtOrExpr::Expr(expr) => {
|
||||
self.expr(&scope, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn function(&mut self, scope: &Scope, fn_: &swc_ecma_ast::Function) {
|
||||
for param in &fn_.params {
|
||||
match ¶m.pat {
|
||||
swc_ecma_ast::Pat::Ident(ident) => {
|
||||
scope.set(ident.id.sym.to_string(), scope_reg("".to_string()))
|
||||
}
|
||||
_ => std::panic!("Not implemented: destructuring"),
|
||||
}
|
||||
}
|
||||
|
||||
for block_stmt in &fn_.body {
|
||||
self.populate_fn_scope(scope, block_stmt);
|
||||
self.block(scope, block_stmt);
|
||||
}
|
||||
}
|
||||
|
||||
fn populate_fn_scope(&mut self, scope: &Scope, block: &swc_ecma_ast::BlockStmt) {
|
||||
for statement in &block.stmts {
|
||||
self.populate_fn_scope_statement(scope, statement);
|
||||
}
|
||||
}
|
||||
|
||||
fn populate_fn_scope_statement(&mut self, scope: &Scope, statement: &swc_ecma_ast::Stmt) {
|
||||
use swc_ecma_ast::Stmt::*;
|
||||
|
||||
match statement {
|
||||
Block(nested_block) => {
|
||||
self.populate_fn_scope(scope, nested_block);
|
||||
}
|
||||
Empty(_) => {}
|
||||
Debugger(_) => {}
|
||||
With(_) => std::panic!("Not supported: With statement"),
|
||||
Return(_) => {}
|
||||
Labeled(_) => std::panic!("Not implemented: Labeled statement"),
|
||||
Break(_) => {}
|
||||
Continue(_) => {}
|
||||
If(if_) => {
|
||||
self.populate_fn_scope_statement(scope, &if_.cons);
|
||||
|
||||
for stmt in &if_.alt {
|
||||
self.populate_fn_scope_statement(scope, stmt);
|
||||
}
|
||||
}
|
||||
Switch(_) => std::panic!("Not implemented: Switch statement"),
|
||||
Throw(_) => {}
|
||||
Try(_) => std::panic!("Not implemented: Try statement"),
|
||||
While(while_) => {
|
||||
self.populate_fn_scope_statement(scope, &while_.body);
|
||||
}
|
||||
DoWhile(do_while) => {
|
||||
self.populate_fn_scope_statement(scope, &do_while.body);
|
||||
}
|
||||
For(for_) => {
|
||||
match &for_.init {
|
||||
Some(swc_ecma_ast::VarDeclOrExpr::VarDecl(var_decl)) => {
|
||||
self.populate_fn_scope_var_decl(var_decl, scope);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
self.populate_fn_scope_statement(scope, &for_.body);
|
||||
}
|
||||
ForIn(_) => std::panic!("Not implemented: ForIn statement"),
|
||||
ForOf(_) => std::panic!("Not implemented: ForOf statement"),
|
||||
Decl(decl) => {
|
||||
use swc_ecma_ast::Decl::*;
|
||||
|
||||
match decl {
|
||||
Class(_) => std::panic!("Not implemented: Class declaration"),
|
||||
Fn(_) => {}
|
||||
Var(var_decl) => self.populate_fn_scope_var_decl(var_decl, scope),
|
||||
TsInterface(_) => {}
|
||||
TsTypeAlias(_) => {}
|
||||
TsEnum(_) => std::panic!("Not implemented: TsEnum declaration"),
|
||||
TsModule(_) => std::panic!("Not implemented: TsModule declaration"),
|
||||
}
|
||||
}
|
||||
Expr(_) => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn populate_fn_scope_var_decl(&mut self, var_decl: &swc_ecma_ast::VarDecl, scope: &Scope) {
|
||||
if var_decl.kind != swc_ecma_ast::VarDeclKind::Var {
|
||||
return;
|
||||
}
|
||||
|
||||
for decl in &var_decl.decls {
|
||||
match &decl.name {
|
||||
swc_ecma_ast::Pat::Ident(ident) => {
|
||||
let name = ident.id.sym.to_string();
|
||||
|
||||
scope.set(name.clone(), scope_reg("".to_string()));
|
||||
}
|
||||
_ => std::panic!("Not implemented: destructuring"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn populate_block_scope(&mut self, scope: &Scope, block: &swc_ecma_ast::BlockStmt) {
|
||||
for statement in &block.stmts {
|
||||
use swc_ecma_ast::Stmt::*;
|
||||
|
||||
match statement {
|
||||
Block(_) => {}
|
||||
Empty(_) => {}
|
||||
Debugger(_) => {}
|
||||
With(_) => std::panic!("Not supported: With statement"),
|
||||
Return(_) => {}
|
||||
Labeled(_) => std::panic!("Not implemented: Labeled statement"),
|
||||
Break(_) => {}
|
||||
Continue(_) => {}
|
||||
If(_) => {}
|
||||
Switch(_) => {}
|
||||
Throw(_) => {}
|
||||
Try(_) => {}
|
||||
While(_) => {}
|
||||
DoWhile(_) => {}
|
||||
For(_) => {}
|
||||
ForIn(_) => {}
|
||||
ForOf(_) => {}
|
||||
Decl(decl) => {
|
||||
use swc_ecma_ast::Decl::*;
|
||||
|
||||
match decl {
|
||||
Class(_) => std::panic!("Not implemented: Class declaration"),
|
||||
Fn(fn_) => {
|
||||
let fn_name = fn_.ident.sym.to_string();
|
||||
|
||||
scope.set(
|
||||
fn_name.clone(),
|
||||
MappedName::Definition(Pointer {
|
||||
name: "".to_string(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
Var(var_decl) => self.populate_block_scope_var_decl(scope, var_decl),
|
||||
TsInterface(_) => {}
|
||||
TsTypeAlias(_) => {}
|
||||
TsEnum(_) => std::panic!("Not implemented: TsEnum declaration"),
|
||||
TsModule(_) => {}
|
||||
}
|
||||
}
|
||||
Expr(_) => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn populate_block_scope_var_decl(&mut self, scope: &Scope, var_decl: &swc_ecma_ast::VarDecl) {
|
||||
if var_decl.kind == swc_ecma_ast::VarDeclKind::Var {
|
||||
return;
|
||||
}
|
||||
|
||||
for decl in &var_decl.decls {
|
||||
match &decl.name {
|
||||
swc_ecma_ast::Pat::Ident(ident) => {
|
||||
let name = ident.id.sym.to_string();
|
||||
|
||||
scope.set(name.clone(), scope_reg("".to_string()));
|
||||
}
|
||||
_ => std::panic!("Not implemented: destructuring"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn block(&mut self, parent_scope: &Scope, block_stmt: &swc_ecma_ast::BlockStmt) {
|
||||
let scope = parent_scope.nest();
|
||||
self.populate_block_scope(&scope, block_stmt);
|
||||
|
||||
for statement in &block_stmt.stmts {
|
||||
self.statement(&scope, statement);
|
||||
}
|
||||
}
|
||||
|
||||
fn statement(&mut self, scope: &Scope, statement: &swc_ecma_ast::Stmt) {
|
||||
use swc_ecma_ast::Stmt::*;
|
||||
|
||||
match statement {
|
||||
Block(block) => self.block(scope, block),
|
||||
Empty(_) => {}
|
||||
Debugger(_) => {}
|
||||
With(_) => std::panic!("Not supported: With statement"),
|
||||
Return(return_) => {
|
||||
for arg in &return_.arg {
|
||||
self.expr(scope, arg);
|
||||
}
|
||||
}
|
||||
Labeled(_) => std::panic!("Not implemented: Labeled statement"),
|
||||
Break(_) => {}
|
||||
Continue(_) => {}
|
||||
If(if_) => {
|
||||
self.expr(scope, &if_.test);
|
||||
self.statement(scope, &if_.cons);
|
||||
|
||||
for alt in &if_.alt {
|
||||
self.statement(scope, alt);
|
||||
}
|
||||
}
|
||||
Switch(_) => std::panic!("Not implemented: Switch statement"),
|
||||
Throw(throw) => {
|
||||
self.expr(scope, &throw.arg);
|
||||
}
|
||||
Try(_) => std::panic!("Not implemented: Try statement"),
|
||||
While(while_) => {
|
||||
self.expr(scope, &while_.test);
|
||||
self.statement(scope, &while_.body);
|
||||
}
|
||||
DoWhile(do_while) => {
|
||||
self.statement(scope, &do_while.body);
|
||||
self.expr(scope, &do_while.test);
|
||||
}
|
||||
For(for_) => {
|
||||
let for_scope = scope.nest();
|
||||
|
||||
match &for_.init {
|
||||
None => {}
|
||||
Some(swc_ecma_ast::VarDeclOrExpr::Expr(expr)) => self.expr(&for_scope, expr),
|
||||
Some(swc_ecma_ast::VarDeclOrExpr::VarDecl(var_decl)) => {
|
||||
self.var_decl(&for_scope, var_decl)
|
||||
}
|
||||
}
|
||||
|
||||
for test in &for_.test {
|
||||
self.expr(&for_scope, test);
|
||||
}
|
||||
|
||||
self.statement(&for_scope, &for_.body);
|
||||
}
|
||||
ForIn(_) => std::panic!("Not implemented: ForIn statement"),
|
||||
ForOf(_) => std::panic!("Not implemented: ForOf statement"),
|
||||
Decl(decl) => {
|
||||
use swc_ecma_ast::Decl::*;
|
||||
|
||||
match decl {
|
||||
Class(_) => std::panic!("Not implemented: Class declaration"),
|
||||
Fn(fn_) => self.fn_decl(scope, fn_),
|
||||
Var(var_decl) => self.var_decl(scope, var_decl),
|
||||
TsInterface(_) => {}
|
||||
TsTypeAlias(_) => {}
|
||||
TsEnum(_) => std::panic!("Not implemented: TsEnum declaration"),
|
||||
TsModule(_) => {}
|
||||
}
|
||||
}
|
||||
Expr(expr) => self.expr(scope, &expr.expr),
|
||||
}
|
||||
}
|
||||
|
||||
fn expr(&mut self, scope: &Scope, expr: &swc_ecma_ast::Expr) {
|
||||
use swc_ecma_ast::Expr::*;
|
||||
|
||||
match expr {
|
||||
This(_) => {}
|
||||
Array(array_exp) => {
|
||||
for option_elem in &array_exp.elems {
|
||||
for elem in option_elem {
|
||||
self.expr(scope, &elem.expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
Object(object_exp) => {
|
||||
for prop in &object_exp.props {
|
||||
match prop {
|
||||
swc_ecma_ast::PropOrSpread::Spread(spread) => {
|
||||
self.expr(scope, &spread.expr);
|
||||
}
|
||||
swc_ecma_ast::PropOrSpread::Prop(p) => {
|
||||
use swc_ecma_ast::Prop::*;
|
||||
|
||||
match &**p {
|
||||
Shorthand(ident) => {
|
||||
self.ref_(scope, ident.sym.to_string());
|
||||
}
|
||||
KeyValue(kv) => {
|
||||
match &kv.key {
|
||||
swc_ecma_ast::PropName::Ident(_) => {}
|
||||
swc_ecma_ast::PropName::Str(_) => {}
|
||||
swc_ecma_ast::PropName::Num(_) => {}
|
||||
swc_ecma_ast::PropName::Computed(comp) => {
|
||||
self.expr(scope, &comp.expr);
|
||||
}
|
||||
swc_ecma_ast::PropName::BigInt(_) => {}
|
||||
}
|
||||
|
||||
self.expr(scope, &kv.value);
|
||||
}
|
||||
Assign(_) => std::panic!("Not implemented: Assign prop"),
|
||||
Getter(_) => std::panic!("Not implemented: Getter prop"),
|
||||
Setter(_) => std::panic!("Not implemented: Setter prop"),
|
||||
Method(_) => std::panic!("Not implemented: Method prop"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Fn(fn_) => self.fn_expr(scope, fn_),
|
||||
Unary(un_exp) => self.expr(scope, &un_exp.arg),
|
||||
Update(update_exp) => self.expr(scope, &update_exp.arg),
|
||||
Bin(bin_exp) => {
|
||||
self.expr(scope, &bin_exp.left);
|
||||
self.expr(scope, &bin_exp.right);
|
||||
}
|
||||
Assign(assign_exp) => {
|
||||
match &assign_exp.left {
|
||||
swc_ecma_ast::PatOrExpr::Pat(pat) => match &**pat {
|
||||
swc_ecma_ast::Pat::Ident(ident) => self.ref_(scope, ident.id.sym.to_string()),
|
||||
swc_ecma_ast::Pat::Expr(expr) => self.expr(scope, expr),
|
||||
_ => std::panic!("Not implemented: destructuring"),
|
||||
},
|
||||
swc_ecma_ast::PatOrExpr::Expr(expr) => self.expr(scope, expr),
|
||||
}
|
||||
|
||||
self.expr(scope, &assign_exp.right);
|
||||
}
|
||||
Member(member_exp) => {
|
||||
self.expr(scope, &member_exp.obj);
|
||||
|
||||
match &member_exp.prop {
|
||||
swc_ecma_ast::MemberProp::Ident(_) => {}
|
||||
swc_ecma_ast::MemberProp::Computed(computed) => {
|
||||
self.expr(scope, &computed.expr);
|
||||
}
|
||||
swc_ecma_ast::MemberProp::PrivateName(_) => {
|
||||
std::panic!("Not implemented: private name");
|
||||
}
|
||||
}
|
||||
}
|
||||
SuperProp(_) => std::panic!("Not implemented: SuperProp expression"),
|
||||
Cond(_) => std::panic!("Not implemented: Cond expression"),
|
||||
Call(call_exp) => {
|
||||
match &call_exp.callee {
|
||||
swc_ecma_ast::Callee::Expr(expr) => self.expr(scope, expr),
|
||||
_ => std::panic!("Not implemented: non-expression callee"),
|
||||
};
|
||||
|
||||
for arg in &call_exp.args {
|
||||
self.expr(scope, &arg.expr);
|
||||
}
|
||||
}
|
||||
New(_) => std::panic!("Not implemented: New expression"),
|
||||
Seq(_) => std::panic!("Not implemented: Seq expression"),
|
||||
Ident(ident) => self.ref_(scope, ident.sym.to_string()),
|
||||
Lit(_) => {}
|
||||
Tpl(_) => std::panic!("Not implemented: Tpl expression"),
|
||||
TaggedTpl(_) => std::panic!("Not implemented: TaggedTpl expression"),
|
||||
Arrow(_) => std::panic!("Not implemented: Arrow expression"),
|
||||
Class(_) => std::panic!("Not implemented: Class expression"),
|
||||
Yield(_) => std::panic!("Not implemented: Yield expression"),
|
||||
MetaProp(_) => std::panic!("Not implemented: MetaProp expression"),
|
||||
Await(_) => std::panic!("Not implemented: Await expression"),
|
||||
Paren(p) => self.expr(scope, &p.expr),
|
||||
JSXMember(_) => std::panic!("Not implemented: JSXMember expression"),
|
||||
JSXNamespacedName(_) => std::panic!("Not implemented: JSXNamespacedName expression"),
|
||||
JSXEmpty(_) => std::panic!("Not implemented: JSXEmpty expression"),
|
||||
JSXElement(_) => std::panic!("Not implemented: JSXElement expression"),
|
||||
JSXFragment(_) => std::panic!("Not implemented: JSXFragment expression"),
|
||||
TsTypeAssertion(_) => std::panic!("Not implemented: TsTypeAssertion expression"),
|
||||
TsConstAssertion(_) => std::panic!("Not implemented: TsConstAssertion expression"),
|
||||
TsNonNull(_) => std::panic!("Not implemented: TsNonNull expression"),
|
||||
TsAs(_) => std::panic!("Not implemented: TsAs expression"),
|
||||
TsInstantiation(_) => std::panic!("Not implemented: TsInstantiation expression"),
|
||||
PrivateName(_) => std::panic!("Not implemented: PrivateName expression"),
|
||||
OptChain(_) => std::panic!("Not implemented: OptChain expression"),
|
||||
Invalid(_) => std::panic!("Not implemented: Invalid expression"),
|
||||
};
|
||||
}
|
||||
|
||||
fn var_decl(&mut self, scope: &Scope, var_decl: &swc_ecma_ast::VarDecl) {
|
||||
for decl in &var_decl.decls {
|
||||
for init in &decl.init {
|
||||
self.expr(scope, init);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,10 @@ use queues::*;
|
||||
use swc_common::Spanned;
|
||||
|
||||
use crate::asm::{Array, Instruction, Label, Object, Pointer, Register, Value};
|
||||
|
||||
use super::capture_finder::CaptureFinder;
|
||||
use super::diagnostic::{Diagnostic, DiagnosticLevel};
|
||||
use super::function_compiler::{FunctionCompiler, Functionish, QueuedFunction};
|
||||
use super::scope::{init_std_scope, MappedName, Scope};
|
||||
use crate::diagnostic::{Diagnostic, DiagnosticLevel};
|
||||
use crate::function_compiler::{FunctionCompiler, Functionish, QueuedFunction};
|
||||
use crate::scope::{MappedName, Scope};
|
||||
use crate::scope_analysis::OwnerId;
|
||||
|
||||
pub struct CompiledExpression {
|
||||
/** It is usually better to access this via functionCompiler.use_ */
|
||||
@@ -1026,8 +1025,32 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
None => self.fnc.allocate_defn_numbered(&"_anon".to_string()),
|
||||
};
|
||||
|
||||
let mut cf = CaptureFinder::new(self.scope.clone());
|
||||
cf.fn_expr(&init_std_scope(), fn_);
|
||||
let capture_params: Vec<String> = {
|
||||
let captures = self
|
||||
.fnc
|
||||
.scope_analysis
|
||||
.captures
|
||||
.get(&OwnerId::Span(fn_.function.span));
|
||||
|
||||
match captures {
|
||||
Some(captures) => captures
|
||||
.iter()
|
||||
.map(|capture| {
|
||||
self
|
||||
.fnc
|
||||
.scope_analysis
|
||||
.names
|
||||
.get(capture)
|
||||
.unwrap_or_else(|| {
|
||||
panic!("Failed to find name for name_id: {:?}", capture);
|
||||
})
|
||||
.sym
|
||||
.to_string()
|
||||
})
|
||||
.collect(),
|
||||
None => Vec::new(),
|
||||
}
|
||||
};
|
||||
|
||||
self
|
||||
.fnc
|
||||
@@ -1035,12 +1058,12 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
.add(QueuedFunction {
|
||||
definition_pointer: definition_pointer.clone(),
|
||||
fn_name: fn_name.clone(),
|
||||
capture_params: cf.ordered_names.clone(),
|
||||
capture_params: capture_params.clone(),
|
||||
functionish: Functionish::Fn(fn_.function.clone()),
|
||||
})
|
||||
.expect("Failed to queue function");
|
||||
|
||||
if cf.ordered_names.len() == 0 {
|
||||
if capture_params.len() == 0 {
|
||||
return self.inline(Value::Pointer(definition_pointer), target_register);
|
||||
}
|
||||
|
||||
@@ -1048,7 +1071,7 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
fn_name,
|
||||
fn_.ident.span(),
|
||||
&definition_pointer,
|
||||
&cf.ordered_names,
|
||||
&capture_params,
|
||||
target_register,
|
||||
);
|
||||
}
|
||||
@@ -1060,8 +1083,32 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
) -> CompiledExpression {
|
||||
let definition_pointer = self.fnc.allocate_defn_numbered(&"_anon".to_string());
|
||||
|
||||
let mut cf = CaptureFinder::new(self.scope.clone());
|
||||
cf.arrow_expr(&init_std_scope(), arrow_expr);
|
||||
let capture_params = {
|
||||
let captures = self
|
||||
.fnc
|
||||
.scope_analysis
|
||||
.captures
|
||||
.get(&OwnerId::Span(arrow_expr.span));
|
||||
|
||||
match captures {
|
||||
Some(captures) => captures
|
||||
.iter()
|
||||
.map(|capture| {
|
||||
self
|
||||
.fnc
|
||||
.scope_analysis
|
||||
.names
|
||||
.get(capture)
|
||||
.unwrap_or_else(|| {
|
||||
panic!("Failed to find name for name_id: {:?}", capture);
|
||||
})
|
||||
.sym
|
||||
.to_string()
|
||||
})
|
||||
.collect(),
|
||||
None => Vec::new(),
|
||||
}
|
||||
};
|
||||
|
||||
self
|
||||
.fnc
|
||||
@@ -1069,12 +1116,12 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
.add(QueuedFunction {
|
||||
definition_pointer: definition_pointer.clone(),
|
||||
fn_name: None,
|
||||
capture_params: cf.ordered_names.clone(),
|
||||
capture_params: capture_params.clone(),
|
||||
functionish: Functionish::Arrow(arrow_expr.clone()),
|
||||
})
|
||||
.expect("Failed to queue function");
|
||||
|
||||
if cf.ordered_names.len() == 0 {
|
||||
if capture_params.len() == 0 {
|
||||
return self.inline(Value::Pointer(definition_pointer), target_register);
|
||||
}
|
||||
|
||||
@@ -1082,7 +1129,7 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
None,
|
||||
arrow_expr.span(),
|
||||
&definition_pointer,
|
||||
&cf.ordered_names,
|
||||
&capture_params,
|
||||
target_register,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,14 +9,13 @@ use crate::asm::{
|
||||
Definition, DefinitionContent, Function, Instruction, InstructionOrLabel, Label, Pointer,
|
||||
Register, Value,
|
||||
};
|
||||
use crate::diagnostic::{Diagnostic, DiagnosticLevel};
|
||||
use crate::expression_compiler::CompiledExpression;
|
||||
use crate::expression_compiler::ExpressionCompiler;
|
||||
use crate::name_allocator::NameAllocator;
|
||||
use crate::scope::scope_reg;
|
||||
|
||||
use super::capture_finder::CaptureFinder;
|
||||
use super::diagnostic::{Diagnostic, DiagnosticLevel};
|
||||
use super::expression_compiler::CompiledExpression;
|
||||
use super::expression_compiler::ExpressionCompiler;
|
||||
use super::name_allocator::NameAllocator;
|
||||
use super::scope::{init_std_scope, MappedName, Scope};
|
||||
use crate::scope::{MappedName, Scope};
|
||||
use crate::scope_analysis::{OwnerId, ScopeAnalysis};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Functionish {
|
||||
@@ -41,6 +40,7 @@ pub struct LoopLabels {
|
||||
pub struct FunctionCompiler {
|
||||
pub current: Function,
|
||||
pub definitions: Vec<Definition>,
|
||||
pub scope_analysis: Rc<ScopeAnalysis>,
|
||||
pub definition_allocator: Rc<RefCell<NameAllocator>>,
|
||||
pub reg_allocator: NameAllocator,
|
||||
pub label_allocator: NameAllocator,
|
||||
@@ -50,7 +50,10 @@ pub struct FunctionCompiler {
|
||||
}
|
||||
|
||||
impl FunctionCompiler {
|
||||
pub fn new(definition_allocator: Rc<RefCell<NameAllocator>>) -> FunctionCompiler {
|
||||
pub fn new(
|
||||
scope_analysis: &Rc<ScopeAnalysis>,
|
||||
definition_allocator: Rc<RefCell<NameAllocator>>,
|
||||
) -> FunctionCompiler {
|
||||
let mut reg_allocator = NameAllocator::default();
|
||||
reg_allocator.allocate(&"return".to_string());
|
||||
reg_allocator.allocate(&"this".to_string());
|
||||
@@ -59,6 +62,7 @@ impl FunctionCompiler {
|
||||
return FunctionCompiler {
|
||||
current: Function::default(),
|
||||
definitions: vec![],
|
||||
scope_analysis: scope_analysis.clone(),
|
||||
definition_allocator,
|
||||
reg_allocator,
|
||||
label_allocator: NameAllocator::default(),
|
||||
@@ -140,10 +144,11 @@ impl FunctionCompiler {
|
||||
definition_pointer: Pointer,
|
||||
fn_name: Option<String>,
|
||||
functionish: Functionish,
|
||||
scope_analysis: &Rc<ScopeAnalysis>,
|
||||
definition_allocator: Rc<RefCell<NameAllocator>>,
|
||||
parent_scope: &Scope,
|
||||
) -> (Vec<Definition>, Vec<Diagnostic>) {
|
||||
let mut self_ = FunctionCompiler::new(definition_allocator);
|
||||
let mut self_ = FunctionCompiler::new(scope_analysis, definition_allocator);
|
||||
|
||||
self_
|
||||
.queue
|
||||
@@ -619,10 +624,20 @@ impl FunctionCompiler {
|
||||
let mut direct_captures_map = HashMap::<String, Vec<String>>::new();
|
||||
|
||||
for fn_ in &function_decls {
|
||||
let mut cf = CaptureFinder::new(synth_scope.clone());
|
||||
cf.fn_decl(&init_std_scope(), fn_);
|
||||
let owner_id = OwnerId::Span(fn_.function.span);
|
||||
|
||||
direct_captures_map.insert(fn_.ident.sym.to_string(), cf.ordered_names);
|
||||
if let Some(captures) = self.scope_analysis.captures.get(&owner_id) {
|
||||
for name_id in captures {
|
||||
let name = self.scope_analysis.names.get(name_id).unwrap_or_else(|| {
|
||||
panic!("Failed to find name for name_id: {:?}", name_id);
|
||||
});
|
||||
|
||||
direct_captures_map
|
||||
.entry(fn_.ident.sym.to_string())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(name.sym.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for fn_ in &function_decls {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
mod asm;
|
||||
mod assembler;
|
||||
mod assembly_parser;
|
||||
mod capture_finder;
|
||||
mod compile;
|
||||
mod constants;
|
||||
mod diagnostic;
|
||||
|
||||
@@ -71,8 +71,7 @@ pub struct CompilerOutput {
|
||||
}
|
||||
|
||||
pub fn compile_program(program: &swc_ecma_ast::Program) -> CompilerOutput {
|
||||
let mut compiler = ModuleCompiler::default();
|
||||
compiler.compile_program(&program);
|
||||
let compiler = ModuleCompiler::compile_program(&program);
|
||||
|
||||
return CompilerOutput {
|
||||
diagnostics: compiler.diagnostics,
|
||||
@@ -98,6 +97,7 @@ pub fn compile_module(source: &str) -> CompilerOutput {
|
||||
struct ModuleCompiler {
|
||||
diagnostics: Vec<Diagnostic>,
|
||||
definition_allocator: Rc<RefCell<NameAllocator>>,
|
||||
scope_analysis: Rc<ScopeAnalysis>,
|
||||
module: Module,
|
||||
}
|
||||
|
||||
@@ -140,19 +140,34 @@ impl ModuleCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_program(&mut self, program: &swc_ecma_ast::Program) {
|
||||
fn compile_program(program: &swc_ecma_ast::Program) -> Self {
|
||||
use swc_ecma_ast::Program::*;
|
||||
|
||||
match program {
|
||||
Module(module) => self.compile_module(module),
|
||||
let module = match program {
|
||||
Module(module) => module,
|
||||
Script(script) => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
let mut self_ = Self::default();
|
||||
|
||||
self_.diagnostics.push(Diagnostic {
|
||||
level: DiagnosticLevel::Error,
|
||||
message: "Scripts are not supported".to_string(),
|
||||
span: script.span,
|
||||
});
|
||||
|
||||
return self_;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let scope_analysis = ScopeAnalysis::run(module);
|
||||
|
||||
let mut self_ = Self {
|
||||
scope_analysis: Rc::new(scope_analysis),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
self_.compile_module(module);
|
||||
|
||||
self_
|
||||
}
|
||||
|
||||
fn compile_module(&mut self, module: &swc_ecma_ast::Module) {
|
||||
@@ -724,6 +739,7 @@ impl ModuleCompiler {
|
||||
defn_pointer,
|
||||
fn_name,
|
||||
functionish,
|
||||
&self.scope_analysis,
|
||||
self.definition_allocator.clone(),
|
||||
parent_scope,
|
||||
);
|
||||
@@ -771,7 +787,8 @@ impl ModuleCompiler {
|
||||
));
|
||||
}
|
||||
|
||||
let mut member_initializers_fnc = FunctionCompiler::new(self.definition_allocator.clone());
|
||||
let mut member_initializers_fnc =
|
||||
FunctionCompiler::new(&self.scope_analysis, self.definition_allocator.clone());
|
||||
|
||||
for class_member in &class.body {
|
||||
match class_member {
|
||||
|
||||
@@ -25,8 +25,8 @@ pub struct Capture {
|
||||
captor_id: OwnerId,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum NameType {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum NameType {
|
||||
Var,
|
||||
Let,
|
||||
Const,
|
||||
@@ -40,18 +40,19 @@ enum NameType {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Name {
|
||||
id: NameId,
|
||||
owner_id: OwnerId,
|
||||
sym: swc_atoms::JsWord,
|
||||
type_: NameType,
|
||||
mutations: Vec<swc_common::Span>,
|
||||
captures: Vec<Capture>,
|
||||
pub id: NameId,
|
||||
pub owner_id: OwnerId,
|
||||
pub sym: swc_atoms::JsWord,
|
||||
pub type_: NameType,
|
||||
pub mutations: Vec<swc_common::Span>,
|
||||
pub captures: Vec<Capture>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ScopeAnalysis {
|
||||
pub names: HashMap<NameId, Name>,
|
||||
pub captures: HashMap<OwnerId, HashSet<swc_common::Span>>,
|
||||
pub owners: HashMap<OwnerId, HashSet<swc_common::Span>>,
|
||||
pub captures: HashMap<OwnerId, HashSet<NameId>>,
|
||||
pub diagnostics: Vec<Diagnostic>,
|
||||
}
|
||||
|
||||
@@ -148,6 +149,12 @@ impl ScopeAnalysis {
|
||||
|
||||
self.names.insert(name.id.clone(), name.clone());
|
||||
|
||||
self
|
||||
.owners
|
||||
.entry(name.owner_id.clone())
|
||||
.or_insert_with(HashSet::new)
|
||||
.insert(origin_ident.span);
|
||||
|
||||
scope.set(
|
||||
&origin_ident.sym,
|
||||
name.id.clone(),
|
||||
@@ -173,7 +180,7 @@ impl ScopeAnalysis {
|
||||
.captures
|
||||
.entry(captor_id.clone())
|
||||
.or_insert_with(HashSet::new)
|
||||
.insert(ref_);
|
||||
.insert(name_id.clone());
|
||||
|
||||
name.captures.push(Capture {
|
||||
ref_,
|
||||
|
||||
Reference in New Issue
Block a user