dsh-ptc-plus 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +65 -78
- package/README.md +65 -78
- package/assets/ptc-plus-bindings-en.png +0 -0
- package/assets/ptc-plus-bindings-zh.png +0 -0
- package/assets/ptc-plus-repair-en.png +0 -0
- package/assets/ptc-plus-repair-zh.png +0 -0
- package/assets/ptc-plus-repl-workspace-en.png +0 -0
- package/assets/ptc-plus-repl-workspace-zh.png +0 -0
- package/assets/ptc-plus-settings-en.png +0 -0
- package/assets/ptc-plus-settings-zh.png +0 -0
- package/client.js +30596 -742
- package/compiler-amaro.cjs +5 -0
- package/compiler-amaro.cjs.map +6 -0
- package/compiler-asset-124f80c1bba92ff5fe79cfec6e8ad518f476de4a42514cae3919538887f510e8.txt +1 -0
- package/compiler-assets.json +3 -0
- package/compiler-core.cjs +554 -0
- package/compiler-core.cjs.map +6 -0
- package/compiler-platform.cjs +2 -0
- package/compiler-platform.cjs.map +6 -0
- package/compiler-typescript.cjs +388 -0
- package/compiler-typescript.cjs.map +6 -0
- package/docs/README.md +6 -0
- package/docs/adr/0004-declare-program-bindings-at-the-host.md +1 -1
- package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +5 -3
- package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +1 -1
- package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -0
- package/docs/adr/0010-session-log-derived-recovery-tips.md +59 -5
- package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +1 -1
- package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +3 -1
- package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +3 -1
- package/docs/adr/0014-persist-cell-rewrite-policy.md +6 -2
- package/docs/adr/0015-preserve-source-positions-through-rewrites.md +1 -1
- package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
- package/docs/adr/0017-track-the-latest-dsh-public-surface.md +49 -0
- package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +3 -3
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +5 -3
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
- package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +12 -0
- package/docs/adr/0023-global-user-bindings.md +104 -0
- package/docs/adr/0024-repl-console-observation.md +33 -0
- package/docs/adr/0025-use-versioned-logical-binding-identities.md +119 -0
- package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +21 -0
- package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +37 -0
- package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +103 -0
- package/docs/adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md +27 -0
- package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +27 -0
- package/docs/architecture.md +73 -21
- package/docs/binding-review-placement-design.md +200 -0
- package/docs/capability-projection.md +1 -1
- package/docs/client-ui.md +95 -19
- package/docs/durability-design.md +25 -10
- package/docs/evaluation.md +78 -6
- package/docs/installation.md +41 -6
- package/docs/publishing.md +5 -3
- package/docs/runtime-reference.md +72 -25
- package/docs/semantic-validation.md +29 -0
- package/docs/stateful-binding-updates-proposal.md +755 -0
- package/docs/user-bindings.en.md +64 -0
- package/docs/user-bindings.md +64 -0
- package/docs/value-wire.md +3 -3
- package/docs/verification.md +57 -0
- package/index.js +369 -92
- package/internal/ast-traversal.js +5 -2
- package/internal/binding-descriptors.js +1 -0
- package/internal/binding-pattern-traversal.js +25 -0
- package/internal/binding-pattern.js +26 -29
- package/internal/binding-source-analysis.js +391 -0
- package/internal/binding-update-policy.js +66 -0
- package/internal/bounded-worker-round.js +56 -0
- package/internal/callable-definition-environment.js +42 -0
- package/internal/callable-source-catalog.js +129 -0
- package/internal/callable-source-encoding.js +47 -0
- package/internal/callable-source-facts.js +459 -0
- package/internal/callable-source-format.js +2 -0
- package/internal/callable-source-lowering.js +123 -0
- package/internal/cell-analysis-contract.js +25 -0
- package/internal/cell-analysis.js +240 -290
- package/internal/cell-completion.js +15 -0
- package/internal/cell-error.js +7 -0
- package/internal/cell-parser.js +66 -0
- package/internal/cell-rewriter.js +3 -677
- package/internal/commonjs-export-evidence.js +63 -0
- package/internal/commonjs-source-evidence.js +72 -0
- package/internal/compiler-amaro.cjs +2 -0
- package/internal/compiler-compression.js +12 -0
- package/internal/compiler-data.js +58 -0
- package/internal/compiler-descriptors.js +54 -0
- package/internal/compiler-dynamic-cache.js +48 -0
- package/internal/compiler-entry.js +35 -0
- package/internal/compiler-generated-names.js +17 -0
- package/internal/compiler-intrinsics.js +84 -0
- package/internal/compiler-module-links.js +34 -0
- package/internal/compiler-operations.js +61 -0
- package/internal/compiler-platform-factory.js +84 -0
- package/internal/compiler-platform.js +136 -0
- package/internal/compiler-record-roles.js +53 -0
- package/internal/compiler-region-output.js +259 -0
- package/internal/compiler-resource-lowering.js +103 -0
- package/internal/compiler-scope-facts.js +115 -0
- package/internal/compiler-service.js +109 -0
- package/internal/compiler-source-cache.js +32 -0
- package/internal/compiler-source-pieces.js +93 -0
- package/internal/compiler-source-regions.js +132 -0
- package/internal/compiler-storage-source.js +54 -0
- package/internal/compiler-text.js +15 -0
- package/internal/compiler-typescript.cjs +2 -0
- package/internal/config-spec.js +83 -27
- package/internal/cordis-tools-owner.js +130 -21
- package/internal/diagnostic.js +27 -1
- package/internal/direct-surface-owner.js +76 -23
- package/internal/dynamic-binding-evidence.js +16 -0
- package/internal/dynamic-environment-compiler.js +779 -0
- package/internal/dynamic-environment-integration.js +87 -0
- package/internal/dynamic-environment-runtime.js +362 -0
- package/internal/dynamic-native-calls.js +150 -0
- package/internal/dynamic-native-runtime.js +248 -0
- package/internal/dynamic-scope-analysis.js +90 -0
- package/internal/edit-transport-owner.js +27 -2
- package/internal/execution-seam-compat.js +193 -0
- package/internal/failure-reporting.js +118 -18
- package/internal/host-rpc.js +66 -0
- package/internal/isolated-worker.js +548 -0
- package/internal/kernel-child.js +139 -0
- package/internal/kernel-worker.js +904 -120
- package/internal/language-semantics.js +14 -0
- package/internal/legacy-binding-catalog.js +48 -0
- package/internal/legacy-cell-analysis.js +600 -0
- package/internal/legacy-cell-parser.js +50 -0
- package/internal/legacy-cell-rewriter.js +631 -0
- package/internal/legacy-repl-convenience.js +291 -0
- package/internal/managed-module-operations.js +170 -0
- package/internal/module-compilation.js +321 -0
- package/internal/module-runtime-platform.js +19 -0
- package/internal/module-transform-contract.js +12 -0
- package/internal/native-await-declarations.js +68 -0
- package/internal/native-root-compilation.js +54 -0
- package/internal/native-root-dynamic.js +67 -0
- package/internal/recovery-tips.js +27 -15
- package/internal/rejected-cell-editor.js +13 -8
- package/internal/repl-convenience.js +2 -289
- package/internal/repl-memory-projection.js +81 -12
- package/internal/repl-observation-interest.js +70 -0
- package/internal/repl-rewrite-contract.js +6 -0
- package/internal/repl-scope-normalizer.js +2091 -0
- package/internal/repl-value-observer.js +114 -0
- package/internal/rpc-contract.js +52 -0
- package/internal/runtime-bridge-owner.js +172 -28
- package/internal/runtime-config.js +48 -52
- package/internal/runtime-contexts.js +82 -10
- package/internal/runtime-messages.js +111 -0
- package/internal/session-cell-executor.js +401 -87
- package/internal/session-journal-recovery.js +684 -0
- package/internal/session-journal-schema.js +106 -0
- package/internal/session-journal.js +184 -654
- package/internal/session-log-view.js +42 -9
- package/internal/session-runtime.js +256 -95
- package/internal/session-state.js +247 -71
- package/internal/source-position-map.js +211 -71
- package/internal/stateful-module-compiler.js +154 -0
- package/internal/stateful-module-runtime.js +303 -0
- package/internal/stateful-root-compiler.js +598 -0
- package/internal/stateful-root-runtime.js +340 -0
- package/internal/typert-codec-compat.js +28 -0
- package/internal/typescript-transform.js +29 -0
- package/internal/user-binding-authoring.js +70 -0
- package/internal/user-binding-console-worker.js +184 -0
- package/internal/user-binding-console.js +148 -0
- package/internal/user-binding-draft-projection.js +335 -0
- package/internal/user-binding-model-context.js +31 -0
- package/internal/user-binding-runner.js +56 -0
- package/internal/user-bindings-owner.js +1065 -0
- package/internal/user-bindings-store.js +293 -0
- package/internal/user-bindings.js +353 -0
- package/internal/value-wire-schema.js +28 -0
- package/internal/value-wire.js +29 -20
- package/internal/worker-client.js +57 -67
- package/internal/worker-environment.js +45 -0
- package/internal/worker-output-relay.js +29 -0
- package/internal/worker-shutdown.js +14 -0
- package/package.json +75 -7
- package/src/client-activity.js +88 -53
- package/src/client-authoring-view.js +580 -0
- package/src/client-binding-review.js +230 -0
- package/src/client-bindings-data.js +29 -0
- package/src/client-catalog.js +127 -0
- package/src/client-code-editor.js +84 -0
- package/src/client-console.js +112 -0
- package/src/client-copy.js +370 -0
- package/src/client-feature-gates.js +62 -0
- package/src/client-host-compat.js +150 -0
- package/src/client-indicator-view.js +267 -0
- package/src/client-repl-view.js +292 -0
- package/src/client-rpc.js +20 -0
- package/src/client-settings-view.js +221 -0
- package/src/client-styles.js +106 -0
- package/src/client-tool-view.js +108 -0
- package/src/client-transport.js +159 -0
- package/src/client-workbench.js +521 -0
- package/src/client.js +233 -615
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { commonJsCompilerImport } from './compiler-module-links.js'
|
|
2
|
+
import { createHash } from 'node:crypto'
|
|
3
|
+
import { createGeneratedNameAllocator } from './binding-pattern.js'
|
|
4
|
+
import { compileDynamicEnvironmentSource } from './dynamic-environment-compiler.js'
|
|
5
|
+
import { applySourceEdits, mappedSourceTransform, mapSourceSpan, sourceLineStarts, sourceTextAtSpan, sourceOffsetAt } from './source-position-map.js'
|
|
6
|
+
import { visitRegionSource, applyRegionEdits } from './compiler-region-output.js'
|
|
7
|
+
import { visitSource } from './compiler-source-regions.js'
|
|
8
|
+
|
|
9
|
+
/** Keep dynamic name resolution behind the lexical facts of the cell compiler. */
|
|
10
|
+
export function adaptDynamicCell(code, sourceMap, options) {
|
|
11
|
+
const parserOptions = { sourceType: options.sourceType ?? 'script',
|
|
12
|
+
...(options.sourceType === 'commonjs' ? {} : { allowAwaitOutsideFunction: true, allowReturnOutsideFunction: true }),
|
|
13
|
+
plugins: options.parserPlugins }
|
|
14
|
+
let rootEnd, directiveEnd, strict, allocate
|
|
15
|
+
let lexicalDynamic = options.sourceRegions?.lexicalDynamic ?? false
|
|
16
|
+
const discoverDynamics = options.sourceRegions?.lexicalDynamic === undefined
|
|
17
|
+
const inspectRegion = region => region.kind === 'program' || discoverDynamics || options.rootRuntime !== undefined
|
|
18
|
+
visitRegionSource({ code, sourceMap, sourceRegions: options.sourceRegions }, parserOptions, input => {
|
|
19
|
+
allocate ??= options.sourceRegions?.allocate ?? createGeneratedNameAllocator(input.tree, options.reservedBindings ?? [])
|
|
20
|
+
if (input.region.kind === 'program') {
|
|
21
|
+
directiveEnd = input.tree.program.directives.at(-1)?.end ?? input.tree.program.interpreter?.end ?? 0
|
|
22
|
+
strict = input.tree.program.directives.some(directive => directive.value.value === 'use strict')
|
|
23
|
+
}
|
|
24
|
+
if (discoverDynamics || options.rootRuntime !== undefined) visitSource(input.tree, {
|
|
25
|
+
VariableDeclarator(path) {
|
|
26
|
+
if (path.node.id.name === options.rootRuntime) rootEnd = sourceOffsetAt(input.sourceMap, path.parent.end - 1) + 1
|
|
27
|
+
},
|
|
28
|
+
CallExpression(path) { if (path.node.callee.type === 'Identifier' && path.node.callee.name === 'eval') lexicalDynamic = true },
|
|
29
|
+
WithStatement() { lexicalDynamic = true },
|
|
30
|
+
})
|
|
31
|
+
}, inspectRegion)
|
|
32
|
+
const environmentName = allocate('dynamic_environment')
|
|
33
|
+
let expression
|
|
34
|
+
let setup
|
|
35
|
+
if (options.module === true) {
|
|
36
|
+
const runtimeUrl = new URL('./dynamic-environment-runtime.js', import.meta.url)
|
|
37
|
+
if (options.sourceType === 'module') {
|
|
38
|
+
const factory = allocate('dynamic_factory')
|
|
39
|
+
setup = `\nimport {createDynamicEnvironmentRuntime as ${factory}} from ${JSON.stringify(runtimeUrl.href)};\n`
|
|
40
|
+
expression = `${factory}(${options.importOperation === undefined ? '' : `{importModule:${options.importOperation}}`}).installIntrinsics().environment({strict:true,getThis:()=>void 0})`
|
|
41
|
+
options = { ...options, internalBindings: new Set([...options.internalBindings ?? [], factory]) }
|
|
42
|
+
} else {
|
|
43
|
+
const names = ['exports', 'module', 'require', '__filename', '__dirname', 'arguments']
|
|
44
|
+
const bindings = names.map(name => `[${JSON.stringify(name)},{kind:"param",get:()=>${name}${name === 'arguments' && strict ? '' : `,set:v=>${name}=v`}}]`).join(',')
|
|
45
|
+
setup = `\nconst ${environmentName}=${commonJsCompilerImport(runtimeUrl)}.createDynamicEnvironmentRuntime(${options.importOperation === undefined ? '' : `{importModule:${options.importOperation}}`}).installIntrinsics().environment({strict:${strict},getThis:()=>this,getNewTarget:()=>new.target,allowNewTarget:true,nativeBindings:[${bindings}]});\n`
|
|
46
|
+
}
|
|
47
|
+
} else setup = options.nativeRoot === true ? `\nconst ${environmentName}=${options.environmentGlobal};\n`
|
|
48
|
+
: `\nconst ${environmentName}=${options.rootRuntime}.dynamic();\n`
|
|
49
|
+
const insertion = options.module === true || options.nativeRoot === true
|
|
50
|
+
? directiveEnd : rootEnd
|
|
51
|
+
const framed = applyRegionEdits({ code, sourceMap, sourceRegions: options.sourceRegions }, [{ start: insertion, end: insertion, text: setup }])
|
|
52
|
+
const callableRanges = options.callableRanges?.map(range => ({ ...range,
|
|
53
|
+
start: range.start >= insertion ? range.start + setup.length : range.start,
|
|
54
|
+
end: range.end > insertion ? range.end + setup.length : range.end }))
|
|
55
|
+
const dynamicOrigins = []
|
|
56
|
+
const sourceIdentity = createHash('sha256').update(options.originalSource).digest('hex')
|
|
57
|
+
const originalLineStarts = sourceLineStarts(options.originalSource)
|
|
58
|
+
const coordinates = { generatedStarts: sourceLineStarts(framed.code), originalStarts: originalLineStarts }
|
|
59
|
+
const evalOrigin = node => {
|
|
60
|
+
const definitionSpan = mapSourceSpan({ line: node.loc.start.line, column: node.loc.start.column + 1,
|
|
61
|
+
end: { line: node.loc.end.line, column: node.loc.end.column + 1 } }, framed.code, options.originalSource, framed.sourceMap, coordinates)
|
|
62
|
+
const target = `eval:${sourceIdentity}:${definitionSpan.line}:${definitionSpan.column}`
|
|
63
|
+
dynamicOrigins.push({ target, definitionSpan })
|
|
64
|
+
return target
|
|
65
|
+
}
|
|
66
|
+
const writeTarget = node => {
|
|
67
|
+
const position = mapSourceSpan({ line: node.loc.start.line, column: node.loc.start.column + 1 },
|
|
68
|
+
framed.code, options.originalSource, framed.sourceMap, coordinates)
|
|
69
|
+
return `write:${sourceIdentity}:${position.line}:${position.column}:${node.name}`
|
|
70
|
+
}
|
|
71
|
+
const calleeSource = node => sourceTextAtSpan(options.originalSource, mapSourceSpan({
|
|
72
|
+
line: node.loc.start.line, column: node.loc.start.column + 1,
|
|
73
|
+
end: { line: node.loc.end.line, column: node.loc.end.column + 1 },
|
|
74
|
+
}, framed.code, options.originalSource, framed.sourceMap, coordinates), originalLineStarts)
|
|
75
|
+
const result = compileDynamicEnvironmentSource(framed.code, { cell: { ...options, environmentName,
|
|
76
|
+
sourceRegions: framed.sourceRegions,
|
|
77
|
+
callableRanges,
|
|
78
|
+
staticOnly: !lexicalDynamic && options.logicalRoots !== true,
|
|
79
|
+
calleeSource,
|
|
80
|
+
environmentExpression: expression, evalOrigin: options.module === true ? undefined : evalOrigin,
|
|
81
|
+
writeTarget: options.module === true ? undefined : writeTarget } })
|
|
82
|
+
const emission = result.sourceOffsets === undefined
|
|
83
|
+
? mappedSourceTransform(framed.code, framed.sourceMap, { code: result.code, map: result.sourceMap })
|
|
84
|
+
: applySourceEdits(framed.code, framed.sourceMap, [{ start: 0, end: framed.code.length, text: result.code, mappings: result.sourceOffsets }])
|
|
85
|
+
return { ...emission, sourceRegions: result.sourceRegions, callableRanges: result.callableRanges,
|
|
86
|
+
dynamicOrigins, dynamicEnvironmentName: environmentName }
|
|
87
|
+
}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { compileDynamicSource, isCompilerSyntaxError } from './compiler-service.js'
|
|
2
|
+
import { createNativeCallAdapter } from './dynamic-native-runtime.js'
|
|
3
|
+
import { captureCompilerIntrinsics, moduleRuntimeIntrinsics as internal } from './compiler-intrinsics.js'
|
|
4
|
+
import { types } from 'node:util'
|
|
5
|
+
|
|
6
|
+
const reflectionIntrinsics = new internal.WeakMap()
|
|
7
|
+
function captureReflection(reflect) {
|
|
8
|
+
let captured = internal.weakMapGet(reflectionIntrinsics, reflect)
|
|
9
|
+
if (captured === undefined) {
|
|
10
|
+
captured = { apply: reflect.apply, construct: reflect.construct, get: reflect.get,
|
|
11
|
+
has: reflect.has, set: reflect.set, deleteProperty: reflect.deleteProperty,
|
|
12
|
+
defineProperty: reflect.defineProperty, ownKeys: reflect.ownKeys }
|
|
13
|
+
internal.weakMapSet(reflectionIntrinsics, reflect, captured)
|
|
14
|
+
internal.weakMapSet(reflectionIntrinsics, captured, captured)
|
|
15
|
+
}
|
|
16
|
+
return captured
|
|
17
|
+
}
|
|
18
|
+
const defaultIntrinsics = { intrinsicEval: eval, realmFunction: Function, globalObject: globalThis, reflect: captureReflection(Reflect) }
|
|
19
|
+
|
|
20
|
+
const isObject = value => value !== null && (typeof value === 'object' || typeof value === 'function')
|
|
21
|
+
const isMap = types.isMap
|
|
22
|
+
const bindingStores = new internal.WeakMap()
|
|
23
|
+
const asBindings = value => {
|
|
24
|
+
if (internal.isArray(value)) {
|
|
25
|
+
const result = new internal.Map()
|
|
26
|
+
for (let index = 0; index < value.length; index++) {
|
|
27
|
+
const entry = value[index]
|
|
28
|
+
internal.mapSet(result, entry[0], entry[1])
|
|
29
|
+
}
|
|
30
|
+
value = result
|
|
31
|
+
}
|
|
32
|
+
// Logical roots implement this same live lookup/update contract. Native Map
|
|
33
|
+
// storage adapts once; callers never select its mutable prototype methods.
|
|
34
|
+
if (!isMap(value)) return value
|
|
35
|
+
let result = internal.weakMapGet(bindingStores, value)
|
|
36
|
+
if (result !== undefined) return result
|
|
37
|
+
result = { has: name => internal.mapHas(value, name), get: name => internal.mapGet(value, name),
|
|
38
|
+
set: (name, binding) => internal.mapSet(value, name, binding), delete: name => internal.mapDelete(value, name),
|
|
39
|
+
forEach: visit => internal.mapForEach(value, visit) }
|
|
40
|
+
internal.weakMapSet(bindingStores, value, result)
|
|
41
|
+
return result
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Native reference operations over compiler-proved lexical and object frames. */
|
|
45
|
+
export function createDynamicEnvironmentRuntime({
|
|
46
|
+
importModule = (source, options) => import(source, options),
|
|
47
|
+
intrinsicEval = defaultIntrinsics.intrinsicEval, realmFunction = defaultIntrinsics.realmFunction, globalObject = defaultIntrinsics.globalObject,
|
|
48
|
+
errors, reflect = defaultIntrinsics.reflect, object, interfaceOwner,
|
|
49
|
+
} = {}) {
|
|
50
|
+
const intrinsics = captureCompilerIntrinsics(realmFunction)
|
|
51
|
+
const { unscopables, Object: intrinsicObject, array: internalArray } = intrinsics
|
|
52
|
+
object ??= intrinsicObject
|
|
53
|
+
errors ??= intrinsics
|
|
54
|
+
// Reference mechanics use the realm's captured operations. Explicit source
|
|
55
|
+
// Reflect calls still observe the mutable user-visible Reflect object.
|
|
56
|
+
reflect = captureReflection(reflect)
|
|
57
|
+
const parameterEnvironments = new internal.WeakMap()
|
|
58
|
+
let rootEnvironment
|
|
59
|
+
let defaultRootEnvironment
|
|
60
|
+
const evaluate = (callee, receiver, args, environment, compilerOptions = {}) => {
|
|
61
|
+
if (!nativeCalls.isEval(callee)) return reflect.apply(callee, receiver, args)
|
|
62
|
+
const source = args[0]
|
|
63
|
+
if (typeof source !== 'string') return source
|
|
64
|
+
let compiled
|
|
65
|
+
try {
|
|
66
|
+
compiled = compileDynamicSource(source, { strict: environment.strict, allowNewTarget: environment.allowNewTarget,
|
|
67
|
+
privateNames: environment.privateNames, allowSuper: environment.allowSuper, allowSuperCall: environment.allowSuperCall,
|
|
68
|
+
forbidArguments: environment.forbidArguments, resolveOriginalSource: nativeCalls.originalSource, ...compilerOptions })
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (!isCompilerSyntaxError(error)) throw error
|
|
71
|
+
throw new errors.SyntaxError(error.message)
|
|
72
|
+
}
|
|
73
|
+
nativeCalls.registerSources(compiled.callableSources)
|
|
74
|
+
environment.declareEvalVars(compiled.varNames)
|
|
75
|
+
return nativeCalls.evaluate(compiled, environment)
|
|
76
|
+
}
|
|
77
|
+
const nativeCalls = createNativeCallAdapter({ realmFunction, intrinsicEval, reflect, errors, evaluate, interfaceOwner,
|
|
78
|
+
rootEnvironment(origin) {
|
|
79
|
+
if (rootEnvironment === undefined && defaultRootEnvironment === undefined) {
|
|
80
|
+
const varFrame = new internal.Map()
|
|
81
|
+
defaultRootEnvironment = environment({ varFrame, frames: [{ kind: 'lexical', bindings: varFrame }],
|
|
82
|
+
declareVars: declareGlobals,
|
|
83
|
+
createVar(name) {
|
|
84
|
+
const target = ambientReference(name, false)
|
|
85
|
+
return { kind: 'var', get: () => target.value, set: value => { target.value = value },
|
|
86
|
+
typeof: () => target.typeof(), delete: () => target.delete() }
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
return (rootEnvironment?.() ?? defaultRootEnvironment).context({ strict: false,
|
|
91
|
+
getThis: () => globalObject, allowNewTarget: false }).at(origin)
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
function declareGlobals(names, functionNames = []) {
|
|
95
|
+
for (let index = 0; index < functionNames.length; index++) {
|
|
96
|
+
const name = functionNames[index]
|
|
97
|
+
if (!internal.includes(names, name)) continue
|
|
98
|
+
const descriptor = intrinsicObject.getOwnPropertyDescriptor(globalObject, name)
|
|
99
|
+
const allowed = descriptor === undefined ? intrinsicObject.isExtensible(globalObject)
|
|
100
|
+
: descriptor.configurable || intrinsicObject.hasOwn(descriptor, 'value') && descriptor.writable && descriptor.enumerable
|
|
101
|
+
if (!allowed) throw new errors.TypeError(`Cannot declare global function '${name}'`)
|
|
102
|
+
}
|
|
103
|
+
nativeCalls.declareGlobals(names)
|
|
104
|
+
}
|
|
105
|
+
const reference = (name, descriptor, receiver, strict, origin, writeTarget) => descriptor.reference === undefined ? ({
|
|
106
|
+
get value() { return descriptor.get() },
|
|
107
|
+
set value(value) {
|
|
108
|
+
if (descriptor.kind === 'self' && descriptor.set === undefined) {
|
|
109
|
+
if (strict) throw new errors.TypeError('Assignment to constant variable.')
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
descriptor.set(value, strict, origin, writeTarget)
|
|
113
|
+
},
|
|
114
|
+
get callee() {
|
|
115
|
+
const value = descriptor.get()
|
|
116
|
+
return nativeCalls.referenceCall(value, receiver)
|
|
117
|
+
},
|
|
118
|
+
get evalInvocation() {
|
|
119
|
+
const value = descriptor.get()
|
|
120
|
+
return (environment, args, callOrigin) => nativeCalls.isEval(value)
|
|
121
|
+
? () => evaluate(value, receiver, args, environment)
|
|
122
|
+
: nativeCalls.beginInvocation(nativeCalls.prepareInvocation(value, receiver, callOrigin), args)
|
|
123
|
+
},
|
|
124
|
+
typeof() { return descriptor.typeof === undefined ? typeof descriptor.get() : descriptor.typeof() },
|
|
125
|
+
delete() { return descriptor.delete === undefined ? false : descriptor.delete(strict) },
|
|
126
|
+
}) : descriptor.reference()
|
|
127
|
+
const forwardReference = resolve => ({
|
|
128
|
+
get value() { return resolve().value },
|
|
129
|
+
set value(value) { resolve().value = value },
|
|
130
|
+
get callee() { return resolve().callee },
|
|
131
|
+
get evalInvocation() { return resolve().evalInvocation },
|
|
132
|
+
typeof() { return resolve().typeof() },
|
|
133
|
+
delete() { return resolve().delete() },
|
|
134
|
+
})
|
|
135
|
+
const objectReference = (object, name, strict) => reference(name, {
|
|
136
|
+
get: () => reflect.get(object, name, object),
|
|
137
|
+
set(value) {
|
|
138
|
+
if (!reflect.set(object, name, value, object) && strict) throw new errors.TypeError(`Cannot assign to property '${name}'`)
|
|
139
|
+
},
|
|
140
|
+
delete() {
|
|
141
|
+
const deleted = reflect.deleteProperty(object, name)
|
|
142
|
+
if (!deleted && strict) throw new errors.TypeError(`Cannot delete property '${name}'`)
|
|
143
|
+
return deleted
|
|
144
|
+
},
|
|
145
|
+
}, object, strict)
|
|
146
|
+
const ambientReference = (name, strict) => reference(name, {
|
|
147
|
+
get() {
|
|
148
|
+
if (!reflect.has(globalObject, name)) throw new errors.ReferenceError(`${name} is not defined`)
|
|
149
|
+
return reflect.get(globalObject, name, globalObject)
|
|
150
|
+
},
|
|
151
|
+
set(value) {
|
|
152
|
+
if (strict && !reflect.has(globalObject, name)) throw new errors.ReferenceError(`${name} is not defined`)
|
|
153
|
+
if (!reflect.set(globalObject, name, value, globalObject) && strict) throw new errors.TypeError(`Cannot assign to '${name}'`)
|
|
154
|
+
},
|
|
155
|
+
typeof: () => reflect.has(globalObject, name) ? typeof reflect.get(globalObject, name, globalObject) : 'undefined',
|
|
156
|
+
delete: () => reflect.deleteProperty(globalObject, name),
|
|
157
|
+
}, undefined, strict)
|
|
158
|
+
|
|
159
|
+
function environment({ frames = [], varFrame = new internal.Map(), strict = false, origin, lexicalContext = {},
|
|
160
|
+
getThis = () => globalObject, getNewTarget = () => undefined, allowNewTarget = false,
|
|
161
|
+
ambient = ambientReference, createVar, declareVars, nativeAwait = false } = {}) {
|
|
162
|
+
varFrame = asBindings(varFrame)
|
|
163
|
+
const capturedFrames = []
|
|
164
|
+
for (let index = 0; index < frames.length; index++) {
|
|
165
|
+
const frame = frames[index]
|
|
166
|
+
internal.appendArray(capturedFrames, frame.kind === 'object' ? frame : { ...frame, bindings: asBindings(frame.bindings) })
|
|
167
|
+
}
|
|
168
|
+
frames = capturedFrames
|
|
169
|
+
const result = {
|
|
170
|
+
importModule,
|
|
171
|
+
internalArray,
|
|
172
|
+
expose: nativeCalls.exposedValue,
|
|
173
|
+
prepareCall: nativeCalls.prepareCall,
|
|
174
|
+
prepareInvocation: nativeCalls.prepareInvocation,
|
|
175
|
+
releaseMemberReceiver: nativeCalls.releaseMemberReceiver,
|
|
176
|
+
prepareMemberInvocation: nativeCalls.prepareMemberInvocation,
|
|
177
|
+
beginInvocation: nativeCalls.beginInvocation,
|
|
178
|
+
prepareTagInvocation: nativeCalls.prepareTagInvocation,
|
|
179
|
+
templateArguments: nativeCalls.templateArguments,
|
|
180
|
+
propagate: nativeCalls.propagate,
|
|
181
|
+
strict,
|
|
182
|
+
allowNewTarget,
|
|
183
|
+
privateNames: internal.Object.keys(lexicalContext.privateReferences ?? {}),
|
|
184
|
+
allowSuper: lexicalContext.getSuper !== undefined,
|
|
185
|
+
allowSuperCall: lexicalContext.callSuper !== undefined,
|
|
186
|
+
forbidArguments: lexicalContext.forbidArguments === true,
|
|
187
|
+
thisValue: () => getThis(),
|
|
188
|
+
newTarget: () => getNewTarget(),
|
|
189
|
+
get superReference() {
|
|
190
|
+
const receiver = getThis()
|
|
191
|
+
return key => reference(key, lexicalContext.getSuper(key), receiver, strict)
|
|
192
|
+
},
|
|
193
|
+
get superCall() { return lexicalContext.callSuper },
|
|
194
|
+
privateReference(name, receiver, optional = false) {
|
|
195
|
+
return optional && receiver == null ? undefined : reference(name, lexicalContext.privateReferences[name](receiver), receiver, strict)
|
|
196
|
+
},
|
|
197
|
+
privateHas(name, receiver) { return lexicalContext.privateReferences[name](receiver).has() },
|
|
198
|
+
reference(name, writeTarget) {
|
|
199
|
+
for (let index = 0; index < frames.length; index++) {
|
|
200
|
+
const frame = frames[index]
|
|
201
|
+
if (frame.kind === 'lexical' || frame.kind === 'self') {
|
|
202
|
+
if (frame.bindings.has(name)) return reference(name, frame.bindings.get(name), undefined, strict, origin, writeTarget)
|
|
203
|
+
} else if (reflect.has(frame.object, name)) {
|
|
204
|
+
const excluded = reflect.get(frame.object, unscopables, frame.object)
|
|
205
|
+
if (!isObject(excluded) || !reflect.get(excluded, name, excluded)) return objectReference(frame.object, name, strict)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return ambient(name, strict, origin, writeTarget)
|
|
209
|
+
},
|
|
210
|
+
deferredReference(name, writeTarget) {
|
|
211
|
+
return forwardReference(() => result.reference(name, writeTarget))
|
|
212
|
+
},
|
|
213
|
+
withReference(name, withDepth, fallback) {
|
|
214
|
+
const select = () => {
|
|
215
|
+
let remaining = withDepth
|
|
216
|
+
for (let index = 0; index < frames.length; index++) {
|
|
217
|
+
const frame = frames[index]
|
|
218
|
+
if (remaining === 0) break
|
|
219
|
+
if (frame.kind !== 'object') continue
|
|
220
|
+
remaining--
|
|
221
|
+
if (!reflect.has(frame.object, name)) continue
|
|
222
|
+
const excluded = reflect.get(frame.object, unscopables, frame.object)
|
|
223
|
+
if (!isObject(excluded) || !reflect.get(excluded, name, excluded)) return objectReference(frame.object, name, strict)
|
|
224
|
+
}
|
|
225
|
+
return reference(name, fallback, undefined, strict, origin)
|
|
226
|
+
}
|
|
227
|
+
return forwardReference(select)
|
|
228
|
+
},
|
|
229
|
+
initialize(name, value) {
|
|
230
|
+
result.reference(name).value = value
|
|
231
|
+
return value
|
|
232
|
+
},
|
|
233
|
+
capture(scopes, nextStrict = strict, rootIndex = -1) {
|
|
234
|
+
const captured = []
|
|
235
|
+
for (let index = 0; index < scopes.length; index++) internal.appendArray(captured, { kind: 'lexical', bindings: asBindings(scopes[index]) })
|
|
236
|
+
let combined = internal.copyArray(frames, 0, frames.length, internal.copyArray(captured))
|
|
237
|
+
if (nativeAwait && rootIndex >= 0) {
|
|
238
|
+
let boundary = 0
|
|
239
|
+
for (let index = 0; index < frames.length; index++) {
|
|
240
|
+
if (frames[index].kind === 'lexical' && frames[index].bindings === varFrame) { boundary = index + 1; break }
|
|
241
|
+
}
|
|
242
|
+
for (let index = rootIndex; index < captured.length; index++) captured[index].bindings.forEach((binding, name) => {
|
|
243
|
+
if (binding.kind === 'hoisted' && !varFrame.has(name)) varFrame.set(name, binding)
|
|
244
|
+
})
|
|
245
|
+
combined = internal.copyArray(captured, 0, rootIndex)
|
|
246
|
+
internal.copyArray(frames, 0, boundary, combined)
|
|
247
|
+
internal.copyArray(captured, rootIndex, captured.length, combined)
|
|
248
|
+
internal.copyArray(frames, boundary, frames.length, combined)
|
|
249
|
+
}
|
|
250
|
+
return environment({ frames: combined,
|
|
251
|
+
varFrame, strict: nextStrict, getThis, getNewTarget, allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin, lexicalContext })
|
|
252
|
+
},
|
|
253
|
+
awaitActivation() {
|
|
254
|
+
const local = new internal.Map()
|
|
255
|
+
return environment({ frames: internal.copyArray(frames, 0, frames.length, [{ kind: 'lexical', bindings: local }]), varFrame: local,
|
|
256
|
+
strict, getThis, getNewTarget, allowNewTarget, ambient, nativeAwait: true, origin, lexicalContext })
|
|
257
|
+
},
|
|
258
|
+
activation(bindings, nextGetThis = getThis, nextGetNewTarget = getNewTarget, nextStrict = strict, ownFunction = true, selfBindings) {
|
|
259
|
+
bindings = asBindings(bindings)
|
|
260
|
+
const activationFrames = [{ kind: 'lexical', bindings }]
|
|
261
|
+
if (selfBindings !== undefined) internal.appendArray(activationFrames, { kind: 'self', bindings: asBindings(selfBindings) })
|
|
262
|
+
return environment({ frames: internal.copyArray(frames, 0, frames.length, activationFrames), varFrame: bindings,
|
|
263
|
+
strict: nextStrict, getThis: nextGetThis, getNewTarget: nextGetNewTarget, allowNewTarget: ownFunction || allowNewTarget, ambient, origin,
|
|
264
|
+
lexicalContext: ownFunction ? { privateReferences: lexicalContext.privateReferences } : lexicalContext })
|
|
265
|
+
},
|
|
266
|
+
parameters(key, bindings, nextGetThis = getThis, nextGetNewTarget = getNewTarget, nextStrict = strict, ownFunction = true, selfBindings) {
|
|
267
|
+
let selected = internal.weakMapGet(parameterEnvironments, key)
|
|
268
|
+
if (selected === undefined) {
|
|
269
|
+
bindings = asBindings(bindings)
|
|
270
|
+
if (ownFunction && !bindings.has('arguments')) {
|
|
271
|
+
let value = key
|
|
272
|
+
bindings.set('arguments', { kind: 'param', get: () => value, set: next => { value = next } })
|
|
273
|
+
}
|
|
274
|
+
const parameterFrames = [{ kind: 'lexical', bindings }]
|
|
275
|
+
if (selfBindings !== undefined) internal.appendArray(parameterFrames, { kind: 'self', bindings: asBindings(selfBindings) })
|
|
276
|
+
selected = environment({ frames: internal.copyArray(frames, 0, frames.length, parameterFrames), varFrame: bindings,
|
|
277
|
+
strict: nextStrict, getThis: nextGetThis, getNewTarget: nextGetNewTarget, allowNewTarget: ownFunction || allowNewTarget, ambient, origin, lexicalContext })
|
|
278
|
+
internal.weakMapSet(parameterEnvironments, key, selected)
|
|
279
|
+
}
|
|
280
|
+
return selected
|
|
281
|
+
},
|
|
282
|
+
propertyKey(value) { return reflect.ownKeys({ [value]: undefined })[0] },
|
|
283
|
+
parameterArrow(fn, name) {
|
|
284
|
+
intrinsics.Reflect.defineProperty(fn, 'length', { value: internal.max(0, fn.length - 1) })
|
|
285
|
+
if (name !== undefined && fn.name === '') intrinsics.Reflect.defineProperty(fn, 'name', { value: name })
|
|
286
|
+
const adapter = new internal.Proxy(fn, { apply(target, receiver, args) {
|
|
287
|
+
return reflect.apply(target, receiver, internal.copyArray(args, 0, args.length, [{}]))
|
|
288
|
+
} })
|
|
289
|
+
return nativeCalls.registerCallableSourceTarget(adapter, fn)
|
|
290
|
+
},
|
|
291
|
+
context(options) { return environment({ frames, varFrame, strict: options.strict ?? strict,
|
|
292
|
+
getThis: options.getThis ?? getThis, getNewTarget: options.getNewTarget ?? getNewTarget,
|
|
293
|
+
allowNewTarget: options.allowNewTarget ?? allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin,
|
|
294
|
+
lexicalContext: { ...lexicalContext, ...options } }) },
|
|
295
|
+
at(nextOrigin) { return environment({ frames, varFrame, strict, getThis, getNewTarget,
|
|
296
|
+
allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin: nextOrigin, lexicalContext }) },
|
|
297
|
+
withObject(value) {
|
|
298
|
+
if (value === null || value === undefined) throw new errors.TypeError('Cannot convert undefined or null to object')
|
|
299
|
+
return environment({ frames: internal.copyArray(frames, 0, frames.length, [{ kind: 'object', object: object(value) }]),
|
|
300
|
+
varFrame, strict, getThis, getNewTarget, allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin, lexicalContext })
|
|
301
|
+
},
|
|
302
|
+
declareEvalVars(names) {
|
|
303
|
+
// EvalDeclarationInstantiation checks every name before any initializer
|
|
304
|
+
// runs. Object environments do not create lexical conflicts.
|
|
305
|
+
for (let index = 0; index < names.length; index++) {
|
|
306
|
+
const name = names[index]
|
|
307
|
+
for (let frameIndex = 0; frameIndex < frames.length; frameIndex++) {
|
|
308
|
+
const frame = frames[frameIndex]
|
|
309
|
+
if (frame.kind !== 'lexical') continue
|
|
310
|
+
const binding = frame.bindings.get(name)
|
|
311
|
+
if (binding !== undefined && binding.kind !== 'var' && binding.kind !== 'param' && binding.kind !== 'hoisted') {
|
|
312
|
+
throw new errors.SyntaxError(`Identifier '${name}' has already been declared`)
|
|
313
|
+
}
|
|
314
|
+
if (frame.bindings === varFrame) break
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (declareVars === undefined) {
|
|
318
|
+
const declarations = []
|
|
319
|
+
for (let index = 0; index < names.length; index++) internal.appendArray(declarations, [names[index]])
|
|
320
|
+
result.initializeEvalDeclarations(declarations)
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
initializeEvalDeclarations(declarations) {
|
|
324
|
+
for (let index = 0; index < declarations.length; index++) {
|
|
325
|
+
const declaration = declarations[index]
|
|
326
|
+
const name = declaration[0], value = declaration[1], isFunction = declaration[2] === true
|
|
327
|
+
declareVars?.([name], isFunction ? [name] : [])
|
|
328
|
+
if (!varFrame.has(name)) {
|
|
329
|
+
if (createVar !== undefined) varFrame.set(name, createVar(name, origin))
|
|
330
|
+
else {
|
|
331
|
+
let current
|
|
332
|
+
const binding = { kind: 'var', get: () => current, set: next => {
|
|
333
|
+
current = next
|
|
334
|
+
varFrame.set(name, binding)
|
|
335
|
+
}, delete: () => varFrame.delete(name) }
|
|
336
|
+
varFrame.set(name, binding)
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (isFunction) result.initializeEvalFunction(name, value)
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
initializeEvalFunction(name, value) { varFrame.get(name).set(value, strict, origin) },
|
|
343
|
+
}
|
|
344
|
+
return result
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
installIntrinsics() { nativeCalls.install(); return this },
|
|
348
|
+
exposedIntrinsic: nativeCalls.exposedValue,
|
|
349
|
+
registerSources: nativeCalls.registerSources,
|
|
350
|
+
declareGlobals,
|
|
351
|
+
setRootEnvironment(getEnvironment) { rootEnvironment = getEnvironment },
|
|
352
|
+
reference,
|
|
353
|
+
environment(options = {}) {
|
|
354
|
+
const varFrame = options.varFrame ?? new internal.Map()
|
|
355
|
+
const frames = internal.copyArray(options.frames ?? [])
|
|
356
|
+
if (options.nativeBindings !== undefined) internal.appendArray(frames, { kind: 'lexical', bindings: asBindings(options.nativeBindings) })
|
|
357
|
+
internal.appendArray(frames, { kind: 'lexical', bindings: varFrame })
|
|
358
|
+
return environment({ ...options, varFrame, frames })
|
|
359
|
+
},
|
|
360
|
+
evaluate,
|
|
361
|
+
}
|
|
362
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import traverseModule from '@babel/traverse'
|
|
2
|
+
import { types as t } from '@babel/core'
|
|
3
|
+
import { transform as transformOptional, transformOptionalChain } from '@babel/plugin-transform-optional-chaining'
|
|
4
|
+
import { isWriteIdentifier as isWriteTarget } from './binding-pattern.js'
|
|
5
|
+
import { withGeneratedNameAllocator } from './compiler-generated-names.js'
|
|
6
|
+
|
|
7
|
+
const traverse = traverseModule.default ?? traverseModule
|
|
8
|
+
|
|
9
|
+
/** Select intrinsic interfaces at owned source value and invocation boundaries. */
|
|
10
|
+
export function rewriteNativeCalls(tree, environment, { origin, skip, operations, originalCallees, allocate }) {
|
|
11
|
+
const { internal } = operations
|
|
12
|
+
let memberReceiver
|
|
13
|
+
let programScope
|
|
14
|
+
const helper = (name, args) => {
|
|
15
|
+
return operations.operation(t.callExpression(t.memberExpression(t.cloneNode(environment), t.identifier(name)), args))
|
|
16
|
+
}
|
|
17
|
+
const skipOwned = path => path.isTSType() || skip(path)
|
|
18
|
+
|| operations.callee(path.node)
|
|
19
|
+
const undefinedValue = () => t.unaryExpression('void', t.numericLiteral(0))
|
|
20
|
+
if (originalCallees === undefined) {
|
|
21
|
+
originalCallees = new WeakSet()
|
|
22
|
+
traverse(tree, {
|
|
23
|
+
enter(path) { if (path.isTSType() || skip(path)) path.skip() },
|
|
24
|
+
'CallExpression|OptionalCallExpression'(path) { originalCallees.add(path.node.callee) },
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
traverse(tree, { Program(path) { programScope = path.scope; path.stop() } })
|
|
28
|
+
const expose = path => {
|
|
29
|
+
// Only GetValue results select an interface. References must retain their
|
|
30
|
+
// write/delete semantics, receivers and optional-chain short circuiting.
|
|
31
|
+
const parent = path.parentPath
|
|
32
|
+
if (operations.owns(path.node) && !operations.isValue(path.node)
|
|
33
|
+
|| !path.isReferenced() || isWriteTarget(path) || parent.isUnaryExpression({ operator: 'delete' })
|
|
34
|
+
|| parent.isUnaryExpression({ operator: 'typeof' }) && path.isIdentifier()
|
|
35
|
+
|| (parent.isCallExpression() || parent.isOptionalCallExpression()) && path.key === 'callee'
|
|
36
|
+
|| parent.isTaggedTemplateExpression() && path.key === 'tag'
|
|
37
|
+
|| parent.isDecorator()
|
|
38
|
+
|| parent.isOptionalMemberExpression() && path.key === 'object'
|
|
39
|
+
|| path.isIdentifier() && internal.has(path.node.name)) return
|
|
40
|
+
if (parent.isObjectProperty() && parent.node.shorthand) {
|
|
41
|
+
parent.node.shorthand = false
|
|
42
|
+
parent.node.computed = true
|
|
43
|
+
parent.node.key = t.stringLiteral(path.node.name)
|
|
44
|
+
}
|
|
45
|
+
path.replaceWith(t.inherits(helper('expose', [path.node]), path.node))
|
|
46
|
+
path.skip()
|
|
47
|
+
}
|
|
48
|
+
const prepare = (callee, target, optional = false) => {
|
|
49
|
+
const stamp = target === undefined ? undefinedValue() : t.valueToNode(target)
|
|
50
|
+
const options = [stamp, t.booleanLiteral(optional)]
|
|
51
|
+
const prepared = (name, args) => t.inherits(helper(name, args), callee)
|
|
52
|
+
if (t.isMemberExpression(callee) || t.isOptionalMemberExpression(callee)) {
|
|
53
|
+
if (t.isSuper(callee.object)) return prepared('prepareInvocation', [callee, t.thisExpression(), ...options])
|
|
54
|
+
if (memberReceiver === undefined) {
|
|
55
|
+
memberReceiver = t.identifier(allocate('member_receiver'))
|
|
56
|
+
programScope.push({ id: memberReceiver })
|
|
57
|
+
internal.add(memberReceiver.name)
|
|
58
|
+
}
|
|
59
|
+
// Argument evaluation saves the receiver before key/getter reentrancy can
|
|
60
|
+
// change the temporary; the member read itself stays in its source frame.
|
|
61
|
+
const receiver = helper('releaseMemberReceiver', [t.cloneNode(memberReceiver),
|
|
62
|
+
t.assignmentExpression('=', t.cloneNode(memberReceiver), undefinedValue())])
|
|
63
|
+
return prepared('prepareMemberInvocation', [t.assignmentExpression('=', t.cloneNode(memberReceiver), callee.object),
|
|
64
|
+
t.inherits(t.memberExpression(receiver, callee.property, callee.computed), callee), ...options])
|
|
65
|
+
}
|
|
66
|
+
return prepared('prepareInvocation', [callee, undefinedValue(), ...options])
|
|
67
|
+
}
|
|
68
|
+
const invoke = (prepared, args) => operations.operation(t.callExpression(helper('beginInvocation', [prepared, args]), []))
|
|
69
|
+
// Receiver extraction must run after complete chains acquire their native
|
|
70
|
+
// short-circuit boundary, including grouped calls and computed-key effects.
|
|
71
|
+
traverse(tree, {
|
|
72
|
+
enter(path) { if (skipOwned(path)) path.skip() },
|
|
73
|
+
'OptionalCallExpression|OptionalMemberExpression'(path) {
|
|
74
|
+
const assumptions = { pureGetters: false, noDocumentAll: false }
|
|
75
|
+
withGeneratedNameAllocator(path.scope, allocate, () => {
|
|
76
|
+
if (path.isOptionalMemberExpression() && path.parentPath.isTaggedTemplateExpression()) {
|
|
77
|
+
const target = origin(path.parent)
|
|
78
|
+
transformOptionalChain(path, assumptions, path, undefinedValue(), callee => helper('prepareTagInvocation', [prepare(callee, target)]))
|
|
79
|
+
} else transformOptional(path, assumptions)
|
|
80
|
+
})
|
|
81
|
+
},
|
|
82
|
+
})
|
|
83
|
+
traverse(tree, {
|
|
84
|
+
enter(path) { if (skipOwned(path)) path.skip() },
|
|
85
|
+
'TSAsExpression|TSSatisfiesExpression|TSNonNullExpression|TSTypeAssertion': { enter(path) {
|
|
86
|
+
path.replaceWith(path.node.expression)
|
|
87
|
+
} },
|
|
88
|
+
ExportSpecifier(path) {
|
|
89
|
+
// Babel's printer compares identifier names when eliding an alias. Both
|
|
90
|
+
// string ModuleExportNames otherwise appear equal as undefined names.
|
|
91
|
+
const { local, exported } = path.node
|
|
92
|
+
if (t.isStringLiteral(local) && t.isStringLiteral(exported)) exported.name = exported.value
|
|
93
|
+
path.skip()
|
|
94
|
+
},
|
|
95
|
+
ReferencedIdentifier: { exit: expose },
|
|
96
|
+
'MemberExpression|OptionalMemberExpression|AwaitExpression|YieldExpression': { exit: expose },
|
|
97
|
+
ThrowStatement: { exit(path) {
|
|
98
|
+
if (operations.owns(path.node)) return
|
|
99
|
+
const argument = path.node.argument
|
|
100
|
+
path.node.argument = t.inherits(helper('propagate', [argument, t.valueToNode(origin(argument))]), argument)
|
|
101
|
+
path.skip()
|
|
102
|
+
} },
|
|
103
|
+
'CallExpression|OptionalCallExpression': { exit(path) {
|
|
104
|
+
if (operations.owns(path.node)) {
|
|
105
|
+
if (operations.isValue(path.node)) expose(path)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
if (t.isSuper(path.node.callee) || t.isImport(path.node.callee)
|
|
109
|
+
|| t.isIdentifier(path.node.callee, { name: 'eval' })) return
|
|
110
|
+
const node = path.node
|
|
111
|
+
// Babel expresses saved receivers through generated call/bind members.
|
|
112
|
+
// The intrinsic interface already owns invocation, so use the saved
|
|
113
|
+
// receiver directly without observing user-replaced call/bind properties.
|
|
114
|
+
if (t.isMemberExpression(node.callee) && !originalCallees.has(node.callee)
|
|
115
|
+
&& t.isIdentifier(node.callee.property) && ['call', 'bind'].includes(node.callee.property.name)) {
|
|
116
|
+
const prepared = helper('prepareInvocation', [node.callee.object, node.arguments[0],
|
|
117
|
+
t.valueToNode(origin(node)), t.booleanLiteral(false)])
|
|
118
|
+
path.replaceWith(t.inherits(node.callee.property.name === 'bind'
|
|
119
|
+
? helper('prepareTagInvocation', [prepared]) : invoke(prepared, t.arrayExpression(node.arguments.slice(1))), node))
|
|
120
|
+
path.skip()
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
const callee = prepare(node.callee, origin(node), node.optional === true)
|
|
124
|
+
path.replaceWith(t.inherits(invoke(callee, t.arrayExpression(node.arguments)), node))
|
|
125
|
+
path.skip()
|
|
126
|
+
} },
|
|
127
|
+
NewExpression: { exit(path) {
|
|
128
|
+
if (operations.owns(path.node)) return
|
|
129
|
+
const target = origin(path.node)
|
|
130
|
+
const invocation = t.inherits(invoke(helper('prepareInvocation', [path.node.callee, undefinedValue(),
|
|
131
|
+
target === undefined ? undefinedValue() : t.valueToNode(target), t.booleanLiteral(false), t.booleanLiteral(true)]), t.arrayExpression(path.node.arguments)), path.node)
|
|
132
|
+
// Native Error construction records the continuation call site. Anchor
|
|
133
|
+
// that private call to the original new expression, after its arguments.
|
|
134
|
+
if (invocation.loc !== undefined) invocation.callee.loc = { ...invocation.loc, end: invocation.loc.start }
|
|
135
|
+
path.replaceWith(invocation)
|
|
136
|
+
path.skip()
|
|
137
|
+
} },
|
|
138
|
+
TaggedTemplateExpression: { exit(path) {
|
|
139
|
+
if (operations.owns(path.node)) return
|
|
140
|
+
const args = t.taggedTemplateExpression(t.memberExpression(t.cloneNode(environment), t.identifier('templateArguments')), path.node.quasi)
|
|
141
|
+
path.replaceWith(t.inherits(invoke(prepare(path.node.tag, origin(path.node)), args), path.node))
|
|
142
|
+
path.skip()
|
|
143
|
+
} },
|
|
144
|
+
Decorator: { exit(path) {
|
|
145
|
+
if (operations.owns(path.node)) return
|
|
146
|
+
path.node.expression = helper('prepareTagInvocation', [prepare(path.node.expression, origin(path.node))])
|
|
147
|
+
path.skip()
|
|
148
|
+
} },
|
|
149
|
+
})
|
|
150
|
+
}
|