From d7b2f4c26f0356e93b9f4f18ac3a6c828c620195 Mon Sep 17 00:00:00 2001 From: Bob Varioa Date: Wed, 31 Jul 2024 07:50:30 -0500 Subject: [PATCH 1/3] codegen: eval tweaks --- compiler/codegen.js | 71 +++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/compiler/codegen.js b/compiler/codegen.js index 6efb3ca3..4202719a 100644 --- a/compiler/codegen.js +++ b/compiler/codegen.js @@ -1874,45 +1874,52 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => { name = func.name; } - if (!decl._new && name === 'eval' && decl.arguments[0]?.type === 'Literal') { - // literal eval hack - const code = decl.arguments[0]?.value ?? ''; - - let parsed; - try { - parsed = parse(code, []); - } catch (e) { - if (e.name === 'SyntaxError') { - // throw syntax errors of evals at runtime instead - return internalThrow(scope, 'SyntaxError', e.message, true); + if (name === 'eval') { + if (!decl._new && decl.arguments[0]?.type === 'Literal') { + // literal eval hack + const code = decl.arguments[0]?.value ?? ''; + + let parsed; + try { + parsed = parse(code, []); + } catch (e) { + if (e.name === 'SyntaxError') { + // throw syntax errors of evals at runtime instead + return internalThrow(scope, 'SyntaxError', e.message, true); + } + + throw e; } - throw e; - } + const out = generate(scope, { + type: 'BlockStatement', + body: parsed.body + }); - const out = generate(scope, { - type: 'BlockStatement', - body: parsed.body - }); + const lastInst = out[out.length - 1]; + if (lastInst && lastInst[0] === Opcodes.drop) { + out.splice(out.length - 1, 1); - const lastInst = out[out.length - 1]; - if (lastInst && lastInst[0] === Opcodes.drop) { - out.splice(out.length - 1, 1); + const finalStatement = parsed.body[parsed.body.length - 1]; + out.push(...setLastType(scope, getNodeType(scope, finalStatement))); + } else if (countLeftover(out) === 0) { + out.push(...number(UNDEFINED)); + out.push(...setLastType(scope, TYPES.undefined)); + } - const finalStatement = parsed.body[parsed.body.length - 1]; - out.push(...setLastType(scope, getNodeType(scope, finalStatement))); - } else if (countLeftover(out) === 0) { - out.push(...number(UNDEFINED)); - out.push(...setLastType(scope, TYPES.undefined)); - } + // if (lastInst && lastInst[0] === Opcodes.drop) { + // out.splice(out.length - 1, 1); + // } else if (countLeftover(out) === 0) { + // out.push(...number(UNDEFINED)); + // } - // if (lastInst && lastInst[0] === Opcodes.drop) { - // out.splice(out.length - 1, 1); - // } else if (countLeftover(out) === 0) { - // out.push(...number(UNDEFINED)); - // } + return out; + } else { + if (decl._new) return internalThrow(scope, 'TypeError', 'eval is not a constructor'); + return todo(scope, 'dynamic eval is not currently supported', true); + } + } - return out; } let protoName, target; From ff961fdde39a1fdfbb2551ba90048d3ea1f0a811 Mon Sep 17 00:00:00 2001 From: Bob Varioa Date: Wed, 31 Jul 2024 07:50:53 -0500 Subject: [PATCH 2/3] codegen: add function constructor for literals --- compiler/codegen.js | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/compiler/codegen.js b/compiler/codegen.js index 4202719a..b84a5d57 100644 --- a/compiler/codegen.js +++ b/compiler/codegen.js @@ -1920,6 +1920,43 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => { } } + if (name === 'Function') { + if (decl.arguments[0]?.type === 'Literal' && (decl.arguments[1] ? decl.arguments[1]?.type === 'Literal' : true)) { + // literal eval hack + + let args = ''; + let code = ''; + if (decl.arguments.length >= 2) { + args = decl.arguments[0]?.value; + code = decl.arguments[1]?.value; + } else { + code = decl.arguments[0]?.value; + } + + // hack: use this template to parse the arguments and code, void is used to force this to be an expression + const template = `void function (${args}) { ${code} }`; + + let parsed; + try { + parsed = parse(template, []); + } catch (e) { + if (e.name === 'SyntaxError') { + // throw syntax errors of evals at runtime instead + return internalThrow(scope, 'SyntaxError', e.message, true); + } + + throw e; + } + + // Program > ExpressionStatement > UnaryExpression > FunctionExpression + parsed = parsed.body[0].expression.argument; + + const [ func, out ] = generateFunc(scope, parsed); + + return out; + } else { + return todo(scope, 'dynamic eval is not currently supported', true); + } } let protoName, target; From dcb5dfb4bb1e7db80b5a9af0e9475b62a2509fa2 Mon Sep 17 00:00:00 2001 From: Bob Varioa Date: Wed, 31 Jul 2024 07:52:01 -0500 Subject: [PATCH 3/3] codegen: add function constructor to getNodeType --- compiler/codegen.js | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/codegen.js b/compiler/codegen.js index b84a5d57..8fb31c9e 100644 --- a/compiler/codegen.js +++ b/compiler/codegen.js @@ -1413,6 +1413,7 @@ const getNodeType = (scope, node) => { if (Object.hasOwn(builtinFuncs, name) && !builtinFuncs[name].typedReturns) return builtinFuncs[name].returnType ?? TYPES.number; if (Object.hasOwn(internalConstrs, name)) return internalConstrs[name].type; + if (name === 'Function') return TYPES.function; // check if this is a prototype function // if so and there is only one impl (eg charCodeAt)