From 6e9938f2eed34ff112f55ad4e118047593f4f0a1 Mon Sep 17 00:00:00 2001 From: Sam Sussman Date: Wed, 21 Sep 2022 09:53:17 -0500 Subject: [PATCH 1/8] basic contributing --- CONTRIBUTING.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e605eae --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,16 @@ +### Pre-req + +* Rust - `curl https://sh.rustup.rs -sSf | sh` + +### Once + +``` +> yarn default +> rustup target add wasm32-wasi +``` + +### Each Change + +``` +> yarn compile +``` From 9fdd59eb7cccade123a701c89822b47c9b400cb3 Mon Sep 17 00:00:00 2001 From: Sam Sussman Date: Thu, 22 Sep 2022 19:37:22 -0500 Subject: [PATCH 2/8] feat: sequence commands --- src/closure_decorator.rs | 297 ++++++++++++++++++++++++++------------- 1 file changed, 198 insertions(+), 99 deletions(-) diff --git a/src/closure_decorator.rs b/src/closure_decorator.rs index 1bad4c6..c5db85b 100644 --- a/src/closure_decorator.rs +++ b/src/closure_decorator.rs @@ -10,26 +10,26 @@ use swc_core::visit::*; use crate::class_like::ClassLike; use crate::js_util::{ - ident_expr, prop_access_expr, ref_expr, require_expr, string_expr, this_expr, + ident_expr, prop_access_expr, ref_expr, require_expr, string_expr, this_expr, undefined_expr, }; use crate::prepend::prepend; use crate::span::{concat_span, get_prop_name_span}; use crate::virtual_machine::VirtualMachine; /** - * Name of the `register` function that is injected into all compiled source files. + * Flags used to identify the Functionless AST association sequences. * - * ```ts - * function register_8269d1a8(func, ast) { - * func[Symbol.for("functionless:AST")] = ast; - * return func; - * } - * ``` - * - * All Function Declarations, Expressions and Arrow Expressions are decorated with - * the `register` function which attaches its AST as a property. + * These can be used by downstream programs to discover and manipulate the injects + * functionless assignment sequences. */ -const REGISTER_FUNCTION_NAME: &str = "register_8269d1a8"; +// (REGISTER,stash=func,stash[]=ast,stash) +const REGISTER_FLAG: &str = "REGISTER_8269d1a8"; +// (REGISTER_REF,stash[]=ast) +const REGISTER_REF_FLAG: &str = "REGISTER_REF_8269d1a8"; +// // (stash=BIND, ... todo) +// const BIND_FLAG: &str = "BIND_8269d1a8"; +// // (stash=PROXY, ... todo) +// const PROXY_FLAG: &str = "PROXY_8269d1a8"; /** * Name of the `bind` function that is injected into all compiled source files. @@ -63,6 +63,24 @@ const BIND_FUNCTION_NAME: &str = "bind_8269d1a8"; const GLOBAL_THIS_NAME: &str = "global_8269d1a8"; +/** + * A unique variable used to story temporary values like registering functions with their AST. + * + * Example: + * ```ts + * const func = () => {}; + * ``` + * + * becomes: + * + * ```ts + * let stash; + * + * const func = (stash = () => {}, stash[Symbol.for(...)] = ast, stash); + * ``` + */ +const STASH_NAME: &str = "stash_8269d1a8"; + const PROXY_FUNCTION_NAME: &str = "proxy_8269d1a8"; const UTIL_FUNCTION_NAME: &str = "util_8269d1a8"; @@ -81,9 +99,9 @@ pub struct ClosureDecorator<'a> { */ pub global: Ident, /** - * An Identifier referencing the `register` interceptor function injected into all processed modules. + * A unique identifier functionless uses to story temporary values for registration. */ - pub register: Ident, + pub stash: Ident, /** * An Identifier referencing the `bind` interceptor function injected into all processed modules. */ @@ -113,7 +131,7 @@ impl<'a> ClosureDecorator<'a> { source_map, vm: VirtualMachine::new(), global: private_ident!(GLOBAL_THIS_NAME), - register: private_ident!(REGISTER_FUNCTION_NAME), + stash: private_ident!(STASH_NAME), bind: private_ident!(BIND_FUNCTION_NAME), proxy: private_ident!(PROXY_FUNCTION_NAME), util: private_ident!(UTIL_FUNCTION_NAME), @@ -125,16 +143,29 @@ impl<'a> ClosureDecorator<'a> { impl<'a> VisitMut for ClosureDecorator<'a> { fn visit_mut_module_items(&mut self, items: &mut Vec) { let new_stmts: Vec = [ + ModuleItem::Stmt(Stmt::Decl(Decl::Var(VarDecl { + span: DUMMY_SP, + declare: false, + decls: vec![VarDeclarator { + definite: false, + name: Pat::Ident(BindingIdent { + id: self.stash.clone(), + type_ann: None, + }), + init: None, + span: DUMMY_SP, + }], + kind: VarDeclKind::Let, + }))), ModuleItem::Stmt(Stmt::Decl(self.create_global_this())), ModuleItem::Stmt(Stmt::Decl(self.create_import_util())), - ModuleItem::Stmt(Stmt::Decl(self.create_register_interceptor())), ModuleItem::Stmt(Stmt::Decl(self.create_bind_interceptor())), ModuleItem::Stmt(Stmt::Decl(self.create_proxy_interceptor())), ] .into_iter() .chain( - // discover all function declarations in the module and create a - // CallExpr to `register` that decorates each function with its AST. + // discover all function declarations in the module and + // add the expressions to `register` function with its AST. items .iter() .filter_map(|item| match item { @@ -159,11 +190,21 @@ impl<'a> VisitMut for ClosureDecorator<'a> { // prepend the `register` and `bind` function declarations // and the `register` calls into the top of every module. prepend_stmts(items, new_stmts.into_iter()); + + items.push(ModuleItem::Stmt(Stmt::Expr(ExprStmt { + expr: Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + op: AssignOp::Assign, + left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), + right: undefined_expr(), + })), + span: DUMMY_SP, + }))) } fn visit_mut_stmts(&mut self, stmts: &mut Vec) { // discover all function declarations in the block and create a - // CallExpr to `register` that decorates each function with its AST. + // add the expressions to `register` function with its AST. let register_stmts: Vec = stmts .iter() .filter_map(|stmt| self.register_stmt_if_func_decl(stmt)) @@ -253,7 +294,7 @@ impl<'a> VisitMut for ClosureDecorator<'a> { *prop = Prop::KeyValue(KeyValueProp { key: method.key.take(), - value: self.register_ast(func, ast), + value: self.register_inline_ast_seq(func, ast), }); } _ => { @@ -269,14 +310,10 @@ impl<'a> VisitMut for ClosureDecorator<'a> { arrow.visit_mut_children_with(self); - // replace the arrow function with a call to the `register` interceptor function - // that decorates the function with its AST + // replace the arrow function with the expressions which associate the function to it's AST // () => {..} // => - // register( - // () => {..}, // original arrow - // () => [..], // function that produces the arrow's AST - // ) + // (stash = () => {...}, stash[Symbol.for("ast")] = () => [..], stash) *expr = *self.register_mut_ast(&mut Expr::Arrow(arrow.take()), ast); } Expr::Fn(func) if func.function.body.is_some() => { @@ -514,40 +551,13 @@ impl<'a> ClosureDecorator<'a> { fn register_ast_stmt(&self, expr: Box, ast: Box) -> Stmt { Stmt::Expr(ExprStmt { - expr: self.register_ast(expr, ast), + expr: self.register_ref_ast_seq(expr, ast), span: DUMMY_SP, }) } fn register_mut_ast(&self, func: &mut Expr, ast: Box) -> Box { - self.register_ast(Box::new(func.take()), ast) - } - - fn register_ast(&self, func: Box, ast: Box) -> Box { - Box::new(Expr::Call(CallExpr { - span: DUMMY_SP, - type_args: None, - // register(() => { .. }, () => new FunctionDecl([..])) - callee: Callee::Expr(Box::new(Expr::Ident(self.register.clone()))), - args: vec![ - ExprOrSpread { - expr: func, - spread: None, - }, - ExprOrSpread { - expr: Box::new(Expr::Arrow(ArrowExpr { - is_async: false, - is_generator: false, - return_type: None, - params: vec![], - span: DUMMY_SP, - type_params: None, - body: BlockStmtOrExpr::Expr(ast), - })), - spread: None, - }, - ], - })) + self.register_inline_ast_seq(Box::new(func.take()), ast) } /** @@ -573,7 +583,18 @@ impl<'a> ClosureDecorator<'a> { span: DUMMY_SP, type_args: None, callee: Callee::Expr(prop_access_expr( - ident_expr(self.register.clone()), + Box::new(Expr::Arrow(ArrowExpr { + is_async: false, + is_generator: false, + return_type: None, + params: vec![], + span: DUMMY_SP, + type_params: None, + body: BlockStmtOrExpr::BlockStmt(BlockStmt { + span: DUMMY_SP, + stmts: vec![], + }), + })), quote_ident!("constructor"), )), args: vec![ExprOrSpread { @@ -612,32 +633,94 @@ impl<'a> ClosureDecorator<'a> { }) } - fn create_register_interceptor(&self) -> Decl { - let func = quote_ident!("func"); - let ast = quote_ident!("ast"); - Decl::Fn(FnDecl { - declare: false, - ident: self.register.clone(), - function: Function { - params: vec![param(func.clone(), false), param(ast.clone(), false)], - decorators: vec![], - span: DUMMY_SP, - body: Some(BlockStmt { + /** + * Registers a function or object with it's AST and returns a reference to it's value using the stash variable. + * + * ```ts + * const x = () => {} + * ``` + * + * becomes + * + * ```ts + * ("REGISTER", stash = () => {}, stash[Symbol.from(functionless::AST)] = ast, stash) + * ``` + */ + fn register_inline_ast_seq(&self, func: Box, ast: Box) -> Box { + return Box::new(Expr::Seq(SeqExpr { + span: DUMMY_SP, + exprs: vec![ + // "I_REGISTER" + Box::new(Expr::Assign(AssignExpr { + left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), + op: AssignOp::Assign, + right: string_expr(REGISTER_FLAG), span: DUMMY_SP, - stmts: vec![ - self.set_symbol(func.clone(), "functionless:AST", ast.clone()), - Stmt::Return(ReturnStmt { - span: DUMMY_SP, - arg: Some(Box::new(Expr::Ident(func.clone()))), - }), - ], - }), - is_generator: false, - is_async: false, - type_params: None, - return_type: None, - }, - }) + })), + // stash=func + Box::new(Expr::Assign(AssignExpr { + left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), + op: AssignOp::Assign, + right: func, + span: DUMMY_SP, + })), + // stash[Symbol.from(functionless::AST)] = ast + Box::new(self.set_symbol_expr( + Box::new(Expr::Ident(self.stash.clone())), + "functionless:AST", + // is this right? + Box::new(Expr::Arrow(ArrowExpr { + is_async: false, + is_generator: false, + return_type: None, + params: vec![], + span: DUMMY_SP, + type_params: None, + body: BlockStmtOrExpr::Expr(ast), + })), + )), + // stash + Box::new(Expr::Ident(self.stash.clone())), + ], + })); + } + + /** + * Registers an identifier with it's AST. + * + * (stash=REGISTER_REF,x[Symbol.for(AST)]=ast) + * function x() { + * .... + * } + */ + fn register_ref_ast_seq(&self, expr: Box, ast: Box) -> Box { + return Box::new(Expr::Seq(SeqExpr { + span: DUMMY_SP, + exprs: vec![ + // "REGISTER" + Box::new(Expr::Assign(AssignExpr { + left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), + op: AssignOp::Assign, + right: string_expr(REGISTER_REF_FLAG), + span: DUMMY_SP, + })), + // stash[Symbol.from(functionless::AST)] = ast + Box::new(self.set_symbol_expr( + expr, + "functionless:AST", + // is this right? + Box::new(Expr::Arrow(ArrowExpr { + is_async: false, + is_generator: false, + return_type: None, + params: vec![], + span: DUMMY_SP, + type_params: None, + body: BlockStmtOrExpr::Expr(ast), + })), + )), + ], + })); } fn create_bind_interceptor(&self) -> Decl { @@ -716,9 +799,21 @@ impl<'a> ClosureDecorator<'a> { // f[Symbol.for("functionless:BoundThis")] = self; // f[Symbol.for("functionless:BoundArgs")] = args; // f[Symbol.for("functionless:TargetFunction")] = func; - self.set_symbol(f.clone(), "functionless:BoundThis", this.clone()), - self.set_symbol(f.clone(), "functionless:BoundArgs", args.clone()), - self.set_symbol(f.clone(), "functionless:TargetFunction", func.clone()), + self.set_symbol( + Box::new(Expr::Ident(f.clone())), + "functionless:BoundThis", + Box::new(Expr::Ident(this.clone())), + ), + self.set_symbol( + Box::new(Expr::Ident(f.clone())), + "functionless:BoundArgs", + Box::new(Expr::Ident(args.clone())), + ), + self.set_symbol( + Box::new(Expr::Ident(f.clone())), + "functionless:TargetFunction", + Box::new(Expr::Ident(func.clone())), + ), ], })), }), @@ -881,23 +976,27 @@ impl<'a> ClosureDecorator<'a> { }) } - fn set_symbol(&self, on: Ident, sym: &str, to: Ident) -> Stmt { + fn set_symbol_expr(&self, on: Box, sym: &str, to: Box) -> Expr { + Expr::Assign(AssignExpr { + // func[Symbol.for("functionless:AST")] = ast + left: PatOrExpr::Expr(Box::new(Expr::Member(MemberExpr { + obj: on, + span: DUMMY_SP, + prop: MemberProp::Computed(ComputedPropName { + span: DUMMY_SP, + expr: self.symbol_for(sym), + }), + }))), + op: AssignOp::Assign, + right: to.clone(), + span: DUMMY_SP, + }) + } + + fn set_symbol(&self, on: Box, sym: &str, to: Box) -> Stmt { Stmt::Expr(ExprStmt { span: DUMMY_SP, - expr: Box::new(Expr::Assign(AssignExpr { - // func[Symbol.for("functionless:AST")] = ast - left: PatOrExpr::Expr(Box::new(Expr::Member(MemberExpr { - obj: Box::new(Expr::Ident(on.clone())), - span: DUMMY_SP, - prop: MemberProp::Computed(ComputedPropName { - span: DUMMY_SP, - expr: self.symbol_for(sym), - }), - }))), - op: AssignOp::Assign, - right: Box::new(Expr::Ident(to.clone())), - span: DUMMY_SP, - })), + expr: Box::new(self.set_symbol_expr(on, sym, to)), }) } From 5761c8de67f0f78616d57ed8649f178d30061d63 Mon Sep 17 00:00:00 2001 From: Sam Sussman Date: Fri, 23 Sep 2022 13:51:22 -0500 Subject: [PATCH 3/8] bind --- src/closure_decorator.rs | 353 +++++++++++++++++++-------------------- 1 file changed, 173 insertions(+), 180 deletions(-) diff --git a/src/closure_decorator.rs b/src/closure_decorator.rs index c5db85b..096ad8c 100644 --- a/src/closure_decorator.rs +++ b/src/closure_decorator.rs @@ -5,7 +5,7 @@ use swc_core::ast::*; use swc_core::common::util::take::Take; use swc_core::common::DUMMY_SP; use swc_core::plugin::proxies::PluginSourceMapProxy; -use swc_core::utils::{prepend_stmts, private_ident, quote_ident}; +use swc_core::utils::{prepend_stmts, private_ident, quote_ident, quote_str}; use swc_core::visit::*; use crate::class_like::ClassLike; @@ -26,41 +26,11 @@ use crate::virtual_machine::VirtualMachine; const REGISTER_FLAG: &str = "REGISTER_8269d1a8"; // (REGISTER_REF,stash[]=ast) const REGISTER_REF_FLAG: &str = "REGISTER_REF_8269d1a8"; -// // (stash=BIND, ... todo) -// const BIND_FLAG: &str = "BIND_8269d1a8"; -// // (stash=PROXY, ... todo) +// // (BIND, ... todo) +const BIND_FLAG: &str = "BIND_8269d1a8"; +// // (PROXY, ... todo) // const PROXY_FLAG: &str = "PROXY_8269d1a8"; -/** - * Name of the `bind` function that is injected into all compiled source files. - * - * ```ts - * function bind_8269d1a8(func, self, ...args) { - * const tmp = func.bind(self, ...args); - * if (typeof func === "function") { - * func[Symbol.for("functionless:BoundThis")] = self; - * func[Symbol.for("functionless:BoundArgs")] = args; - * func[Symbol.for("functionless:TargetFunction")] = func; - * } - * return tmp; - * } - * ``` - * - * All CallExpressions with the shape .bind(...) are re-written as calls - * to this special function which intercepts the call. - * ```ts - * .bind(...) - * // => - * bind_8269d1a8(, ...) - * ``` - * - * If `` is a Function, then the values of BoundThis, BoundArgs and TargetFunction - * are added to the bound Function. - * - * If `` is not a Function, then the call is proxied without modification. - */ -const BIND_FUNCTION_NAME: &str = "bind_8269d1a8"; - const GLOBAL_THIS_NAME: &str = "global_8269d1a8"; /** @@ -102,10 +72,6 @@ pub struct ClosureDecorator<'a> { * A unique identifier functionless uses to story temporary values for registration. */ pub stash: Ident, - /** - * An Identifier referencing the `bind` interceptor function injected into all processed modules. - */ - pub bind: Ident, /** * An Identifier referencing the `proxy` interceptor function injected into all processed modules. */ @@ -132,7 +98,6 @@ impl<'a> ClosureDecorator<'a> { vm: VirtualMachine::new(), global: private_ident!(GLOBAL_THIS_NAME), stash: private_ident!(STASH_NAME), - bind: private_ident!(BIND_FUNCTION_NAME), proxy: private_ident!(PROXY_FUNCTION_NAME), util: private_ident!(UTIL_FUNCTION_NAME), ids: 0, @@ -159,7 +124,6 @@ impl<'a> VisitMut for ClosureDecorator<'a> { }))), ModuleItem::Stmt(Stmt::Decl(self.create_global_this())), ModuleItem::Stmt(Stmt::Decl(self.create_import_util())), - ModuleItem::Stmt(Stmt::Decl(self.create_bind_interceptor())), ModuleItem::Stmt(Stmt::Decl(self.create_proxy_interceptor())), ] .into_iter() @@ -227,49 +191,6 @@ impl<'a> VisitMut for ClosureDecorator<'a> { self.visit_mut_class_like(class_expr); } - fn visit_mut_call_expr(&mut self, call: &mut CallExpr) { - // detect if this looks like a call to Function.bind - // e.g. `foo.bind(self)` - // in general: `.bind(...)` - let maybe_bind_expr = match &mut call.callee { - Callee::Expr(expr) => match expr.as_mut() { - Expr::Member(member) => match &member.prop { - MemberProp::Ident(ident) if &ident.sym == "bind" => Some(member.obj.as_mut()), - _ => None, - }, - _ => None, - }, - _ => None, - }; - - if maybe_bind_expr.is_some() { - let expr = maybe_bind_expr.unwrap(); - - let args = iter::once(ExprOrSpread { - expr: Box::new(expr.take()), - spread: None, - }) - .chain(call.args.iter_mut().map(|arg| ExprOrSpread { - spread: None, - expr: arg.expr.take(), - })) - .collect(); - - // replace the CallExpr with a call to the `bind` interceptor function - // foo.bind(bar) - // => - // bind(foo, bar); - *call = CallExpr { - callee: Callee::Expr(Box::new(Expr::Ident(self.bind.clone()))), - span: call.span.clone(), - type_args: None, - args, - } - } - - call.visit_mut_children_with(self); - } - fn visit_mut_prop(&mut self, prop: &mut Prop) { match prop { // { method() { } } @@ -373,6 +294,36 @@ impl<'a> VisitMut for ClosureDecorator<'a> { expr.visit_mut_children_with(self); } + Expr::Call(call) => { + let maybe_bind_expr = match &mut call.callee { + Callee::Expr(expr) => match expr.as_mut() { + Expr::Member(member) => match member { + MemberExpr { obj, prop, .. } => match prop { + MemberProp::Ident(ident) if &ident.sym == "bind" => obj + .as_member() + .and_then(|mem| mem.obj.as_ident()) + .filter(|ident| ident.sym.to_string() == STASH_NAME) + .map_or(Some(obj.clone()), |_| None), + _ => None, + }, + }, + _ => None, + }, + _ => None, + }; + + if maybe_bind_expr.is_some() { + let func = maybe_bind_expr.unwrap(); + + // replace the CallExpr with a call to the `bind` interceptor function + // foo.bind(bar) + // => + // ("BIND", ...); + *expr = self.update_bind(func, call.args[0].expr.clone(), call.args[1..].to_vec()) + } + + expr.visit_mut_children_with(self); + } _ => { expr.visit_mut_children_with(self); } @@ -650,7 +601,7 @@ impl<'a> ClosureDecorator<'a> { return Box::new(Expr::Seq(SeqExpr { span: DUMMY_SP, exprs: vec![ - // "I_REGISTER" + // "REGISTER" Box::new(Expr::Assign(AssignExpr { left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), op: AssignOp::Assign, @@ -723,112 +674,161 @@ impl<'a> ClosureDecorator<'a> { })); } - fn create_bind_interceptor(&self) -> Decl { - let func = quote_ident!("func"); - let this = quote_ident!("self"); - let args = quote_ident!("args"); - let f = quote_ident!("f"); - Decl::Fn(FnDecl { - declare: false, - ident: self.bind.clone(), - function: Function { - params: vec![ - param(func.clone(), false), - param(this.clone(), false), - param(args.clone(), true), - ], - decorators: vec![], - span: DUMMY_SP, - body: Some(BlockStmt { + /** + * ("BIND", + * stash={ args: args, self: this, func: func }, + * stash={ f: stash.func.bind(stash.self, ...stash.args), ...stash }, + * typeof stash.f === "function" && ( + * stash.f[Symbol.for("functionless:BoundThis")] = stash.self, + * stash.f[Symbol.for("functionless:BoundArgs")] = stash.args, + * stash.f[Symbol.for("functionless:TargetFunction")] = stash.func + * ), + * stash + * ) + */ + fn update_bind(&self, func: Box, this: Box, args: Vec) -> Expr { + let member_f = Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(self.stash.clone())), + prop: MemberProp::Ident(quote_ident!("f")), + })); + // the original function stored in stash + let member_func = Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(self.stash.clone())), + prop: MemberProp::Ident(quote_ident!("func")), + })); + let member_args = Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(self.stash.clone())), + prop: MemberProp::Ident(quote_ident!("args")), + })); + // + let member_this = Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(self.stash.clone())), + prop: MemberProp::Ident(quote_ident!("this")), + })); + + return Expr::Seq(SeqExpr { + span: DUMMY_SP, + exprs: vec![ + Box::new(Expr::Assign(AssignExpr { + left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), + op: AssignOp::Assign, + right: string_expr(BIND_FLAG), span: DUMMY_SP, - stmts: vec![ - // const f = func.bind(self, ...args); - Stmt::Decl(Decl::Var(VarDecl { - declare: false, - kind: VarDeclKind::Const, - decls: vec![VarDeclarator { - definite: false, - span: DUMMY_SP, - name: Pat::Ident(BindingIdent { - id: f.clone(), - type_ann: None, - }), - init: Some(Box::new(Expr::Call(CallExpr { + })), + // stash={ args, self, func} + Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), + op: AssignOp::Assign, + right: Box::new(Expr::Object(ObjectLit { + span: DUMMY_SP, + props: vec![ + // args = [args] + PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Ident(quote_ident!("args")), + value: Box::new(Expr::Array(ArrayLit { + span: DUMMY_SP, + elems: args.into_iter().map(Some).collect(), + })), + }))), + // this = this + PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Ident(quote_ident!("this")), + value: this, + }))), + // func = func + PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Ident(quote_ident!("func")), + value: func, + }))), + ], + })), + })), + // stash = { f: stash.func.bind(stash.this, stash.args), ...stash } + Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), + op: AssignOp::Assign, + right: Box::new(Expr::Object(ObjectLit { + span: DUMMY_SP, + props: vec![ + PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Ident(quote_ident!("f")), + value: Box::new(Expr::Call(CallExpr { span: DUMMY_SP, type_args: None, callee: Callee::Expr(Box::new(Expr::Member(MemberExpr { - obj: Box::new(Expr::Ident(func.clone())), + obj: member_func.clone(), prop: MemberProp::Ident(quote_ident!("bind")), span: DUMMY_SP, }))), args: vec![ ExprOrSpread { - expr: Box::new(Expr::Ident(this.clone())), + expr: member_this.clone(), spread: None, }, + // ...stash.args ExprOrSpread { - expr: Box::new(Expr::Ident(args.clone())), + expr: member_args.clone(), spread: Some(DUMMY_SP), }, ], - }))), - }], - span: DUMMY_SP, - })), - // if(typeof func === "function") - Stmt::If(IfStmt { - span: DUMMY_SP, - test: Box::new(Expr::Bin(BinExpr { - span: DUMMY_SP, - left: Box::new(Expr::Unary(UnaryExpr { - arg: Box::new(Expr::Ident(func.clone())), - span: DUMMY_SP, - op: UnaryOp::TypeOf, })), - op: BinaryOp::EqEqEq, - right: Box::new(Expr::Lit(Lit::Str(Str { - raw: None, - span: DUMMY_SP, - value: JsWord::from("function"), - }))), - })), - alt: None, - cons: Box::new(Stmt::Block(BlockStmt { - span: DUMMY_SP, - stmts: vec![ - // f[Symbol.for("functionless:BoundThis")] = self; - // f[Symbol.for("functionless:BoundArgs")] = args; - // f[Symbol.for("functionless:TargetFunction")] = func; - self.set_symbol( - Box::new(Expr::Ident(f.clone())), - "functionless:BoundThis", - Box::new(Expr::Ident(this.clone())), - ), - self.set_symbol( - Box::new(Expr::Ident(f.clone())), - "functionless:BoundArgs", - Box::new(Expr::Ident(args.clone())), - ), - self.set_symbol( - Box::new(Expr::Ident(f.clone())), - "functionless:TargetFunction", - Box::new(Expr::Ident(func.clone())), - ), - ], - })), - }), - Stmt::Return(ReturnStmt { + }))), + // ...stash + PropOrSpread::Spread(SpreadElement { + dot3_token: DUMMY_SP, + expr: Box::new(Expr::Ident(self.stash.clone())), + }), + ], + })), + })), + // typeof stash.f === "function" && (stash.f[]=..., stash.f[]=..., stash.f[]=...) + Box::new(Expr::Bin(BinExpr { + span: DUMMY_SP, + op: BinaryOp::LogicalAnd, + left: Box::new(Expr::Bin(BinExpr { + span: DUMMY_SP, + left: Box::new(Expr::Unary(UnaryExpr { + arg: member_f.clone(), span: DUMMY_SP, - arg: Some(Box::new(Expr::Ident(f.clone()))), - }), - ], - }), - is_generator: false, - is_async: false, - type_params: None, - return_type: None, - }, - }) + op: UnaryOp::TypeOf, + })), + op: BinaryOp::EqEqEq, + right: Box::new(Expr::Lit(Lit::Str(quote_str!("function")))), + })), + right: Box::new(Expr::Seq(SeqExpr { + span: DUMMY_SP, + exprs: vec![ + // stash.f["functionless:BoundThis"] = stash.this; + Box::new(self.set_symbol_expr( + member_f.clone(), + "functionless:BoundThis", + member_this.clone(), + )), + // stash.f["functionless:BoundArgs"] = stash.args; + Box::new(self.set_symbol_expr( + member_f.clone(), + "functionless:BoundArgs", + member_args.clone(), + )), + // stash.f["functionless:TargetFunction"] = stash.func; + Box::new(self.set_symbol_expr( + member_f.clone(), + "functionless:TargetFunction", + member_func.clone(), + )), + ], + })), + })), + // return stash.f + member_f.clone(), + ], + }); } fn create_proxy_interceptor(&self) -> Decl { @@ -993,13 +993,6 @@ impl<'a> ClosureDecorator<'a> { }) } - fn set_symbol(&self, on: Box, sym: &str, to: Box) -> Stmt { - Stmt::Expr(ExprStmt { - span: DUMMY_SP, - expr: Box::new(self.set_symbol_expr(on, sym, to)), - }) - } - fn symbol_for(&self, sym: &str) -> Box { Box::new(Expr::Call(CallExpr { callee: Callee::Expr(prop_access_expr(self.symbol_ref(), quote_ident!("for"))), From 2e5dd49ed2d22bf79fbf2a2fbe3f26b8c4e8a043 Mon Sep 17 00:00:00 2001 From: Sam Sussman Date: Fri, 23 Sep 2022 16:45:59 -0500 Subject: [PATCH 4/8] proxy --- src/closure_decorator.rs | 369 +++++++++++++++++++-------------------- 1 file changed, 179 insertions(+), 190 deletions(-) diff --git a/src/closure_decorator.rs b/src/closure_decorator.rs index 096ad8c..cf61794 100644 --- a/src/closure_decorator.rs +++ b/src/closure_decorator.rs @@ -10,7 +10,7 @@ use swc_core::visit::*; use crate::class_like::ClassLike; use crate::js_util::{ - ident_expr, prop_access_expr, ref_expr, require_expr, string_expr, this_expr, undefined_expr, + prop_access_expr, ref_expr, require_expr, string_expr, this_expr, undefined_expr, }; use crate::prepend::prepend; use crate::span::{concat_span, get_prop_name_span}; @@ -29,7 +29,7 @@ const REGISTER_REF_FLAG: &str = "REGISTER_REF_8269d1a8"; // // (BIND, ... todo) const BIND_FLAG: &str = "BIND_8269d1a8"; // // (PROXY, ... todo) -// const PROXY_FLAG: &str = "PROXY_8269d1a8"; +const PROXY_FLAG: &str = "PROXY_8269d1a8"; const GLOBAL_THIS_NAME: &str = "global_8269d1a8"; @@ -51,8 +51,6 @@ const GLOBAL_THIS_NAME: &str = "global_8269d1a8"; */ const STASH_NAME: &str = "stash_8269d1a8"; -const PROXY_FUNCTION_NAME: &str = "proxy_8269d1a8"; - const UTIL_FUNCTION_NAME: &str = "util_8269d1a8"; pub struct ClosureDecorator<'a> { @@ -72,10 +70,6 @@ pub struct ClosureDecorator<'a> { * A unique identifier functionless uses to story temporary values for registration. */ pub stash: Ident, - /** - * An Identifier referencing the `proxy` interceptor function injected into all processed modules. - */ - pub proxy: Ident, /** * An Identifier referencing NodeJS's `util` module. */ @@ -98,7 +92,6 @@ impl<'a> ClosureDecorator<'a> { vm: VirtualMachine::new(), global: private_ident!(GLOBAL_THIS_NAME), stash: private_ident!(STASH_NAME), - proxy: private_ident!(PROXY_FUNCTION_NAME), util: private_ident!(UTIL_FUNCTION_NAME), ids: 0, } @@ -124,7 +117,6 @@ impl<'a> VisitMut for ClosureDecorator<'a> { }))), ModuleItem::Stmt(Stmt::Decl(self.create_global_this())), ModuleItem::Stmt(Stmt::Decl(self.create_import_util())), - ModuleItem::Stmt(Stmt::Decl(self.create_proxy_interceptor())), ] .into_iter() .chain( @@ -252,60 +244,52 @@ impl<'a> VisitMut for ClosureDecorator<'a> { // ) *expr = *self.register_mut_ast(&mut Expr::Fn(func.take()), ast); } - Expr::New(new) if new.args.is_some() => { + Expr::New(NewExpr { args, callee, .. }) if args.is_some() => { // detect if this looks like a new Proxy // e.g. `new Proxy({}, {})` - let maybe_proxy_class = match new.callee.as_mut() { - Expr::Ident(ident) if &ident.sym == "Proxy" => Some(ident), - _ => None, - }; + let maybe_proxy_class = callee.as_mut_ident().filter(|ident| &ident.sym == "Proxy"); if maybe_proxy_class.is_some() { let proxy_class = maybe_proxy_class.unwrap(); - let args: Vec = iter::once(ExprOrSpread { - expr: Box::new(Expr::Ident(proxy_class.take())), - spread: None, - }) - .chain( - new - .args - .as_mut() - .unwrap() - .iter_mut() - .map(|arg| ExprOrSpread { - spread: None, - expr: arg.expr.take(), - }), - ) - .collect(); + args + .iter_mut() + .for_each(|arg| arg.visit_mut_children_with(self)); + + let args = args + .as_mut() + .unwrap() + .iter_mut() + .map(|arg| ExprOrSpread { + spread: None, + expr: arg.expr.take(), + }) + .collect(); + + proxy_class.visit_mut_children_with(self); // replace the NewExpr with a call to the `bind` interceptor function - // foo.bind(bar) + // new Proxy({}, {}) // => - // bind(foo, bar); - *expr = Expr::Call(CallExpr { - callee: Callee::Expr(Box::new(Expr::Ident(self.proxy.clone()))), - span: new.span.clone(), - type_args: None, - args: args, - }); + // ("PROXY", ...) + *expr = self.wrap_proxy(Box::new(proxy_class.take()), args); + } else { + expr.visit_mut_children_with(self) } - - expr.visit_mut_children_with(self); } Expr::Call(call) => { let maybe_bind_expr = match &mut call.callee { Callee::Expr(expr) => match expr.as_mut() { Expr::Member(member) => match member { - MemberExpr { obj, prop, .. } => match prop { - MemberProp::Ident(ident) if &ident.sym == "bind" => obj - .as_member() - .and_then(|mem| mem.obj.as_ident()) - .filter(|ident| ident.sym.to_string() == STASH_NAME) - .map_or(Some(obj.clone()), |_| None), - _ => None, - }, + MemberExpr { obj, prop, .. } + if prop + .as_ident() + .filter(|ident| &ident.sym == "bind") + .is_some() => + { + Some(obj) + } + _ => None, }, _ => None, }, @@ -314,15 +298,25 @@ impl<'a> VisitMut for ClosureDecorator<'a> { if maybe_bind_expr.is_some() { let func = maybe_bind_expr.unwrap(); + call + .args + .iter_mut() + .for_each(|arg| arg.visit_mut_children_with(self)); + + func.visit_mut_children_with(self); // replace the CallExpr with a call to the `bind` interceptor function // foo.bind(bar) // => // ("BIND", ...); - *expr = self.update_bind(func, call.args[0].expr.clone(), call.args[1..].to_vec()) + *expr = self.wrap_bind( + func.take(), + call.args[0].expr.clone(), + call.args[1..].to_vec(), + ) + } else { + expr.visit_mut_children_with(self); } - - expr.visit_mut_children_with(self); } _ => { expr.visit_mut_children_with(self); @@ -686,7 +680,7 @@ impl<'a> ClosureDecorator<'a> { * stash * ) */ - fn update_bind(&self, func: Box, this: Box, args: Vec) -> Expr { + fn wrap_bind(&self, func: Box, this: Box, args: Vec) -> Expr { let member_f = Box::new(Expr::Member(MemberExpr { span: DUMMY_SP, obj: Box::new(Expr::Ident(self.stash.clone())), @@ -831,11 +825,20 @@ impl<'a> ClosureDecorator<'a> { }); } - fn create_proxy_interceptor(&self) -> Decl { - let clss = quote_ident!("clss"); - let args = quote_ident!("args"); - let proxy = quote_ident!("proxy"); - let proxy_map = quote_ident!("proxyMap"); + /** + * ("PROXY", + * stash={ args }, // ensure the args are only evaluated once + * stash={ proxy: new clss(...stash.args), ...stash }, + * globalThis.util.types.isProxy(stash.proxy) && ( + * globalThis.proxies = globalThis.proxies ?? new globalThis.WeakMap(), + * proxyMap.set(proxy, args) + * ), + * proxy + * ) + */ + fn wrap_proxy(&self, clss: Box, args: Vec) -> Expr { + let ident_args = quote_ident!("args"); + let ident_proxy = quote_ident!("proxy"); let global_proxies = Expr::Member(MemberExpr { span: DUMMY_SP, obj: Box::new(Expr::Ident(self.global.clone())), @@ -845,135 +848,138 @@ impl<'a> ClosureDecorator<'a> { }), }); - Decl::Fn(FnDecl { - declare: false, - ident: self.proxy.clone(), - function: Function { - is_async: false, - is_generator: false, - decorators: vec![], - span: DUMMY_SP, - type_params: None, - return_type: None, - params: vec![param(clss.clone(), false), param(args.clone(), true)], - body: Some(BlockStmt { + let member_proxy = Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(self.stash.clone())), + prop: MemberProp::Ident(ident_proxy.clone()), + })); + let member_args = Box::new(Expr::Member(MemberExpr { + span: DUMMY_SP, + obj: Box::new(Expr::Ident(self.stash.clone())), + prop: MemberProp::Ident(ident_args.clone()), + })); + + return Expr::Seq(SeqExpr { + span: DUMMY_SP, + exprs: vec![ + Box::new(Expr::Assign(AssignExpr { + left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), + op: AssignOp::Assign, + right: string_expr(PROXY_FLAG), span: DUMMY_SP, - stmts: vec![ - // const proxy = new clss(...args); - Stmt::Decl(Decl::Var(VarDecl { - declare: false, - kind: VarDeclKind::Const, - decls: vec![VarDeclarator { - definite: false, - span: DUMMY_SP, - name: Pat::Ident(BindingIdent { - id: proxy.clone(), - type_ann: None, - }), - init: Some(Box::new(Expr::New(NewExpr { + })), + // stash={ args } + Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), + op: AssignOp::Assign, + right: Box::new(Expr::Object(ObjectLit { + span: DUMMY_SP, + props: vec![ + // args = [args] + PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Ident(ident_args.clone()), + value: Box::new(Expr::Array(ArrayLit { + span: DUMMY_SP, + elems: args.into_iter().map(Some).collect(), + })), + }))), + ], + })), + })), + // stash = { proxy: new clss(...args), ...stash } + Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), + op: AssignOp::Assign, + right: Box::new(Expr::Object(ObjectLit { + span: DUMMY_SP, + props: vec![ + PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Ident(ident_proxy.clone()), + value: Box::new(Expr::New(NewExpr { span: DUMMY_SP, type_args: None, - callee: Box::new(Expr::Ident(clss.clone())), + callee: Box::new(Expr::Ident(*clss)), args: Some(vec![ExprOrSpread { - expr: Box::new(Expr::Ident(args.clone())), + expr: member_args.clone(), spread: Some(DUMMY_SP), }]), - }))), - }], + })), + }))), + // ...stash + PropOrSpread::Spread(SpreadElement { + dot3_token: DUMMY_SP, + expr: Box::new(Expr::Ident(self.stash.clone())), + }), + ], + })), + })), + // (typeof stash.proxy === "function" && + // (globalThis.proxies = globalThis.proxies ?? new globalThis.WeakMap()) + // .set(stash.proxy, stash.args), stash.proxy) + Box::new(Expr::Bin(BinExpr { + span: DUMMY_SP, + op: BinaryOp::LogicalAnd, + // typeof stash.proxy === "function" + left: Box::new(Expr::Bin(BinExpr { + span: DUMMY_SP, + left: Box::new(Expr::Unary(UnaryExpr { + arg: member_proxy.clone(), span: DUMMY_SP, + op: UnaryOp::TypeOf, })), - // if (globalThis.util.types.isProxy(proxy)) - Stmt::If(IfStmt { - test: Box::new(Expr::Call(CallExpr { - type_args: None, - span: DUMMY_SP, - callee: Callee::Expr(prop_access_expr( - prop_access_expr(ident_expr(self.util.clone()), quote_ident!("types")), - quote_ident!("isProxy"), - )), - args: vec![ExprOrSpread { - expr: Box::new(Expr::Ident(proxy.clone())), - spread: None, - }], - })), - alt: None, - span: DUMMY_SP, - cons: Box::new(Stmt::Block(BlockStmt { + op: BinaryOp::EqEqEq, + right: Box::new(Expr::Lit(Lit::Str(quote_str!("function")))), + })), + right: Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + callee: Callee::Expr(Box::new(Expr::Member(MemberExpr { + // globalThis.proxies = globalThis.proxies ?? new globalThis.WeakMap()) + obj: Box::new(Expr::Assign(AssignExpr { + // globalThis.proxies + left: PatOrExpr::Expr(Box::new(global_proxies.clone())), + op: AssignOp::Assign, span: DUMMY_SP, - stmts: vec![ - // const proxyMap = (globalThis.proxies = globalThis.proxies ?? new globalThis.WeakMap()); - Stmt::Decl(Decl::Var(VarDecl { - declare: false, + right: Box::new(Expr::Bin(BinExpr { + op: BinaryOp::NullishCoalescing, + // globalThis.proxies + left: Box::new(global_proxies.clone()), + span: DUMMY_SP, + // new globalThis.WeakMap() + right: Box::new(Expr::New(NewExpr { + type_args: None, span: DUMMY_SP, - kind: VarDeclKind::Const, - decls: vec![VarDeclarator { - definite: false, - span: DUMMY_SP, - name: Pat::Ident(BindingIdent { - id: proxy_map.clone(), - type_ann: None, - }), - init: Some(Box::new(Expr::Assign(AssignExpr { - // globalThis.proxies - left: PatOrExpr::Expr(Box::new(global_proxies.clone())), - op: AssignOp::Assign, - span: DUMMY_SP, - right: Box::new(Expr::Bin(BinExpr { - op: BinaryOp::NullishCoalescing, - // globalThis.proxies - left: Box::new(global_proxies.clone()), - span: DUMMY_SP, - // new globalThis.WeakMap() - right: Box::new(Expr::New(NewExpr { - type_args: None, - span: DUMMY_SP, - // globalThis.WeakMap - callee: Box::new(Expr::Member(MemberExpr { - span: DUMMY_SP, - obj: Box::new(Expr::Ident(self.global.clone())), - prop: MemberProp::Ident(quote_ident!("WeakMap")), - })), - args: None, - })), - })), - }))), - }], - })), - // proxyMap.set(proxy, args), - Stmt::Expr(ExprStmt { - expr: Box::new(Expr::Call(CallExpr { - type_args: None, + // globalThis.WeakMap + callee: Box::new(Expr::Member(MemberExpr { span: DUMMY_SP, - callee: Callee::Expr(Box::new(Expr::Member(MemberExpr { - obj: Box::new(Expr::Ident(proxy_map.clone())), - prop: MemberProp::Ident(quote_ident!("set")), - span: DUMMY_SP, - }))), - args: vec![ - ExprOrSpread { - expr: Box::new(Expr::Ident(proxy.clone())), - spread: None, - }, - ExprOrSpread { - expr: Box::new(Expr::Ident(args.clone())), - spread: None, - }, - ], + obj: Box::new(Expr::Ident(self.global.clone())), + prop: MemberProp::Ident(quote_ident!("WeakMap")), })), - span: DUMMY_SP, - }), - ], + args: None, + })), + })), })), - }), - // return proxy - Stmt::Return(ReturnStmt { span: DUMMY_SP, - arg: Some(Box::new(Expr::Ident(proxy.clone()))), - }), - ], - }), - }, - }) + prop: MemberProp::Ident(quote_ident!("set")), + }))), + args: vec![ + ExprOrSpread { + spread: None, + expr: member_proxy.clone(), + }, + ExprOrSpread { + spread: None, + expr: member_args.clone(), + }, + ], + type_args: None, + })), + })), + // return stash.proxy + member_proxy.clone(), + ], + }); } fn set_symbol_expr(&self, on: Box, sym: &str, to: Box) -> Expr { @@ -1009,20 +1015,3 @@ impl<'a> ClosureDecorator<'a> { })) } } - -fn param(id: Ident, rest: bool) -> Param { - Param { - decorators: vec![], - span: DUMMY_SP, - pat: if rest { - Pat::Rest(RestPat { - arg: Box::new(Pat::Ident(BindingIdent { id, type_ann: None })), - dot3_token: DUMMY_SP, - span: DUMMY_SP, - type_ann: None, - }) - } else { - Pat::Ident(BindingIdent { id, type_ann: None }) - }, - } -} From ec644ee753bd22b3252c993e58af1f5c985ceabf Mon Sep 17 00:00:00 2001 From: Sam Sussman Date: Fri, 23 Sep 2022 16:52:28 -0500 Subject: [PATCH 5/8] update --- src/closure_decorator.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/closure_decorator.rs b/src/closure_decorator.rs index cf61794..773dd96 100644 --- a/src/closure_decorator.rs +++ b/src/closure_decorator.rs @@ -26,9 +26,9 @@ use crate::virtual_machine::VirtualMachine; const REGISTER_FLAG: &str = "REGISTER_8269d1a8"; // (REGISTER_REF,stash[]=ast) const REGISTER_REF_FLAG: &str = "REGISTER_REF_8269d1a8"; -// // (BIND, ... todo) +// // (BIND, ...) const BIND_FLAG: &str = "BIND_8269d1a8"; -// // (PROXY, ... todo) +// // (PROXY, ...) const PROXY_FLAG: &str = "PROXY_8269d1a8"; const GLOBAL_THIS_NAME: &str = "global_8269d1a8"; @@ -828,10 +828,10 @@ impl<'a> ClosureDecorator<'a> { /** * ("PROXY", * stash={ args }, // ensure the args are only evaluated once - * stash={ proxy: new clss(...stash.args), ...stash }, + * stash={ proxy: new clss(...stash.args), ...stash }, // create the proxy * globalThis.util.types.isProxy(stash.proxy) && ( * globalThis.proxies = globalThis.proxies ?? new globalThis.WeakMap(), - * proxyMap.set(proxy, args) + * proxyMap.set(stash.proxy, stash.args) * ), * proxy * ) From 03735effb1cce20ecc584a938412efcfa9794061 Mon Sep 17 00:00:00 2001 From: Sam Sussman Date: Sat, 24 Sep 2022 12:04:20 -0500 Subject: [PATCH 6/8] feedback --- src/closure_decorator.rs | 49 +++++++++++----------------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/src/closure_decorator.rs b/src/closure_decorator.rs index 773dd96..36539fe 100644 --- a/src/closure_decorator.rs +++ b/src/closure_decorator.rs @@ -9,9 +9,7 @@ use swc_core::utils::{prepend_stmts, private_ident, quote_ident, quote_str}; use swc_core::visit::*; use crate::class_like::ClassLike; -use crate::js_util::{ - prop_access_expr, ref_expr, require_expr, string_expr, this_expr, undefined_expr, -}; +use crate::js_util::{prop_access_expr, ref_expr, require_expr, string_expr, this_expr}; use crate::prepend::prepend; use crate::span::{concat_span, get_prop_name_span}; use crate::virtual_machine::VirtualMachine; @@ -146,16 +144,6 @@ impl<'a> VisitMut for ClosureDecorator<'a> { // prepend the `register` and `bind` function declarations // and the `register` calls into the top of every module. prepend_stmts(items, new_stmts.into_iter()); - - items.push(ModuleItem::Stmt(Stmt::Expr(ExprStmt { - expr: Box::new(Expr::Assign(AssignExpr { - span: DUMMY_SP, - op: AssignOp::Assign, - left: PatOrExpr::Expr(Box::new(Expr::Ident(self.stash.clone()))), - right: undefined_expr(), - })), - span: DUMMY_SP, - }))) } fn visit_mut_stmts(&mut self, stmts: &mut Vec) { @@ -207,7 +195,7 @@ impl<'a> VisitMut for ClosureDecorator<'a> { *prop = Prop::KeyValue(KeyValueProp { key: method.key.take(), - value: self.register_inline_ast_seq(func, ast), + value: self.register_ast_seq(func, ast), }); } _ => { @@ -226,7 +214,7 @@ impl<'a> VisitMut for ClosureDecorator<'a> { // replace the arrow function with the expressions which associate the function to it's AST // () => {..} // => - // (stash = () => {...}, stash[Symbol.for("ast")] = () => [..], stash) + // ("REGISTER", stash = () => {...}, stash[Symbol.for("AST")] = ast, stash) *expr = *self.register_mut_ast(&mut Expr::Arrow(arrow.take()), ast); } Expr::Fn(func) if func.function.body.is_some() => { @@ -238,10 +226,7 @@ impl<'a> VisitMut for ClosureDecorator<'a> { // that decorates the function with its AST // function foo() {..} // => - // register( - // function foo() {..}, // original function expression - // () => [..], // function that produces the function expression's AST - // ) + // ("REGISTER", stash = function foo() {..}, stash[Symbol.for("AST")] = ast, stash) *expr = *self.register_mut_ast(&mut Expr::Fn(func.take()), ast); } Expr::New(NewExpr { args, callee, .. }) if args.is_some() => { @@ -256,23 +241,16 @@ impl<'a> VisitMut for ClosureDecorator<'a> { .iter_mut() .for_each(|arg| arg.visit_mut_children_with(self)); - let args = args - .as_mut() - .unwrap() - .iter_mut() - .map(|arg| ExprOrSpread { - spread: None, - expr: arg.expr.take(), - }) - .collect(); - proxy_class.visit_mut_children_with(self); // replace the NewExpr with a call to the `bind` interceptor function // new Proxy({}, {}) // => // ("PROXY", ...) - *expr = self.wrap_proxy(Box::new(proxy_class.take()), args); + *expr = self.wrap_proxy( + Box::new(proxy_class.take()), + args.take().unwrap_or_default(), + ); } else { expr.visit_mut_children_with(self) } @@ -502,7 +480,7 @@ impl<'a> ClosureDecorator<'a> { } fn register_mut_ast(&self, func: &mut Expr, ast: Box) -> Box { - self.register_inline_ast_seq(Box::new(func.take()), ast) + self.register_ast_seq(Box::new(func.take()), ast) } /** @@ -591,7 +569,7 @@ impl<'a> ClosureDecorator<'a> { * ("REGISTER", stash = () => {}, stash[Symbol.from(functionless::AST)] = ast, stash) * ``` */ - fn register_inline_ast_seq(&self, func: Box, ast: Box) -> Box { + fn register_ast_seq(&self, func: Box, ast: Box) -> Box { return Box::new(Expr::Seq(SeqExpr { span: DUMMY_SP, exprs: vec![ @@ -829,10 +807,9 @@ impl<'a> ClosureDecorator<'a> { * ("PROXY", * stash={ args }, // ensure the args are only evaluated once * stash={ proxy: new clss(...stash.args), ...stash }, // create the proxy - * globalThis.util.types.isProxy(stash.proxy) && ( - * globalThis.proxies = globalThis.proxies ?? new globalThis.WeakMap(), - * proxyMap.set(stash.proxy, stash.args) - * ), + * (globalThis.util.types.isProxy(stash.proxy) && ( + * globalThis.proxies = globalThis.proxies ?? new globalThis.WeakMap() + * ).set(stash.proxy, stash.args) * proxy * ) */ From 06d9df105e672e77e8f594e7e1d2bf6580b33554 Mon Sep 17 00:00:00 2001 From: Sam Sussman Date: Sat, 24 Sep 2022 22:15:58 -0500 Subject: [PATCH 7/8] remove salt --- src/closure_decorator.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/closure_decorator.rs b/src/closure_decorator.rs index 36539fe..c33b5b7 100644 --- a/src/closure_decorator.rs +++ b/src/closure_decorator.rs @@ -20,14 +20,14 @@ use crate::virtual_machine::VirtualMachine; * These can be used by downstream programs to discover and manipulate the injects * functionless assignment sequences. */ -// (REGISTER,stash=func,stash[]=ast,stash) -const REGISTER_FLAG: &str = "REGISTER_8269d1a8"; -// (REGISTER_REF,stash[]=ast) -const REGISTER_REF_FLAG: &str = "REGISTER_REF_8269d1a8"; -// // (BIND, ...) -const BIND_FLAG: &str = "BIND_8269d1a8"; -// // (PROXY, ...) -const PROXY_FLAG: &str = "PROXY_8269d1a8"; +// (stash=REGISTER,stash=func,stash[]=ast,stash) +const REGISTER_FLAG: &str = "REGISTER"; +// (stash=REGISTER_REF,stash[]=ast) +const REGISTER_REF_FLAG: &str = "REGISTER_REF"; +// // (stash=BIND, ...) +const BIND_FLAG: &str = "BIND"; +// // (stash=PROXY, ...) +const PROXY_FLAG: &str = "PROXY"; const GLOBAL_THIS_NAME: &str = "global_8269d1a8"; From 83046f2d9a0cca6892e7f599c286368c6e6fc335 Mon Sep 17 00:00:00 2001 From: Sam Sussman Date: Sat, 24 Sep 2022 22:41:28 -0500 Subject: [PATCH 8/8] copied the wrong check --- src/closure_decorator.rs | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/closure_decorator.rs b/src/closure_decorator.rs index c33b5b7..3bc1ace 100644 --- a/src/closure_decorator.rs +++ b/src/closure_decorator.rs @@ -9,7 +9,9 @@ use swc_core::utils::{prepend_stmts, private_ident, quote_ident, quote_str}; use swc_core::visit::*; use crate::class_like::ClassLike; -use crate::js_util::{prop_access_expr, ref_expr, require_expr, string_expr, this_expr}; +use crate::js_util::{ + ident_expr, prop_access_expr, ref_expr, require_expr, string_expr, this_expr, +}; use crate::prepend::prepend; use crate::span::{concat_span, get_prop_name_span}; use crate::virtual_machine::VirtualMachine; @@ -804,12 +806,13 @@ impl<'a> ClosureDecorator<'a> { } /** - * ("PROXY", + * (stash="PROXY", * stash={ args }, // ensure the args are only evaluated once * stash={ proxy: new clss(...stash.args), ...stash }, // create the proxy - * (globalThis.util.types.isProxy(stash.proxy) && ( - * globalThis.proxies = globalThis.proxies ?? new globalThis.WeakMap() - * ).set(stash.proxy, stash.args) + * (globalThis.util.types.isProxy(stash.proxy) && + * (globalThis.proxies = globalThis.proxies ?? new globalThis.WeakMap()) + * .set(stash.proxy, stash.args) + * ), * proxy * ) */ @@ -892,22 +895,24 @@ impl<'a> ClosureDecorator<'a> { ], })), })), - // (typeof stash.proxy === "function" && + // (globalThis.util.types.isProxy(proxy) && // (globalThis.proxies = globalThis.proxies ?? new globalThis.WeakMap()) // .set(stash.proxy, stash.args), stash.proxy) Box::new(Expr::Bin(BinExpr { span: DUMMY_SP, op: BinaryOp::LogicalAnd, - // typeof stash.proxy === "function" - left: Box::new(Expr::Bin(BinExpr { + // globalThis.util.types.isProxy(proxy) + left: Box::new(Expr::Call(CallExpr { + type_args: None, span: DUMMY_SP, - left: Box::new(Expr::Unary(UnaryExpr { - arg: member_proxy.clone(), - span: DUMMY_SP, - op: UnaryOp::TypeOf, - })), - op: BinaryOp::EqEqEq, - right: Box::new(Expr::Lit(Lit::Str(quote_str!("function")))), + callee: Callee::Expr(prop_access_expr( + prop_access_expr(ident_expr(self.util.clone()), quote_ident!("types")), + quote_ident!("isProxy"), + )), + args: vec![ExprOrSpread { + expr: member_proxy.clone(), + spread: None, + }], })), right: Box::new(Expr::Call(CallExpr { span: DUMMY_SP,