diff --git a/README.md b/README.md index 3e824f2..d075fc8 100644 --- a/README.md +++ b/README.md @@ -440,6 +440,7 @@ not the subset of ValueScript that has actually been implemented. - This is a value semantics thing - objects don't have identity - TypeScript enums - TypeScript parameter properties +- Capturing `this` in arrow functions - Many unusual JS things: - `[] + [] -> ""` - `[10, 1, 3].sort() -> [1, 10, 3]` @@ -479,7 +480,6 @@ not the subset of ValueScript that has actually been implemented. - Rest params - Async functions - TypeScript namespaces -- Capturing `this` in arrow functions - `export * from` - (`export { name } from` _does_ work) - `import.meta` diff --git a/inputs/passing/capture.ts b/inputs/passing/captures/capture.ts similarity index 100% rename from inputs/passing/capture.ts rename to inputs/passing/captures/capture.ts diff --git a/inputs/passing/captureBeforeInit.ts b/inputs/passing/captures/captureBeforeInit.ts similarity index 100% rename from inputs/passing/captureBeforeInit.ts rename to inputs/passing/captures/captureBeforeInit.ts diff --git a/inputs/passing/captureBeforeInitFnExpr.ts b/inputs/passing/captures/captureBeforeInitFnExpr.ts similarity index 100% rename from inputs/passing/captureBeforeInitFnExpr.ts rename to inputs/passing/captures/captureBeforeInitFnExpr.ts diff --git a/inputs/passing/captureBeforeInitFnMixed.ts b/inputs/passing/captures/captureBeforeInitFnMixed.ts similarity index 100% rename from inputs/passing/captureBeforeInitFnMixed.ts rename to inputs/passing/captures/captureBeforeInitFnMixed.ts diff --git a/inputs/passing/captureButNotRefBeforeInit.ts b/inputs/passing/captures/captureButNotRefBeforeInit.ts similarity index 100% rename from inputs/passing/captureButNotRefBeforeInit.ts rename to inputs/passing/captures/captureButNotRefBeforeInit.ts diff --git a/inputs/passing/captureMutated.ts b/inputs/passing/captures/captureMutated.ts similarity index 100% rename from inputs/passing/captureMutated.ts rename to inputs/passing/captures/captureMutated.ts diff --git a/inputs/passing/captureShadowed.ts b/inputs/passing/captures/captureShadowed.ts similarity index 100% rename from inputs/passing/captureShadowed.ts rename to inputs/passing/captures/captureShadowed.ts diff --git a/inputs/passing/captureSimple.ts b/inputs/passing/captures/captureSimple.ts similarity index 100% rename from inputs/passing/captureSimple.ts rename to inputs/passing/captures/captureSimple.ts diff --git a/inputs/passing/captures/captureThis.ts b/inputs/passing/captures/captureThis.ts new file mode 100644 index 0000000..203a938 --- /dev/null +++ b/inputs/passing/captures/captureThis.ts @@ -0,0 +1,20 @@ +//! test_output("bar") + +export default function () { + const foo = new Foo(); + const cloner = foo.cloner(); + + return cloner().bar(); +} + +class Foo { + barString = "bar"; + + bar() { + return this.barString; + } + + cloner() { + return () => this; + } +} diff --git a/inputs/passing/captures/captureThisMemberExpr.ts b/inputs/passing/captures/captureThisMemberExpr.ts new file mode 100644 index 0000000..ebcfbc0 --- /dev/null +++ b/inputs/passing/captures/captureThisMemberExpr.ts @@ -0,0 +1,20 @@ +//! test_output("bar") + +export default function () { + const foo = new Foo(); + const barCaller = foo.barCaller(); + + return barCaller(); +} + +class Foo { + barString = "bar"; + + bar() { + return this.barString; + } + + barCaller() { + return () => this.bar(); + } +} diff --git a/valuescript_compiler/src/expression_compiler.rs b/valuescript_compiler/src/expression_compiler.rs index 6da4d7b..9dac43c 100644 --- a/valuescript_compiler/src/expression_compiler.rs +++ b/valuescript_compiler/src/expression_compiler.rs @@ -6,6 +6,7 @@ use swc_common::Spanned; use crate::asm::{Array, Instruction, Label, Number, Object, Register, Value}; use crate::diagnostic::{Diagnostic, DiagnosticLevel}; use crate::function_compiler::{FunctionCompiler, Functionish, QueuedFunction}; +use crate::ident::Ident as CrateIdent; use crate::scope::{NameId, OwnerId}; use crate::scope_analysis::{fn_to_owner_id, NameType}; use crate::target_accessor::TargetAccessor; @@ -86,7 +87,7 @@ impl<'a> ExpressionCompiler<'a> { use swc_ecma_ast::Expr::*; match expr { - This(_) => Value::Register(Register::this()).to_ce(), + This(this) => self.ident(&CrateIdent::this(this.span), target_register), Array(array_exp) => self.array_expression(array_exp, target_register), Object(object_exp) => self.object_expression(object_exp, target_register), Fn(fn_) => self.fn_expression(fn_, target_register), @@ -123,7 +124,7 @@ impl<'a> ExpressionCompiler<'a> { self.compile(seq_exp.exprs.last().unwrap(), target_register) } - Ident(ident) => self.identifier(ident, target_register), + Ident(ident) => self.ident(&CrateIdent::from_swc_ident(ident), target_register), Lit(lit) => self.compile_literal(lit).to_ce(), Tpl(tpl) => self.template_literal(tpl, target_register), TaggedTpl(tagged_tpl) => { @@ -292,7 +293,7 @@ impl<'a> ExpressionCompiler<'a> { CompiledExpression::new(Value::Register(target), nested_registers) } - pub fn get_register_for_ident_mutation(&mut self, ident: &swc_ecma_ast::Ident) -> Register { + pub fn get_register_for_ident_mutation(&mut self, ident: &CrateIdent) -> Register { let (reg, err_msg) = match self.fnc.lookup_value(ident) { Some(Value::Register(reg)) => (Some(reg), None), lookup_result => ( @@ -343,7 +344,9 @@ impl<'a> ExpressionCompiler<'a> { ) -> CompiledExpression { let mut at = match &assign_expr.left { swc_ecma_ast::PatOrExpr::Pat(pat) => match &**pat { - swc_ecma_ast::Pat::Ident(ident) => TargetAccessor::compile_ident(self, &ident.id), + swc_ecma_ast::Pat::Ident(ident) => { + TargetAccessor::compile_ident(self, &CrateIdent::from_swc_ident(&ident.id)) + } swc_ecma_ast::Pat::Expr(expr) => TargetAccessor::compile(self, expr, true), _ => return self.assign_pat_eq(pat, &assign_expr.right, target_register), }, @@ -410,9 +413,9 @@ impl<'a> ExpressionCompiler<'a> { let mut target = match &assign_expr.left { PatOrExpr::Expr(expr) => TargetAccessor::compile(self, expr, true), PatOrExpr::Pat(pat) => match &**pat { - Pat::Ident(ident) => { - TargetAccessor::Register(self.get_register_for_ident_mutation(&ident.id)) - } + Pat::Ident(ident) => TargetAccessor::Register( + self.get_register_for_ident_mutation(&CrateIdent::from_swc_ident(&ident.id)), + ), _ => { self.fnc.diagnostics.push(Diagnostic { level: DiagnosticLevel::Error, @@ -496,7 +499,7 @@ impl<'a> ExpressionCompiler<'a> { Prop::Shorthand(ident) => { let prop_key = Value::String(ident.sym.to_string()); - let mut compiled_value = self.identifier(ident, None); + let mut compiled_value = self.ident(&CrateIdent::from_swc_ident(ident), None); sub_nested_registers.append(&mut compiled_value.nested_registers); compiled_value.release_checker.has_unreleased_registers = false; let prop_value = compiled_value.value; @@ -1224,9 +1227,9 @@ impl<'a> ExpressionCompiler<'a> { CompiledExpression::new(Value::Register(dst), nested_registers) } - pub fn identifier( + pub fn ident( &mut self, - ident: &swc_ecma_ast::Ident, + ident: &CrateIdent, target_register: Option, ) -> CompiledExpression { let fn_as_owner_id = match self.fnc.scope_analysis.lookup(ident) { @@ -1251,6 +1254,8 @@ impl<'a> ExpressionCompiler<'a> { } }; + let value = self.fnc.lookup_value(ident).unwrap_or_default(); + let name = match self.fnc.lookup(ident) { Some(v) => v, None => { @@ -1258,8 +1263,6 @@ impl<'a> ExpressionCompiler<'a> { } }; - let value = name.value.clone(); - match fn_as_owner_id { Some(owner_id) => { let capture_params = self.fnc.scope_analysis.get_register_captures(&owner_id); @@ -1376,7 +1379,9 @@ impl<'a> ExpressionCompiler<'a> { } ObjectPatProp::Assign(assign) => { let key = assign.key.sym.to_string(); - let reg = self.fnc.get_variable_register(&assign.key); + let reg = self + .fnc + .get_variable_register(&CrateIdent::from_swc_ident(&assign.key)); self.fnc.push(Instruction::Sub( Value::Register(register.clone()), diff --git a/valuescript_compiler/src/function_compiler.rs b/valuescript_compiler/src/function_compiler.rs index 6e2043c..ea17269 100644 --- a/valuescript_compiler/src/function_compiler.rs +++ b/valuescript_compiler/src/function_compiler.rs @@ -14,6 +14,7 @@ use crate::compile_enum_value::compile_enum_value; use crate::diagnostic::{Diagnostic, DiagnosticLevel}; use crate::expression_compiler::CompiledExpression; use crate::expression_compiler::ExpressionCompiler; +use crate::ident::Ident; use crate::name_allocator::{NameAllocator, RegAllocator}; use crate::scope::{NameId, OwnerId}; use crate::scope_analysis::{fn_to_owner_id, Name, ScopeAnalysis}; @@ -132,7 +133,7 @@ impl FunctionCompiler { self.current.body.push(FnLine::Comment(message)); } - pub fn lookup(&mut self, ident: &swc_ecma_ast::Ident) -> Option<&Name> { + pub fn lookup(&mut self, ident: &Ident) -> Option<&Name> { let name = self.scope_analysis.lookup(ident); if name.is_none() { @@ -146,7 +147,7 @@ impl FunctionCompiler { name } - pub fn lookup_value(&self, ident: &swc_ecma_ast::Ident) -> Option { + pub fn lookup_value(&self, ident: &Ident) -> Option { self.scope_analysis.lookup_value(&self.owner_id, ident) } @@ -404,7 +405,7 @@ impl FunctionCompiler { swc_ecma_ast::TsParamPropParam::Ident(ident) => { match ident.id.sym.to_string().as_str() { "this" => None, - _ => Some(self.get_variable_register(&ident.id)), + _ => Some(self.get_variable_register(&Ident::from_swc_ident(&ident.id))), } } swc_ecma_ast::TsParamPropParam::Assign(assign) => { @@ -431,7 +432,7 @@ impl FunctionCompiler { Some(match param_pat { Pat::Ident(ident) => match ident.id.sym.to_string().as_str() { "this" => return None, - _ => self.get_variable_register(&ident.id), + _ => self.get_variable_register(&Ident::from_swc_ident(&ident.id)), }, Pat::Assign(assign) => return self.get_pattern_register_opt(&assign.left), Pat::Array(_) => self.allocate_numbered_reg("_array_pat"), @@ -452,7 +453,7 @@ impl FunctionCompiler { } } - pub fn get_variable_register(&mut self, ident: &swc_ecma_ast::Ident) -> Register { + pub fn get_variable_register(&mut self, ident: &Ident) -> Register { match self.scope_analysis.lookup_value(&self.owner_id, ident) { Some(Value::Register(reg)) => reg, lookup_result => { @@ -462,7 +463,7 @@ impl FunctionCompiler { "Register should have been allocated for variable {}, instead: {:?}", ident.sym, lookup_result, ), - span: ident.span(), + span: ident.span, }); self.allocate_numbered_reg("_error_variable_without_register") @@ -1220,7 +1221,7 @@ impl FunctionCompiler { self .queue .add(QueuedFunction { - definition_pointer: match self.lookup_value(&fn_decl.ident) { + definition_pointer: match self.lookup_value(&Ident::from_swc_ident(&fn_decl.ident)) { Some(Value::Pointer(p)) => p, _ => { self.diagnostics.push(Diagnostic { @@ -1228,7 +1229,7 @@ impl FunctionCompiler { message: format!( "Lookup of function {} was not a pointer, lookup_result: {:?}", fn_decl.ident.sym, - self.lookup_value(&fn_decl.ident) + self.lookup_value(&Ident::from_swc_ident(&fn_decl.ident)) ), span: fn_decl.ident.span, }); @@ -1247,7 +1248,7 @@ impl FunctionCompiler { TsEnum(ts_enum) => { let pointer = match self .scope_analysis - .lookup_value(&OwnerId::Module, &ts_enum.id) + .lookup_value(&OwnerId::Module, &Ident::from_swc_ident(&ts_enum.id)) { Some(Value::Pointer(p)) => p, _ => { diff --git a/valuescript_compiler/src/ident.rs b/valuescript_compiler/src/ident.rs index 6992868..fa5ca34 100644 --- a/valuescript_compiler/src/ident.rs +++ b/valuescript_compiler/src/ident.rs @@ -1,3 +1,4 @@ +#[derive(Debug)] pub struct Ident { pub sym: swc_atoms::JsWord, pub span: swc_common::Span, diff --git a/valuescript_compiler/src/module_compiler.rs b/valuescript_compiler/src/module_compiler.rs index 66b5540..f60fe42 100644 --- a/valuescript_compiler/src/module_compiler.rs +++ b/valuescript_compiler/src/module_compiler.rs @@ -16,6 +16,7 @@ use crate::compile_enum_value::compile_enum_value; use crate::diagnostic::{Diagnostic, DiagnosticLevel}; use crate::expression_compiler::{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; @@ -205,7 +206,7 @@ impl ModuleCompiler { let value = match &*ede.expr { swc_ecma_ast::Expr::Ident(ident) => self .scope_analysis - .lookup(ident) + .lookup(&Ident::from_swc_ident(ident)) .map(|name| name.value.clone()), expr => static_eval_expr(&self.scope_analysis, &self.constants_map.borrow(), expr), }; @@ -315,7 +316,7 @@ impl ModuleCompiler { } }; - let pointer = match self.scope_analysis.lookup(ident) { + let pointer = match self.scope_analysis.lookup(&Ident::from_swc_ident(ident)) { Some(name) => match &name.value { Value::Pointer(p) => p.clone(), _ => { @@ -363,7 +364,7 @@ impl ModuleCompiler { let pointer = match self .scope_analysis - .lookup_value(&OwnerId::Module, &fn_.ident) + .lookup_value(&OwnerId::Module, &Ident::from_swc_ident(&fn_.ident)) { Some(Value::Pointer(p)) => p, _ => { @@ -396,7 +397,7 @@ impl ModuleCompiler { fn compile_enum_decl(&mut self, export: bool, ts_enum: &swc_ecma_ast::TsEnumDecl) { let pointer = match self .scope_analysis - .lookup_value(&OwnerId::Module, &ts_enum.id) + .lookup_value(&OwnerId::Module, &Ident::from_swc_ident(&ts_enum.id)) { Some(Value::Pointer(p)) => p, _ => { @@ -443,7 +444,10 @@ impl ModuleCompiler { Some(ident) => { let fn_name = ident.sym.to_string(); - let defn = match self.scope_analysis.lookup_value(&OwnerId::Module, ident) { + let defn = match self + .scope_analysis + .lookup_value(&OwnerId::Module, &Ident::from_swc_ident(ident)) + { Some(Value::Pointer(p)) => p, _ => { self.diagnostics.push(Diagnostic { @@ -569,7 +573,7 @@ impl ModuleCompiler { } None => match self .scope_analysis - .lookup_value(&OwnerId::Module, orig_name) + .lookup_value(&OwnerId::Module, &Ident::from_swc_ident(orig_name)) { Some(Value::Pointer(p)) => Some(p), lookup_result => { @@ -694,7 +698,7 @@ impl ModuleCompiler { let pointer = match self .scope_analysis - .lookup_value(&OwnerId::Module, &named.local) + .lookup_value(&OwnerId::Module, &Ident::from_swc_ident(&named.local)) { Some(Value::Pointer(p)) => p, _ => { @@ -730,7 +734,7 @@ impl ModuleCompiler { let pointer = match self .scope_analysis - .lookup_value(&OwnerId::Module, &default.local) + .lookup_value(&OwnerId::Module, &Ident::from_swc_ident(&default.local)) { Some(Value::Pointer(p)) => p, _ => { @@ -759,7 +763,7 @@ impl ModuleCompiler { let pointer = match self .scope_analysis - .lookup_value(&OwnerId::Module, &namespace.local) + .lookup_value(&OwnerId::Module, &Ident::from_swc_ident(&namespace.local)) { Some(Value::Pointer(p)) => p, _ => { @@ -819,7 +823,10 @@ impl ModuleCompiler { let mut dependent_definitions: Vec; let defn_name = match ident { - Some(ident) => match self.scope_analysis.lookup_value(&OwnerId::Module, ident) { + Some(ident) => match self + .scope_analysis + .lookup_value(&OwnerId::Module, &Ident::from_swc_ident(ident)) + { Some(Value::Pointer(p)) => p, _ => { self.diagnostics.push(Diagnostic { diff --git a/valuescript_compiler/src/scope_analysis.rs b/valuescript_compiler/src/scope_analysis.rs index db04be4..b0f83dc 100644 --- a/valuescript_compiler/src/scope_analysis.rs +++ b/valuescript_compiler/src/scope_analysis.rs @@ -136,12 +136,12 @@ impl ScopeAnalysis { sa } - pub fn lookup(&self, ident: &swc_ecma_ast::Ident) -> Option<&Name> { + pub fn lookup(&self, ident: &Ident) -> Option<&Name> { let name_id = &self.refs.get(&ident.span)?.name_id; self.names.get(name_id) } - pub fn lookup_value(&self, scope: &OwnerId, ident: &swc_ecma_ast::Ident) -> Option { + pub fn lookup_value(&self, scope: &OwnerId, ident: &Ident) -> Option { let name_id = &self.refs.get(&ident.span)?.name_id; self.lookup_by_name_id(scope, name_id) } diff --git a/valuescript_compiler/src/static_eval_expr.rs b/valuescript_compiler/src/static_eval_expr.rs index 0cd9747..de09689 100644 --- a/valuescript_compiler/src/static_eval_expr.rs +++ b/valuescript_compiler/src/static_eval_expr.rs @@ -5,6 +5,7 @@ use valuescript_vm::operations::to_i32; use crate::{ asm::{Array, Builtin, Number, Object, Pointer, Value}, expression_compiler::value_from_literal, + ident::Ident, scope_analysis::ScopeAnalysis, }; @@ -84,7 +85,10 @@ pub fn static_eval_expr( 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 sa.lookup(ident).map(|name| name.value.clone()) { + swc_ecma_ast::Expr::Ident(ident) => match sa + .lookup(&Ident::from_swc_ident(ident)) + .map(|name| name.value.clone()) + { Some(Value::Pointer(p)) => cm.get(&p).cloned(), Some(value) => Some(value), None => None, diff --git a/valuescript_compiler/src/target_accessor.rs b/valuescript_compiler/src/target_accessor.rs index 17d0329..74a8637 100644 --- a/valuescript_compiler/src/target_accessor.rs +++ b/valuescript_compiler/src/target_accessor.rs @@ -3,6 +3,7 @@ use std::mem::take; use crate::{ asm::{Instruction, Register, Value}, expression_compiler::{CompiledExpression, ExpressionCompiler}, + ident::Ident as CrateIdent, Diagnostic, DiagnosticLevel, }; use swc_common::Spanned; @@ -23,7 +24,7 @@ impl TargetAccessor { use swc_ecma_ast::Expr::*; return match expr { - Ident(ident) => match ec.fnc.lookup(ident) { + Ident(ident) => match ec.fnc.lookup(&crate::ident::Ident::from_swc_ident(ident)) { Some(name) => !name.effectively_const, _ => false, // TODO: InternalError? }, @@ -56,8 +57,8 @@ impl TargetAccessor { use swc_ecma_ast::Expr::*; return match expr { - Ident(ident) => TargetAccessor::compile_ident(ec, ident), - This(_) => TargetAccessor::Register(Register::this()), + Ident(ident) => TargetAccessor::compile_ident(ec, &CrateIdent::from_swc_ident(ident)), + This(this) => TargetAccessor::compile_ident(ec, &CrateIdent::this(this.span)), Member(member) => { let obj = TargetAccessor::compile(ec, &member.obj, false); let subscript = ec.member_prop(&member.prop, None); @@ -100,7 +101,7 @@ impl TargetAccessor { }; } - pub fn compile_ident(ec: &mut ExpressionCompiler, ident: &swc_ecma_ast::Ident) -> TargetAccessor { + pub fn compile_ident(ec: &mut ExpressionCompiler, ident: &CrateIdent) -> TargetAccessor { TargetAccessor::Register(ec.get_register_for_ident_mutation(ident)) }