mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-04-18 03:00:27 -04:00
Fix capturing for function declarations
This commit is contained in:
@@ -4,10 +4,10 @@ use queues::*;
|
||||
|
||||
use swc_common::Spanned;
|
||||
|
||||
use crate::asm::{Array, Instruction, Label, Object, Pointer, Register, Value};
|
||||
use crate::asm::{Array, Instruction, Label, Object, Register, Value};
|
||||
use crate::diagnostic::{Diagnostic, DiagnosticLevel};
|
||||
use crate::function_compiler::{FunctionCompiler, Functionish, QueuedFunction};
|
||||
use crate::scope_analysis::{NameId, OwnerId};
|
||||
use crate::scope_analysis::{fn_to_owner_id, NameId, NameType, OwnerId};
|
||||
|
||||
pub struct CompiledExpression {
|
||||
/** It is usually better to access this via functionCompiler.use_ */
|
||||
@@ -318,7 +318,7 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
}
|
||||
|
||||
fn get_register_for_ident_mutation(&mut self, ident: &swc_ecma_ast::Ident) -> Register {
|
||||
let (reg, err_msg) = match self.fnc.lookup(ident) {
|
||||
let (reg, err_msg) = match self.fnc.lookup_value(ident) {
|
||||
Some(Value::Register(reg)) => (Some(reg), None),
|
||||
lookup_result => (
|
||||
None,
|
||||
@@ -1031,7 +1031,7 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
.fnc
|
||||
.scope_analysis
|
||||
.captures
|
||||
.get(&OwnerId::Span(fn_.function.span))
|
||||
.get(&fn_to_owner_id(&fn_.ident, &fn_.function))
|
||||
.cloned();
|
||||
|
||||
self
|
||||
@@ -1040,7 +1040,7 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
.add(QueuedFunction {
|
||||
definition_pointer: definition_pointer.clone(),
|
||||
fn_name: fn_name.clone(),
|
||||
functionish: Functionish::Fn(fn_.function.clone()),
|
||||
functionish: Functionish::Fn(fn_.ident.clone(), fn_.function.clone()),
|
||||
})
|
||||
.expect("Failed to queue function");
|
||||
|
||||
@@ -1048,7 +1048,7 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
None => self.inline(Value::Pointer(definition_pointer), target_register),
|
||||
Some(capture_params) => self.capturing_fn_ref(
|
||||
fn_name,
|
||||
&definition_pointer,
|
||||
&Value::Pointer(definition_pointer),
|
||||
&capture_params,
|
||||
target_register,
|
||||
),
|
||||
@@ -1081,16 +1081,19 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
|
||||
match capture_params {
|
||||
None => self.inline(Value::Pointer(definition_pointer), target_register),
|
||||
Some(capture_params) => {
|
||||
self.capturing_fn_ref(None, &definition_pointer, &capture_params, target_register)
|
||||
}
|
||||
Some(capture_params) => self.capturing_fn_ref(
|
||||
None,
|
||||
&Value::Pointer(definition_pointer),
|
||||
&capture_params,
|
||||
target_register,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn capturing_fn_ref(
|
||||
&mut self,
|
||||
fn_name: Option<String>,
|
||||
definition_pointer: &Pointer,
|
||||
fn_value: &Value,
|
||||
captures: &HashSet<NameId>,
|
||||
target_register: Option<Register>,
|
||||
) -> CompiledExpression {
|
||||
@@ -1113,25 +1116,27 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
let mut bind_values = Array::default();
|
||||
|
||||
for cap in captures {
|
||||
bind_values.values.push(match self.fnc.lookup_name_id(cap) {
|
||||
Some(v) => match v {
|
||||
Value::Register(_) => v,
|
||||
_ => continue,
|
||||
},
|
||||
None => {
|
||||
self.fnc.diagnostics.push(Diagnostic {
|
||||
level: DiagnosticLevel::InternalError,
|
||||
message: format!("Failed to find capture {:?}", cap),
|
||||
span: cap.span(),
|
||||
});
|
||||
bind_values
|
||||
.values
|
||||
.push(match self.fnc.lookup_by_name_id(cap) {
|
||||
Some(v) => match v {
|
||||
Value::Register(_) => v,
|
||||
_ => continue,
|
||||
},
|
||||
None => {
|
||||
self.fnc.diagnostics.push(Diagnostic {
|
||||
level: DiagnosticLevel::InternalError,
|
||||
message: format!("Failed to find capture {:?}", cap),
|
||||
span: cap.span(),
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
});
|
||||
continue;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
self.fnc.push(Instruction::Bind(
|
||||
Value::Pointer(definition_pointer.clone()),
|
||||
fn_value.clone(),
|
||||
Value::Array(Box::new(bind_values)),
|
||||
reg.clone(),
|
||||
));
|
||||
@@ -1237,7 +1242,29 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
return self.inline(Value::Undefined, target_register);
|
||||
}
|
||||
|
||||
let value = match self.fnc.lookup(ident) {
|
||||
let fn_as_owner_id = match self.fnc.scope_analysis.lookup(ident) {
|
||||
Some(name) => match name.type_ == NameType::Function {
|
||||
true => match name.id {
|
||||
// TODO: This is a bit of a hack, it might break...
|
||||
// functions have an owner id, and the name id should
|
||||
// have the same span... at least it does now
|
||||
NameId::Span(span) => Some(OwnerId::Span(span)),
|
||||
_ => None, // Internal error?
|
||||
},
|
||||
false => None,
|
||||
},
|
||||
_ => {
|
||||
self.fnc.diagnostics.push(Diagnostic {
|
||||
level: DiagnosticLevel::InternalError,
|
||||
message: format!("Failed to lookup identifier `{}`", ident.sym),
|
||||
span: ident.span,
|
||||
});
|
||||
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let value = match self.fnc.lookup_value(ident) {
|
||||
Some(v) => v, // TODO: Capturing functions
|
||||
None => {
|
||||
self.fnc.diagnostics.push(Diagnostic {
|
||||
@@ -1254,7 +1281,22 @@ impl<'a> ExpressionCompiler<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
self.inline(value, target_register)
|
||||
match fn_as_owner_id {
|
||||
Some(owner_id) => {
|
||||
let capture_params = self.fnc.scope_analysis.captures.get(&owner_id).cloned();
|
||||
|
||||
match capture_params {
|
||||
Some(capture_params) => self.capturing_fn_ref(
|
||||
Some(ident.sym.to_string()),
|
||||
&value,
|
||||
&capture_params,
|
||||
target_register,
|
||||
),
|
||||
None => self.inline(value, target_register),
|
||||
}
|
||||
}
|
||||
None => self.inline(value, target_register),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_literal(&mut self, lit: &swc_ecma_ast::Lit) -> Value {
|
||||
@@ -1532,7 +1574,7 @@ impl TargetAccessor {
|
||||
use swc_ecma_ast::Expr::*;
|
||||
|
||||
return match expr {
|
||||
Ident(ident) => match ec.fnc.lookup(ident) {
|
||||
Ident(ident) => match ec.fnc.lookup_value(ident) {
|
||||
Some(Value::Register(_)) => true,
|
||||
_ => false,
|
||||
},
|
||||
|
||||
@@ -13,11 +13,11 @@ use crate::diagnostic::{Diagnostic, DiagnosticLevel};
|
||||
use crate::expression_compiler::CompiledExpression;
|
||||
use crate::expression_compiler::ExpressionCompiler;
|
||||
use crate::name_allocator::{NameAllocator, RegAllocator};
|
||||
use crate::scope_analysis::{NameId, OwnerId, ScopeAnalysis};
|
||||
use crate::scope_analysis::{fn_to_owner_id, NameId, OwnerId, ScopeAnalysis};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Functionish {
|
||||
Fn(swc_ecma_ast::Function),
|
||||
Fn(Option<swc_ecma_ast::Ident>, swc_ecma_ast::Function),
|
||||
Arrow(swc_ecma_ast::ArrowExpr),
|
||||
Constructor(
|
||||
Vec<InstructionOrLabel>,
|
||||
@@ -29,7 +29,7 @@ pub enum Functionish {
|
||||
impl Spanned for Functionish {
|
||||
fn span(&self) -> swc_common::Span {
|
||||
match self {
|
||||
Functionish::Fn(fn_) => fn_.span,
|
||||
Functionish::Fn(_, fn_) => fn_.span,
|
||||
Functionish::Arrow(arrow) => arrow.span,
|
||||
Functionish::Constructor(_, class_span, _) => *class_span,
|
||||
}
|
||||
@@ -38,7 +38,10 @@ impl Spanned for Functionish {
|
||||
|
||||
impl Functionish {
|
||||
pub fn owner_id(&self) -> OwnerId {
|
||||
OwnerId::Span(self.span().clone())
|
||||
match self {
|
||||
Functionish::Fn(ident, fn_) => fn_to_owner_id(ident, fn_),
|
||||
_ => OwnerId::Span(self.span().clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,12 +120,14 @@ impl FunctionCompiler {
|
||||
self.current.body.push(InstructionOrLabel::Label(label));
|
||||
}
|
||||
|
||||
pub fn lookup(&self, ident: &swc_ecma_ast::Ident) -> Option<Value> {
|
||||
self.scope_analysis.lookup(&self.owner_id, ident)
|
||||
pub fn lookup_value(&self, ident: &swc_ecma_ast::Ident) -> Option<Value> {
|
||||
self.scope_analysis.lookup_value(&self.owner_id, ident)
|
||||
}
|
||||
|
||||
pub fn lookup_name_id(&self, name_id: &NameId) -> Option<Value> {
|
||||
self.scope_analysis.lookup_name_id(&self.owner_id, name_id)
|
||||
pub fn lookup_by_name_id(&self, name_id: &NameId) -> Option<Value> {
|
||||
self
|
||||
.scope_analysis
|
||||
.lookup_by_name_id(&self.owner_id, name_id)
|
||||
}
|
||||
|
||||
pub fn todo(&mut self, span: swc_common::Span, message: &str) {
|
||||
@@ -256,7 +261,7 @@ impl FunctionCompiler {
|
||||
self.add_param_code(functionish, ¶m_registers);
|
||||
|
||||
match functionish {
|
||||
Functionish::Fn(fn_) => {
|
||||
Functionish::Fn(_, fn_) => {
|
||||
match &fn_.body {
|
||||
Some(block) => {
|
||||
self.handle_block_body(block);
|
||||
@@ -316,7 +321,7 @@ impl FunctionCompiler {
|
||||
let mut param_registers = Vec::<Register>::new();
|
||||
|
||||
match functionish {
|
||||
Functionish::Fn(fn_) => {
|
||||
Functionish::Fn(_, fn_) => {
|
||||
for p in &fn_.params {
|
||||
param_registers.push(self.get_pattern_register(&p.pat));
|
||||
}
|
||||
@@ -359,7 +364,7 @@ impl FunctionCompiler {
|
||||
}
|
||||
|
||||
pub fn get_variable_register(&mut self, ident: &swc_ecma_ast::Ident) -> Register {
|
||||
match self.scope_analysis.lookup(&self.owner_id, ident) {
|
||||
match self.scope_analysis.lookup_value(&self.owner_id, ident) {
|
||||
Some(Value::Register(reg)) => reg,
|
||||
lookup_result => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
@@ -379,7 +384,7 @@ impl FunctionCompiler {
|
||||
|
||||
fn add_param_code(&mut self, functionish: &Functionish, param_registers: &Vec<Register>) {
|
||||
match functionish {
|
||||
Functionish::Fn(fn_) => {
|
||||
Functionish::Fn(_, fn_) => {
|
||||
for (i, p) in fn_.params.iter().enumerate() {
|
||||
let mut ec = ExpressionCompiler { fnc: self };
|
||||
ec.pat(&p.pat, ¶m_registers[i], false);
|
||||
@@ -1043,7 +1048,7 @@ impl FunctionCompiler {
|
||||
self
|
||||
.queue
|
||||
.add(QueuedFunction {
|
||||
definition_pointer: match self.lookup(&fn_decl.ident) {
|
||||
definition_pointer: match self.lookup_value(&fn_decl.ident) {
|
||||
Some(Value::Pointer(p)) => p,
|
||||
_ => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
@@ -1051,7 +1056,7 @@ impl FunctionCompiler {
|
||||
message: format!(
|
||||
"Lookup of function {} was not a pointer, lookup_result: {:?}",
|
||||
fn_decl.ident.sym,
|
||||
self.lookup(&fn_decl.ident)
|
||||
self.lookup_value(&fn_decl.ident)
|
||||
),
|
||||
span: fn_decl.ident.span,
|
||||
});
|
||||
@@ -1060,7 +1065,7 @@ impl FunctionCompiler {
|
||||
}
|
||||
},
|
||||
fn_name: Some(fn_decl.ident.sym.to_string()),
|
||||
functionish: Functionish::Fn(fn_decl.function.clone()),
|
||||
functionish: Functionish::Fn(Some(fn_decl.ident.clone()), fn_decl.function.clone()),
|
||||
})
|
||||
.expect("Failed to add function to queue");
|
||||
}
|
||||
|
||||
@@ -254,7 +254,10 @@ impl ModuleCompiler {
|
||||
fn compile_fn_decl(&mut self, export: bool, fn_: &swc_ecma_ast::FnDecl) {
|
||||
let fn_name = fn_.ident.sym.to_string();
|
||||
|
||||
let pointer = match self.scope_analysis.lookup(&OwnerId::Module, &fn_.ident) {
|
||||
let pointer = match self
|
||||
.scope_analysis
|
||||
.lookup_value(&OwnerId::Module, &fn_.ident)
|
||||
{
|
||||
Some(Value::Pointer(p)) => p,
|
||||
_ => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
@@ -277,7 +280,7 @@ impl ModuleCompiler {
|
||||
let mut fn_defns = self.compile_fn(
|
||||
pointer,
|
||||
Some(fn_name),
|
||||
Functionish::Fn(fn_.function.clone()),
|
||||
Functionish::Fn(Some(fn_.ident.clone()), fn_.function.clone()),
|
||||
);
|
||||
|
||||
self.module.definitions.append(&mut fn_defns);
|
||||
@@ -296,7 +299,7 @@ impl ModuleCompiler {
|
||||
Some(ident) => {
|
||||
let fn_name = ident.sym.to_string();
|
||||
|
||||
let defn = match self.scope_analysis.lookup(&OwnerId::Module, ident) {
|
||||
let defn = match self.scope_analysis.lookup_value(&OwnerId::Module, ident) {
|
||||
Some(Value::Pointer(p)) => p,
|
||||
_ => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
@@ -316,7 +319,11 @@ impl ModuleCompiler {
|
||||
|
||||
self.module.export_default = Value::Pointer(defn.clone());
|
||||
|
||||
let mut fn_defns = self.compile_fn(defn, fn_name, Functionish::Fn(fn_.function.clone()));
|
||||
let mut fn_defns = self.compile_fn(
|
||||
defn,
|
||||
fn_name,
|
||||
Functionish::Fn(fn_.ident.clone(), fn_.function.clone()),
|
||||
);
|
||||
|
||||
self.module.definitions.append(&mut fn_defns);
|
||||
}
|
||||
@@ -408,7 +415,10 @@ impl ModuleCompiler {
|
||||
|
||||
Some(defn)
|
||||
}
|
||||
None => match self.scope_analysis.lookup(&OwnerId::Module, &orig_name) {
|
||||
None => match self
|
||||
.scope_analysis
|
||||
.lookup_value(&OwnerId::Module, &orig_name)
|
||||
{
|
||||
Some(Value::Pointer(p)) => Some(p),
|
||||
lookup_result => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
@@ -522,7 +532,10 @@ impl ModuleCompiler {
|
||||
None => local_name.clone(),
|
||||
};
|
||||
|
||||
let pointer = match self.scope_analysis.lookup(&OwnerId::Module, &named.local) {
|
||||
let pointer = match self
|
||||
.scope_analysis
|
||||
.lookup_value(&OwnerId::Module, &named.local)
|
||||
{
|
||||
Some(Value::Pointer(p)) => p,
|
||||
_ => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
@@ -555,7 +568,10 @@ impl ModuleCompiler {
|
||||
Default(default) => {
|
||||
let local_name = default.local.sym.to_string();
|
||||
|
||||
let pointer = match self.scope_analysis.lookup(&OwnerId::Module, &default.local) {
|
||||
let pointer = match self
|
||||
.scope_analysis
|
||||
.lookup_value(&OwnerId::Module, &default.local)
|
||||
{
|
||||
Some(Value::Pointer(p)) => p,
|
||||
_ => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
@@ -583,7 +599,7 @@ impl ModuleCompiler {
|
||||
|
||||
let pointer = match self
|
||||
.scope_analysis
|
||||
.lookup(&OwnerId::Module, &namespace.local)
|
||||
.lookup_value(&OwnerId::Module, &namespace.local)
|
||||
{
|
||||
Some(Value::Pointer(p)) => p,
|
||||
_ => {
|
||||
@@ -641,7 +657,7 @@ impl ModuleCompiler {
|
||||
let mut dependent_definitions: Vec<Definition>;
|
||||
|
||||
let defn_name = match ident {
|
||||
Some(ident) => match self.scope_analysis.lookup(&OwnerId::Module, ident) {
|
||||
Some(ident) => match self.scope_analysis.lookup_value(&OwnerId::Module, ident) {
|
||||
Some(Value::Pointer(p)) => p,
|
||||
_ => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
@@ -766,7 +782,7 @@ impl ModuleCompiler {
|
||||
dependent_definitions.append(&mut self.compile_fn(
|
||||
method_defn_name.clone(),
|
||||
None,
|
||||
Functionish::Fn(method.function.clone()),
|
||||
Functionish::Fn(None, method.function.clone()),
|
||||
));
|
||||
|
||||
methods
|
||||
|
||||
@@ -164,12 +164,17 @@ impl ScopeAnalysis {
|
||||
return sa;
|
||||
}
|
||||
|
||||
pub fn lookup(&self, scope: &OwnerId, ident: &swc_ecma_ast::Ident) -> Option<Value> {
|
||||
pub fn lookup(&self, ident: &swc_ecma_ast::Ident) -> Option<&Name> {
|
||||
let name_id = self.refs.get(&ident.span)?;
|
||||
self.lookup_name_id(scope, name_id)
|
||||
self.names.get(name_id)
|
||||
}
|
||||
|
||||
pub fn lookup_name_id(&self, scope: &OwnerId, name_id: &NameId) -> Option<Value> {
|
||||
pub fn lookup_value(&self, scope: &OwnerId, ident: &swc_ecma_ast::Ident) -> Option<Value> {
|
||||
let name_id = self.refs.get(&ident.span)?;
|
||||
self.lookup_by_name_id(scope, name_id)
|
||||
}
|
||||
|
||||
pub fn lookup_by_name_id(&self, scope: &OwnerId, name_id: &NameId) -> Option<Value> {
|
||||
let name = self.names.get(name_id)?;
|
||||
|
||||
match &name.value {
|
||||
@@ -450,7 +455,7 @@ impl ScopeAnalysis {
|
||||
name: &Option<swc_ecma_ast::Ident>,
|
||||
function: &swc_ecma_ast::Function,
|
||||
) {
|
||||
let child_scope = scope.nest(Some(OwnerId::Span(function.span.clone())));
|
||||
let child_scope = scope.nest(Some(fn_to_owner_id(name, function)));
|
||||
|
||||
if let Some(name) = name {
|
||||
self.insert_pointer_name(&child_scope, NameType::Function, name);
|
||||
@@ -1909,3 +1914,13 @@ fn is_declare(decl: &swc_ecma_ast::Decl) -> bool {
|
||||
swc_ecma_ast::Decl::TsModule(ts_module_decl) => ts_module_decl.declare,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fn_to_owner_id(
|
||||
name: &Option<swc_ecma_ast::Ident>,
|
||||
function: &swc_ecma_ast::Function,
|
||||
) -> OwnerId {
|
||||
OwnerId::Span(match name {
|
||||
Some(name) => name.span,
|
||||
None => function.span,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user