Replace capture_finder with scope_analysis data

This commit is contained in:
Andrew Morris
2023-03-22 14:27:06 +11:00
parent 120cede42d
commit 7594eeeadd
6 changed files with 131 additions and 516 deletions

View File

@@ -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 &param {
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 &param.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);
}
}
}
}

View File

@@ -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,
);
}

View File

@@ -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 {

View File

@@ -1,7 +1,6 @@
mod asm;
mod assembler;
mod assembly_parser;
mod capture_finder;
mod compile;
mod constants;
mod diagnostic;

View File

@@ -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 {

View File

@@ -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_,