@geastack/compiler 1.0.15
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/LICENSE +202 -0
- package/README.md +149 -0
- package/dist/cli-analyze.d.ts +1 -0
- package/dist/cli-analyze.js +61 -0
- package/dist/cli-coverage.d.ts +1 -0
- package/dist/cli-coverage.js +329 -0
- package/dist/cli-emit.d.ts +10 -0
- package/dist/cli-emit.js +398 -0
- package/dist/cli-module-graph.d.ts +18 -0
- package/dist/cli-module-graph.js +123 -0
- package/dist/cli-package-source.d.ts +5 -0
- package/dist/cli-package-source.js +116 -0
- package/dist/cli-project.d.ts +2 -0
- package/dist/cli-project.js +60 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +199 -0
- package/dist/compiler.d.ts +228 -0
- package/dist/compiler.js +1029 -0
- package/dist/conversion/algebra.d.ts +218 -0
- package/dist/conversion/algebra.js +155 -0
- package/dist/conversion/build.d.ts +67 -0
- package/dist/conversion/build.js +1378 -0
- package/dist/conversion/derive.d.ts +37 -0
- package/dist/conversion/derive.js +260 -0
- package/dist/conversion/graph-validation.d.ts +8 -0
- package/dist/conversion/graph-validation.js +97 -0
- package/dist/conversion/native-callable-adapter.d.ts +13 -0
- package/dist/conversion/native-callable-adapter.js +53 -0
- package/dist/conversion/native-class-reference.d.ts +12 -0
- package/dist/conversion/native-class-reference.js +39 -0
- package/dist/conversion/native-payload-transport.d.ts +25 -0
- package/dist/conversion/native-payload-transport.js +33 -0
- package/dist/conversion/native-selection.d.ts +49 -0
- package/dist/conversion/native-selection.js +135 -0
- package/dist/conversion/native-sum.d.ts +42 -0
- package/dist/conversion/native-sum.js +115 -0
- package/dist/conversion/nodes.d.ts +55 -0
- package/dist/conversion/nodes.js +91 -0
- package/dist/conversion/operand-view.d.ts +14 -0
- package/dist/conversion/operand-view.js +20 -0
- package/dist/conversion/record-view.d.ts +157 -0
- package/dist/conversion/record-view.js +273 -0
- package/dist/conversion/registry.d.ts +217 -0
- package/dist/conversion/registry.js +1 -0
- package/dist/diagnostics/model.d.ts +76 -0
- package/dist/diagnostics/model.js +60 -0
- package/dist/diagnostics/sweep.d.ts +31 -0
- package/dist/diagnostics/sweep.js +112 -0
- package/dist/identity/ids.d.ts +179 -0
- package/dist/identity/ids.js +212 -0
- package/dist/ir/absent-class-arm.d.ts +48 -0
- package/dist/ir/absent-class-arm.js +157 -0
- package/dist/ir/borrow-effects.d.ts +23 -0
- package/dist/ir/borrow-effects.js +151 -0
- package/dist/ir/borrowed-call-arguments.d.ts +40 -0
- package/dist/ir/borrowed-call-arguments.js +117 -0
- package/dist/ir/build.d.ts +168 -0
- package/dist/ir/build.js +459 -0
- package/dist/ir/call-dispatch.d.ts +38 -0
- package/dist/ir/call-dispatch.js +502 -0
- package/dist/ir/call-entry.d.ts +142 -0
- package/dist/ir/call-entry.js +386 -0
- package/dist/ir/callable-class-flow.d.ts +27 -0
- package/dist/ir/callable-class-flow.js +1386 -0
- package/dist/ir/callable-field-slots.d.ts +22 -0
- package/dist/ir/callable-field-slots.js +166 -0
- package/dist/ir/callable-identity-demand.d.ts +52 -0
- package/dist/ir/callable-identity-demand.js +460 -0
- package/dist/ir/callable-member-candidates.d.ts +9 -0
- package/dist/ir/callable-member-candidates.js +39 -0
- package/dist/ir/callable-records.d.ts +21 -0
- package/dist/ir/callable-records.js +411 -0
- package/dist/ir/captures.d.ts +26 -0
- package/dist/ir/captures.js +335 -0
- package/dist/ir/certificate.d.ts +45 -0
- package/dist/ir/certificate.js +47 -0
- package/dist/ir/certify/carrier-keys.d.ts +73 -0
- package/dist/ir/certify/carrier-keys.js +221 -0
- package/dist/ir/certify/function-source.d.ts +4 -0
- package/dist/ir/certify/function-source.js +28 -0
- package/dist/ir/certify/has-property-key.d.ts +88 -0
- package/dist/ir/certify/has-property-key.js +116 -0
- package/dist/ir/certify/instanceof-key.d.ts +24 -0
- package/dist/ir/certify/instanceof-key.js +35 -0
- package/dist/ir/certify/property-access-keys.d.ts +172 -0
- package/dist/ir/certify/property-access-keys.js +291 -0
- package/dist/ir/certify/property-access.d.ts +3 -0
- package/dist/ir/certify/property-access.js +597 -0
- package/dist/ir/certify/runtime-helper.d.ts +3 -0
- package/dist/ir/certify/runtime-helper.js +326 -0
- package/dist/ir/certify/typeof-operand.d.ts +14 -0
- package/dist/ir/certify/typeof-operand.js +16 -0
- package/dist/ir/certify.d.ts +123 -0
- package/dist/ir/certify.js +481 -0
- package/dist/ir/class-evaluation.d.ts +26 -0
- package/dist/ir/class-evaluation.js +50 -0
- package/dist/ir/class-static-fields.d.ts +60 -0
- package/dist/ir/class-static-fields.js +108 -0
- package/dist/ir/construct-entry.d.ts +26 -0
- package/dist/ir/construct-entry.js +117 -0
- package/dist/ir/dead-values.d.ts +90 -0
- package/dist/ir/dead-values.js +184 -0
- package/dist/ir/deferral.d.ts +99 -0
- package/dist/ir/deferral.js +409 -0
- package/dist/ir/dense-loops.d.ts +230 -0
- package/dist/ir/dense-loops.js +697 -0
- package/dist/ir/dominance.d.ts +82 -0
- package/dist/ir/dominance.js +268 -0
- package/dist/ir/emission-representations.d.ts +71 -0
- package/dist/ir/emission-representations.js +350 -0
- package/dist/ir/facts.d.ts +218 -0
- package/dist/ir/facts.js +181 -0
- package/dist/ir/fixed-data-definition.d.ts +19 -0
- package/dist/ir/fixed-data-definition.js +49 -0
- package/dist/ir/generator-split.d.ts +38 -0
- package/dist/ir/generator-split.js +329 -0
- package/dist/ir/hoist.d.ts +55 -0
- package/dist/ir/hoist.js +375 -0
- package/dist/ir/instantiation.d.ts +61 -0
- package/dist/ir/instantiation.js +137 -0
- package/dist/ir/integer-storage.d.ts +170 -0
- package/dist/ir/integer-storage.js +822 -0
- package/dist/ir/integers.d.ts +161 -0
- package/dist/ir/integers.js +539 -0
- package/dist/ir/integrity-restrictions.d.ts +50 -0
- package/dist/ir/integrity-restrictions.js +118 -0
- package/dist/ir/local-iterators.d.ts +4 -0
- package/dist/ir/local-iterators.js +27 -0
- package/dist/ir/lower-allocation.d.ts +4 -0
- package/dist/ir/lower-allocation.js +325 -0
- package/dist/ir/lower-completion.d.ts +15 -0
- package/dist/ir/lower-completion.js +25 -0
- package/dist/ir/lower-destructuring.d.ts +5 -0
- package/dist/ir/lower-destructuring.js +693 -0
- package/dist/ir/lower-element.d.ts +29 -0
- package/dist/ir/lower-element.js +111 -0
- package/dist/ir/lower-exceptions.d.ts +47 -0
- package/dist/ir/lower-exceptions.js +92 -0
- package/dist/ir/lower-flow.d.ts +137 -0
- package/dist/ir/lower-flow.js +600 -0
- package/dist/ir/lower-graph.d.ts +218 -0
- package/dist/ir/lower-graph.js +687 -0
- package/dist/ir/lower-invocation.d.ts +4 -0
- package/dist/ir/lower-invocation.js +514 -0
- package/dist/ir/lower-narrow.d.ts +53 -0
- package/dist/ir/lower-narrow.js +320 -0
- package/dist/ir/lower-operands.d.ts +272 -0
- package/dist/ir/lower-operands.js +461 -0
- package/dist/ir/lower-property.d.ts +21 -0
- package/dist/ir/lower-property.js +132 -0
- package/dist/ir/lower-protocol.d.ts +11 -0
- package/dist/ir/lower-protocol.js +118 -0
- package/dist/ir/lower-short-circuit.d.ts +41 -0
- package/dist/ir/lower-short-circuit.js +63 -0
- package/dist/ir/lower.d.ts +82 -0
- package/dist/ir/lower.js +1346 -0
- package/dist/ir/model.d.ts +1474 -0
- package/dist/ir/model.js +6 -0
- package/dist/ir/native-absent-property.d.ts +3 -0
- package/dist/ir/native-absent-property.js +13 -0
- package/dist/ir/native-array-transport.d.ts +7 -0
- package/dist/ir/native-array-transport.js +46 -0
- package/dist/ir/native-callable-bind.d.ts +9 -0
- package/dist/ir/native-callable-bind.js +30 -0
- package/dist/ir/native-carrier-predicate.d.ts +34 -0
- package/dist/ir/native-carrier-predicate.js +49 -0
- package/dist/ir/native-class-accessor.d.ts +18 -0
- package/dist/ir/native-class-accessor.js +52 -0
- package/dist/ir/native-class-construction.d.ts +16 -0
- package/dist/ir/native-class-construction.js +71 -0
- package/dist/ir/native-class-initialization.d.ts +15 -0
- package/dist/ir/native-class-initialization.js +56 -0
- package/dist/ir/native-class-origins.d.ts +13 -0
- package/dist/ir/native-class-origins.js +237 -0
- package/dist/ir/native-dictionary-transport.d.ts +6 -0
- package/dist/ir/native-dictionary-transport.js +37 -0
- package/dist/ir/native-enumeration.d.ts +14 -0
- package/dist/ir/native-enumeration.js +26 -0
- package/dist/ir/native-equality.d.ts +10 -0
- package/dist/ir/native-equality.js +18 -0
- package/dist/ir/native-field-owner.d.ts +37 -0
- package/dist/ir/native-field-owner.js +183 -0
- package/dist/ir/native-fixed-layout.d.ts +41 -0
- package/dist/ir/native-fixed-layout.js +232 -0
- package/dist/ir/native-host-construction.d.ts +53 -0
- package/dist/ir/native-host-construction.js +62 -0
- package/dist/ir/native-key-query.d.ts +4 -0
- package/dist/ir/native-key-query.js +38 -0
- package/dist/ir/native-merge-transport.d.ts +25 -0
- package/dist/ir/native-merge-transport.js +71 -0
- package/dist/ir/native-record-index-transport.d.ts +11 -0
- package/dist/ir/native-record-index-transport.js +34 -0
- package/dist/ir/native-record-index.d.ts +12 -0
- package/dist/ir/native-record-index.js +27 -0
- package/dist/ir/native-reflect-field.d.ts +5 -0
- package/dist/ir/native-reflect-field.js +33 -0
- package/dist/ir/native-sequence-transport.d.ts +7 -0
- package/dist/ir/native-sequence-transport.js +53 -0
- package/dist/ir/numeric-intrinsics.d.ts +13 -0
- package/dist/ir/numeric-intrinsics.js +57 -0
- package/dist/ir/object-value-conversions.d.ts +20 -0
- package/dist/ir/object-value-conversions.js +50 -0
- package/dist/ir/physical-class-reflection.d.ts +9 -0
- package/dist/ir/physical-class-reflection.js +57 -0
- package/dist/ir/presence-proof.d.ts +42 -0
- package/dist/ir/presence-proof.js +490 -0
- package/dist/ir/program-facts.d.ts +106 -0
- package/dist/ir/program-facts.js +319 -0
- package/dist/ir/proven-branches.d.ts +16 -0
- package/dist/ir/proven-branches.js +219 -0
- package/dist/ir/queries.d.ts +41 -0
- package/dist/ir/queries.js +213 -0
- package/dist/ir/reflection-demand.d.ts +64 -0
- package/dist/ir/reflection-demand.js +1394 -0
- package/dist/ir/refusal.d.ts +43 -0
- package/dist/ir/refusal.js +28 -0
- package/dist/ir/shake.d.ts +37 -0
- package/dist/ir/shake.js +1078 -0
- package/dist/ir/static-callables.d.ts +11 -0
- package/dist/ir/static-callables.js +163 -0
- package/dist/ir/string-layout-reuse.d.ts +13 -0
- package/dist/ir/string-layout-reuse.js +39 -0
- package/dist/ir/string-length-reuse.d.ts +8 -0
- package/dist/ir/string-length-reuse.js +47 -0
- package/dist/ir/transfer.d.ts +78 -0
- package/dist/ir/transfer.js +270 -0
- package/dist/ir/type-query-results.d.ts +25 -0
- package/dist/ir/type-query-results.js +96 -0
- package/dist/ir/typed-property-access.d.ts +100 -0
- package/dist/ir/typed-property-access.js +161 -0
- package/dist/ir/verify.d.ts +19 -0
- package/dist/ir/verify.js +355 -0
- package/dist/plugins/apple/constructors.d.ts +112 -0
- package/dist/plugins/apple/constructors.js +217 -0
- package/dist/plugins/apple/host.d.ts +181 -0
- package/dist/plugins/apple/host.js +262 -0
- package/dist/plugins/apple/jsx.d.ts +2 -0
- package/dist/plugins/apple/jsx.js +293 -0
- package/dist/plugins/apple/members.d.ts +16 -0
- package/dist/plugins/apple/members.js +190 -0
- package/dist/plugins/apple/plugin.d.ts +2 -0
- package/dist/plugins/apple/plugin.js +156 -0
- package/dist/plugins/gea/component-classes.d.ts +25 -0
- package/dist/plugins/gea/component-classes.js +162 -0
- package/dist/plugins/gea/component-inline.d.ts +13 -0
- package/dist/plugins/gea/component-inline.js +532 -0
- package/dist/plugins/gea/constructors.d.ts +23 -0
- package/dist/plugins/gea/constructors.js +100 -0
- package/dist/plugins/gea/contract.d.ts +150 -0
- package/dist/plugins/gea/contract.js +195 -0
- package/dist/plugins/gea/element-ref.d.ts +31 -0
- package/dist/plugins/gea/element-ref.js +45 -0
- package/dist/plugins/gea/host.d.ts +520 -0
- package/dist/plugins/gea/host.js +762 -0
- package/dist/plugins/gea/lower.d.ts +6 -0
- package/dist/plugins/gea/lower.js +195 -0
- package/dist/plugins/gea/members.d.ts +22 -0
- package/dist/plugins/gea/members.js +221 -0
- package/dist/plugins/gea/plugin.d.ts +22 -0
- package/dist/plugins/gea/plugin.js +307 -0
- package/dist/plugins/gea/prelude.d.ts +78 -0
- package/dist/plugins/gea/prelude.js +153 -0
- package/dist/plugins/gea/producer.d.ts +5 -0
- package/dist/plugins/gea/producer.js +52 -0
- package/dist/plugins/gea/reactive-slots.d.ts +49 -0
- package/dist/plugins/gea/reactive-slots.js +578 -0
- package/dist/plugins/gea/render-bridge.d.ts +6 -0
- package/dist/plugins/gea/render-bridge.js +281 -0
- package/dist/plugins/gea/slots.d.ts +15 -0
- package/dist/plugins/gea/slots.js +36 -0
- package/dist/plugins/gea/template-analysis.d.ts +151 -0
- package/dist/plugins/gea/template-analysis.js +346 -0
- package/dist/plugins/gea/user-agent-styles.d.ts +9 -0
- package/dist/plugins/gea/user-agent-styles.js +94 -0
- package/dist/plugins/installed.d.ts +19 -0
- package/dist/plugins/installed.js +21 -0
- package/dist/plugins/load.d.ts +7 -0
- package/dist/plugins/load.js +207 -0
- package/dist/plugins/model.d.ts +735 -0
- package/dist/plugins/model.js +47 -0
- package/dist/plugins/webgl/host.d.ts +77 -0
- package/dist/plugins/webgl/host.js +162 -0
- package/dist/plugins/webgl/plugin.d.ts +40 -0
- package/dist/plugins/webgl/plugin.js +99 -0
- package/dist/preflight/obligations.d.ts +206 -0
- package/dist/preflight/obligations.js +36 -0
- package/dist/preflight/report.d.ts +20 -0
- package/dist/preflight/report.js +61 -0
- package/dist/preflight/run.d.ts +39 -0
- package/dist/preflight/run.js +403 -0
- package/dist/project-preparation.d.ts +33 -0
- package/dist/project-preparation.js +314 -0
- package/dist/projection/abi.d.ts +82 -0
- package/dist/projection/abi.js +349 -0
- package/dist/projection/apply-arguments.d.ts +12 -0
- package/dist/projection/apply-arguments.js +20 -0
- package/dist/projection/bindings.d.ts +250 -0
- package/dist/projection/bindings.js +340 -0
- package/dist/projection/callee.d.ts +196 -0
- package/dist/projection/callee.js +444 -0
- package/dist/projection/class-property-presence.d.ts +28 -0
- package/dist/projection/class-property-presence.js +58 -0
- package/dist/projection/class-prototype.d.ts +5 -0
- package/dist/projection/class-prototype.js +23 -0
- package/dist/projection/class-storage.d.ts +26 -0
- package/dist/projection/class-storage.js +236 -0
- package/dist/projection/classes.d.ts +283 -0
- package/dist/projection/classes.js +944 -0
- package/dist/projection/coercions.d.ts +20 -0
- package/dist/projection/coercions.js +33 -0
- package/dist/projection/dispatch.d.ts +167 -0
- package/dist/projection/dispatch.js +379 -0
- package/dist/projection/fields.d.ts +123 -0
- package/dist/projection/fields.js +383 -0
- package/dist/projection/instance-test.d.ts +78 -0
- package/dist/projection/instance-test.js +156 -0
- package/dist/projection/slots.d.ts +146 -0
- package/dist/projection/slots.js +663 -0
- package/dist/projection/synthesized-abi.d.ts +61 -0
- package/dist/projection/synthesized-abi.js +94 -0
- package/dist/representation/array-index.d.ts +14 -0
- package/dist/representation/array-index.js +17 -0
- package/dist/representation/callable-object.d.ts +3 -0
- package/dist/representation/callable-object.js +6 -0
- package/dist/representation/collections.d.ts +84 -0
- package/dist/representation/collections.js +139 -0
- package/dist/representation/derive.d.ts +159 -0
- package/dist/representation/derive.js +2546 -0
- package/dist/representation/difference.d.ts +30 -0
- package/dist/representation/difference.js +240 -0
- package/dist/representation/field-descriptor-policy.d.ts +19 -0
- package/dist/representation/field-descriptor-policy.js +39 -0
- package/dist/representation/function-constructor.d.ts +13 -0
- package/dist/representation/function-constructor.js +9 -0
- package/dist/representation/host-abi.d.ts +32 -0
- package/dist/representation/host-abi.js +97 -0
- package/dist/representation/host-templates.d.ts +67 -0
- package/dist/representation/host-templates.js +94 -0
- package/dist/representation/intersection.d.ts +84 -0
- package/dist/representation/intersection.js +149 -0
- package/dist/representation/literal-destination.d.ts +43 -0
- package/dist/representation/literal-destination.js +133 -0
- package/dist/representation/merge.d.ts +18 -0
- package/dist/representation/merge.js +83 -0
- package/dist/representation/model.d.ts +1160 -0
- package/dist/representation/model.js +1019 -0
- package/dist/representation/numeric-index.d.ts +13 -0
- package/dist/representation/numeric-index.js +29 -0
- package/dist/representation/object-shape.d.ts +109 -0
- package/dist/representation/object-shape.js +123 -0
- package/dist/representation/optional.d.ts +12 -0
- package/dist/representation/optional.js +87 -0
- package/dist/representation/plan.d.ts +60 -0
- package/dist/representation/plan.js +78 -0
- package/dist/representation/policies.d.ts +589 -0
- package/dist/representation/policies.js +107 -0
- package/dist/representation/primitive-domain.d.ts +1 -0
- package/dist/representation/primitive-domain.js +1 -0
- package/dist/representation/primitives.d.ts +44 -0
- package/dist/representation/primitives.js +78 -0
- package/dist/representation/publish.d.ts +49 -0
- package/dist/representation/publish.js +648 -0
- package/dist/representation/record-fields.d.ts +96 -0
- package/dist/representation/record-fields.js +116 -0
- package/dist/representation/template-object.d.ts +11 -0
- package/dist/representation/template-object.js +26 -0
- package/dist/representation/union.d.ts +30 -0
- package/dist/representation/union.js +324 -0
- package/dist/representation/value-records.d.ts +3 -0
- package/dist/representation/value-records.js +307 -0
- package/dist/representation/verify.d.ts +17 -0
- package/dist/representation/verify.js +221 -0
- package/dist/semantics/alias-this-field-declaration-transform.d.ts +4 -0
- package/dist/semantics/alias-this-field-declaration-transform.js +207 -0
- package/dist/semantics/ambient-type-realization-transform.d.ts +62 -0
- package/dist/semantics/ambient-type-realization-transform.js +168 -0
- package/dist/semantics/ambient.d.ts +24 -0
- package/dist/semantics/ambient.js +119 -0
- package/dist/semantics/borrowed-builtin-call-bind-source-transform.d.ts +4 -0
- package/dist/semantics/borrowed-builtin-call-bind-source-transform.js +341 -0
- package/dist/semantics/callable-origins.d.ts +46 -0
- package/dist/semantics/callable-origins.js +354 -0
- package/dist/semantics/class-alias.d.ts +7 -0
- package/dist/semantics/class-alias.js +37 -0
- package/dist/semantics/class-heritage.d.ts +34 -0
- package/dist/semantics/class-heritage.js +104 -0
- package/dist/semantics/commonjs-wrapper.d.ts +69 -0
- package/dist/semantics/commonjs-wrapper.js +231 -0
- package/dist/semantics/constructor-slot-subclasses.d.ts +28 -0
- package/dist/semantics/constructor-slot-subclasses.js +112 -0
- package/dist/semantics/declaration-overlay-transform.d.ts +35 -0
- package/dist/semantics/declaration-overlay-transform.js +2157 -0
- package/dist/semantics/define-property-source-transform.d.ts +4 -0
- package/dist/semantics/define-property-source-transform.js +437 -0
- package/dist/semantics/diagnostic-source-preparation.d.ts +24 -0
- package/dist/semantics/diagnostic-source-preparation.js +82 -0
- package/dist/semantics/documentation-ranges.d.ts +22 -0
- package/dist/semantics/documentation-ranges.js +36 -0
- package/dist/semantics/dynamic-fallback.d.ts +86 -0
- package/dist/semantics/dynamic-fallback.js +249 -0
- package/dist/semantics/frontend-timing.d.ts +6 -0
- package/dist/semantics/frontend-timing.js +35 -0
- package/dist/semantics/frontend.d.ts +504 -0
- package/dist/semantics/frontend.js +1157 -0
- package/dist/semantics/host-declaration-provenance.d.ts +11 -0
- package/dist/semantics/host-declaration-provenance.js +18 -0
- package/dist/semantics/host-methods.d.ts +24 -0
- package/dist/semantics/host-methods.js +74 -0
- package/dist/semantics/host-protocols.d.ts +429 -0
- package/dist/semantics/host-protocols.js +1501 -0
- package/dist/semantics/inherited-accessor.d.ts +7 -0
- package/dist/semantics/inherited-accessor.js +48 -0
- package/dist/semantics/interface-families.d.ts +70 -0
- package/dist/semantics/interface-families.js +180 -0
- package/dist/semantics/interface-implementors.d.ts +53 -0
- package/dist/semantics/interface-implementors.js +87 -0
- package/dist/semantics/jsdoc-namepath-transform.d.ts +4 -0
- package/dist/semantics/jsdoc-namepath-transform.js +85 -0
- package/dist/semantics/model/coverage.d.ts +68 -0
- package/dist/semantics/model/coverage.js +73 -0
- package/dist/semantics/model/edges.d.ts +103 -0
- package/dist/semantics/model/edges.js +20 -0
- package/dist/semantics/model/graph.d.ts +55 -0
- package/dist/semantics/model/graph.js +129 -0
- package/dist/semantics/model/operands.d.ts +159 -0
- package/dist/semantics/model/operands.js +26 -0
- package/dist/semantics/model/operations.d.ts +496 -0
- package/dist/semantics/model/operations.js +2 -0
- package/dist/semantics/model/primitive-domain.d.ts +26 -0
- package/dist/semantics/model/primitive-domain.js +38 -0
- package/dist/semantics/model/selected-signature.d.ts +261 -0
- package/dist/semantics/model/selected-signature.js +55 -0
- package/dist/semantics/model/structural-type-table.d.ts +93 -0
- package/dist/semantics/model/structural-type-table.js +237 -0
- package/dist/semantics/model/structural-types.d.ts +367 -0
- package/dist/semantics/model/structural-types.js +200 -0
- package/dist/semantics/module-resolution.d.ts +23 -0
- package/dist/semantics/module-resolution.js +227 -0
- package/dist/semantics/new-callee-class-tag-source-transform.d.ts +4 -0
- package/dist/semantics/new-callee-class-tag-source-transform.js +64 -0
- package/dist/semantics/node-project.d.ts +13 -0
- package/dist/semantics/node-project.js +107 -0
- package/dist/semantics/node-source-hooks.d.ts +1 -0
- package/dist/semantics/node-source-hooks.js +63 -0
- package/dist/semantics/normalize/absent-globals.d.ts +143 -0
- package/dist/semantics/normalize/absent-globals.js +191 -0
- package/dist/semantics/normalize/arguments-objects.d.ts +43 -0
- package/dist/semantics/normalize/arguments-objects.js +60 -0
- package/dist/semantics/normalize/asserted-arm-absence.d.ts +28 -0
- package/dist/semantics/normalize/asserted-arm-absence.js +61 -0
- package/dist/semantics/normalize/assignment-patterns.d.ts +70 -0
- package/dist/semantics/normalize/assignment-patterns.js +147 -0
- package/dist/semantics/normalize/bag-absence.d.ts +8 -0
- package/dist/semantics/normalize/bag-absence.js +42 -0
- package/dist/semantics/normalize/binding-fixpoint.d.ts +36 -0
- package/dist/semantics/normalize/binding-fixpoint.js +140 -0
- package/dist/semantics/normalize/callback-parameter-contracts.d.ts +16 -0
- package/dist/semantics/normalize/callback-parameter-contracts.js +91 -0
- package/dist/semantics/normalize/cells/agreement.d.ts +46 -0
- package/dist/semantics/normalize/cells/agreement.js +34 -0
- package/dist/semantics/normalize/cells/candidates.d.ts +17 -0
- package/dist/semantics/normalize/cells/candidates.js +35 -0
- package/dist/semantics/normalize/cells/facts.d.ts +19 -0
- package/dist/semantics/normalize/cells/facts.js +90 -0
- package/dist/semantics/normalize/cells/index.d.ts +10 -0
- package/dist/semantics/normalize/cells/index.js +6 -0
- package/dist/semantics/normalize/cells/model.d.ts +98 -0
- package/dist/semantics/normalize/cells/model.js +2 -0
- package/dist/semantics/normalize/cells/policies/bag.d.ts +44 -0
- package/dist/semantics/normalize/cells/policies/bag.js +114 -0
- package/dist/semantics/normalize/cells/policies/collection.d.ts +42 -0
- package/dist/semantics/normalize/cells/policies/collection.js +218 -0
- package/dist/semantics/normalize/cells/policies/field.d.ts +28 -0
- package/dist/semantics/normalize/cells/policies/field.js +40 -0
- package/dist/semantics/normalize/cells/policies/index.d.ts +49 -0
- package/dist/semantics/normalize/cells/policies/index.js +58 -0
- package/dist/semantics/normalize/cells/policies/local.d.ts +18 -0
- package/dist/semantics/normalize/cells/policies/local.js +37 -0
- package/dist/semantics/normalize/cells/policies/parameter.d.ts +28 -0
- package/dist/semantics/normalize/cells/policies/parameter.js +39 -0
- package/dist/semantics/normalize/cells/policies/return.d.ts +26 -0
- package/dist/semantics/normalize/cells/policies/return.js +45 -0
- package/dist/semantics/normalize/cells/policies/shared.d.ts +33 -0
- package/dist/semantics/normalize/cells/policies/shared.js +45 -0
- package/dist/semantics/normalize/cells/policy.d.ts +72 -0
- package/dist/semantics/normalize/cells/policy.js +18 -0
- package/dist/semantics/normalize/cells/registry.d.ts +14 -0
- package/dist/semantics/normalize/cells/registry.js +17 -0
- package/dist/semantics/normalize/census-refusal.d.ts +62 -0
- package/dist/semantics/normalize/census-refusal.js +27 -0
- package/dist/semantics/normalize/census.d.ts +109 -0
- package/dist/semantics/normalize/census.js +667 -0
- package/dist/semantics/normalize/collection-bindings.d.ts +278 -0
- package/dist/semantics/normalize/collection-bindings.js +677 -0
- package/dist/semantics/normalize/commonjs-module-record.d.ts +21 -0
- package/dist/semantics/normalize/commonjs-module-record.js +289 -0
- package/dist/semantics/normalize/commonjs-require.d.ts +13 -0
- package/dist/semantics/normalize/commonjs-require.js +1527 -0
- package/dist/semantics/normalize/contribution.d.ts +63 -0
- package/dist/semantics/normalize/contribution.js +172 -0
- package/dist/semantics/normalize/dead-typeof-guards.d.ts +64 -0
- package/dist/semantics/normalize/dead-typeof-guards.js +152 -0
- package/dist/semantics/normalize/deferred-intrinsic-protocols.d.ts +57 -0
- package/dist/semantics/normalize/deferred-intrinsic-protocols.js +109 -0
- package/dist/semantics/normalize/derived-expression-type.d.ts +1070 -0
- package/dist/semantics/normalize/derived-expression-type.js +3463 -0
- package/dist/semantics/normalize/evaluation-order.d.ts +16 -0
- package/dist/semantics/normalize/evaluation-order.js +37 -0
- package/dist/semantics/normalize/field-bindings.d.ts +167 -0
- package/dist/semantics/normalize/field-bindings.js +1125 -0
- package/dist/semantics/normalize/flow/array-element-continuation.d.ts +27 -0
- package/dist/semantics/normalize/flow/array-element-continuation.js +1452 -0
- package/dist/semantics/normalize/flow/callable-array-origins.d.ts +42 -0
- package/dist/semantics/normalize/flow/callable-array-origins.js +318 -0
- package/dist/semantics/normalize/flow/callable-completions.d.ts +45 -0
- package/dist/semantics/normalize/flow/callable-completions.js +82 -0
- package/dist/semantics/normalize/flow/callable-reach.d.ts +237 -0
- package/dist/semantics/normalize/flow/callable-reach.js +7174 -0
- package/dist/semantics/normalize/flow/class-family-member-read.d.ts +16 -0
- package/dist/semantics/normalize/flow/class-family-member-read.js +992 -0
- package/dist/semantics/normalize/flow/collection-value-continuation.d.ts +21 -0
- package/dist/semantics/normalize/flow/collection-value-continuation.js +192 -0
- package/dist/semantics/normalize/flow/component-solver.d.ts +199 -0
- package/dist/semantics/normalize/flow/component-solver.js +587 -0
- package/dist/semantics/normalize/flow/computed-key-set.d.ts +84 -0
- package/dist/semantics/normalize/flow/computed-key-set.js +660 -0
- package/dist/semantics/normalize/flow/export-importers.d.ts +24 -0
- package/dist/semantics/normalize/flow/export-importers.js +269 -0
- package/dist/semantics/normalize/flow/host-text-sink.d.ts +25 -0
- package/dist/semantics/normalize/flow/host-text-sink.js +87 -0
- package/dist/semantics/normalize/flow/intrinsic-array-callback-frames.d.ts +84 -0
- package/dist/semantics/normalize/flow/intrinsic-array-callback-frames.js +180 -0
- package/dist/semantics/normalize/flow/intrinsic-data-definition.d.ts +35 -0
- package/dist/semantics/normalize/flow/intrinsic-data-definition.js +140 -0
- package/dist/semantics/normalize/flow/invocation-facts.d.ts +98 -0
- package/dist/semantics/normalize/flow/invocation-facts.js +257 -0
- package/dist/semantics/normalize/flow/member-call-forwarding.d.ts +122 -0
- package/dist/semantics/normalize/flow/member-call-forwarding.js +835 -0
- package/dist/semantics/normalize/flow/model.d.ts +357 -0
- package/dist/semantics/normalize/flow/model.js +177 -0
- package/dist/semantics/normalize/flow/native-collection-protocol.d.ts +24 -0
- package/dist/semantics/normalize/flow/native-collection-protocol.js +252 -0
- package/dist/semantics/normalize/flow/node-path-token.d.ts +3 -0
- package/dist/semantics/normalize/flow/node-path-token.js +53 -0
- package/dist/semantics/normalize/flow/object-binding-continuation.d.ts +11 -0
- package/dist/semantics/normalize/flow/object-binding-continuation.js +42 -0
- package/dist/semantics/normalize/flow/origin-authority.d.ts +56 -0
- package/dist/semantics/normalize/flow/origin-authority.js +2 -0
- package/dist/semantics/normalize/flow/owned-class-receivers.d.ts +35 -0
- package/dist/semantics/normalize/flow/owned-class-receivers.js +191 -0
- package/dist/semantics/normalize/flow/parameter-values.d.ts +27 -0
- package/dist/semantics/normalize/flow/parameter-values.js +251 -0
- package/dist/semantics/normalize/flow/proof-hypotheses.d.ts +66 -0
- package/dist/semantics/normalize/flow/proof-hypotheses.js +162 -0
- package/dist/semantics/normalize/flow/record-alias-closure.d.ts +27 -0
- package/dist/semantics/normalize/flow/record-alias-closure.js +298 -0
- package/dist/semantics/normalize/flow/seeded-origins.d.ts +43 -0
- package/dist/semantics/normalize/flow/seeded-origins.js +54 -0
- package/dist/semantics/normalize/flow/source-class-data.d.ts +132 -0
- package/dist/semantics/normalize/flow/source-class-data.js +838 -0
- package/dist/semantics/normalize/flow/source-class-instanceof.d.ts +13 -0
- package/dist/semantics/normalize/flow/source-class-instanceof.js +37 -0
- package/dist/semantics/normalize/flow/source-class-static-data.d.ts +16 -0
- package/dist/semantics/normalize/flow/source-class-static-data.js +47 -0
- package/dist/semantics/normalize/flow/source-construction-frames.d.ts +12 -0
- package/dist/semantics/normalize/flow/source-construction-frames.js +118 -0
- package/dist/semantics/normalize/flow/source-invocation-frame-layout.d.ts +34 -0
- package/dist/semantics/normalize/flow/source-invocation-frame-layout.js +78 -0
- package/dist/semantics/normalize/flow/source-invocation-receiver.d.ts +37 -0
- package/dist/semantics/normalize/flow/source-invocation-receiver.js +95 -0
- package/dist/semantics/normalize/flow/source-prototype-method-identity.d.ts +23 -0
- package/dist/semantics/normalize/flow/source-prototype-method-identity.js +81 -0
- package/dist/semantics/normalize/flow/source-record-data.d.ts +29 -0
- package/dist/semantics/normalize/flow/source-record-data.js +626 -0
- package/dist/semantics/normalize/flow/source-value-session.d.ts +77 -0
- package/dist/semantics/normalize/flow/source-value-session.js +3089 -0
- package/dist/semantics/normalize/flow/targets.d.ts +118 -0
- package/dist/semantics/normalize/flow/targets.js +405 -0
- package/dist/semantics/normalize/flow/value-flow.d.ts +36 -0
- package/dist/semantics/normalize/flow/value-flow.js +823 -0
- package/dist/semantics/normalize/flow/value-provenance.d.ts +31 -0
- package/dist/semantics/normalize/flow/value-provenance.js +112 -0
- package/dist/semantics/normalize/gating.d.ts +51 -0
- package/dist/semantics/normalize/gating.js +560 -0
- package/dist/semantics/normalize/generic-function-choice.d.ts +31 -0
- package/dist/semantics/normalize/generic-function-choice.js +115 -0
- package/dist/semantics/normalize/global-host-mutations.d.ts +51 -0
- package/dist/semantics/normalize/global-host-mutations.js +5989 -0
- package/dist/semantics/normalize/host-effect-contracts.d.ts +77 -0
- package/dist/semantics/normalize/host-effect-contracts.js +143 -0
- package/dist/semantics/normalize/host-mutation-computed-keys.d.ts +38 -0
- package/dist/semantics/normalize/host-mutation-computed-keys.js +26 -0
- package/dist/semantics/normalize/host-mutation-key-reader.d.ts +66 -0
- package/dist/semantics/normalize/host-mutation-key-reader.js +192 -0
- package/dist/semantics/normalize/host-mutation-keys.d.ts +114 -0
- package/dist/semantics/normalize/host-mutation-keys.js +183 -0
- package/dist/semantics/normalize/identities.d.ts +172 -0
- package/dist/semantics/normalize/identities.js +426 -0
- package/dist/semantics/normalize/implicit-arguments-tuple.d.ts +97 -0
- package/dist/semantics/normalize/implicit-arguments-tuple.js +197 -0
- package/dist/semantics/normalize/implicit-arguments.d.ts +11 -0
- package/dist/semantics/normalize/implicit-arguments.js +39 -0
- package/dist/semantics/normalize/instantiation.d.ts +73 -0
- package/dist/semantics/normalize/instantiation.js +399 -0
- package/dist/semantics/normalize/intrinsic-property-call.d.ts +18 -0
- package/dist/semantics/normalize/intrinsic-property-call.js +69 -0
- package/dist/semantics/normalize/intrinsic-prototype.d.ts +41 -0
- package/dist/semantics/normalize/intrinsic-prototype.js +87 -0
- package/dist/semantics/normalize/intrinsic-static-member.d.ts +14 -0
- package/dist/semantics/normalize/intrinsic-static-member.js +23 -0
- package/dist/semantics/normalize/jsdoc-type-names.d.ts +32 -0
- package/dist/semantics/normalize/jsdoc-type-names.js +512 -0
- package/dist/semantics/normalize/keyof.d.ts +32 -0
- package/dist/semantics/normalize/keyof.js +110 -0
- package/dist/semantics/normalize/local-bindings.d.ts +176 -0
- package/dist/semantics/normalize/local-bindings.js +1826 -0
- package/dist/semantics/normalize/logical-result-type.d.ts +16 -0
- package/dist/semantics/normalize/logical-result-type.js +102 -0
- package/dist/semantics/normalize/namespace-paths.d.ts +57 -0
- package/dist/semantics/normalize/namespace-paths.js +108 -0
- package/dist/semantics/normalize/normalize.d.ts +57 -0
- package/dist/semantics/normalize/normalize.js +68 -0
- package/dist/semantics/normalize/object-bag-bindings.d.ts +305 -0
- package/dist/semantics/normalize/object-bag-bindings.js +1290 -0
- package/dist/semantics/normalize/omitted-stated-parameter.d.ts +53 -0
- package/dist/semantics/normalize/omitted-stated-parameter.js +59 -0
- package/dist/semantics/normalize/open-type-form.d.ts +10 -0
- package/dist/semantics/normalize/open-type-form.js +32 -0
- package/dist/semantics/normalize/parameter-bindings.d.ts +361 -0
- package/dist/semantics/normalize/parameter-bindings.js +3339 -0
- package/dist/semantics/normalize/parameter-slot.d.ts +264 -0
- package/dist/semantics/normalize/parameter-slot.js +491 -0
- package/dist/semantics/normalize/physical-overload-result.d.ts +77 -0
- package/dist/semantics/normalize/physical-overload-result.js +99 -0
- package/dist/semantics/normalize/primitive-property-absence.d.ts +12 -0
- package/dist/semantics/normalize/primitive-property-absence.js +60 -0
- package/dist/semantics/normalize/producer-context.d.ts +376 -0
- package/dist/semantics/normalize/producer-context.js +1 -0
- package/dist/semantics/normalize/producers/allocations.d.ts +3 -0
- package/dist/semantics/normalize/producers/allocations.js +863 -0
- package/dist/semantics/normalize/producers/binding-kind.d.ts +37 -0
- package/dist/semantics/normalize/producers/binding-kind.js +36 -0
- package/dist/semantics/normalize/producers/bindings.d.ts +85 -0
- package/dist/semantics/normalize/producers/bindings.js +710 -0
- package/dist/semantics/normalize/producers/boundary.d.ts +34 -0
- package/dist/semantics/normalize/producers/boundary.js +123 -0
- package/dist/semantics/normalize/producers/class-lifecycle.d.ts +3 -0
- package/dist/semantics/normalize/producers/class-lifecycle.js +902 -0
- package/dist/semantics/normalize/producers/computations.d.ts +3 -0
- package/dist/semantics/normalize/producers/computations.js +613 -0
- package/dist/semantics/normalize/producers/control-loops.d.ts +30 -0
- package/dist/semantics/normalize/producers/control-loops.js +91 -0
- package/dist/semantics/normalize/producers/control.d.ts +30 -0
- package/dist/semantics/normalize/producers/control.js +923 -0
- package/dist/semantics/normalize/producers/declaration-lifecycle.d.ts +3 -0
- package/dist/semantics/normalize/producers/declaration-lifecycle.js +390 -0
- package/dist/semantics/normalize/producers/destructuring.d.ts +45 -0
- package/dist/semantics/normalize/producers/destructuring.js +1180 -0
- package/dist/semantics/normalize/producers/dynamic-language.d.ts +3 -0
- package/dist/semantics/normalize/producers/dynamic-language.js +70 -0
- package/dist/semantics/normalize/producers/erasure.d.ts +51 -0
- package/dist/semantics/normalize/producers/erasure.js +90 -0
- package/dist/semantics/normalize/producers/installed.d.ts +3 -0
- package/dist/semantics/normalize/producers/installed.js +55 -0
- package/dist/semantics/normalize/producers/invocations.d.ts +35 -0
- package/dist/semantics/normalize/producers/invocations.js +1796 -0
- package/dist/semantics/normalize/producers/iteration-yield.d.ts +59 -0
- package/dist/semantics/normalize/producers/iteration-yield.js +235 -0
- package/dist/semantics/normalize/producers/jsx.d.ts +3 -0
- package/dist/semantics/normalize/producers/jsx.js +360 -0
- package/dist/semantics/normalize/producers/mint.d.ts +39 -0
- package/dist/semantics/normalize/producers/mint.js +44 -0
- package/dist/semantics/normalize/producers/nullish.d.ts +16 -0
- package/dist/semantics/normalize/producers/nullish.js +27 -0
- package/dist/semantics/normalize/producers/object-assignment.d.ts +8 -0
- package/dist/semantics/normalize/producers/object-assignment.js +204 -0
- package/dist/semantics/normalize/producers/object-tag.d.ts +9 -0
- package/dist/semantics/normalize/producers/object-tag.js +119 -0
- package/dist/semantics/normalize/producers/optional-chain.d.ts +44 -0
- package/dist/semantics/normalize/producers/optional-chain.js +75 -0
- package/dist/semantics/normalize/producers/properties.d.ts +21 -0
- package/dist/semantics/normalize/producers/properties.js +1053 -0
- package/dist/semantics/normalize/producers/protocol.d.ts +67 -0
- package/dist/semantics/normalize/producers/protocol.js +695 -0
- package/dist/semantics/normalize/producers/references.d.ts +53 -0
- package/dist/semantics/normalize/producers/references.js +1027 -0
- package/dist/semantics/normalize/producers/shared.d.ts +561 -0
- package/dist/semantics/normalize/producers/shared.js +1683 -0
- package/dist/semantics/normalize/producers/spread-arguments.d.ts +72 -0
- package/dist/semantics/normalize/producers/spread-arguments.js +375 -0
- package/dist/semantics/normalize/producers/tagged-template.d.ts +5 -0
- package/dist/semantics/normalize/producers/tagged-template.js +307 -0
- package/dist/semantics/normalize/producers/tuple-spread.d.ts +189 -0
- package/dist/semantics/normalize/producers/tuple-spread.js +279 -0
- package/dist/semantics/normalize/property-key-domain.d.ts +36 -0
- package/dist/semantics/normalize/property-key-domain.js +150 -0
- package/dist/semantics/normalize/reachability.d.ts +189 -0
- package/dist/semantics/normalize/reachability.js +1057 -0
- package/dist/semantics/normalize/reassigned-bindings.d.ts +13 -0
- package/dist/semantics/normalize/reassigned-bindings.js +41 -0
- package/dist/semantics/normalize/record-storage-families.d.ts +11 -0
- package/dist/semantics/normalize/record-storage-families.js +109 -0
- package/dist/semantics/normalize/return-bindings.d.ts +260 -0
- package/dist/semantics/normalize/return-bindings.js +1311 -0
- package/dist/semantics/normalize/return-paths.d.ts +2 -0
- package/dist/semantics/normalize/return-paths.js +28 -0
- package/dist/semantics/normalize/script-global-redefinition.d.ts +44 -0
- package/dist/semantics/normalize/script-global-redefinition.js +75 -0
- package/dist/semantics/normalize/specialization.d.ts +201 -0
- package/dist/semantics/normalize/specialization.js +1824 -0
- package/dist/semantics/normalize/structural-array-element.d.ts +176 -0
- package/dist/semantics/normalize/structural-array-element.js +700 -0
- package/dist/semantics/normalize/structural-array-read.d.ts +13 -0
- package/dist/semantics/normalize/structural-array-read.js +124 -0
- package/dist/semantics/normalize/structural-callable.d.ts +12 -0
- package/dist/semantics/normalize/structural-callable.js +82 -0
- package/dist/semantics/normalize/structural-creation-order.d.ts +32 -0
- package/dist/semantics/normalize/structural-creation-order.js +111 -0
- package/dist/semantics/normalize/structural-declarations.d.ts +395 -0
- package/dist/semantics/normalize/structural-declarations.js +968 -0
- package/dist/semantics/normalize/structural-declared-body.d.ts +25 -0
- package/dist/semantics/normalize/structural-declared-body.js +147 -0
- package/dist/semantics/normalize/structural-generics.d.ts +56 -0
- package/dist/semantics/normalize/structural-generics.js +120 -0
- package/dist/semantics/normalize/structural-indexed-access.d.ts +11 -0
- package/dist/semantics/normalize/structural-indexed-access.js +126 -0
- package/dist/semantics/normalize/structural-instantiated-member.d.ts +64 -0
- package/dist/semantics/normalize/structural-instantiated-member.js +407 -0
- package/dist/semantics/normalize/structural-joins.d.ts +44 -0
- package/dist/semantics/normalize/structural-joins.js +143 -0
- package/dist/semantics/normalize/structural-layout-relevance.d.ts +29 -0
- package/dist/semantics/normalize/structural-layout-relevance.js +391 -0
- package/dist/semantics/normalize/structural-layout-type.d.ts +11 -0
- package/dist/semantics/normalize/structural-layout-type.js +1468 -0
- package/dist/semantics/normalize/structural-leaves.d.ts +49 -0
- package/dist/semantics/normalize/structural-leaves.js +125 -0
- package/dist/semantics/normalize/structural-local-union.d.ts +13 -0
- package/dist/semantics/normalize/structural-local-union.js +133 -0
- package/dist/semantics/normalize/structural-members.d.ts +26 -0
- package/dist/semantics/normalize/structural-members.js +84 -0
- package/dist/semantics/normalize/structural-mutable-method.d.ts +15 -0
- package/dist/semantics/normalize/structural-mutable-method.js +109 -0
- package/dist/semantics/normalize/structural-parts.d.ts +131 -0
- package/dist/semantics/normalize/structural-parts.js +737 -0
- package/dist/semantics/normalize/structural-receiver.d.ts +66 -0
- package/dist/semantics/normalize/structural-receiver.js +551 -0
- package/dist/semantics/normalize/structural-rules.d.ts +112 -0
- package/dist/semantics/normalize/structural-rules.js +93 -0
- package/dist/semantics/normalize/structural-self-reference.d.ts +150 -0
- package/dist/semantics/normalize/structural-self-reference.js +494 -0
- package/dist/semantics/normalize/structural.d.ts +202 -0
- package/dist/semantics/normalize/structural.js +4218 -0
- package/dist/semantics/normalize/unreduced-type-form.d.ts +41 -0
- package/dist/semantics/normalize/unreduced-type-form.js +53 -0
- package/dist/semantics/normalize/unresolvable-names.d.ts +56 -0
- package/dist/semantics/normalize/unresolvable-names.js +140 -0
- package/dist/semantics/package-sources.d.ts +16 -0
- package/dist/semantics/package-sources.js +365 -0
- package/dist/semantics/program.d.ts +151 -0
- package/dist/semantics/program.js +667 -0
- package/dist/semantics/prototype-install-source-transform.d.ts +4 -0
- package/dist/semantics/prototype-install-source-transform.js +341 -0
- package/dist/semantics/prototype-object-class-source-transform.d.ts +4 -0
- package/dist/semantics/prototype-object-class-source-transform.js +525 -0
- package/dist/semantics/prototype-reparenting.d.ts +50 -0
- package/dist/semantics/prototype-reparenting.js +317 -0
- package/dist/semantics/stable-checker.d.ts +10 -0
- package/dist/semantics/stable-checker.js +148 -0
- package/dist/semantics/subclass-member-overlay-transform.d.ts +35 -0
- package/dist/semantics/subclass-member-overlay-transform.js +1418 -0
- package/dist/semantics/symbol-keyed-expando-source-transform.d.ts +4 -0
- package/dist/semantics/symbol-keyed-expando-source-transform.js +66 -0
- package/dist/semantics/this-constructor-source-transform.d.ts +4 -0
- package/dist/semantics/this-constructor-source-transform.js +122 -0
- package/dist/semantics/uninstantiable-classes.d.ts +22 -0
- package/dist/semantics/uninstantiable-classes.js +75 -0
- package/dist/targets/cpp/balanced-units.d.ts +3 -0
- package/dist/targets/cpp/balanced-units.js +58 -0
- package/dist/targets/cpp/borrowed-call-entry.d.ts +30 -0
- package/dist/targets/cpp/borrowed-call-entry.js +68 -0
- package/dist/targets/cpp/captures.d.ts +68 -0
- package/dist/targets/cpp/captures.js +269 -0
- package/dist/targets/cpp/class-layout.d.ts +313 -0
- package/dist/targets/cpp/class-layout.js +483 -0
- package/dist/targets/cpp/class-properties/computed-method-value.d.ts +25 -0
- package/dist/targets/cpp/class-properties/computed-method-value.js +22 -0
- package/dist/targets/cpp/class-properties/emit-class-properties.d.ts +216 -0
- package/dist/targets/cpp/class-properties/emit-class-properties.js +917 -0
- package/dist/targets/cpp/class-properties/native-prototype.d.ts +11 -0
- package/dist/targets/cpp/class-properties/native-prototype.js +101 -0
- package/dist/targets/cpp/class-ref-transport.d.ts +12 -0
- package/dist/targets/cpp/class-ref-transport.js +32 -0
- package/dist/targets/cpp/conversions.d.ts +3 -0
- package/dist/targets/cpp/conversions.js +2027 -0
- package/dist/targets/cpp/deferral-safety.d.ts +82 -0
- package/dist/targets/cpp/deferral-safety.js +86 -0
- package/dist/targets/cpp/direct-call-receivers.d.ts +37 -0
- package/dist/targets/cpp/direct-call-receivers.js +79 -0
- package/dist/targets/cpp/document.d.ts +74 -0
- package/dist/targets/cpp/document.js +106 -0
- package/dist/targets/cpp/emit-allocation.d.ts +60 -0
- package/dist/targets/cpp/emit-allocation.js +573 -0
- package/dist/targets/cpp/emit-arrays.d.ts +119 -0
- package/dist/targets/cpp/emit-arrays.js +1047 -0
- package/dist/targets/cpp/emit-binding-reference.d.ts +17 -0
- package/dist/targets/cpp/emit-binding-reference.js +120 -0
- package/dist/targets/cpp/emit-bindings.d.ts +158 -0
- package/dist/targets/cpp/emit-bindings.js +769 -0
- package/dist/targets/cpp/emit-buffers.d.ts +156 -0
- package/dist/targets/cpp/emit-buffers.js +573 -0
- package/dist/targets/cpp/emit-callable.d.ts +230 -0
- package/dist/targets/cpp/emit-callable.js +2154 -0
- package/dist/targets/cpp/emit-carrier-members.d.ts +406 -0
- package/dist/targets/cpp/emit-carrier-members.js +1224 -0
- package/dist/targets/cpp/emit-coercion.d.ts +26 -0
- package/dist/targets/cpp/emit-coercion.js +39 -0
- package/dist/targets/cpp/emit-context.d.ts +1882 -0
- package/dist/targets/cpp/emit-context.js +904 -0
- package/dist/targets/cpp/emit-dynamic-properties.d.ts +174 -0
- package/dist/targets/cpp/emit-dynamic-properties.js +1249 -0
- package/dist/targets/cpp/emit-equality.d.ts +39 -0
- package/dist/targets/cpp/emit-equality.js +472 -0
- package/dist/targets/cpp/emit-exceptions.d.ts +104 -0
- package/dist/targets/cpp/emit-exceptions.js +513 -0
- package/dist/targets/cpp/emit-field-owner.d.ts +4 -0
- package/dist/targets/cpp/emit-field-owner.js +27 -0
- package/dist/targets/cpp/emit-in.d.ts +31 -0
- package/dist/targets/cpp/emit-in.js +426 -0
- package/dist/targets/cpp/emit-instanceof.d.ts +19 -0
- package/dist/targets/cpp/emit-instanceof.js +601 -0
- package/dist/targets/cpp/emit-integers.d.ts +68 -0
- package/dist/targets/cpp/emit-integers.js +184 -0
- package/dist/targets/cpp/emit-iterator.d.ts +100 -0
- package/dist/targets/cpp/emit-iterator.js +1137 -0
- package/dist/targets/cpp/emit-json.d.ts +73 -0
- package/dist/targets/cpp/emit-json.js +823 -0
- package/dist/targets/cpp/emit-jsx.d.ts +74 -0
- package/dist/targets/cpp/emit-jsx.js +806 -0
- package/dist/targets/cpp/emit-mixed-binary.d.ts +51 -0
- package/dist/targets/cpp/emit-mixed-binary.js +60 -0
- package/dist/targets/cpp/emit-namespaces.d.ts +101 -0
- package/dist/targets/cpp/emit-namespaces.js +133 -0
- package/dist/targets/cpp/emit-narrowing.d.ts +738 -0
- package/dist/targets/cpp/emit-narrowing.js +3967 -0
- package/dist/targets/cpp/emit-native-equality.d.ts +3 -0
- package/dist/targets/cpp/emit-native-equality.js +14 -0
- package/dist/targets/cpp/emit-native-selection.d.ts +5 -0
- package/dist/targets/cpp/emit-native-selection.js +37 -0
- package/dist/targets/cpp/emit-object-tag.d.ts +4 -0
- package/dist/targets/cpp/emit-object-tag.js +108 -0
- package/dist/targets/cpp/emit-owned-record.d.ts +2 -0
- package/dist/targets/cpp/emit-owned-record.js +15 -0
- package/dist/targets/cpp/emit-presence.d.ts +78 -0
- package/dist/targets/cpp/emit-presence.js +376 -0
- package/dist/targets/cpp/emit-properties.d.ts +105 -0
- package/dist/targets/cpp/emit-properties.js +1640 -0
- package/dist/targets/cpp/emit-record-view.d.ts +20 -0
- package/dist/targets/cpp/emit-record-view.js +354 -0
- package/dist/targets/cpp/emit-return.d.ts +5 -0
- package/dist/targets/cpp/emit-return.js +237 -0
- package/dist/targets/cpp/emit-sum-widening.d.ts +10 -0
- package/dist/targets/cpp/emit-sum-widening.js +69 -0
- package/dist/targets/cpp/emit-tonumber.d.ts +38 -0
- package/dist/targets/cpp/emit-tonumber.js +177 -0
- package/dist/targets/cpp/emit-tostring.d.ts +92 -0
- package/dist/targets/cpp/emit-tostring.js +556 -0
- package/dist/targets/cpp/emit-typeof.d.ts +49 -0
- package/dist/targets/cpp/emit-typeof.js +317 -0
- package/dist/targets/cpp/emit-union-properties.d.ts +181 -0
- package/dist/targets/cpp/emit-union-properties.js +1281 -0
- package/dist/targets/cpp/emit.d.ts +45 -0
- package/dist/targets/cpp/emit.js +2225 -0
- package/dist/targets/cpp/error-types.d.ts +4 -0
- package/dist/targets/cpp/error-types.js +11 -0
- package/dist/targets/cpp/function-source-reads.d.ts +72 -0
- package/dist/targets/cpp/function-source-reads.js +148 -0
- package/dist/targets/cpp/host/atomics.d.ts +25 -0
- package/dist/targets/cpp/host/atomics.js +63 -0
- package/dist/targets/cpp/host/core-globals.d.ts +108 -0
- package/dist/targets/cpp/host/core-globals.js +158 -0
- package/dist/targets/cpp/host/dynamic-argument-members.d.ts +42 -0
- package/dist/targets/cpp/host/dynamic-argument-members.js +61 -0
- package/dist/targets/cpp/host/emit-host-arity.d.ts +139 -0
- package/dist/targets/cpp/host/emit-host-arity.js +232 -0
- package/dist/targets/cpp/host/emit-host-invoke.d.ts +91 -0
- package/dist/targets/cpp/host/emit-host-invoke.js +1105 -0
- package/dist/targets/cpp/host/emit-host-object.d.ts +55 -0
- package/dist/targets/cpp/host/emit-host-object.js +2206 -0
- package/dist/targets/cpp/host/emit-host-properties.d.ts +69 -0
- package/dist/targets/cpp/host/emit-host-properties.js +533 -0
- package/dist/targets/cpp/host/emit-host-reflect.d.ts +4 -0
- package/dist/targets/cpp/host/emit-host-reflect.js +180 -0
- package/dist/targets/cpp/host/emit-host-value.d.ts +120 -0
- package/dist/targets/cpp/host/emit-host-value.js +392 -0
- package/dist/targets/cpp/host/host-members.d.ts +505 -0
- package/dist/targets/cpp/host/host-members.js +819 -0
- package/dist/targets/cpp/host/host-method-aliases.d.ts +30 -0
- package/dist/targets/cpp/host/host-method-aliases.js +76 -0
- package/dist/targets/cpp/host/native-protocols.d.ts +47 -0
- package/dist/targets/cpp/host/native-protocols.js +183 -0
- package/dist/targets/cpp/host/object-protocol.d.ts +351 -0
- package/dist/targets/cpp/host/object-protocol.js +671 -0
- package/dist/targets/cpp/host-namespace-reads.d.ts +83 -0
- package/dist/targets/cpp/host-namespace-reads.js +113 -0
- package/dist/targets/cpp/manifest/capabilities.d.ts +39 -0
- package/dist/targets/cpp/manifest/capabilities.js +1484 -0
- package/dist/targets/cpp/manifest.d.ts +23 -0
- package/dist/targets/cpp/manifest.js +113 -0
- package/dist/targets/cpp/native-error-base.d.ts +38 -0
- package/dist/targets/cpp/native-error-base.js +74 -0
- package/dist/targets/cpp/native-narrowing-transport.d.ts +12 -0
- package/dist/targets/cpp/native-narrowing-transport.js +151 -0
- package/dist/targets/cpp/native-selection-helpers.d.ts +11 -0
- package/dist/targets/cpp/native-selection-helpers.js +46 -0
- package/dist/targets/cpp/native-symbol-keys.d.ts +8 -0
- package/dist/targets/cpp/native-symbol-keys.js +34 -0
- package/dist/targets/cpp/ownership.d.ts +43 -0
- package/dist/targets/cpp/ownership.js +38 -0
- package/dist/targets/cpp/owning-conversion-input.d.ts +14 -0
- package/dist/targets/cpp/owning-conversion-input.js +12 -0
- package/dist/targets/cpp/property-read-claims.d.ts +62 -0
- package/dist/targets/cpp/property-read-claims.js +23 -0
- package/dist/targets/cpp/property-store-claims.d.ts +62 -0
- package/dist/targets/cpp/property-store-claims.js +26 -0
- package/dist/targets/cpp/prototype/emit-prototype-array.d.ts +111 -0
- package/dist/targets/cpp/prototype/emit-prototype-array.js +602 -0
- package/dist/targets/cpp/prototype/emit-prototype-date.d.ts +133 -0
- package/dist/targets/cpp/prototype/emit-prototype-date.js +515 -0
- package/dist/targets/cpp/prototype/emit-prototype-error.d.ts +13 -0
- package/dist/targets/cpp/prototype/emit-prototype-error.js +54 -0
- package/dist/targets/cpp/prototype/emit-prototype-invoke.d.ts +34 -0
- package/dist/targets/cpp/prototype/emit-prototype-invoke.js +1003 -0
- package/dist/targets/cpp/prototype/emit-prototype-iterator.d.ts +47 -0
- package/dist/targets/cpp/prototype/emit-prototype-iterator.js +250 -0
- package/dist/targets/cpp/prototype/emit-prototype-promise.d.ts +46 -0
- package/dist/targets/cpp/prototype/emit-prototype-promise.js +143 -0
- package/dist/targets/cpp/prototype/emit-prototype-regexp.d.ts +335 -0
- package/dist/targets/cpp/prototype/emit-prototype-regexp.js +853 -0
- package/dist/targets/cpp/prototype/emit-prototype-string.d.ts +42 -0
- package/dist/targets/cpp/prototype/emit-prototype-string.js +252 -0
- package/dist/targets/cpp/prototype/prototype-method-reads.d.ts +25 -0
- package/dist/targets/cpp/prototype/prototype-method-reads.js +182 -0
- package/dist/targets/cpp/reactive-dependencies.d.ts +140 -0
- package/dist/targets/cpp/reactive-dependencies.js +432 -0
- package/dist/targets/cpp/reactive-origins.d.ts +44 -0
- package/dist/targets/cpp/reactive-origins.js +82 -0
- package/dist/targets/cpp/records.d.ts +277 -0
- package/dist/targets/cpp/records.js +2427 -0
- package/dist/targets/cpp/recursive-containers.d.ts +43 -0
- package/dist/targets/cpp/recursive-containers.js +144 -0
- package/dist/targets/cpp/regexp-types.d.ts +56 -0
- package/dist/targets/cpp/regexp-types.js +59 -0
- package/dist/targets/cpp/substrate.d.ts +125 -0
- package/dist/targets/cpp/substrate.js +12 -0
- package/dist/targets/cpp/translation-unit.d.ts +219 -0
- package/dist/targets/cpp/translation-unit.js +2063 -0
- package/dist/targets/cpp/types.d.ts +280 -0
- package/dist/targets/cpp/types.js +1135 -0
- package/dist/targets/cpp/virtual-methods.d.ts +95 -0
- package/dist/targets/cpp/virtual-methods.js +264 -0
- package/package.json +95 -0
- package/src/targets/cpp/runtime/gea_dynamic_proxy.h +824 -0
- package/src/targets/cpp/runtime/gea_eval.h +1376 -0
- package/src/targets/cpp/runtime/gea_native_class_prototype.h +44 -0
- package/src/targets/cpp/runtime/gea_runtime.h +29222 -0
- package/src/targets/cpp/runtime/gea_runtime_builtins.cpp +55 -0
|
@@ -0,0 +1,2063 @@
|
|
|
1
|
+
import { nativeSelectionHelpers } from './native-selection-helpers.js';
|
|
2
|
+
import { cppErrorNativeType } from './error-types.js';
|
|
3
|
+
import { isNativeErrorBaseRefusal, nativeErrorBaseInitializeStatements } from './native-error-base.js';
|
|
4
|
+
import { classFieldStorageOwnerOf, classMemberOf, classMethodOverrideOf } from '../../projection/fields.js';
|
|
5
|
+
import { balanceCppUnits } from './balanced-units.js';
|
|
6
|
+
import { stableBorrowEntryOf } from './borrowed-call-entry.js';
|
|
7
|
+
import { programFactsOf } from '../../ir/program-facts.js';
|
|
8
|
+
import { nativeOrdinaryConstructInstanceMatches } from '../../ir/construct-entry.js';
|
|
9
|
+
import { fileIdentityOf, isRegionId } from '../../identity/ids.js';
|
|
10
|
+
import { constructedBaseOf, runtimeClassLayoutsOf } from '../../projection/classes.js';
|
|
11
|
+
import { allOperationsOf } from '../../ir/model.js';
|
|
12
|
+
import { representationKey } from '../../representation/model.js';
|
|
13
|
+
import { hostCallName } from './host/host-members.js';
|
|
14
|
+
import { reactiveBoundRecordFields, reactiveDependenciesOfBodies } from './reactive-dependencies.js';
|
|
15
|
+
import { buildDirectCallableIndex, buildCaptureIndex } from './captures.js';
|
|
16
|
+
import { createCppDocumentBuilder, emptyCppFacts, render, spliceRendered } from './document.js';
|
|
17
|
+
import { beginUnionAliasing, endUnionAliasing } from './types.js';
|
|
18
|
+
import { cppConstructedThunkName, cppConstructThunkName, cppFormalName, cppReceiverName, cppThunkName, emitBody, isCppEmitBlockedError } from './emit.js';
|
|
19
|
+
import { cppCaptureFieldName, cppCaptureReceiverFieldName, cppEnvironmentLocalName, cppEnvironmentParamName, cppEnvironmentSlotName, cppEnvironmentStructName, effectiveAbiOf, symbolKeyDefinitions, templateObjectDefinitions } from './emit-context.js';
|
|
20
|
+
import { censusClassStaticFieldStorage, censusLazyArrowFields, classBoxable, cppFieldInitializerStatements, publishBoxableClasses, publishClassStaticFieldStorage, publishLazyArrowFieldPlans } from './class-layout.js';
|
|
21
|
+
import { classStaticFieldStorageRows, cppRecordDeclarations, cppStructNameOf, declaredFieldRepresentationOf, declaredRecordFieldOf, recordAccessorBodiesOf, representationNamesMintedStruct, withUnreadParametersUnnamed } from './records.js';
|
|
22
|
+
import { prototypeReadHooks, virtualMethodEmission, virtualMethodFamiliesOf } from './virtual-methods.js';
|
|
23
|
+
import { virtualDispatchVerdictOf } from '../../projection/dispatch.js';
|
|
24
|
+
import { stringConstantsOf } from '../../ir/dead-values.js';
|
|
25
|
+
import { integerParameterSlot, integerResultSlot, integerStorageCensusOf, integerStorageSlot } from '../../ir/integer-storage.js';
|
|
26
|
+
import { classesConstructedUnobservably, functionsIgnoringTheirReceiver } from '../../ir/instantiation.js';
|
|
27
|
+
import { renderJsonStructDeclarations } from './emit-json.js';
|
|
28
|
+
import { alignedValueText } from './emit-narrowing.js';
|
|
29
|
+
import { recordLayoutPolicyOf } from '../../projection/fields.js';
|
|
30
|
+
import { cppAbiParameterType, cppAbiType, cppStringLiteral, cppStringViewLiteral, cppBodyName, cppCallableDeclarationTagName, cppCommonJsModuleName, cppCommonJsRecordName, cppNarrowedIntegerType, cppRefcountedReceiver, cppBoxedType, cppClassName, cppConstructName, cppGlobalName, cppInitializeName, cppRecordFieldName, cppRecordStructName, cppResultTypeOf, cppTypeOf, sanitizeForCppIdentifier } from './types.js';
|
|
31
|
+
import { buildHostMethodAliasIndex } from './host/host-method-aliases.js';
|
|
32
|
+
import { cppRecursiveContainerDeclarations, cppRecursiveContainerTraceEdges } from './recursive-containers.js';
|
|
33
|
+
/**
|
|
34
|
+
* One C++ translation unit, assembled from what earlier stages sealed.
|
|
35
|
+
*
|
|
36
|
+
* Assembly is the last place where order is a decision rather than a fact, and
|
|
37
|
+
* there are exactly two ordering constraints: a struct must be declared before
|
|
38
|
+
* a body mentions it, and a body must be declared before a thunk names it.
|
|
39
|
+
* Everything else -- which body comes first, which struct -- is already fixed
|
|
40
|
+
* deterministically upstream, and re-deciding it here would make two runs over
|
|
41
|
+
* one program differ for no reason a reader could name.
|
|
42
|
+
*
|
|
43
|
+
* Every body is forward-declared before any body is defined, so a call to a
|
|
44
|
+
* function defined later in the file, and mutual recursion between two of them,
|
|
45
|
+
* both resolve. Emitting definitions in a dependency order instead would make
|
|
46
|
+
* this file re-derive a call graph the semantic layer already published, and
|
|
47
|
+
* would still have no answer for a cycle.
|
|
48
|
+
*
|
|
49
|
+
* The certificate is a parameter and not a courtesy. Emission is what turns a
|
|
50
|
+
* missing capability into a crash halfway through a file, so the type requires
|
|
51
|
+
* proof that preflight cleared before any text is produced.
|
|
52
|
+
*/
|
|
53
|
+
/**
|
|
54
|
+
* The prelude every emitted unit needs.
|
|
55
|
+
*
|
|
56
|
+
* `gea_runtime.h` is the compiled-once runtime (`targets/cpp/runtime/`), and it
|
|
57
|
+
* is included rather than inlined so that the carriers it defines have one
|
|
58
|
+
* definition across every translation unit this compiler emits -- an inlined
|
|
59
|
+
* copy per file is a second definition waiting to drift from the first.
|
|
60
|
+
*/
|
|
61
|
+
const standardIncludes = ['#include <cmath>', '#include <cstdint>', '#include <memory>', '#include <string>'];
|
|
62
|
+
/**
|
|
63
|
+
* The compiled-once runtime, LAST of the preludes.
|
|
64
|
+
*
|
|
65
|
+
* Last because a host's own header, when the unit needs one, has to be seen
|
|
66
|
+
* first: `gea_runtime.h` carries stand-ins for the engine's types so that a
|
|
67
|
+
* program using none of them still compiles standalone, and those stand-ins
|
|
68
|
+
* step aside for the real definitions by asking whether the host declared
|
|
69
|
+
* itself (`GEA_HOST_DECLARED`, the guard the plugin's own preamble defines).
|
|
70
|
+
* A question asked before the answer exists is answered wrong -- 23 "definition
|
|
71
|
+
* of type X conflicts with type alias of the same name", one per stand-in.
|
|
72
|
+
*/
|
|
73
|
+
const runtimeInclude = '#include "gea_runtime.h"';
|
|
74
|
+
/**
|
|
75
|
+
* The host headers this particular unit needs, and no others.
|
|
76
|
+
*
|
|
77
|
+
* A host's templates name types this compiler never wrote -- `NSStackView` is
|
|
78
|
+
* declared by the Apple bridge, not by `gea_runtime.h` -- so a unit that uses
|
|
79
|
+
* one has to include the host's declarations. Decided from the carriers the
|
|
80
|
+
* plan actually selected rather than from which plugins were installed: a
|
|
81
|
+
* compilation with the Apple plugin installed and no Apple type in the program
|
|
82
|
+
* must emit no Apple header, or every gea program starts carrying AppKit.
|
|
83
|
+
*/
|
|
84
|
+
const hostIncludesOf = (representations, hosts) => {
|
|
85
|
+
if (hosts.includes.size === 0)
|
|
86
|
+
return [];
|
|
87
|
+
const headers = new Set();
|
|
88
|
+
for (const carrier of representations) {
|
|
89
|
+
if (carrier.kind !== 'native-handle' || carrier.native === null)
|
|
90
|
+
continue;
|
|
91
|
+
const header = hosts.includes.get(carrier.native);
|
|
92
|
+
if (header !== undefined)
|
|
93
|
+
headers.add(header);
|
|
94
|
+
}
|
|
95
|
+
return [...headers].sort().map((header) => `#include "${header}"`);
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* The declarations this unit must carry before it may name a host's spellings.
|
|
99
|
+
*
|
|
100
|
+
* Decided from the PLACEMENTS, the way `hostIncludesOf` is decided from the
|
|
101
|
+
* plan: a program that names no host global carries no host declaration, and a
|
|
102
|
+
* compilation with a plugin installed but none of its globals used emits
|
|
103
|
+
* nothing of the plugin's.
|
|
104
|
+
*
|
|
105
|
+
* A namespace contributes what its MEMBERS require rather than what its own
|
|
106
|
+
* name does, because the members are what the tables state -- there is no row
|
|
107
|
+
* for the bare path `deviceInfo`, only for `gea::host::device_info::deviceId`
|
|
108
|
+
* and
|
|
109
|
+
* its siblings. A unit that names the namespace at all can reach any of them,
|
|
110
|
+
* so it takes the union: the declarations for a namespace it uses, not for a
|
|
111
|
+
* member it happens to call.
|
|
112
|
+
*/
|
|
113
|
+
const hostPreamblesOf = (representations, placements, hosts, bodies) => {
|
|
114
|
+
if (hosts.preambles.size === 0)
|
|
115
|
+
return [];
|
|
116
|
+
const spellings = new Set();
|
|
117
|
+
for (const body of bodies) {
|
|
118
|
+
for (const block of body.blocks.values()) {
|
|
119
|
+
for (const operation of block.operations) {
|
|
120
|
+
if (operation.kind !== 'get' || !operation.hostMethod)
|
|
121
|
+
continue;
|
|
122
|
+
const member = hosts.members.get(`${operation.hostMethod.protocol}.${operation.hostMethod.member}`);
|
|
123
|
+
if (member?.kind === 'method')
|
|
124
|
+
spellings.add(member.emit);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// A carrier contributes what its MEMBERS require, the same rule a namespace
|
|
129
|
+
// gets below and for the same reason: the tables state rows for
|
|
130
|
+
// `<carrier>.fillRect`, never for the carrier's bare name. A unit that holds
|
|
131
|
+
// a value of that carrier at all can reach any of its members, so it takes
|
|
132
|
+
// the union rather than guessing which ones a body calls -- and the plan is
|
|
133
|
+
// where holding one is decided.
|
|
134
|
+
for (const carrier of representations) {
|
|
135
|
+
if (carrier.kind !== 'native-handle' || carrier.native === null)
|
|
136
|
+
continue;
|
|
137
|
+
const prefix = `${carrier.native}.`;
|
|
138
|
+
for (const [key, member] of hosts.members) {
|
|
139
|
+
if (!key.startsWith(prefix))
|
|
140
|
+
continue;
|
|
141
|
+
if (member.emit !== null)
|
|
142
|
+
spellings.add(member.emit);
|
|
143
|
+
if (member.kind === 'property' && member.store !== null)
|
|
144
|
+
spellings.add(member.store);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
for (const placement of placements.values()) {
|
|
148
|
+
const storage = placement.storage;
|
|
149
|
+
if (storage.kind === 'host-function' || storage.kind === 'host-constant') {
|
|
150
|
+
spellings.add(storage.emit);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (storage.kind !== 'host-namespace')
|
|
154
|
+
continue;
|
|
155
|
+
const prefix = `${storage.linkageName}.`;
|
|
156
|
+
for (const [path, spelling] of hosts.namespaces.methods)
|
|
157
|
+
if (path.startsWith(prefix))
|
|
158
|
+
spellings.add(hostCallName(spelling));
|
|
159
|
+
for (const [path, emit] of hosts.namespaces.properties)
|
|
160
|
+
if (path.startsWith(prefix))
|
|
161
|
+
spellings.add(emit);
|
|
162
|
+
}
|
|
163
|
+
const lines = new Set();
|
|
164
|
+
for (const spelling of [...spellings].sort()) {
|
|
165
|
+
for (const line of hosts.preambles.get(spelling) ?? [])
|
|
166
|
+
lines.add(line);
|
|
167
|
+
}
|
|
168
|
+
return [...lines];
|
|
169
|
+
};
|
|
170
|
+
const storageSpelling = (type, name) => ({
|
|
171
|
+
declaration: `extern ${type} ${name};`,
|
|
172
|
+
definition: `${type} ${name};`
|
|
173
|
+
});
|
|
174
|
+
/**
|
|
175
|
+
* File-scope variables for the cells a run-once region owns.
|
|
176
|
+
*
|
|
177
|
+
* A cell whose carrier the plan never selected is skipped rather than given a
|
|
178
|
+
* guessed type -- the body that reads it then refuses by name, which is the
|
|
179
|
+
* answer, instead of this file inventing a layout to make the file compile.
|
|
180
|
+
*/
|
|
181
|
+
const globalStorage = (placements, omit) => [...placements.entries()]
|
|
182
|
+
.filter(([declaration, placement]) => placement.storage.kind === 'region' && placement.representation !== null && !omit.has(declaration))
|
|
183
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
184
|
+
.flatMap(([declaration, placement]) => {
|
|
185
|
+
const representation = placement.representation;
|
|
186
|
+
if (!representation || representation.kind === 'unresolved' || representation.kind === 'void')
|
|
187
|
+
return [];
|
|
188
|
+
return [storageSpelling(cppTypeOf(representation), cppGlobalName(declaration))];
|
|
189
|
+
});
|
|
190
|
+
const absentDefinitions = (placements) => [...placements.entries()]
|
|
191
|
+
.filter(([, placement]) => placement.storage.kind === 'absent' && placement.representation !== null)
|
|
192
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
193
|
+
.flatMap(([declaration, placement]) => {
|
|
194
|
+
const representation = placement.representation;
|
|
195
|
+
if (!representation || representation.kind === 'unresolved' || representation.kind === 'void')
|
|
196
|
+
return [];
|
|
197
|
+
const spelling = storageSpelling(cppTypeOf(representation), cppGlobalName(declaration));
|
|
198
|
+
return [{ text: spelling.definition, declaration: spelling.declaration, representation }];
|
|
199
|
+
});
|
|
200
|
+
const externDeclarations = (placements) => [...placements.entries()]
|
|
201
|
+
.filter(([, placement]) => placement.storage.kind === 'external' && placement.representation !== null)
|
|
202
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
203
|
+
.flatMap(([, placement]) => {
|
|
204
|
+
const { storage, representation } = placement;
|
|
205
|
+
if (storage.kind !== 'external' || !representation || representation.kind === 'unresolved' || representation.kind === 'void') {
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
return [{ text: `extern ${cppTypeOf(representation)} ${storage.linkageName};`, representation }];
|
|
209
|
+
});
|
|
210
|
+
/** The formals one calling convention declares, receiver first, in the order `cppAbiType` keys them. */
|
|
211
|
+
/**
|
|
212
|
+
* A body's formals.
|
|
213
|
+
*
|
|
214
|
+
* `narrowed` is the whole-program integer census's answer for this body's own
|
|
215
|
+
* positions (`ir/integer-storage.ts`): a `number` formal every call site writes
|
|
216
|
+
* an integer into is declared `long long`, so the body works in one rather than
|
|
217
|
+
* converting at entry and back at every recursive call. It is the BODY's
|
|
218
|
+
* spelling only -- the ABI, the `CallableObject` carrier and the thunk's own
|
|
219
|
+
* external signature all keep the convention every caller agrees on, and the
|
|
220
|
+
* thunk casts across (`thunkOf`). Passing an empty set gives the ABI spelling,
|
|
221
|
+
* which is what the thunk and the constructor definitions want.
|
|
222
|
+
*/
|
|
223
|
+
const formalsOf = (abi, narrowed = new Set(), borrowReceiver = false, borrowed = new Set()) => [
|
|
224
|
+
...(abi.receiver === null
|
|
225
|
+
? []
|
|
226
|
+
: [`${borrowReceiver ? `const ${cppTypeOf(abi.receiver)}&` : cppTypeOf(abi.receiver)} ${cppReceiverName}`]),
|
|
227
|
+
...abi.parameters.map((parameter, ordinal) => {
|
|
228
|
+
const type = narrowed.has(ordinal)
|
|
229
|
+
? cppNarrowedIntegerType
|
|
230
|
+
: borrowed.has(ordinal)
|
|
231
|
+
? `const ${cppAbiParameterType(parameter)}&`
|
|
232
|
+
: cppAbiParameterType(parameter);
|
|
233
|
+
return `${type} ${cppFormalName(ordinal)}`;
|
|
234
|
+
})
|
|
235
|
+
];
|
|
236
|
+
/**
|
|
237
|
+
* The formals a *body itself* declares, as opposed to the ones its thunk
|
|
238
|
+
* exposes externally.
|
|
239
|
+
*
|
|
240
|
+
* A capturing body gets one extra leading formal -- a pointer to its own
|
|
241
|
+
* environment struct -- that no caller ever supplies directly and no ABI
|
|
242
|
+
* states: it is populated by the thunk's own unpacking, from the pointer
|
|
243
|
+
* `CallableObject.environment` carries. `effectiveAbi` already carries the
|
|
244
|
+
* *captured* receiver's type in `.receiver` when one applies (see
|
|
245
|
+
* `effectiveAbiOf`), so `formalsOf(effectiveAbi)` alone renders the receiver
|
|
246
|
+
* formal correctly either way; only the environment pointer itself is this
|
|
247
|
+
* function's own addition.
|
|
248
|
+
*/
|
|
249
|
+
const bodyFormalsOf = (owner, effectiveAbi, admission, narrowed, borrowReceiver, borrowed = new Set()) => [
|
|
250
|
+
...(admission.kind === 'ok' ? [`${cppEnvironmentStructName(owner)}* ${cppEnvironmentLocalName}`] : []),
|
|
251
|
+
...formalsOf(effectiveAbi, narrowed, borrowReceiver, borrowed)
|
|
252
|
+
];
|
|
253
|
+
/**
|
|
254
|
+
* Whether this body is emitted as a C++20 coroutine -- `emit.ts`'s `emitYield`
|
|
255
|
+
* renders `co_yield`, which makes the whole function one.
|
|
256
|
+
*
|
|
257
|
+
* Asked of the body's own DECLARATION rather than of its result carrier: a
|
|
258
|
+
* function that merely RETURNS a `gea::Iterator<T>` (the `get-iterator` step
|
|
259
|
+
* over an array builds and returns one, and `function makeGen() { return g() }`
|
|
260
|
+
* hands back a generator's cursor unchanged) is an ordinary function, and its
|
|
261
|
+
* result carrier is the very same `iterator(source: generator)` a real
|
|
262
|
+
* `function*` publishes -- the carrier cannot tell them apart, only the
|
|
263
|
+
* `function*` itself can.
|
|
264
|
+
*/
|
|
265
|
+
const isCoroutineBody = (body) => body.generator === true || [...body.blocks.values()].some((block) => block.operations.some((operation) => operation.kind === 'yield'));
|
|
266
|
+
/**
|
|
267
|
+
* Whether this body may take its receiver by reference.
|
|
268
|
+
*
|
|
269
|
+
* Only a receiver the ABI itself states, never a CAPTURED one: a captured
|
|
270
|
+
* receiver is a field of an environment the callable owns, and binding a
|
|
271
|
+
* reference to it would outlive nothing this frame can see. A stated receiver
|
|
272
|
+
* is an argument the caller evaluates -- a local it owns for the whole call, or
|
|
273
|
+
* a temporary whose lifetime a `const&` parameter already extends past it.
|
|
274
|
+
*
|
|
275
|
+
* NEVER for a coroutine, and that is a correctness rule rather than a
|
|
276
|
+
* preference. C++20 copies a coroutine's parameters into the frame, but a
|
|
277
|
+
* REFERENCE parameter is copied as a reference: the frame holds a reference to
|
|
278
|
+
* whatever the caller passed. A coroutine suspends at `initial_suspend`
|
|
279
|
+
* (`gea::Iterator<E>::promise_type`, runtime/gea_runtime.h) and returns to its
|
|
280
|
+
* caller immediately, so by the time the first `next()` resumes the body, the
|
|
281
|
+
* caller's own argument -- the thunk's by-value `gea_this`, which is what every
|
|
282
|
+
* generator method is reached through -- is long destroyed and the reference
|
|
283
|
+
* dangles.
|
|
284
|
+
*
|
|
285
|
+
* That produced a program that certified, cleared clang with no warning, and
|
|
286
|
+
* read freed memory: `class Counter { *[Symbol.iterator]() { for (let i = 0; i
|
|
287
|
+
* < this.limit; ...) yield i } }` walked zero elements, because `this->limit`
|
|
288
|
+
* read a destroyed refcount handle. Whether the loop runs at all is undefined
|
|
289
|
+
* behaviour, which is exactly why no gate above this one could have caught it.
|
|
290
|
+
*/
|
|
291
|
+
const borrowsReceiver = (body) => body.abi?.receiver != null && cppRefcountedReceiver(body.abi.receiver) && !isCoroutineBody(body);
|
|
292
|
+
/**
|
|
293
|
+
* The environment struct one capturing function's allocation populates and
|
|
294
|
+
* its thunk unpacks, or `null` for a function that captures nothing.
|
|
295
|
+
*
|
|
296
|
+
* One struct per capturing function, not a shared layout, because two
|
|
297
|
+
* closures capture different cells in general and a shared struct would need
|
|
298
|
+
* a field for everything any closure anywhere ever captures. Declared ahead
|
|
299
|
+
* of every body signature (`renderTranslationUnit`), because a body's own
|
|
300
|
+
* formal names this struct as a pointer type before any body is defined.
|
|
301
|
+
*/
|
|
302
|
+
const environmentDeclarationOf = (owner, admission) => {
|
|
303
|
+
if (admission.kind !== 'ok')
|
|
304
|
+
return null;
|
|
305
|
+
const fields = [
|
|
306
|
+
...admission.layout.slots.map((slot, index) => ` ${slot.boxed ? cppBoxedType(slot.representation) : cppTypeOf(slot.representation)} ${cppCaptureFieldName(index)};`),
|
|
307
|
+
...(admission.layout.receiver !== null ? [` ${cppTypeOf(admission.layout.receiver)} ${cppCaptureReceiverFieldName};`] : [])
|
|
308
|
+
];
|
|
309
|
+
const traceFields = [
|
|
310
|
+
...admission.layout.slots.map((_, index) => cppCaptureFieldName(index)),
|
|
311
|
+
...(admission.layout.receiver !== null ? [cppCaptureReceiverFieldName] : [])
|
|
312
|
+
];
|
|
313
|
+
const traceableFields = traceFields.map((field) => `gea::detail::TraceEdges<decltype(${field})>::supported`);
|
|
314
|
+
return [
|
|
315
|
+
`struct ${cppEnvironmentStructName(owner)} {`,
|
|
316
|
+
...fields,
|
|
317
|
+
// Same reasoning as `records.ts`'s own `geaTraceRefs`: whether any capture
|
|
318
|
+
// in this environment reaches a ref is a program-wide fact (which types
|
|
319
|
+
// this closure happened to capture), not something this struct's own
|
|
320
|
+
// renderer predicts, so it is marked unconditionally rather than only
|
|
321
|
+
// when `traceableFields` looks empty from here.
|
|
322
|
+
` [[maybe_unused]] friend auto geaTraceRefs(const ${cppEnvironmentStructName(owner)}& value, gea::detail::RefVisitor& visitor)`,
|
|
323
|
+
` -> std::bool_constant<${traceableFields.length ? traceableFields.join(' || ') : 'false'}> {`,
|
|
324
|
+
...traceFields.map((field) => ` gea::detail::traceRefs(value.${field}, visitor);`),
|
|
325
|
+
' return {};',
|
|
326
|
+
' }',
|
|
327
|
+
'};'
|
|
328
|
+
].join('\n');
|
|
329
|
+
};
|
|
330
|
+
/**
|
|
331
|
+
* What one class's initialization runs against an object that already exists --
|
|
332
|
+
* everything `[[Construct]]` does after `OrdinaryCreateFromConstructor`.
|
|
333
|
+
*
|
|
334
|
+
* The three shapes are the language's three, not a convenience split:
|
|
335
|
+
*
|
|
336
|
+
* - A **base** class runs its own field initializers in declaration order, then
|
|
337
|
+
* its constructor body. The order matters: a constructor that reads a field
|
|
338
|
+
* before its initializer ran must read the initialized value, not a zeroed
|
|
339
|
+
* struct member.
|
|
340
|
+
* - A **derived class with a written constructor** runs *only* that body. Its
|
|
341
|
+
* own field initializers do not belong here at all: the language runs them at
|
|
342
|
+
* the `super(...)` call, after the base chain returns and before the next
|
|
343
|
+
* statement of the constructor, and `emit.ts`'s super-initialization is where
|
|
344
|
+
* that happens. Running them here as well would initialize each field twice
|
|
345
|
+
* and, worse, would run them before a base constructor that the derived
|
|
346
|
+
* constructor may deliberately let observe them absent.
|
|
347
|
+
* - A **derived class with no written constructor** has the implicit
|
|
348
|
+
* `constructor(...args) { super(...args) }`: the base's initialization takes
|
|
349
|
+
* this construction's own arguments unchanged, and the field initializers run
|
|
350
|
+
* after it returns.
|
|
351
|
+
*/
|
|
352
|
+
const initializationStatements = (site, deriver, classes, layout, abi, actuals, bodyAbis) => {
|
|
353
|
+
const fieldInitializers = cppFieldInitializerStatements(site, layout.declaration, layout.fields, cppReceiverName, (field) => layout.instance === null ? null : declaredRecordFieldOf(deriver, layout.instance, field.key, classes));
|
|
354
|
+
if (typeof fieldInitializers === 'string')
|
|
355
|
+
return fieldInitializers;
|
|
356
|
+
let constructorCall = [];
|
|
357
|
+
if (layout.constructor) {
|
|
358
|
+
const bodyAbi = bodyAbis.get(String(layout.constructor));
|
|
359
|
+
if (!bodyAbi)
|
|
360
|
+
return `its constructor body ${layout.constructor} published no callable ABI`;
|
|
361
|
+
if (bodyAbi.parameters.length !== abi.parameters.length) {
|
|
362
|
+
return `its construct convention declares ${abi.parameters.length} parameter(s), but constructor body ${layout.constructor} declares ${bodyAbi.parameters.length}`;
|
|
363
|
+
}
|
|
364
|
+
const converted = [];
|
|
365
|
+
for (let index = 0; index < actuals.length; index += 1) {
|
|
366
|
+
const source = abi.parameters[index]?.value;
|
|
367
|
+
const target = bodyAbi.parameters[index]?.value;
|
|
368
|
+
const actual = actuals[index];
|
|
369
|
+
if (!source || !target || actual === undefined)
|
|
370
|
+
return `its constructor parameter ${index} has no complete ABI mapping`;
|
|
371
|
+
const text = alignedValueText(site, 'translation-unit.ts:722', source, target, actual);
|
|
372
|
+
if (text === null) {
|
|
373
|
+
return (`its construct parameter ${index} carries ${representationKey(source)}, while constructor body ${layout.constructor} carries ` +
|
|
374
|
+
`${representationKey(target)}, and no conversion is installed between them`);
|
|
375
|
+
}
|
|
376
|
+
converted.push(text);
|
|
377
|
+
}
|
|
378
|
+
constructorCall = [`${cppBodyName(layout.constructor)}(${[cppReceiverName, ...converted].join(', ')});`];
|
|
379
|
+
}
|
|
380
|
+
if (constructedBaseOf(layout) === null && layout.nativeBase === null)
|
|
381
|
+
return [...fieldInitializers, ...constructorCall];
|
|
382
|
+
if (layout.constructor)
|
|
383
|
+
return constructorCall;
|
|
384
|
+
if (layout.nativeBase !== null) {
|
|
385
|
+
// The implicit `constructor(...args) { super(...args) }` forwards this
|
|
386
|
+
// construction's own arguments to the native base unchanged, which is
|
|
387
|
+
// exactly what `emitSuperInitialize` renders for a class that writes the
|
|
388
|
+
// constructor out -- so it is the same shared renderer, not a second
|
|
389
|
+
// reading of 20.5.1.1. The field initializers follow it for the same
|
|
390
|
+
// reason they follow a written `super()`: the language runs them once the
|
|
391
|
+
// base chain has returned.
|
|
392
|
+
if (layout.nativeBase.instance.native !== cppErrorNativeType) {
|
|
393
|
+
return (`it extends native base ${layout.nativeBase.protocol}, which uses "${layout.nativeBase.instance.native ?? 'no native layout'}"; ` +
|
|
394
|
+
'only the intrinsic Error layout has an existing-receiver initializer');
|
|
395
|
+
}
|
|
396
|
+
const baseStatements = nativeErrorBaseInitializeStatements(deriver, cppReceiverName, abi.parameters.slice(0, 2).map((parameter, index) => {
|
|
397
|
+
const actual = actuals[index];
|
|
398
|
+
return actual === undefined ? undefined : { representation: parameter.value, text: actual };
|
|
399
|
+
}));
|
|
400
|
+
if (isNativeErrorBaseRefusal(baseStatements))
|
|
401
|
+
return baseStatements.reason;
|
|
402
|
+
return [...baseStatements, ...fieldInitializers];
|
|
403
|
+
}
|
|
404
|
+
const baseDeclaration = layout.base;
|
|
405
|
+
if (baseDeclaration === null)
|
|
406
|
+
return 'it has no base class after native-base handling';
|
|
407
|
+
const base = classes.get(baseDeclaration);
|
|
408
|
+
if (!base || !base.construct) {
|
|
409
|
+
return `its base ${layout.base} published no construct convention, so the implicit \`super(...)\` has no frame to fill`;
|
|
410
|
+
}
|
|
411
|
+
// The implicit constructor forwards every argument positionally, so the two
|
|
412
|
+
// conventions have to agree on how many there are. They do whenever the
|
|
413
|
+
// checker gave the derived class its base's construct signature, which is
|
|
414
|
+
// what it does for a class that declares no constructor -- a disagreement
|
|
415
|
+
// here is a fact about the program this file cannot repair by dropping or
|
|
416
|
+
// inventing an argument.
|
|
417
|
+
if (base.construct.parameters.length !== abi.parameters.length) {
|
|
418
|
+
return (`it declares no constructor, so its implicit one forwards all ${abi.parameters.length} argument(s) to ` +
|
|
419
|
+
`base ${baseDeclaration}, whose construct convention declares ${base.construct.parameters.length}`);
|
|
420
|
+
}
|
|
421
|
+
return [`${cppInitializeName(baseDeclaration)}(${[cppReceiverName, ...actuals].join(', ')});`, ...fieldInitializers];
|
|
422
|
+
};
|
|
423
|
+
// `[[maybe_unused]]` because whether a minted function has a user in this unit
|
|
424
|
+
// is a property of the PROGRAM, not of the generator: a thunk exists so a body
|
|
425
|
+
// CAN be taken as a value, and a program that never does so leaves a correct,
|
|
426
|
+
// unreferenced definition behind. Only internal linkage needs it -- an external
|
|
427
|
+
// one is nameable from another unit, so no compiler can call it unused. Without
|
|
428
|
+
// it the shipping ESP-IDF component, which compiles with `-Wall -Wextra
|
|
429
|
+
// -Werror`, refuses the emitted unit outright: 114 of one app's 289
|
|
430
|
+
// warnings were this one diagnostic.
|
|
431
|
+
const linkagePrefix = (linkage) => (linkage === 'internal' ? '[[maybe_unused]] static ' : '');
|
|
432
|
+
const constructionsOf = (site, deriver, classes, refused, linkage, bodyAbis,
|
|
433
|
+
/** The classes whose struct holds `gea_method_state` statically -- `cppRecordDeclarations`' own report, never re-derived here. */
|
|
434
|
+
staticMethodStateClasses = new Set()) => {
|
|
435
|
+
// Layout-only classes publish no requested construction. Every runtime
|
|
436
|
+
// construction still passes the complete ABI/initialization checks below.
|
|
437
|
+
const ordered = [...runtimeClassLayoutsOf(classes)].sort((left, right) => left.declaration.localeCompare(right.declaration));
|
|
438
|
+
const extended = new Set(ordered.flatMap((layout) => (layout.base === null ? [] : [layout.base])));
|
|
439
|
+
const constructions = [];
|
|
440
|
+
for (const layout of ordered) {
|
|
441
|
+
const abi = layout.construct;
|
|
442
|
+
const instance = layout.instance;
|
|
443
|
+
if (!abi || !instance || instance.kind !== 'class-ref') {
|
|
444
|
+
refused.push({
|
|
445
|
+
owner: layout.declaration,
|
|
446
|
+
reason: `class ${layout.declaration} published no construct convention, so no construction can be rendered for it`,
|
|
447
|
+
key: 'print:refused'
|
|
448
|
+
});
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
const formals = abi.parameters.map((parameter, ordinal) => `${cppAbiParameterType(parameter)} ${cppFormalName(ordinal)}`);
|
|
452
|
+
// Each parameter is forwarded exactly once. Preserve borrowed ABI slots,
|
|
453
|
+
// and transfer owned strings, optionals and handles instead of undoing
|
|
454
|
+
// the moves performed by the caller and the constructor body.
|
|
455
|
+
const actuals = abi.parameters.map((parameter, ordinal) => `std::forward<${cppAbiParameterType(parameter)}>(${cppFormalName(ordinal)})`);
|
|
456
|
+
const statements = initializationStatements(site, deriver, classes, layout, abi, actuals, bodyAbis);
|
|
457
|
+
if (typeof statements === 'string') {
|
|
458
|
+
refused.push({
|
|
459
|
+
owner: layout.declaration,
|
|
460
|
+
reason: `class ${layout.declaration} cannot be constructed: ${statements}`,
|
|
461
|
+
key: 'print:refused'
|
|
462
|
+
});
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
const result = cppTypeOf(instance);
|
|
466
|
+
const prefix = linkagePrefix(linkage);
|
|
467
|
+
const initializerName = cppInitializeName(layout.declaration);
|
|
468
|
+
// A base class with no field initializers and no written constructor body
|
|
469
|
+
// (`statements` empty) never reads its own receiver -- same "deliberately
|
|
470
|
+
// unused formal" shape `records.ts`'s reflection hooks already spell by
|
|
471
|
+
// omitting the name, applied here via the same helper rather than a
|
|
472
|
+
// second `[[maybe_unused]]`-on-parameters idiom this file would have to
|
|
473
|
+
// invent and keep in sync.
|
|
474
|
+
const initializerSignature = withUnreadParametersUnnamed(`${prefix}void ${initializerName}(${[`${result} ${cppReceiverName}`, ...formals].join(', ')})`, statements);
|
|
475
|
+
let initializerPrototype = null;
|
|
476
|
+
const definitions = [];
|
|
477
|
+
// Only a class something extends is ever initialized through a receiver it
|
|
478
|
+
// did not allocate, so only such a class needs the half emitted separately;
|
|
479
|
+
// every other construction inlines the same statements.
|
|
480
|
+
if (extended.has(layout.declaration)) {
|
|
481
|
+
initializerPrototype = `${initializerSignature};`;
|
|
482
|
+
definitions.push([`${initializerSignature} {`, ...statements, '}'].join('\n'));
|
|
483
|
+
}
|
|
484
|
+
const name = cppConstructName(layout.declaration);
|
|
485
|
+
// A raw pointer, not a `Ref`: the caller reads it off a class cell it
|
|
486
|
+
// holds for the whole call (the cell's `environmentOwner` owns the
|
|
487
|
+
// state), and a `Ref` argument was a retain and a release of the SAME
|
|
488
|
+
// shared count around every construction -- in `binary_trees`' `build`
|
|
489
|
+
// the two read-modify-writes and the release's branches were the hottest
|
|
490
|
+
// lines after the construct itself.
|
|
491
|
+
const stateFormal = 'gea::NativeClassMethodState* gea_method_state';
|
|
492
|
+
const constructSignature = `${prefix}${result} ${name}(${[stateFormal, ...formals].join(', ')})`;
|
|
493
|
+
const thunkSignature = `${prefix}${result} ${cppConstructThunkName(layout.declaration)}(${['void* gea_environment', ...formals].join(', ')})`;
|
|
494
|
+
const allocation = `${result} ${cppReceiverName} = gea::makeRef<${cppClassName(layout.declaration)}>();`;
|
|
495
|
+
const initialization = extended.has(layout.declaration)
|
|
496
|
+
? [`${initializerName}(${[cppReceiverName, ...actuals].join(', ')});`]
|
|
497
|
+
: statements;
|
|
498
|
+
// A static state (`records.ts`'s `staticMethodState`) is the one the
|
|
499
|
+
// program's single evaluation minted: fill it in on first construction
|
|
500
|
+
// and thereafter only confirm it, cheaper than a handle copy per instance
|
|
501
|
+
// and unable to disagree with the per-instance store it replaces. It goes
|
|
502
|
+
// BEFORE the allocation so that nothing with a call in it (the first
|
|
503
|
+
// fill's release of the old handle) sits between `makeRef`'s
|
|
504
|
+
// zero-initialization of the fields and the constructor body's stores:
|
|
505
|
+
// with a call in between, clang cannot see that a field it is about to
|
|
506
|
+
// move-assign still holds the null it was just given, and re-tests the
|
|
507
|
+
// old value of every handle field for something to release.
|
|
508
|
+
const className = cppClassName(layout.declaration);
|
|
509
|
+
const staticState = staticMethodStateClasses.has(layout.declaration);
|
|
510
|
+
const adoptedState = 'gea::Ref<gea::NativeClassMethodState>::adopt(gea_method_state, true)';
|
|
511
|
+
definitions.push([
|
|
512
|
+
`${constructSignature} {`,
|
|
513
|
+
...(staticState
|
|
514
|
+
? [`if (${className}::gea_method_state.get() != gea_method_state) ${className}::gea_method_state = ${adoptedState};`]
|
|
515
|
+
: []),
|
|
516
|
+
allocation,
|
|
517
|
+
...(staticState ? [] : [`${cppReceiverName}->gea_method_state = ${adoptedState};`]),
|
|
518
|
+
...initialization,
|
|
519
|
+
`return ${cppReceiverName};`,
|
|
520
|
+
'}'
|
|
521
|
+
].join('\n'), `${thunkSignature} { return ${name}(${['static_cast<gea::NativeClassMethodState*>(gea_environment)', ...actuals].join(', ')}); }`);
|
|
522
|
+
constructions.push({
|
|
523
|
+
declaration: layout.declaration,
|
|
524
|
+
initializerPrototype,
|
|
525
|
+
constructPrototypes: [`${constructSignature};`, `${thunkSignature};`],
|
|
526
|
+
definitions
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
return constructions;
|
|
530
|
+
};
|
|
531
|
+
/**
|
|
532
|
+
* Every class's construction as one flat section, in the order the single-unit
|
|
533
|
+
* layout has always used: every initializer declared ahead of every definition,
|
|
534
|
+
* so a base defined after the derived class that calls it -- or a chain of any
|
|
535
|
+
* depth -- resolves without this file computing an order. Construct wrappers
|
|
536
|
+
* need no prototype there: each is defined before any body, and its thunk
|
|
537
|
+
* follows it directly.
|
|
538
|
+
*/
|
|
539
|
+
const constructDefinitionsOf = (constructions) => [
|
|
540
|
+
...constructions.flatMap((construction) => (construction.initializerPrototype === null ? [] : [construction.initializerPrototype])),
|
|
541
|
+
...constructions.flatMap((construction) => construction.definitions)
|
|
542
|
+
];
|
|
543
|
+
/**
|
|
544
|
+
* One body's C++ signature.
|
|
545
|
+
*
|
|
546
|
+
* `void ...()` for a body with no convention is not a fallback: a module body,
|
|
547
|
+
* a field initializer, and a static block are evaluated, never called, so they
|
|
548
|
+
* genuinely take nothing and return nothing. A callable body spells the ABI the
|
|
549
|
+
* projection published, so the frame it reads and the frame it declares are the
|
|
550
|
+
* same object rather than two agreeing guesses.
|
|
551
|
+
*/
|
|
552
|
+
const signatureOf = (body, captures, narrowed = new Set(), narrowedResult = false, borrowed = new Set(), name = cppBodyName(body.sourceOwner)) => {
|
|
553
|
+
// A body with no convention is entered by the region walker, or by nothing at
|
|
554
|
+
// all when its region is never reached -- so an unreferenced definition here
|
|
555
|
+
// is a fact about the program, not a defect in the emission. A callable body
|
|
556
|
+
// is not marked: something demanded its ABI, so an unused one is worth seeing.
|
|
557
|
+
if (!body.abi)
|
|
558
|
+
return `[[maybe_unused]] void ${name}()`;
|
|
559
|
+
const admission = captures.of(body.sourceOwner);
|
|
560
|
+
const effectiveAbi = effectiveAbiOf(body.abi, admission) ?? body.abi;
|
|
561
|
+
const result = narrowedResult ? cppNarrowedIntegerType : cppResultTypeOf(effectiveAbi.result);
|
|
562
|
+
const formals = bodyFormalsOf(body.sourceOwner, effectiveAbi, admission, narrowed, borrowsReceiver(body), borrowed);
|
|
563
|
+
return `${result} ${name}(${formals.join(', ')})`;
|
|
564
|
+
};
|
|
565
|
+
const thunkOf = (body, captures, narrowed, narrowedResult, linkage, preserveFunctionFacts) => {
|
|
566
|
+
if (!body.abi)
|
|
567
|
+
return null;
|
|
568
|
+
const abi = body.abi;
|
|
569
|
+
const admission = captures.of(body.sourceOwner);
|
|
570
|
+
const hasEnvironment = admission.kind === 'ok';
|
|
571
|
+
const formals = [hasEnvironment ? `void* ${cppEnvironmentParamName}` : 'void*', ...formalsOf(abi)];
|
|
572
|
+
// One pointer of stack, which `gea::unpackEnvironment` copies the captured
|
|
573
|
+
// state into where the state fits in the pointer the carrier holds and
|
|
574
|
+
// ignores where the state is on the heap. Declared here rather than inside
|
|
575
|
+
// the helper because a heap environment's members must not be constructed
|
|
576
|
+
// once per call just to be overwritten by a pointer cast.
|
|
577
|
+
const unpack = hasEnvironment
|
|
578
|
+
? `alignas(void*) unsigned char ${cppEnvironmentSlotName}[sizeof(void*)]; ` +
|
|
579
|
+
`auto* ${cppEnvironmentLocalName} = gea::unpackEnvironment<${cppEnvironmentStructName(body.sourceOwner)}>(${cppEnvironmentParamName}, ${cppEnvironmentSlotName}); `
|
|
580
|
+
: '';
|
|
581
|
+
const receiverActual = abi.receiver !== null
|
|
582
|
+
? [cppReceiverName]
|
|
583
|
+
: admission.kind === 'ok' && admission.layout.receiver !== null
|
|
584
|
+
? [`${cppEnvironmentLocalName}->${cppCaptureReceiverFieldName}`]
|
|
585
|
+
: [];
|
|
586
|
+
const call = `${cppBodyName(body.sourceOwner)}(${[
|
|
587
|
+
...(hasEnvironment ? [cppEnvironmentLocalName] : []),
|
|
588
|
+
...receiverActual,
|
|
589
|
+
// The thunk's own formals stay the ABI's, so the carrier's function-pointer
|
|
590
|
+
// type is unchanged; a narrowed body formal is converted here, at the one
|
|
591
|
+
// boundary where the two spellings meet.
|
|
592
|
+
...abi.parameters.map((parameter, ordinal) => narrowed.has(ordinal)
|
|
593
|
+
? `static_cast<${cppNarrowedIntegerType}>(${cppFormalName(ordinal)})`
|
|
594
|
+
: `std::forward<${cppAbiParameterType(parameter)}>(${cppFormalName(ordinal)})`)
|
|
595
|
+
].join(', ')})`;
|
|
596
|
+
// The thunk's own result stays the ABI's, so the carrier's function-pointer
|
|
597
|
+
// type is unchanged; a narrowed body result converts back here.
|
|
598
|
+
const returned = narrowedResult ? `static_cast<${cppResultTypeOf(abi.result)}>(${call})` : call;
|
|
599
|
+
const statement = `${unpack}${abi.result.kind === 'void' ? `${call};` : `return ${returned};`}`;
|
|
600
|
+
const signature = `${linkagePrefix(linkage)}${cppResultTypeOf(abi.result)} ${cppThunkName(body.sourceOwner)}(${formals.join(', ')})`;
|
|
601
|
+
const construct = constructThunkOf(body, abi, hasEnvironment, linkage);
|
|
602
|
+
return {
|
|
603
|
+
prototype: [`${signature};`, ...(construct === null ? [] : [construct.prototype])].join('\n'),
|
|
604
|
+
definition: [
|
|
605
|
+
`${signature} { ${statement} }`,
|
|
606
|
+
...(!preserveFunctionFacts || body.functionSource === undefined
|
|
607
|
+
? []
|
|
608
|
+
: [
|
|
609
|
+
`[[maybe_unused]] static const bool ${cppThunkName(body.sourceOwner)}_source = ` +
|
|
610
|
+
`gea::CallableObject<${cppAbiType(abi)}>::registerSource<&${cppThunkName(body.sourceOwner)}>(` +
|
|
611
|
+
`${cppStringViewLiteral(body.functionName ?? '')}, ${body.functionLength ?? 0}, ${cppStringViewLiteral(body.functionSource)});`
|
|
612
|
+
]),
|
|
613
|
+
...(construct === null ? [] : [construct.definition])
|
|
614
|
+
].join('\n')
|
|
615
|
+
};
|
|
616
|
+
};
|
|
617
|
+
/**
|
|
618
|
+
* The `[[Construct]]` half of a pre-`class` JavaScript constructor function:
|
|
619
|
+
* allocate the instance, enter the body with it, evaluate to it.
|
|
620
|
+
*
|
|
621
|
+
* ECMA-262 10.2.2 in three steps, and the reason a construction cannot reuse
|
|
622
|
+
* the invoke pointer: `[[Call]]` is HANDED a receiver and returns whatever the
|
|
623
|
+
* body returns (`void`, for nine of the ten in three.js's renderer), while
|
|
624
|
+
* `[[Construct]]` manufactures the receiver and evaluates to it. The two
|
|
625
|
+
* conventions differ in both ends, which is why `gea::CallableConstructorObject`
|
|
626
|
+
* holds two pointers rather than one.
|
|
627
|
+
*
|
|
628
|
+
* The instance's own allocation is `emit-allocation.ts`'s `emitAllocateRecord`
|
|
629
|
+
* ownership switch, and deliberately the same two spellings: `owned` is a value
|
|
630
|
+
* (`T{}`) and `shared-refcount` is a counted reference (`gea::makeRef<T>()`).
|
|
631
|
+
* `borrowed` is refused there for the reason it is refused here -- an
|
|
632
|
+
* allocation has no object to point at.
|
|
633
|
+
*
|
|
634
|
+
* The receiver the body declares and the object this returns must be the SAME
|
|
635
|
+
* carrier, and where they are not, what is rendered is a fault rather than a
|
|
636
|
+
* construction. That is not a hedge: it is the `this.setState = function (
|
|
637
|
+
* material ) { this.numPlanes += n; }` case, whose receiver is the instance it
|
|
638
|
+
* was INSTALLED on (`structural-receiver.ts`'s `jsConstructorReceiverOf`) while
|
|
639
|
+
* TypeScript's constructor-function inference still gives it a construct
|
|
640
|
+
* signature returning the subset of fields it happens to assign. Nothing can
|
|
641
|
+
* `new` such a value through the field it lives in without saying so, and if
|
|
642
|
+
* something does, a named abort is the honest answer -- a silent one would
|
|
643
|
+
* allocate a two-field record and run a body that expects the whole instance.
|
|
644
|
+
*/
|
|
645
|
+
const constructThunkOf = (body, abi, hasEnvironment, linkage) => {
|
|
646
|
+
const construct = body.construct;
|
|
647
|
+
if (!construct)
|
|
648
|
+
return null;
|
|
649
|
+
const instance = construct.result;
|
|
650
|
+
const formals = [hasEnvironment ? `void* ${cppEnvironmentParamName}` : 'void*', ...formalsOf(construct)];
|
|
651
|
+
const signature = `${linkagePrefix(linkage)}${cppResultTypeOf(instance)} ${cppConstructedThunkName(body.sourceOwner)}(${formals.join(', ')})`;
|
|
652
|
+
// A body that never reads `this` declares no receiver (`structural-
|
|
653
|
+
// receiver.ts` gates the JS-constructor receiver on `bodyReadsThis`), and
|
|
654
|
+
// `[[Construct]]` of it is still a construction: allocate the instance, run
|
|
655
|
+
// the body with the convention it has, return the instance. `function F()
|
|
656
|
+
// {}` constructed with `new F()` is exactly that -- test262 builds most of
|
|
657
|
+
// its throwaway constructors this way -- and rendering it as a fault made
|
|
658
|
+
// a certified program abort at runtime.
|
|
659
|
+
const actuals = [
|
|
660
|
+
...(hasEnvironment ? [cppEnvironmentParamName] : ['nullptr']),
|
|
661
|
+
...(abi.receiver !== null ? [cppReceiverName] : []),
|
|
662
|
+
...construct.parameters.map((_, ordinal) => cppFormalName(ordinal))
|
|
663
|
+
];
|
|
664
|
+
const buildable = nativeOrdinaryConstructInstanceMatches(abi, instance);
|
|
665
|
+
if (!buildable) {
|
|
666
|
+
const why = abi.receiver === null
|
|
667
|
+
? `its construction evaluates to ${representationKey(instance)}, which is not an allocatable record`
|
|
668
|
+
: `its body is entered with ${representationKey(abi.receiver)} while its construction evaluates to ${representationKey(instance)}`;
|
|
669
|
+
return {
|
|
670
|
+
prototype: `${signature};`,
|
|
671
|
+
definition: `${signature} { gea::detail::failUnconstructableFunction("${cppBodyName(body.sourceOwner)}", "${why}"); }`
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
const allocation = instance.ownership === 'owned'
|
|
675
|
+
? `${cppTypeOf(instance)} ${cppReceiverName}{};`
|
|
676
|
+
: `${cppTypeOf(instance)} ${cppReceiverName} = gea::makeRef<${cppRecordStructName(instance.shapeId)}>();`;
|
|
677
|
+
// Through the INVOKE thunk, not the body: the thunk is the one place that
|
|
678
|
+
// knows how this body's captured state is packed, and rebuilding that
|
|
679
|
+
// unpacking here would be a second answer to `gea::packEnvironment`'s own
|
|
680
|
+
// question. A body with no environment is called through it just the same,
|
|
681
|
+
// with the `void*` the signature carries either way.
|
|
682
|
+
const entry = `${cppThunkName(body.sourceOwner)}(${actuals.join(', ')});`;
|
|
683
|
+
// Published against the INVOKE pointer, beside the `name`/`length`/source
|
|
684
|
+
// text `registerSource` publishes against the same key. A value that is
|
|
685
|
+
// later viewed under a type naming its `[[Construct]]` -- `Factory as typeof
|
|
686
|
+
// Factory & (new (v: number) => T)` -- carries that pointer and nothing
|
|
687
|
+
// else about its declaration, so this is what lets the conversion stay a
|
|
688
|
+
// property of the VALUE rather than a guess about which declaration a cell
|
|
689
|
+
// holds (`gea::withConstructEntry`, gea_runtime.h).
|
|
690
|
+
const registration = `[[maybe_unused]] static const bool ${cppConstructedThunkName(body.sourceOwner)}_entry = ` +
|
|
691
|
+
`gea::registerConstructEntry(&${cppThunkName(body.sourceOwner)}, &${cppConstructedThunkName(body.sourceOwner)});`;
|
|
692
|
+
return {
|
|
693
|
+
prototype: `${signature};`,
|
|
694
|
+
definition: `${signature} { ${allocation} ${entry} return ${cppReceiverName}; }\n${registration}`
|
|
695
|
+
};
|
|
696
|
+
};
|
|
697
|
+
/**
|
|
698
|
+
* The program's entry: the module bodies, called in evaluation order.
|
|
699
|
+
*
|
|
700
|
+
* This is the one function in an emitted unit that no operation in the graph
|
|
701
|
+
* asked for, and it exists because module evaluation is not an operation --
|
|
702
|
+
* it is what a *program* is. Every other body here is reached from a call the
|
|
703
|
+
* program makes; a module body is reached because the host started the program.
|
|
704
|
+
*
|
|
705
|
+
* The order is the frontend's (`FrontendResult.moduleOrder`), never this
|
|
706
|
+
* file's: which module runs first is decided by the import graph, which is a
|
|
707
|
+
* question only the checker can answer, and re-deriving it from the bodies --
|
|
708
|
+
* which carry no import edges at all -- would be inventing an answer.
|
|
709
|
+
*
|
|
710
|
+
* A named region with no lowered body is refused rather than skipped. Skipping
|
|
711
|
+
* would emit an entry that silently runs fewer modules than the program has,
|
|
712
|
+
* which is a program whose module state is half-built and whose failure lands
|
|
713
|
+
* at runtime with nothing pointing back here.
|
|
714
|
+
*/
|
|
715
|
+
const entryDefinitionOf = (entrySymbol, moduleOrder, bodies, commonJsModules, hasBuiltinModuleRegistry) => {
|
|
716
|
+
const byOwner = new Map(bodies.map((body) => [body.sourceOwner, body]));
|
|
717
|
+
const calls = hasBuiltinModuleRegistry ? ['gea_register_commonjs_builtin_modules();'] : [];
|
|
718
|
+
for (const region of moduleOrder) {
|
|
719
|
+
const body = byOwner.get(region);
|
|
720
|
+
if (!body) {
|
|
721
|
+
return {
|
|
722
|
+
refusal: {
|
|
723
|
+
owner: region,
|
|
724
|
+
reason: `module body ${region} is in this program's evaluation order but lowered no body to call`,
|
|
725
|
+
key: 'print:refused'
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
// `signatureOf` renders a body with no ABI as `void name()`, which is
|
|
730
|
+
// exactly what a run-once region is and exactly what this can call. An ABI
|
|
731
|
+
// would mean parameters, and parameters mean this entry would have to
|
|
732
|
+
// invent arguments for a module body -- so it refuses instead.
|
|
733
|
+
if (body.abi) {
|
|
734
|
+
return {
|
|
735
|
+
refusal: {
|
|
736
|
+
owner: region,
|
|
737
|
+
reason: `module body ${region} lowered with a calling convention; a module body takes no arguments and this entry has none to pass`,
|
|
738
|
+
key: 'print:refused'
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
calls.push(commonJsModules.has(region) ? `${cppCommonJsModuleName(region)}();` : `${cppBodyName(region)}();`);
|
|
743
|
+
}
|
|
744
|
+
// Script evaluation ends with a microtask checkpoint. Synchronously settled
|
|
745
|
+
// Promise reactions queued by a module body must run before a standalone
|
|
746
|
+
// entry returns; otherwise a plain compiled program drops `Promise.resolve()
|
|
747
|
+
// .then(...)` work at process exit. Long-lived hosts keep using their own
|
|
748
|
+
// frame checkpoint for jobs that settle later through I/O.
|
|
749
|
+
calls.push('gea::detail::drainPromiseJobs();');
|
|
750
|
+
return { text: [`void ${entrySymbol}() {`, ...calls, '}'].join('\n') };
|
|
751
|
+
};
|
|
752
|
+
const commonJsDefinitionsOf = (bodies) => {
|
|
753
|
+
const targets = new Set();
|
|
754
|
+
const builtinTargets = new Map();
|
|
755
|
+
const nativeRecords = new Map();
|
|
756
|
+
const refused = [];
|
|
757
|
+
const addBuiltinTarget = (owner, name, target) => {
|
|
758
|
+
const prior = builtinTargets.get(name);
|
|
759
|
+
if (prior !== undefined && prior !== target) {
|
|
760
|
+
refused.push({
|
|
761
|
+
owner,
|
|
762
|
+
reason: `builtin module "${name}" resolved to two CommonJS module records (${prior} and ${target})`,
|
|
763
|
+
key: 'print:refused'
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
builtinTargets.set(name, target);
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
for (const body of bodies)
|
|
771
|
+
for (const block of body.blocks.values())
|
|
772
|
+
for (const operation of allOperationsOf(block)) {
|
|
773
|
+
if (operation.kind === 'commonjs-require') {
|
|
774
|
+
targets.add(operation.owner);
|
|
775
|
+
targets.add(operation.target);
|
|
776
|
+
if (operation.builtinModule !== null) {
|
|
777
|
+
addBuiltinTarget(operation.owner, operation.builtinModule, operation.target);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
if (operation.kind === 'call' && operation.builtinModuleLookup) {
|
|
781
|
+
targets.add(operation.builtinModuleLookup.target);
|
|
782
|
+
addBuiltinTarget(operation.builtinModuleLookup.target, operation.builtinModuleLookup.builtinModule, operation.builtinModuleLookup.target);
|
|
783
|
+
}
|
|
784
|
+
if (operation.kind === 'commonjs-binding' || operation.kind === 'commonjs-binding-set')
|
|
785
|
+
targets.add(operation.owner);
|
|
786
|
+
// The semantic proof is consumed by publication: unproved CommonJS
|
|
787
|
+
// bindings are forced to `dynamic`, so this carrier distinction is
|
|
788
|
+
// exact evidence at IR rather than ambient-shape inference.
|
|
789
|
+
if (operation.kind === 'commonjs-binding' && operation.result.representation.kind !== 'dynamic') {
|
|
790
|
+
if (operation.global !== 'module' || operation.result.representation.kind !== 'record') {
|
|
791
|
+
refused.push({
|
|
792
|
+
owner: operation.owner,
|
|
793
|
+
reason: `native CommonJS module proof lowered through ${operation.global}:${operation.result.representation.kind}, not one native record`,
|
|
794
|
+
key: 'print:refused'
|
|
795
|
+
});
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
const fields = operation.result.representation.fields.filter((field) => field.key === 'exports');
|
|
799
|
+
if (fields.length !== 1 ||
|
|
800
|
+
operation.result.representation.fields.length !== 1 ||
|
|
801
|
+
operation.result.representation.accessors.length !== 0 ||
|
|
802
|
+
fields[0]?.required !== true) {
|
|
803
|
+
refused.push({
|
|
804
|
+
owner: operation.owner,
|
|
805
|
+
reason: 'native CommonJS module proof did not lower to exactly one stored exports field',
|
|
806
|
+
key: 'print:refused'
|
|
807
|
+
});
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
const field = fields[0];
|
|
811
|
+
if (!field)
|
|
812
|
+
continue;
|
|
813
|
+
if (field.value.kind === 'dynamic' || field.value.kind === 'unresolved') {
|
|
814
|
+
refused.push({
|
|
815
|
+
owner: operation.owner,
|
|
816
|
+
reason: `native CommonJS exports field selected ${field.value.kind}; an exact module record cannot contain a boxed or unresolved export`,
|
|
817
|
+
key: 'print:refused'
|
|
818
|
+
});
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
const prior = nativeRecords.get(operation.owner);
|
|
822
|
+
if (prior && representationKey(prior.record) !== representationKey(operation.result.representation)) {
|
|
823
|
+
refused.push({
|
|
824
|
+
owner: operation.owner,
|
|
825
|
+
reason: 'one CommonJS module lowered to multiple native record carriers',
|
|
826
|
+
key: 'print:refused'
|
|
827
|
+
});
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
830
|
+
nativeRecords.set(operation.owner, { record: operation.result.representation, exports: field.value });
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
for (const body of bodies)
|
|
834
|
+
for (const block of body.blocks.values())
|
|
835
|
+
for (const operation of allOperationsOf(block)) {
|
|
836
|
+
if (operation.kind !== 'commonjs-require' || operation.result.representation.kind === 'dynamic')
|
|
837
|
+
continue;
|
|
838
|
+
const native = nativeRecords.get(operation.target);
|
|
839
|
+
if (!native) {
|
|
840
|
+
refused.push({
|
|
841
|
+
owner: operation.owner,
|
|
842
|
+
reason: `native CommonJS require target ${operation.target} has no matching native module record`,
|
|
843
|
+
key: 'print:refused'
|
|
844
|
+
});
|
|
845
|
+
continue;
|
|
846
|
+
}
|
|
847
|
+
if (representationKey(native.exports) !== representationKey(operation.result.representation)) {
|
|
848
|
+
refused.push({
|
|
849
|
+
owner: operation.owner,
|
|
850
|
+
reason: `native CommonJS require carrier ${representationKey(operation.result.representation)} does not match target exports carrier ${representationKey(native.exports)}`,
|
|
851
|
+
key: 'print:refused'
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
for (const [name, target] of builtinTargets) {
|
|
856
|
+
if (nativeRecords.has(target)) {
|
|
857
|
+
refused.push({
|
|
858
|
+
owner: target,
|
|
859
|
+
reason: `builtin module "${name}" has a native CommonJS exports carrier, but the dynamic builtin registry cannot own it without boxing`,
|
|
860
|
+
key: 'print:refused'
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
const byOwner = new Map(bodies.map((body) => [body.sourceOwner, body]));
|
|
865
|
+
const definitions = [];
|
|
866
|
+
for (const target of targets) {
|
|
867
|
+
const body = byOwner.get(target);
|
|
868
|
+
if (!body) {
|
|
869
|
+
refused.push({
|
|
870
|
+
owner: target,
|
|
871
|
+
reason: `CommonJS module record ${target} has no lowered module body to initialize`,
|
|
872
|
+
key: 'print:refused'
|
|
873
|
+
});
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
876
|
+
if (body.abi) {
|
|
877
|
+
refused.push({
|
|
878
|
+
owner: target,
|
|
879
|
+
reason: `CommonJS module record ${target} resolved to a body with a calling convention; module initializers take no arguments`,
|
|
880
|
+
key: 'print:refused'
|
|
881
|
+
});
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
const native = nativeRecords.get(target);
|
|
885
|
+
if (!native) {
|
|
886
|
+
definitions.push(`inline gea::commonjs::ModuleRecord& ${cppCommonJsRecordName(target)}() { static gea::commonjs::ModuleRecord record; return record; }\n` +
|
|
887
|
+
`inline gea::Value ${cppCommonJsModuleName(target)}() { return gea::commonjs::evaluate(${cppCommonJsRecordName(target)}(), [] { ${cppBodyName(target)}(); }); }`);
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
if (native.record.ownership !== 'shared-refcount') {
|
|
891
|
+
refused.push({
|
|
892
|
+
owner: target,
|
|
893
|
+
reason: `native CommonJS module record requires shared ownership, but publication selected ${native.record.ownership}`,
|
|
894
|
+
key: 'print:refused'
|
|
895
|
+
});
|
|
896
|
+
continue;
|
|
897
|
+
}
|
|
898
|
+
const stateName = `${cppCommonJsRecordName(target)}_state`;
|
|
899
|
+
const stateAccessor = `${stateName}_of`;
|
|
900
|
+
const recordType = cppTypeOf(native.record);
|
|
901
|
+
const exportType = cppTypeOf(native.exports);
|
|
902
|
+
const exportField = cppRecordFieldName('exports');
|
|
903
|
+
const recordInit = `gea::makeRef<${cppRecordStructName(native.record.shapeId)}>()`;
|
|
904
|
+
definitions.push([
|
|
905
|
+
`struct ${stateName} {`,
|
|
906
|
+
' enum class Phase { fresh, loading, loaded };',
|
|
907
|
+
' Phase phase = Phase::fresh;',
|
|
908
|
+
` ${recordType} module = ${recordInit};`,
|
|
909
|
+
'};',
|
|
910
|
+
`inline ${stateName}& ${stateAccessor}() { static ${stateName} state; return state; }`,
|
|
911
|
+
`inline ${recordType} ${cppCommonJsRecordName(target)}() { return ${stateAccessor}().module; }`,
|
|
912
|
+
`inline ${exportType} ${cppCommonJsModuleName(target)}() {`,
|
|
913
|
+
` auto& state = ${stateAccessor}();`,
|
|
914
|
+
` if (state.phase != ${stateName}::Phase::fresh) return state.module->${exportField};`,
|
|
915
|
+
` state.phase = ${stateName}::Phase::loading;`,
|
|
916
|
+
` try { ${cppBodyName(target)}(); state.phase = ${stateName}::Phase::loaded; return state.module->${exportField}; }`,
|
|
917
|
+
` catch (...) { state.phase = ${stateName}::Phase::fresh; state.module = ${recordInit}; throw; }`,
|
|
918
|
+
'}'
|
|
919
|
+
].join('\n'));
|
|
920
|
+
}
|
|
921
|
+
if (builtinTargets.size > 0) {
|
|
922
|
+
const registrations = [...builtinTargets.entries()]
|
|
923
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
924
|
+
.map(([name, target]) => `gea::commonjs::registerBuiltinModule(${cppStringLiteral(name)}, &${cppCommonJsModuleName(target)});`);
|
|
925
|
+
definitions.push(`inline void gea_register_commonjs_builtin_modules() {\n` +
|
|
926
|
+
` static const bool registered = [] { ${registrations.join(' ')} return true; }();\n` +
|
|
927
|
+
` (void)registered;\n` +
|
|
928
|
+
`}`);
|
|
929
|
+
}
|
|
930
|
+
return { definitions, modules: targets, hasBuiltinModuleRegistry: builtinTargets.size > 0, refused };
|
|
931
|
+
};
|
|
932
|
+
const commonJsOwnerOf = (body) => {
|
|
933
|
+
const owners = new Set();
|
|
934
|
+
let nativeRecord = false;
|
|
935
|
+
let needsDynamicScope = false;
|
|
936
|
+
for (const block of body.blocks.values()) {
|
|
937
|
+
for (const operation of allOperationsOf(block)) {
|
|
938
|
+
if (operation.kind === 'commonjs-require' || operation.kind === 'commonjs-binding' || operation.kind === 'commonjs-binding-set')
|
|
939
|
+
owners.add(operation.owner);
|
|
940
|
+
if (operation.kind === 'commonjs-binding' && operation.result.representation.kind !== 'dynamic')
|
|
941
|
+
nativeRecord = true;
|
|
942
|
+
if (operation.kind === 'commonjs-binding' && operation.result.representation.kind === 'dynamic')
|
|
943
|
+
needsDynamicScope = true;
|
|
944
|
+
if (operation.kind === 'commonjs-binding-set')
|
|
945
|
+
needsDynamicScope = true;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
if (owners.size === 0)
|
|
949
|
+
return null;
|
|
950
|
+
if (owners.size === 1) {
|
|
951
|
+
const owner = [...owners][0];
|
|
952
|
+
if (nativeRecord && needsDynamicScope) {
|
|
953
|
+
return {
|
|
954
|
+
owner,
|
|
955
|
+
reason: 'one CommonJS body selected a native module record while still requiring a dynamic wrapper scope',
|
|
956
|
+
key: 'print:refused'
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
return { owner, nativeRecord };
|
|
960
|
+
}
|
|
961
|
+
return {
|
|
962
|
+
owner: body.sourceOwner,
|
|
963
|
+
reason: `one lexical body reached CommonJS operations for multiple module records (${[...owners].join(', ')}); normalization must carry one source-module owner`,
|
|
964
|
+
key: 'print:refused'
|
|
965
|
+
};
|
|
966
|
+
};
|
|
967
|
+
/** The text-only sections a layout places; `empty` facts because none of them is authored by one semantic result. */
|
|
968
|
+
const plain = (text) => ({ text, facts: emptyCppFacts });
|
|
969
|
+
/**
|
|
970
|
+
* The name of one module unit: the base name, the source file relative to the
|
|
971
|
+
* directory every module file shares, and `.cpp`.
|
|
972
|
+
*
|
|
973
|
+
* Spelled with a character walk rather than a RegExp because the architecture
|
|
974
|
+
* gate forbids RegExp literals under `targets/cpp/` -- the same reason
|
|
975
|
+
* `sanitizeForCppIdentifier` walks. The extension is dropped so `a.ts` and
|
|
976
|
+
* `a.tsx` read the same way in a directory listing, and every path separator
|
|
977
|
+
* becomes `_` so the name is one file-system entry. Two files that sanitize to
|
|
978
|
+
* one spelling keep their file identity as a suffix rather than colliding.
|
|
979
|
+
*/
|
|
980
|
+
const moduleUnitNames = (base, files) => {
|
|
981
|
+
const segmentsOf = (name) => name.split('/').filter((segment) => segment.length > 0);
|
|
982
|
+
// A file no name was published for is spelled by its identity and takes no
|
|
983
|
+
// part in the prefix: one `f57` in the set would otherwise leave every other
|
|
984
|
+
// unit carrying its file's whole absolute path.
|
|
985
|
+
const named = files.filter((file) => file.displayName !== file.identity);
|
|
986
|
+
const split = named.map((file) => segmentsOf(file.displayName));
|
|
987
|
+
// The directory every module shares is dropped, and a lone module keeps only
|
|
988
|
+
// its own name: a one-file program's unit is `<stem>.index.cpp`, not the
|
|
989
|
+
// file's whole absolute path spelled with underscores.
|
|
990
|
+
const first = split[0] ?? [];
|
|
991
|
+
let shared = split.length === 1 ? Math.max(0, first.length - 1) : 0;
|
|
992
|
+
if (split.length > 1) {
|
|
993
|
+
while (shared < first.length - 1 && split.every((segments) => segments[shared] === first[shared]))
|
|
994
|
+
shared += 1;
|
|
995
|
+
}
|
|
996
|
+
const sanitize = (raw) => {
|
|
997
|
+
let out = '';
|
|
998
|
+
for (const character of raw)
|
|
999
|
+
out += cppIdentifierCharacters.includes(character) || character === '-' ? character : '_';
|
|
1000
|
+
return out;
|
|
1001
|
+
};
|
|
1002
|
+
const stem = (segments) => {
|
|
1003
|
+
const relative = segments.slice(shared);
|
|
1004
|
+
const last = relative[relative.length - 1] ?? '';
|
|
1005
|
+
const dot = last.lastIndexOf('.');
|
|
1006
|
+
const trimmed = dot > 0 ? last.slice(0, dot) : last;
|
|
1007
|
+
return sanitize([...relative.slice(0, -1), trimmed].join('/'));
|
|
1008
|
+
};
|
|
1009
|
+
const counts = new Map();
|
|
1010
|
+
const stems = new Map(named.map((file, index) => [file.identity, stem(split[index] ?? [])]));
|
|
1011
|
+
for (const value of stems.values())
|
|
1012
|
+
counts.set(value, (counts.get(value) ?? 0) + 1);
|
|
1013
|
+
const names = new Map();
|
|
1014
|
+
for (const file of files) {
|
|
1015
|
+
const value = stems.get(file.identity) ?? file.identity;
|
|
1016
|
+
const unique = (counts.get(value) ?? 0) > 1 ? `${value}_${file.identity}` : value;
|
|
1017
|
+
names.set(file.identity, `${base}.${unique}.cpp`);
|
|
1018
|
+
}
|
|
1019
|
+
return names;
|
|
1020
|
+
};
|
|
1021
|
+
const cppIdentifierCharacters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_';
|
|
1022
|
+
export const renderTranslationUnit = (input) => {
|
|
1023
|
+
const emissionRepresentations = input.emissionRepresentations ?? [...input.plan.selected.values()];
|
|
1024
|
+
const printerDrift = [];
|
|
1025
|
+
const refuse = (refused) => ({
|
|
1026
|
+
source: null,
|
|
1027
|
+
units: [],
|
|
1028
|
+
refused: Object.freeze([...refused]),
|
|
1029
|
+
printerDrift
|
|
1030
|
+
});
|
|
1031
|
+
// An isolated unit puts everything it defines in a namespace whose names no
|
|
1032
|
+
// other unit can reach by accident, and a name declared there has internal
|
|
1033
|
+
// linkage when the namespace is unnamed -- including an `extern` one. So the
|
|
1034
|
+
// externs are emitted AHEAD of the namespace, where they keep the external
|
|
1035
|
+
// linkage that is their whole point.
|
|
1036
|
+
//
|
|
1037
|
+
// That works while their types are declared ahead of it too, which is the
|
|
1038
|
+
// ordinary case: a host global is a `gea::NativeHandle<gea_native_protocol_
|
|
1039
|
+
// Math_v1>` and both spellings come from `gea_runtime.h` and
|
|
1040
|
+
// `generated_support.hpp`, which the includes above already brought in. What
|
|
1041
|
+
// does NOT work is an extern whose type names a struct this compilation
|
|
1042
|
+
// minted -- `extern gea::CallableObject<NodeHandle(gea::Ref<gea_record_type_
|
|
1043
|
+
// 253>)> Image;` -- because that struct is defined inside the namespace and
|
|
1044
|
+
// cannot be named before it. Such a unit is refused rather than reordered:
|
|
1045
|
+
// the struct's own name is per-compilation, so hoisting the definition out
|
|
1046
|
+
// would put the very thing isolation exists to hide back in the global
|
|
1047
|
+
// namespace.
|
|
1048
|
+
const externs = externDeclarations(input.placements);
|
|
1049
|
+
const absent = absentDefinitions(input.placements);
|
|
1050
|
+
// Spelled in full, above: an extern or an absent global is declared at
|
|
1051
|
+
// global scope, before the program's namespace and before the alias block
|
|
1052
|
+
// inside it, so neither may name an alias. Everything rendered from here on
|
|
1053
|
+
// may, and the block is spliced in at `unionAliasMarker` once every
|
|
1054
|
+
// spelling is known.
|
|
1055
|
+
beginUnionAliasing();
|
|
1056
|
+
const selectionHelpers = input.layout === 'balanced' ? nativeSelectionHelpers(input.bodies, input.conversions) : undefined;
|
|
1057
|
+
// Whether a declaration's OWN representation names a struct this
|
|
1058
|
+
// compilation mints -- asked of the representation `cppTypeOf` rendered
|
|
1059
|
+
// `text` from, not re-derived by searching that rendered text for the
|
|
1060
|
+
// struct-name prefixes. See `representationNamesMintedStruct` (records.ts):
|
|
1061
|
+
// it walks the same representation tree `cppRecordDeclarations` orders
|
|
1062
|
+
// structs from, so this and that ordering can never disagree about what a
|
|
1063
|
+
// carrier names.
|
|
1064
|
+
const programMinted = [...externs, ...absent].filter((declaration) => representationNamesMintedStruct(declaration.representation));
|
|
1065
|
+
// A unit that only PREFERS isolation and cannot have it is emitted the way
|
|
1066
|
+
// every unit was before isolation existed. Refusing is right only where
|
|
1067
|
+
// isolation is what keeps two units apart.
|
|
1068
|
+
const isolate = input.isolateSymbols !== 'off' && programMinted.length === 0;
|
|
1069
|
+
if (input.isolateSymbols === 'required' && programMinted.length > 0) {
|
|
1070
|
+
return refuse([
|
|
1071
|
+
{
|
|
1072
|
+
owner: 'translation-unit',
|
|
1073
|
+
reason: `symbol isolation was requested for a unit whose external global names a struct this compilation minted, which cannot be declared ahead of the unnamed namespace that defines it: ${programMinted.map((declaration) => declaration.text).join(' ')}`,
|
|
1074
|
+
key: 'print:refused'
|
|
1075
|
+
}
|
|
1076
|
+
]);
|
|
1077
|
+
}
|
|
1078
|
+
const perFile = input.layout !== 'single';
|
|
1079
|
+
// The per-file layout's namespace is NAMED, because its units have to reach
|
|
1080
|
+
// each other's definitions and an unnamed namespace is a different one in
|
|
1081
|
+
// every unit. The name is the program's -- its entry symbol -- so two
|
|
1082
|
+
// programs a resident build links keep their namespaces apart exactly as the
|
|
1083
|
+
// unnamed one kept them, and `using namespace` after the close restores the
|
|
1084
|
+
// unqualified lookup the host-required definitions and the entry relied on
|
|
1085
|
+
// when the unnamed namespace's implicit using-directive supplied it.
|
|
1086
|
+
const namespaceName = perFile ? `gea_program_${sanitizeForCppIdentifier(input.entrySymbol ?? 'unit')}` : null;
|
|
1087
|
+
const namespaceOpen = namespaceName === null ? 'namespace {' : `namespace ${namespaceName} {`;
|
|
1088
|
+
const namespaceClose = namespaceName === null ? '} // namespace' : `} // namespace ${namespaceName}\nusing namespace ${namespaceName};`;
|
|
1089
|
+
// Internal linkage stays the single layout's answer for the functions this
|
|
1090
|
+
// file mints (see `CppLinkage`); the per-file layout has to let every unit
|
|
1091
|
+
// name them.
|
|
1092
|
+
const linkage = perFile ? 'external' : 'internal';
|
|
1093
|
+
// Computed once from the lowered bodies the caller already has: which
|
|
1094
|
+
// functions capture, and whether each one's environment is safe to build.
|
|
1095
|
+
// Every later section -- the struct declarations, the forward signatures,
|
|
1096
|
+
// the thunks, and each body's own statements -- reads the same index, so a
|
|
1097
|
+
// function's admission cannot come apart between where it is declared and
|
|
1098
|
+
// where it is used.
|
|
1099
|
+
//
|
|
1100
|
+
// `captures`/`directCallables` stay here rather than in `programFactsOf`,
|
|
1101
|
+
// and for two different reasons. `buildCaptureIndex` decides nothing: every
|
|
1102
|
+
// input it reads is already sealed on `IrBody.facts` by `ir/captures.ts`,
|
|
1103
|
+
// so it is an INDEX -- a lookup shape over one authority's answers -- and
|
|
1104
|
+
// moving it would relocate a projection, not a decision. `directCallables`
|
|
1105
|
+
// is the one whose admission compares two carriers' C++ SPELLING
|
|
1106
|
+
// (`cppTypeOf`), a target decision `ir/program-facts.ts` must not re-derive. Everything downstream of them -- which cells route their
|
|
1107
|
+
// call by name, which constructors run repeatedly, which arguments die,
|
|
1108
|
+
// and the borrow fixed point -- is a question about the lowered IR alone,
|
|
1109
|
+
// so it is asked once, in `programFactsOf`'s own dependency order, with
|
|
1110
|
+
// this target's remaining decisions (capture admission, coroutine-ness,
|
|
1111
|
+
// which writes are private to their owning body) arriving as hooks.
|
|
1112
|
+
// An accessor body is named by the shape, never allocated as a value, so the
|
|
1113
|
+
// set has to come from the carriers rather than from the operations -- see
|
|
1114
|
+
// `recordAccessorBodiesOf`.
|
|
1115
|
+
const captures = buildCaptureIndex(input.bodies, input.placements, recordAccessorBodiesOf(emissionRepresentations, input.deriver));
|
|
1116
|
+
const directCallables = buildDirectCallableIndex(input.bodies, captures, input.placements);
|
|
1117
|
+
const { callableMemberCandidates, repeatedConstructors, dyingArguments, formalsBorrowedIn, bodyCallsUnsafeKnownCallee, callableIdentityDemand, nativeIntegrityRestricted, fixedFieldStateConstant, singleEvaluationClasses } = programFactsOf(input.bodies, directCallables, input.placements, {
|
|
1118
|
+
captureFree: (functionId) => captures.of(functionId).kind === 'none',
|
|
1119
|
+
isBoxed: (declaration) => captures.isBoxed(declaration),
|
|
1120
|
+
isCoroutineBody,
|
|
1121
|
+
classInstanceOf: (declaration) => input.classes.get(declaration)?.instance ?? null,
|
|
1122
|
+
plainFieldRead: (receiver, key) => {
|
|
1123
|
+
if (receiver.kind === 'class-ref') {
|
|
1124
|
+
// A class over a host base reads its members through the host's
|
|
1125
|
+
// protocol; only a wholly projected class has plain member loads.
|
|
1126
|
+
if (input.classes.get(receiver.declaration)?.nativeBase !== null)
|
|
1127
|
+
return false;
|
|
1128
|
+
return classMemberOf(input.classes, receiver.declaration, key)?.kind === 'field';
|
|
1129
|
+
}
|
|
1130
|
+
if (receiver.kind === 'record')
|
|
1131
|
+
return receiver.fields.some((field) => field.key === key) && !receiver.accessors.some((accessor) => accessor.key === key);
|
|
1132
|
+
return false;
|
|
1133
|
+
},
|
|
1134
|
+
isPrivateLocal: (body, declaration) => {
|
|
1135
|
+
const placement = input.placements.get(declaration);
|
|
1136
|
+
return (placement?.storage.kind === 'local' &&
|
|
1137
|
+
String(placement.storage.owner) === String(body.sourceOwner) &&
|
|
1138
|
+
!captures.isBoxed(declaration));
|
|
1139
|
+
}
|
|
1140
|
+
});
|
|
1141
|
+
// The one authority on what a structural type physically is, for
|
|
1142
|
+
// `emit-properties.ts` to ask a receiver's own declared field
|
|
1143
|
+
// representation when widening a concrete value into a `dynamic` field.
|
|
1144
|
+
// The deriver that built the plan, not a fresh one. A carrier depends on the
|
|
1145
|
+
// policies this compilation supplied -- the frontend's host-protocol and
|
|
1146
|
+
// typed-array censuses -- so an instance constructed here would default them
|
|
1147
|
+
// to `() => null` and answer a different question than the plan did. That is
|
|
1148
|
+
// not hypothetical: measured on one 14-line fixture, the two disagreed about
|
|
1149
|
+
// 10 of 32 structural types, a default-policy deriver reading
|
|
1150
|
+
// `typed-array(float32)` as `native-record-ref` and `native-handle(
|
|
1151
|
+
// ArrayBuffer@1)` as `native-record-ref`. One plan, one deriver.
|
|
1152
|
+
const deriver = input.deriver;
|
|
1153
|
+
// The prelude and the struct declarations carry no single semantic result:
|
|
1154
|
+
// a struct is required by every carrier that names it, not authored by one
|
|
1155
|
+
// of them. `empty` facts are exactly right here and nowhere else in this
|
|
1156
|
+
// file -- a body section that reached for them would be hiding the authority
|
|
1157
|
+
// it does have.
|
|
1158
|
+
// Which record members a JSX slot binds, decided before the structs are
|
|
1159
|
+
// rendered because it is what narrows their reactive storage. It reads the
|
|
1160
|
+
// bodies only -- never the cell plan it feeds -- so the two stay acyclic.
|
|
1161
|
+
const boundRecordFields = reactiveBoundRecordFields(input.bodies);
|
|
1162
|
+
// Dispatch for the methods this program overrides, decided before the structs
|
|
1163
|
+
// render because it puts a member INSIDE them. The conventions come from the
|
|
1164
|
+
// bodies themselves -- one authority, the same one `signatureOf` spells --
|
|
1165
|
+
// rather than from a second derivation that could disagree with the
|
|
1166
|
+
// definition it has to match.
|
|
1167
|
+
const abiByBody = new Map(input.bodies.map((body) => [String(body.sourceOwner), body.abi]));
|
|
1168
|
+
// Capture-freedom for the dispatchability verdict below, read directly off
|
|
1169
|
+
// the published `IrBody.facts` (`ir/captures.ts`'s `publishCaptureFacts`,
|
|
1170
|
+
// sealed onto every body before `compiler.ts` calls `renderTranslationUnit`)
|
|
1171
|
+
// rather than the render-time `CaptureIndex`: a plain instance method is
|
|
1172
|
+
// almost never named by an `allocate-callable` operation, so the `CaptureIndex`
|
|
1173
|
+
// -- keyed on exactly that -- answered `{ kind: 'none' }` for one whether or
|
|
1174
|
+
// not its body actually captured anything. The raw fact is the one
|
|
1175
|
+
// the move of facts out of the target names as the unblocking
|
|
1176
|
+
// answer.
|
|
1177
|
+
const bodyFactsBySourceOwner = new Map(input.bodies.map((body) => [String(body.sourceOwner), body.facts]));
|
|
1178
|
+
const capturesNothingOf = (callable) => {
|
|
1179
|
+
const facts = bodyFactsBySourceOwner.get(String(callable));
|
|
1180
|
+
return facts === undefined || (facts.capturedDeclarations.length === 0 && facts.capturedReceiver === null);
|
|
1181
|
+
};
|
|
1182
|
+
// The conversion site of everything rendered outside a body: construct
|
|
1183
|
+
// thunks, field initializers, virtual dispatch adapters. Same census, same
|
|
1184
|
+
// drift list, one owner name.
|
|
1185
|
+
const programSite = {
|
|
1186
|
+
conversions: input.conversions,
|
|
1187
|
+
...(selectionHelpers === undefined ? {} : { nativeSelectionHelpers: selectionHelpers }),
|
|
1188
|
+
printerDrift,
|
|
1189
|
+
owner: 'program',
|
|
1190
|
+
layouts: recordLayoutPolicyOf(deriver, input.classes),
|
|
1191
|
+
classes: input.classes,
|
|
1192
|
+
captures
|
|
1193
|
+
};
|
|
1194
|
+
// The dispatchability VERDICT itself -- `projection/dispatch.ts`'s
|
|
1195
|
+
// `virtualDispatchVerdictOf` -- moved out of this file's `virtual-methods.ts`
|
|
1196
|
+
// (a fact moved out of the target); `virtualMethodEmission` below
|
|
1197
|
+
// now only renders the C++ struct members and adapter bodies for whatever
|
|
1198
|
+
// it says is dispatchable.
|
|
1199
|
+
const virtualVerdict = virtualDispatchVerdictOf(input.classes, (callable) => abiByBody.get(String(callable)) ?? null, capturesNothingOf, input.conversions);
|
|
1200
|
+
const virtuals = virtualMethodEmission(programSite, input.classes, (callable) => abiByBody.get(String(callable)) ?? null, virtualVerdict);
|
|
1201
|
+
// Which classes a box can hold, by the reflection census's own verdict. A
|
|
1202
|
+
// prototype property is read through a `gea::Value` only where an instance
|
|
1203
|
+
// reached a dynamic carrier the census could not see through -- the
|
|
1204
|
+
// `promoteFull` boundaries of `ir/reflection-demand.ts`, which leave the
|
|
1205
|
+
// demand UNRESTRICTED (no `fieldOperations` map). A `full` demand whose
|
|
1206
|
+
// field operations are sealed came from named operations on a typed
|
|
1207
|
+
// instance (`a.hook = f`, `Reflect.deleteProperty(a, 'hook')`): every key
|
|
1208
|
+
// is spelled, no box ever holds the instance, and the hook -- whose method
|
|
1209
|
+
// arm boxes each method into a function object -- must not be emitted for
|
|
1210
|
+
// it. An incomplete census or an uncensused class keeps the hook, as
|
|
1211
|
+
// `records.ts` keeps the struct's protocol; a base keeps it whenever any
|
|
1212
|
+
// descendant needs it, because the descendant reaches its hooks through
|
|
1213
|
+
// the base's `virtual` members.
|
|
1214
|
+
const dynamicallyReadClasses = (() => {
|
|
1215
|
+
const reflection = input.reflection;
|
|
1216
|
+
if (reflection === undefined || !reflection.complete)
|
|
1217
|
+
return null;
|
|
1218
|
+
const held = new Set();
|
|
1219
|
+
for (const declaration of input.classes.keys()) {
|
|
1220
|
+
const demand = reflection.classes.get(declaration);
|
|
1221
|
+
if (demand !== undefined && (demand.level !== 'full' || demand.fieldOperations !== undefined))
|
|
1222
|
+
continue;
|
|
1223
|
+
for (let base = declaration; base !== null && !held.has(base); base = input.classes.get(base)?.base ?? null)
|
|
1224
|
+
held.add(base);
|
|
1225
|
+
}
|
|
1226
|
+
return held;
|
|
1227
|
+
})();
|
|
1228
|
+
publishBoxableClasses(input.classes, dynamicallyReadClasses);
|
|
1229
|
+
const prototypeHooks = prototypeReadHooks(input.classes, (callable) => abiByBody.get(String(callable)) ?? null, capturesNothingOf, (declaration) => classBoxable(input.classes, declaration));
|
|
1230
|
+
const structMembers = new Map(virtuals.membersByStruct);
|
|
1231
|
+
for (const [struct, members] of prototypeHooks.membersByStruct)
|
|
1232
|
+
structMembers.set(struct, [...(structMembers.get(struct) ?? []), ...members]);
|
|
1233
|
+
// Which record and class members may be held in a `long long`, decided before
|
|
1234
|
+
// the structs are rendered because it is what their storage is spelled from.
|
|
1235
|
+
//
|
|
1236
|
+
// The exclusions are the other authorities over the same member's C++ type: a
|
|
1237
|
+
// JSON overload binds a reference to it, and a JSX slot binds one to a prop
|
|
1238
|
+
// of the type the element declares. Each of those decides the member's type
|
|
1239
|
+
// for itself, and a census that narrowed one anyway would produce two
|
|
1240
|
+
// spellings of one storage.
|
|
1241
|
+
const jsonStructs = renderJsonStructDeclarations(input.bodies, deriver);
|
|
1242
|
+
// A reactive class is NOT among them. `records.ts`'s `fieldStorageType`
|
|
1243
|
+
// spells a celled member from this same answer -- `Signal<long long>` where
|
|
1244
|
+
// the slot narrowed, `Signal<double>` where it did not -- so the cell and the
|
|
1245
|
+
// census are one authority by construction rather than two that agree. Every
|
|
1246
|
+
// integer flag of `examples/apps/weather`'s store (`active`, `managing`,
|
|
1247
|
+
// `synced`, `fetchInFlight`, `refreshPending`, `wifiRequested`,
|
|
1248
|
+
// `wifiRetryTicks`, `searchResultVisible`, `searchRequestId`,
|
|
1249
|
+
// `searchTimerId`, `toastTimerId`) was a `Signal<double>` compared and
|
|
1250
|
+
// stepped in software floating point on a core with no double FPU.
|
|
1251
|
+
const excludedStructs = new Set([...jsonStructs.structNames, ...boundRecordFields.keys()]);
|
|
1252
|
+
// Reflected field protocols exchange the published carrier, even when an
|
|
1253
|
+
// ordinary direct read could tolerate an implicit integer conversion. A
|
|
1254
|
+
// NativeFieldRead<double> cannot read a long long slot, and native writes
|
|
1255
|
+
// must likewise retain their declared carrier. The reflection census has
|
|
1256
|
+
// already closed inherited physical protocols, so this includes a base's
|
|
1257
|
+
// storage reached through a derived-class Reflect call.
|
|
1258
|
+
const hasPayloadProtocol = (demand) => demand.level === 'full' &&
|
|
1259
|
+
(demand.fieldOperations === undefined ||
|
|
1260
|
+
[...demand.fieldOperations.values()].some((operations) => [...operations].some((operation) => operation === 'read' ||
|
|
1261
|
+
operation === 'write' ||
|
|
1262
|
+
operation === 'native-read' ||
|
|
1263
|
+
operation === 'native-write' ||
|
|
1264
|
+
operation === 'descriptor' ||
|
|
1265
|
+
operation === 'define')));
|
|
1266
|
+
for (const [declaration, demand] of input.reflection?.classes ?? [])
|
|
1267
|
+
if (hasPayloadProtocol(demand))
|
|
1268
|
+
excludedStructs.add(cppClassName(declaration));
|
|
1269
|
+
for (const [shape, demand] of input.reflection?.records ?? [])
|
|
1270
|
+
if (hasPayloadProtocol(demand))
|
|
1271
|
+
excludedStructs.add(cppRecordStructName(shape));
|
|
1272
|
+
const fieldStructNameOf = (representation, key) => {
|
|
1273
|
+
if (representation.kind !== 'class-ref')
|
|
1274
|
+
return cppStructNameOf(representation);
|
|
1275
|
+
const owner = classFieldStorageOwnerOf(deriver, representation, key, input.classes);
|
|
1276
|
+
return owner === null ? null : cppClassName(owner);
|
|
1277
|
+
};
|
|
1278
|
+
const structFamilyOf = (representation) => {
|
|
1279
|
+
const name = cppStructNameOf(representation);
|
|
1280
|
+
if (name === null)
|
|
1281
|
+
return [];
|
|
1282
|
+
const names = [name];
|
|
1283
|
+
if (representation.kind !== 'class-ref')
|
|
1284
|
+
return names;
|
|
1285
|
+
const seen = new Set([representation.declaration]);
|
|
1286
|
+
const classes = input.physicalClasses ?? input.classes;
|
|
1287
|
+
for (let base = classes.get(representation.declaration)?.base; base != null && !seen.has(base); base = classes.get(base)?.base) {
|
|
1288
|
+
seen.add(base);
|
|
1289
|
+
names.push(cppClassName(base));
|
|
1290
|
+
}
|
|
1291
|
+
return names;
|
|
1292
|
+
};
|
|
1293
|
+
const fieldSeeds = new Map();
|
|
1294
|
+
for (const layout of input.classes.values()) {
|
|
1295
|
+
for (const field of layout.fields) {
|
|
1296
|
+
const owner = layout.instance === null ? null : fieldStructNameOf(layout.instance, field.key);
|
|
1297
|
+
if (field.initializer !== null && owner !== null) {
|
|
1298
|
+
const slot = integerStorageSlot(owner, field.key);
|
|
1299
|
+
const seeds = fieldSeeds.get(slot) ?? [];
|
|
1300
|
+
seeds.push({
|
|
1301
|
+
initializer: field.initializer,
|
|
1302
|
+
representation: layout.instance === null ? null : declaredFieldRepresentationOf(deriver, layout.instance, field.key, input.classes)
|
|
1303
|
+
});
|
|
1304
|
+
fieldSeeds.set(slot, seeds);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
// Which body a `receiver.key(...)` reaches, for the census's own attribution
|
|
1309
|
+
// of an argument to a formal. Built off the class layouts the emitter binds
|
|
1310
|
+
// from, and deliberately empty for any key a virtual family overrides -- there
|
|
1311
|
+
// the receiver's static class does not decide which body runs.
|
|
1312
|
+
const families = virtualMethodFamiliesOf(input.classes);
|
|
1313
|
+
const overriddenKeys = new Set(families.map((family) => family.key));
|
|
1314
|
+
const excludedFormalOwners = new Set(families.flatMap((family) => family.implementors.map((implementor) => String(implementor.callable))));
|
|
1315
|
+
for (const layout of input.classes.values())
|
|
1316
|
+
if (layout.constructor !== null)
|
|
1317
|
+
excludedFormalOwners.add(String(layout.constructor));
|
|
1318
|
+
const methodBodies = new Map();
|
|
1319
|
+
for (const [declaration, layout] of input.classes) {
|
|
1320
|
+
const bound = new Set();
|
|
1321
|
+
let current = layout;
|
|
1322
|
+
while (current !== undefined) {
|
|
1323
|
+
for (const method of current.methods) {
|
|
1324
|
+
if (method.callable === null ||
|
|
1325
|
+
bound.has(method.key) ||
|
|
1326
|
+
overriddenKeys.has(method.key) ||
|
|
1327
|
+
classMethodOverrideOf(input.classes, declaration, method.key) !== null)
|
|
1328
|
+
continue;
|
|
1329
|
+
bound.add(method.key);
|
|
1330
|
+
methodBodies.set(`${declaration} ${method.key}`, method.callable);
|
|
1331
|
+
}
|
|
1332
|
+
current = current.base === null ? undefined : input.classes.get(current.base);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
// A signature slot may only be narrowed where the ABI says the slot holds a
|
|
1336
|
+
// number. Every other slot is excluded by name: the census reads call-site
|
|
1337
|
+
// arguments to decide a formal is integral, and an argument widened into a
|
|
1338
|
+
// union arm on the way in still arrives as the `double` it was.
|
|
1339
|
+
//
|
|
1340
|
+
// The RESULT is the same rule at the other end of the frame, and `async` is
|
|
1341
|
+
// why it has to be stated: the census reads the terminator, which carries the
|
|
1342
|
+
// returned `number`, while the convention returns `gea::Promise<double>`
|
|
1343
|
+
// because the emitter wraps that value on the way out. Narrowing from the
|
|
1344
|
+
// terminator alone spelled `long long gea_body_fn_decl_f168_30(...)` around
|
|
1345
|
+
// `return gea::Promise<double>(v0);` -- certified, and refused by clang.
|
|
1346
|
+
// What a construction is worth keeping -- see `ir/instantiation.ts`. A
|
|
1347
|
+
// stateless component's render ignores `this`, so the `construct` that exists
|
|
1348
|
+
// only to give it one has no reader and no consequence, and goes whole. Both
|
|
1349
|
+
// halves are whole-program questions, so they are answered once here rather
|
|
1350
|
+
// than per body.
|
|
1351
|
+
const instantiation = {
|
|
1352
|
+
receiverIgnoringFunctions: functionsIgnoringTheirReceiver(input.bodies),
|
|
1353
|
+
unobservableConstructions: classesConstructedUnobservably(new Map([...input.classes].map(([declaration, layout]) => [
|
|
1354
|
+
declaration,
|
|
1355
|
+
{
|
|
1356
|
+
base: constructedBaseOf(layout),
|
|
1357
|
+
constructor: layout.constructor,
|
|
1358
|
+
initializers: layout.fields.flatMap((field) => (field.initializer === null ? [] : [field.initializer]))
|
|
1359
|
+
}
|
|
1360
|
+
])), input.bodies)
|
|
1361
|
+
};
|
|
1362
|
+
const excludedSignatureSlots = new Set();
|
|
1363
|
+
for (const body of input.bodies) {
|
|
1364
|
+
const abi = body.abi;
|
|
1365
|
+
if (abi === null)
|
|
1366
|
+
continue;
|
|
1367
|
+
abi.parameters.forEach((parameter, ordinal) => {
|
|
1368
|
+
if (parameter.value.kind === 'scalar' && parameter.value.domain === 'number')
|
|
1369
|
+
return;
|
|
1370
|
+
excludedSignatureSlots.add(integerParameterSlot(body.sourceOwner, ordinal));
|
|
1371
|
+
});
|
|
1372
|
+
if (abi.result.kind !== 'scalar' || abi.result.domain !== 'number')
|
|
1373
|
+
excludedSignatureSlots.add(integerResultSlot(body.sourceOwner));
|
|
1374
|
+
}
|
|
1375
|
+
const narrowedStorage = integerStorageCensusOf({
|
|
1376
|
+
bodies: input.bodies,
|
|
1377
|
+
structNameOf: cppStructNameOf,
|
|
1378
|
+
structFamilyOf,
|
|
1379
|
+
fieldStructNameOf,
|
|
1380
|
+
fieldRepresentationOf: (representation, key) => declaredFieldRepresentationOf(deriver, representation, key, input.classes),
|
|
1381
|
+
excludedStructs,
|
|
1382
|
+
fieldSeeds,
|
|
1383
|
+
directCallees: directCallables,
|
|
1384
|
+
methodBodies,
|
|
1385
|
+
excludedFormalOwners,
|
|
1386
|
+
excludedSignatureSlots
|
|
1387
|
+
});
|
|
1388
|
+
// Published before `cppRecordDeclarations` runs, and for the same reason as
|
|
1389
|
+
// `classStaticFields` below: a class field's lazy-materialization plan is a
|
|
1390
|
+
// whole-compile fact (`class-layout.ts`'s `censusLazyArrowFields`), and
|
|
1391
|
+
// `cppFieldInitializerStatements` (constructor emission), `records.ts`'s
|
|
1392
|
+
// dynamic-read dispatcher (built by the very next call), and
|
|
1393
|
+
// `emit-properties.ts` (every static read) must all agree on it without any
|
|
1394
|
+
// of the three re-deriving it. Unlike `classStaticFields`, this one has an
|
|
1395
|
+
// actual reader in this same function -- `cppRecordDeclarations` itself --
|
|
1396
|
+
// so it cannot be published after, the way that one is.
|
|
1397
|
+
publishLazyArrowFieldPlans(input.classes, censusLazyArrowFields(input.bodies, input.classes, captures));
|
|
1398
|
+
const structs = cppRecordDeclarations(input.plan, deriver, input.classes, input.hosts.reactive, boundRecordFields, structMembers, narrowedStorage.slots, input.wellKnownSymbols, perFile, input.reflection, emissionRepresentations, input.physicalClasses ?? input.classes, (body) => captures.of(body).kind === 'ok', fixedFieldStateConstant, singleEvaluationClasses);
|
|
1399
|
+
const recursiveContainers = cppRecursiveContainerDeclarations(input.plan, emissionRepresentations);
|
|
1400
|
+
// Real storage for every `ClassName.KEY = value` site the whole program
|
|
1401
|
+
// contains -- three.js's own idiom for a class static, spelled as a bare
|
|
1402
|
+
// assignment rather than a `static` member (`class-layout.ts`'s own doc
|
|
1403
|
+
// comment on `ClassStaticFieldStorage`). Published as a whole-compile
|
|
1404
|
+
// sidecar (keyed off `input.classes`'s own identity) BEFORE any body
|
|
1405
|
+
// renders, so a `constructor-family` `[[Get]]`/`[[Set]]` site anywhere in
|
|
1406
|
+
// the program can resolve it the same way `classStaticMemberOf` resolves a
|
|
1407
|
+
// REAL static -- by (declaration, key), never by re-deriving anything.
|
|
1408
|
+
// After the struct declarations and before every body, mirroring
|
|
1409
|
+
// `globalStorage`'s own ordering below: a static whose carrier is
|
|
1410
|
+
// itself a struct needs that struct to already be a complete type, and
|
|
1411
|
+
// every body that reads or writes one has to find its extern-free
|
|
1412
|
+
// definition already in scope.
|
|
1413
|
+
const classStaticFields = censusClassStaticFieldStorage(input.bodies, input.classes);
|
|
1414
|
+
publishClassStaticFieldStorage(input.classes, classStaticFields.storage);
|
|
1415
|
+
const classStatics = classStaticFieldStorageRows(classStaticFields.storage).map((row) => storageSpelling(row.type, row.name));
|
|
1416
|
+
// The reactive plan, completed with the two answers only this stage has.
|
|
1417
|
+
//
|
|
1418
|
+
// `revisions` is the struct renderer's own decision about which reactive
|
|
1419
|
+
// fields could not hold a cell and got a companion revision one instead, and
|
|
1420
|
+
// it is read back rather than recomputed so an emitted member pointer names
|
|
1421
|
+
// a member the struct actually declares.
|
|
1422
|
+
//
|
|
1423
|
+
// `dependencies` is decided once over every lowered body, because a JSX slot
|
|
1424
|
+
// subscribes a THUNK it did not itself render (`emit-jsx.ts`) -- the caller
|
|
1425
|
+
// and the callee are separate bodies, emitted independently and in no
|
|
1426
|
+
// guaranteed order. It is computed after `revisions` because which member a
|
|
1427
|
+
// dependency names depends on it.
|
|
1428
|
+
const reactive = { ...input.hosts.reactive, revisions: structs.revisionFields, celled: structs.celledFields, boundRecordFields };
|
|
1429
|
+
// Built here rather than beside the other includes above because one of its
|
|
1430
|
+
// lines is decided by the struct rendering that just ran: the cell's own
|
|
1431
|
+
// header is carried only where a field is ACTUALLY celled. `input.hosts
|
|
1432
|
+
// .reactive.fields` is the plugin's statement that a class has reactive
|
|
1433
|
+
// fields; `structs.celledFields`/`revisionFields` is whether this unit
|
|
1434
|
+
// rendered storage for one. Only the second may pull in the engine, because
|
|
1435
|
+
// the engine's headers are on the include path for an engine build alone --
|
|
1436
|
+
// which is exactly why `gea_runtime.h` forward-declares the cell instead of
|
|
1437
|
+
// including it.
|
|
1438
|
+
const cellPreamble = reactive.cell !== null && (structs.celledFields.size > 0 || structs.revisionFields.size > 0) ? input.hosts.reactive.cellPreamble : [];
|
|
1439
|
+
const prelude = [
|
|
1440
|
+
...standardIncludes,
|
|
1441
|
+
...hostPreamblesOf(emissionRepresentations, input.placements, input.hosts, input.bodies),
|
|
1442
|
+
...cellPreamble,
|
|
1443
|
+
runtimeInclude,
|
|
1444
|
+
...hostIncludesOf(emissionRepresentations, input.hosts)
|
|
1445
|
+
].join('\n');
|
|
1446
|
+
const reactiveCensus = reactiveDependenciesOfBodies(input.bodies, input.classes, reactive);
|
|
1447
|
+
const hosts = {
|
|
1448
|
+
...input.hosts,
|
|
1449
|
+
reactive: { ...reactive, dependencies: reactiveCensus.all, nodeDependencies: reactiveCensus.node }
|
|
1450
|
+
};
|
|
1451
|
+
const hostMethodAliases = buildHostMethodAliasIndex(input.bodies, input.placements, hosts);
|
|
1452
|
+
// The JSON overload set the runtime header declares, re-introduced HERE when
|
|
1453
|
+
// this unit is isolated.
|
|
1454
|
+
//
|
|
1455
|
+
// `gea_json_write`/`gea_json_read` are deliberately un-namespaced so that a
|
|
1456
|
+
// generated overload can call a sibling, or one of the header's primitives,
|
|
1457
|
+
// by a plain unqualified name (`gea_runtime.h`'s own note says so). A
|
|
1458
|
+
// namespace breaks exactly that: an overload declared inside one HIDES every
|
|
1459
|
+
// global-scope declaration of the same name for unqualified lookup, and
|
|
1460
|
+
// argument-dependent lookup cannot make up the difference for a
|
|
1461
|
+
// `std::string` or a `double` field, whose associated namespace is `std` or
|
|
1462
|
+
// nothing. A record with one string member then failed to compile -- "no
|
|
1463
|
+
// matching function for call to `gea_json_write`", with only this unit's own
|
|
1464
|
+
// record overloads offered as candidates.
|
|
1465
|
+
//
|
|
1466
|
+
// Two using-declarations put both sets in one scope, which is what overload
|
|
1467
|
+
// resolution needs. Only when isolated: at global scope a `using ::name;`
|
|
1468
|
+
// would name a member of the namespace it appears in, which is ill-formed.
|
|
1469
|
+
const jsonUsing = isolate && jsonStructs.declarations.length > 0 ? ['using ::gea_json_write;\nusing ::gea_json_read;'] : [];
|
|
1470
|
+
// A host-method alias cell is never written or read as storage -- both ends
|
|
1471
|
+
// name the host member instead (`buildHostMethodAliasIndex`) -- so declaring
|
|
1472
|
+
// it would leave a `CallableObject` of the method's own convention in the
|
|
1473
|
+
// unit, boxing an `any` formal that no code ever passes.
|
|
1474
|
+
const globals = globalStorage(input.placements, new Set([...input.omitGlobals, ...hostMethodAliases.keys()]));
|
|
1475
|
+
// Environment structs ahead of every forward signature: a capturing body's
|
|
1476
|
+
// own formal names its struct as a pointer type, so the struct must already
|
|
1477
|
+
// be a complete type by the time that formal is spelled.
|
|
1478
|
+
const environments = input.bodies.flatMap((body) => {
|
|
1479
|
+
const declaration = environmentDeclarationOf(body.sourceOwner, captures.of(body.sourceOwner));
|
|
1480
|
+
return declaration === null ? [] : [declaration];
|
|
1481
|
+
});
|
|
1482
|
+
// The census answers per SLOT; a signature is spelled per body, so its
|
|
1483
|
+
// formal slots are read back here into the positions each body declares.
|
|
1484
|
+
// A cycle can only run through something this unit renders that carries a
|
|
1485
|
+
// `trace`: a struct, a recursive container, or a captured environment.
|
|
1486
|
+
// `gea::bufferCycleCandidate` no-ops for every other `Ref`, so for a program
|
|
1487
|
+
// with none of the three the engine's deferral hooks are provably dead code
|
|
1488
|
+
// -- and `borrow-helper-chain.ts` pins their absence, because emitting them
|
|
1489
|
+
// put `gea::collectCyclesIfNeeded()` into a program that allocates nothing
|
|
1490
|
+
// collectable at all.
|
|
1491
|
+
const cycleCollectableProgram = structs.declarations.length > 0 || recursiveContainers.length > 0 || environments.length > 0;
|
|
1492
|
+
const runtimeDefinitions = input.runtimeDefinitions
|
|
1493
|
+
.filter((definition) => definition.requires === null || cycleCollectableProgram)
|
|
1494
|
+
.map((definition) => definition.text);
|
|
1495
|
+
const narrowedFormals = new Map();
|
|
1496
|
+
for (const slot of narrowedStorage.slots) {
|
|
1497
|
+
const boundary = slot.lastIndexOf('#');
|
|
1498
|
+
if (boundary <= 0)
|
|
1499
|
+
continue;
|
|
1500
|
+
const ordinal = Number(slot.slice(boundary + 1));
|
|
1501
|
+
if (!Number.isInteger(ordinal))
|
|
1502
|
+
continue;
|
|
1503
|
+
const owner = slot.slice(0, boundary);
|
|
1504
|
+
const positions = narrowedFormals.get(owner) ?? new Set();
|
|
1505
|
+
positions.add(ordinal);
|
|
1506
|
+
narrowedFormals.set(owner, positions);
|
|
1507
|
+
}
|
|
1508
|
+
const formalsNarrowedIn = (owner) => narrowedFormals.get(String(owner)) ?? new Set();
|
|
1509
|
+
const narrowedResults = new Set();
|
|
1510
|
+
for (const slot of narrowedStorage.slots) {
|
|
1511
|
+
const boundary = slot.lastIndexOf('#');
|
|
1512
|
+
if (boundary > 0 && slot.slice(boundary + 1) === 'result')
|
|
1513
|
+
narrowedResults.add(slot.slice(0, boundary));
|
|
1514
|
+
}
|
|
1515
|
+
const resultNarrowedIn = (owner) => narrowedResults.has(String(owner));
|
|
1516
|
+
// A field initializer is only a candidate. The runtime guard authenticates
|
|
1517
|
+
// it before a borrowed body is entered; all other targets keep owning ABI
|
|
1518
|
+
// parameters. Reuse the same borrowing and capture proofs as direct calls.
|
|
1519
|
+
// Integer-adapted signatures and receivers still need their normal thunk.
|
|
1520
|
+
const borrowableMemberBodies = new Set();
|
|
1521
|
+
for (const candidate of callableMemberCandidates.values()) {
|
|
1522
|
+
const body = input.bodies.find((body) => body.sourceOwner === candidate);
|
|
1523
|
+
if (body?.abi?.receiver !== null || captures.of(candidate).kind !== 'none')
|
|
1524
|
+
continue;
|
|
1525
|
+
if (formalsBorrowedIn(candidate).size === 0 || formalsNarrowedIn(candidate).size > 0 || resultNarrowedIn(candidate))
|
|
1526
|
+
continue;
|
|
1527
|
+
borrowableMemberBodies.add(candidate);
|
|
1528
|
+
}
|
|
1529
|
+
// Keep the old entry convention for every unproved caller. A second entry
|
|
1530
|
+
// may borrow stable caller slots even when the implementation re-enters JS.
|
|
1531
|
+
const stableBorrowEntries = new Map();
|
|
1532
|
+
const physicalCounts = new Map();
|
|
1533
|
+
for (const body of input.bodies)
|
|
1534
|
+
physicalCounts.set(String(body.sourceOwner), (physicalCounts.get(String(body.sourceOwner)) ?? 0) + 1);
|
|
1535
|
+
for (const body of input.bodies) {
|
|
1536
|
+
if (isRegionId(body.sourceOwner))
|
|
1537
|
+
continue;
|
|
1538
|
+
const entry = stableBorrowEntryOf(body, body.sourceOwner, (declaration) => {
|
|
1539
|
+
const placement = input.placements.get(declaration);
|
|
1540
|
+
return placement?.storage.kind === 'local' && placement.storage.owner === body.sourceOwner && !captures.isBoxed(declaration)
|
|
1541
|
+
? placement.representation
|
|
1542
|
+
: null;
|
|
1543
|
+
}, formalsBorrowedIn(body.sourceOwner), dyingArguments, bodyCallsUnsafeKnownCallee(body.sourceOwner), {
|
|
1544
|
+
captureFree: captures.of(body.sourceOwner).kind === 'none',
|
|
1545
|
+
synchronous: !isCoroutineBody(body),
|
|
1546
|
+
singleBody: physicalCounts.get(String(body.sourceOwner)) === 1,
|
|
1547
|
+
unchangedNumericAbi: formalsNarrowedIn(body.sourceOwner).size === 0 && !resultNarrowedIn(body.sourceOwner)
|
|
1548
|
+
});
|
|
1549
|
+
if (entry)
|
|
1550
|
+
stableBorrowEntries.set(cppBodyName(body.sourceOwner), entry);
|
|
1551
|
+
}
|
|
1552
|
+
const signatures = input.bodies.flatMap((body) => {
|
|
1553
|
+
const original = `${signatureOf(body, captures, formalsNarrowedIn(body.sourceOwner), resultNarrowedIn(body.sourceOwner), formalsBorrowedIn(body.sourceOwner))};`;
|
|
1554
|
+
const entry = stableBorrowEntries.get(cppBodyName(body.sourceOwner));
|
|
1555
|
+
return entry === undefined ? [original] : [original, `${signatureOf(body, captures, new Set(), false, entry.formals, entry.name)};`];
|
|
1556
|
+
});
|
|
1557
|
+
// Source/name/length reflection keeps its facts program-wide, including
|
|
1558
|
+
// functions arriving through fields and ABI adapters -- one registration
|
|
1559
|
+
// table backs all three (`gea::CallableObject::facts()`), so a program that
|
|
1560
|
+
// reads any of `.toString()`, `.name` or `.length` off a callable needs
|
|
1561
|
+
// every body's registration, not just the one the read happens to reach.
|
|
1562
|
+
// Programs with none of these three reads need neither the strings nor the
|
|
1563
|
+
// static registrations at all.
|
|
1564
|
+
//
|
|
1565
|
+
// `Object.getOwnPropertyDescriptor(fn, "name")` and its reflective siblings
|
|
1566
|
+
// read the same facts a direct `fn.name` does, one call later: the `get`
|
|
1567
|
+
// fetching the `Object.*` member is noted, and a call through that value
|
|
1568
|
+
// handing over a callable is the read. A callable read through a RUNTIME
|
|
1569
|
+
// key (`fn[k]`) may name any of the three, so it counts as well.
|
|
1570
|
+
const reflectiveObjectMembers = new Set([
|
|
1571
|
+
'getOwnPropertyDescriptor',
|
|
1572
|
+
'getOwnPropertyNames',
|
|
1573
|
+
'hasOwn',
|
|
1574
|
+
'defineProperty',
|
|
1575
|
+
'keys',
|
|
1576
|
+
'entries',
|
|
1577
|
+
'values'
|
|
1578
|
+
]);
|
|
1579
|
+
// One read anywhere turns the source text on for EVERY function in the
|
|
1580
|
+
// program, so when it is on the only question worth asking is which body
|
|
1581
|
+
// turned it on. Env-gated because the answer is a single line and the
|
|
1582
|
+
// question is only asked while sizing a binary.
|
|
1583
|
+
const traceFunctionFacts = (body, why) => {
|
|
1584
|
+
if (process.env['GEA_FUNCTION_FACTS_DEBUG'])
|
|
1585
|
+
console.log(`[FACTS] ${String(body.sourceOwner)}: ${why}`);
|
|
1586
|
+
};
|
|
1587
|
+
const preserveFunctionFacts = input.bodies.some((body) => {
|
|
1588
|
+
const keys = stringConstantsOf(body);
|
|
1589
|
+
const callable = (representation) => representation.kind === 'function-value-dispatch' || representation.kind === 'function-and-constructor';
|
|
1590
|
+
const reflectors = new Set();
|
|
1591
|
+
for (const block of body.blocks.values())
|
|
1592
|
+
for (const operation of block.operations) {
|
|
1593
|
+
// A callable BOXED into a dynamic carrier (`const named: any =
|
|
1594
|
+
// function named() {...}`) can reach `Function.prototype.toString`
|
|
1595
|
+
// through any later `String(x)`/template-literal/`+` coercion of that
|
|
1596
|
+
// dynamic value -- `gea::host::detail::toString` dispatches on the
|
|
1597
|
+
// boxed VALUE's own runtime tag, not on which read site the census
|
|
1598
|
+
// happened to see, so the box itself is the read that matters, not a
|
|
1599
|
+
// later member access this census could name. Missing this left
|
|
1600
|
+
// every boxed callable answering `Function.prototype.toString` with
|
|
1601
|
+
// the registry's generic "function () { [native code] }" fallback,
|
|
1602
|
+
// silently dropping the function's own name and source text.
|
|
1603
|
+
if (operation.kind === 'convert' &&
|
|
1604
|
+
callable(operation.source.representation) &&
|
|
1605
|
+
operation.result.representation.kind === 'dynamic') {
|
|
1606
|
+
traceFunctionFacts(body, 'a callable boxed into a dynamic carrier');
|
|
1607
|
+
return true;
|
|
1608
|
+
}
|
|
1609
|
+
if (operation.kind === 'get') {
|
|
1610
|
+
if (callable(operation.receiver.representation)) {
|
|
1611
|
+
const key = keys.get(operation.key.value);
|
|
1612
|
+
if (key === undefined || key === 'toString' || key === 'name' || key === 'length') {
|
|
1613
|
+
traceFunctionFacts(body, `a read of "${key ?? '<runtime key>'}" off a callable`);
|
|
1614
|
+
return true;
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
const receiver = operation.receiver.representation;
|
|
1618
|
+
const member = operation.hostMethod?.protocol === 'ObjectConstructor'
|
|
1619
|
+
? operation.hostMethod.member
|
|
1620
|
+
: receiver.kind === 'native-handle' && (receiver.native ?? receiver.protocol) === 'ObjectConstructor'
|
|
1621
|
+
? keys.get(operation.key.value)
|
|
1622
|
+
: undefined;
|
|
1623
|
+
if (member !== undefined && reflectiveObjectMembers.has(member))
|
|
1624
|
+
reflectors.add(operation.result.id);
|
|
1625
|
+
}
|
|
1626
|
+
if (operation.kind === 'call' &&
|
|
1627
|
+
reflectors.has(operation.callee.value) &&
|
|
1628
|
+
operation.arguments.some((argument) => callable(argument.representation))) {
|
|
1629
|
+
traceFunctionFacts(body, 'a reflective Object.* call handed a callable');
|
|
1630
|
+
return true;
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
return false;
|
|
1634
|
+
});
|
|
1635
|
+
const thunks = new Map();
|
|
1636
|
+
for (const body of input.bodies) {
|
|
1637
|
+
const thunk = thunkOf(body, captures, formalsNarrowedIn(body.sourceOwner), resultNarrowedIn(body.sourceOwner), linkage, preserveFunctionFacts);
|
|
1638
|
+
if (thunk)
|
|
1639
|
+
thunks.set(body, thunk);
|
|
1640
|
+
}
|
|
1641
|
+
// ONE tag object per source declaration, shared by every monomorphic copy of
|
|
1642
|
+
// it. `gea::identifyCallable<&tag>` instantiates
|
|
1643
|
+
// `detail::CallableDeclarationTag` on this address, and the runtime documents
|
|
1644
|
+
// that address as "one program-wide address per emitted source declaration" --
|
|
1645
|
+
// which it was not while the emitter passed the per-COPY thunk pointer. Two
|
|
1646
|
+
// instantiations of one generic function are two thunks and still ONE
|
|
1647
|
+
// JavaScript function object, so `stateStack[i] !== State.done` compared two
|
|
1648
|
+
// identities of one `State.done` and answered true forever.
|
|
1649
|
+
//
|
|
1650
|
+
// Deduplicated by NAME rather than by body, since that is exactly the
|
|
1651
|
+
// equivalence being expressed: two bodies whose owners differ only in their
|
|
1652
|
+
// `@N` copy ordinal share this object.
|
|
1653
|
+
//
|
|
1654
|
+
// Taken from every body, not only the ones a thunk was rendered for: the tag
|
|
1655
|
+
// is named at the ALLOCATION site, and a body can reach one without
|
|
1656
|
+
// `thunkOf` producing a thunk of its own.
|
|
1657
|
+
const declarationTags = [...new Set(input.bodies.map((body) => cppCallableDeclarationTagName(body.sourceOwner)))].map((name) => `inline constexpr char ${name} = 0;`);
|
|
1658
|
+
// A refused body is an answer, not a crash. Emission is the last stage that
|
|
1659
|
+
// can discover a missing capability, and the discovery has to travel back as
|
|
1660
|
+
// a named gap the same way a lowering blocker does -- an exception escaping
|
|
1661
|
+
// here would take down a compilation that has a perfectly good report to give.
|
|
1662
|
+
const refused = structs.refused.map((refusal) => ({
|
|
1663
|
+
owner: refusal.structName,
|
|
1664
|
+
reason: refusal.reason,
|
|
1665
|
+
key: 'print:refused'
|
|
1666
|
+
}));
|
|
1667
|
+
for (const conflict of classStaticFields.conflicts) {
|
|
1668
|
+
refused.push({
|
|
1669
|
+
owner: conflict,
|
|
1670
|
+
reason: `cpp emission refuses to declare static field storage for ${conflict}: its writes carry incompatible representations`,
|
|
1671
|
+
key: 'print:refused'
|
|
1672
|
+
});
|
|
1673
|
+
}
|
|
1674
|
+
// `virtuals.refused` is deliberately NOT among them. A family with no dispatch
|
|
1675
|
+
// member is only a defect where something actually CALLS it through a base --
|
|
1676
|
+
// and `emit-properties.ts` refuses exactly there, naming the call. Reporting
|
|
1677
|
+
// the family itself withholds the certificate for a program that may never
|
|
1678
|
+
// dispatch on it: the gea framework's own `Component.template` is overridden
|
|
1679
|
+
// by every app component under a different convention, and every JSX app
|
|
1680
|
+
// resolves it concretely through the plugin's render bridge, so raising it
|
|
1681
|
+
// here failed 40-odd programs that had nothing wrong with them.
|
|
1682
|
+
const constructions = constructionsOf(programSite, deriver, input.classes, refused, linkage, abiByBody, structs.staticMethodStateClasses);
|
|
1683
|
+
// One intern table for the whole program, shared by every body: two bodies
|
|
1684
|
+
// that name the same `Symbol.for` key must reach the same static, and a
|
|
1685
|
+
// per-body table would give them one each.
|
|
1686
|
+
const symbolKeys = new Map();
|
|
1687
|
+
// One table for the whole program for the same reason, and with a stricter
|
|
1688
|
+
// requirement: a tagged-template site's object must be ONE object, so the
|
|
1689
|
+
// definition every body that reaches that site calls has to be the same one.
|
|
1690
|
+
const templateObjects = new Map();
|
|
1691
|
+
// The bodies are rendered before any section is placed, because the symbol
|
|
1692
|
+
// statics they reference are only known once every body has been rendered,
|
|
1693
|
+
// and C++ requires a namespace-scope name to be declared before it is used.
|
|
1694
|
+
// Rendering first is the whole of the reordering: each body's artifacts keep
|
|
1695
|
+
// their own facts and their own order.
|
|
1696
|
+
const renderedBodies = [];
|
|
1697
|
+
for (const body of input.bodies) {
|
|
1698
|
+
// A body's statements are not a translation unit on their own: they need a
|
|
1699
|
+
// signature to live in, and the owner is what names it. The open and close
|
|
1700
|
+
// are structure with no semantic operation behind them, which is exactly
|
|
1701
|
+
// what `empty` facts are for -- the statements inside keep their own.
|
|
1702
|
+
const templateObjectsBefore = templateObjects.size;
|
|
1703
|
+
const commonJsOwner = commonJsOwnerOf(body);
|
|
1704
|
+
if (commonJsOwner !== null && 'reason' in commonJsOwner) {
|
|
1705
|
+
refused.push(commonJsOwner);
|
|
1706
|
+
continue;
|
|
1707
|
+
}
|
|
1708
|
+
try {
|
|
1709
|
+
const sections = emitBody(body, input.placements, input.classes, hosts, deriver, input.wellKnownSymbols, captures, symbolKeys, templateObjects, directCallables, virtuals.dispatched, narrowedStorage.factsOf(body.sourceOwner), formalsNarrowedIn(body.sourceOwner), repeatedConstructors, dyingArguments, instantiation, (callable) => abiByBody.get(String(callable)) ?? null, hostMethodAliases, callableMemberCandidates, borrowableMemberBodies, stableBorrowEntries, printerDrift, input.conversions, selectionHelpers, callableIdentityDemand, nativeIntegrityRestricted, fixedFieldStateConstant);
|
|
1710
|
+
const stableEntry = stableBorrowEntries.get(cppBodyName(body.sourceOwner));
|
|
1711
|
+
const commonJsScope = commonJsOwner === null || commonJsOwner.nativeRecord
|
|
1712
|
+
? []
|
|
1713
|
+
: [`gea::commonjs::Scope commonjs_scope(${cppCommonJsRecordName(commonJsOwner.owner)}());`];
|
|
1714
|
+
// A body's formals are named `gea_this`/`gea_arg_N`/`gea_e` by this
|
|
1715
|
+
// emitter, never by the user's own source -- so whether the source
|
|
1716
|
+
// *read* a given position is a fact only the rendered body text can
|
|
1717
|
+
// answer, exactly as `records.ts`'s reflection hooks already spell
|
|
1718
|
+
// "unread" by omitting the name rather than by (void)-casting it.
|
|
1719
|
+
const opening = withUnreadParametersUnnamed(signatureOf(body, captures, formalsNarrowedIn(body.sourceOwner), resultNarrowedIn(body.sourceOwner), stableEntry?.formals ?? formalsBorrowedIn(body.sourceOwner), stableEntry?.name ?? cppBodyName(body.sourceOwner)), [...commonJsScope, ...sections.map((section) => section.text)]);
|
|
1720
|
+
renderedBodies.push({
|
|
1721
|
+
body,
|
|
1722
|
+
artifacts: [
|
|
1723
|
+
plain(`${opening} {`),
|
|
1724
|
+
...commonJsScope.map(plain),
|
|
1725
|
+
...sections,
|
|
1726
|
+
plain('}'),
|
|
1727
|
+
...(stableEntry === undefined
|
|
1728
|
+
? []
|
|
1729
|
+
: [
|
|
1730
|
+
plain(`${signatureOf(body, captures, new Set(), false, formalsBorrowedIn(body.sourceOwner))} {`),
|
|
1731
|
+
plain(
|
|
1732
|
+
// The stable entry's own signature always states `gea_this`
|
|
1733
|
+
// first when the body has a receiver (`formalsOf` spells it
|
|
1734
|
+
// unconditionally), a fact `stableEntry.abi.parameters` --
|
|
1735
|
+
// receiver-less by construction -- never carries. This
|
|
1736
|
+
// owning wrapper's own formal is exactly that receiver, so
|
|
1737
|
+
// it forwards unchanged: never moved (the receiver formal
|
|
1738
|
+
// above is never in `narrowed`/moved sets) and never boxed.
|
|
1739
|
+
`return ${stableEntry.name}(${[
|
|
1740
|
+
...(stableEntry.abi.receiver !== null ? [cppReceiverName] : []),
|
|
1741
|
+
...stableEntry.abi.parameters.map((_, ordinal) => stableEntry.formals.has(ordinal) ? cppFormalName(ordinal) : `std::move(${cppFormalName(ordinal)})`)
|
|
1742
|
+
].join(', ')});`),
|
|
1743
|
+
plain('}')
|
|
1744
|
+
])
|
|
1745
|
+
],
|
|
1746
|
+
templateObjects: [...templateObjects.values()].slice(templateObjectsBefore)
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
catch (error) {
|
|
1750
|
+
if (!isCppEmitBlockedError(error))
|
|
1751
|
+
throw error;
|
|
1752
|
+
refused.push({ owner: body.sourceOwner, reason: error.message, key: error.kind });
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
let entry = null;
|
|
1756
|
+
const commonJs = commonJsDefinitionsOf(input.bodies);
|
|
1757
|
+
refused.push(...commonJs.refused);
|
|
1758
|
+
if (input.entrySymbol !== null) {
|
|
1759
|
+
const rendered = entryDefinitionOf(input.entrySymbol, input.moduleOrder, input.bodies, commonJs.modules, commonJs.hasBuiltinModuleRegistry);
|
|
1760
|
+
if ('refusal' in rendered)
|
|
1761
|
+
refused.push(rendered.refusal);
|
|
1762
|
+
else
|
|
1763
|
+
entry = rendered.text;
|
|
1764
|
+
}
|
|
1765
|
+
if (refused.length > 0)
|
|
1766
|
+
return refuse(refused);
|
|
1767
|
+
// The union alias block goes where `unionAliasMarker` was appended: inside
|
|
1768
|
+
// the program's namespace, ahead of every struct body (a struct's fields
|
|
1769
|
+
// spell unions) and every signature. A union's arms name program structs
|
|
1770
|
+
// through `gea::Ref<T>`, which needs only a forward declaration, so the
|
|
1771
|
+
// block opens by forward-declaring every struct the unit declares anyway --
|
|
1772
|
+
// the same lines `appendStructDeclarations` emits, repeated, which C++
|
|
1773
|
+
// permits -- and then declares each alias in first-spelling order. Spliced
|
|
1774
|
+
// into the rendered text rather than appended, because the aliases are
|
|
1775
|
+
// known only once the LAST body has been rendered, and the block has to
|
|
1776
|
+
// come first.
|
|
1777
|
+
const unionAliasMarker = '// gea-union-aliases';
|
|
1778
|
+
const spliceUnionAliases = (source) => {
|
|
1779
|
+
const aliases = endUnionAliasing();
|
|
1780
|
+
const forwards = [...recursiveContainers, ...structs.declarations, ...jsonStructs.declarations].filter((declaration) => declaration.startsWith('struct ') && declaration.endsWith(';') && !declaration.includes('{'));
|
|
1781
|
+
const block = [...forwards, ...aliases.map(({ name, spelling }) => `using ${name} = ${spelling};`)].join('\n');
|
|
1782
|
+
return spliceRendered(source, unionAliasMarker, block);
|
|
1783
|
+
};
|
|
1784
|
+
const appendStructDeclarations = (builder) => {
|
|
1785
|
+
for (const declaration of recursiveContainers)
|
|
1786
|
+
builder.append(plain(declaration));
|
|
1787
|
+
for (const declaration of structs.declarations)
|
|
1788
|
+
builder.append(plain(declaration));
|
|
1789
|
+
const qualifier = isolate && namespaceName !== null ? `${namespaceName}::` : '';
|
|
1790
|
+
// A recursive callable/container wrapper's `gea::detail::TraceEdges`
|
|
1791
|
+
// specialisation has the exact same problem `structs.runtimeClassBases`
|
|
1792
|
+
// solves below: re-opening `namespace gea::detail` from INSIDE the
|
|
1793
|
+
// isolating namespace declares a shadow `gea`, not the real one. So it is
|
|
1794
|
+
// closed out to global scope here too, sharing the one close/reopen
|
|
1795
|
+
// rather than doing it twice.
|
|
1796
|
+
const recursiveContainerTraceEdges = cppRecursiveContainerTraceEdges(input.plan, qualifier, emissionRepresentations);
|
|
1797
|
+
if (recursiveContainerTraceEdges.length === 0 && structs.runtimeClassBases.length === 0)
|
|
1798
|
+
return;
|
|
1799
|
+
// Explicit specializations belong to the runtime template's namespace,
|
|
1800
|
+
// never a nested gea namespace inside the isolated program. Named program
|
|
1801
|
+
// types stay qualified so separately linked programs cannot collide.
|
|
1802
|
+
if (isolate)
|
|
1803
|
+
builder.append(plain(namespaceClose));
|
|
1804
|
+
for (const declaration of recursiveContainerTraceEdges)
|
|
1805
|
+
builder.append(plain(declaration));
|
|
1806
|
+
if (structs.runtimeClassBases.length > 0) {
|
|
1807
|
+
builder.append(plain('namespace gea::detail {'));
|
|
1808
|
+
for (const { derived, base } of structs.runtimeClassBases) {
|
|
1809
|
+
builder.append(plain(`template <> struct ClassRefBase<${qualifier}${derived}> { using type = ${qualifier}${base}; };`));
|
|
1810
|
+
}
|
|
1811
|
+
builder.append(plain('} // namespace gea::detail'));
|
|
1812
|
+
}
|
|
1813
|
+
if (isolate)
|
|
1814
|
+
builder.append(plain(namespaceOpen));
|
|
1815
|
+
};
|
|
1816
|
+
if (!perFile) {
|
|
1817
|
+
const builder = createCppDocumentBuilder();
|
|
1818
|
+
builder.append(plain(prelude));
|
|
1819
|
+
// Everything from here to `runtimeDefinitions` is this program's own, and in
|
|
1820
|
+
// a resident build no other unit may see any of it. See `isolateSymbols`.
|
|
1821
|
+
//
|
|
1822
|
+
// Nothing with EXTERNAL linkage may be declared inside, which is why an
|
|
1823
|
+
// isolated unit with an `extern` global is refused above rather than wrapped:
|
|
1824
|
+
// an unnamed namespace would turn that declaration into a second, internal
|
|
1825
|
+
// entity and the real symbol would go unreferenced.
|
|
1826
|
+
if (isolate) {
|
|
1827
|
+
for (const declaration of [...externs, ...absent])
|
|
1828
|
+
builder.append(plain(declaration.text));
|
|
1829
|
+
builder.append(plain(namespaceOpen));
|
|
1830
|
+
}
|
|
1831
|
+
builder.append(plain(unionAliasMarker));
|
|
1832
|
+
appendStructDeclarations(builder);
|
|
1833
|
+
for (const spelling of classStatics)
|
|
1834
|
+
builder.append(plain(spelling.definition));
|
|
1835
|
+
for (const text of jsonUsing)
|
|
1836
|
+
builder.append(plain(text));
|
|
1837
|
+
for (const declaration of jsonStructs.declarations)
|
|
1838
|
+
builder.append(plain(declaration));
|
|
1839
|
+
if (!isolate)
|
|
1840
|
+
for (const declaration of [...externs, ...absent])
|
|
1841
|
+
builder.append(plain(declaration.text));
|
|
1842
|
+
for (const spelling of globals)
|
|
1843
|
+
builder.append(plain(spelling.definition));
|
|
1844
|
+
for (const declaration of environments)
|
|
1845
|
+
builder.append(plain(declaration));
|
|
1846
|
+
for (const signature of signatures)
|
|
1847
|
+
builder.append(plain(signature));
|
|
1848
|
+
// A field dispatcher the struct could not define inline. An accessor arm
|
|
1849
|
+
// CALLS a body, and every struct is declared long before any body has a
|
|
1850
|
+
// name, so `records.ts` puts that struct's whole dispatcher out of line and
|
|
1851
|
+
// this is the first point at which the names it calls exist. The map holds
|
|
1852
|
+
// only those structs in this layout (`needsOutOfLineFields`), so nothing
|
|
1853
|
+
// else moves out of the class body.
|
|
1854
|
+
for (const definitions of structs.fieldDefinitionsByStruct.values())
|
|
1855
|
+
for (const definition of definitions)
|
|
1856
|
+
builder.append(plain(definition));
|
|
1857
|
+
for (const definition of commonJs.definitions)
|
|
1858
|
+
builder.append(plain(definition));
|
|
1859
|
+
// After every body has a name, because each dispatch member forwards to one.
|
|
1860
|
+
for (const definition of virtuals.definitions)
|
|
1861
|
+
builder.append(plain(definition));
|
|
1862
|
+
for (const definition of prototypeHooks.definitions)
|
|
1863
|
+
builder.append(plain(definition));
|
|
1864
|
+
for (const tag of declarationTags)
|
|
1865
|
+
builder.append(plain(tag));
|
|
1866
|
+
for (const thunk of thunks.values())
|
|
1867
|
+
builder.append(plain(thunk.definition));
|
|
1868
|
+
// After the body declarations: a construct function calls the field
|
|
1869
|
+
// initializers and the constructor body by name.
|
|
1870
|
+
for (const definition of constructDefinitionsOf(constructions))
|
|
1871
|
+
builder.append(plain(definition));
|
|
1872
|
+
for (const definition of symbolKeyDefinitions(symbolKeys))
|
|
1873
|
+
builder.append(plain(definition));
|
|
1874
|
+
for (const definition of templateObjectDefinitions(templateObjects))
|
|
1875
|
+
builder.append(plain(definition));
|
|
1876
|
+
for (const rendered of renderedBodies)
|
|
1877
|
+
for (const artifact of rendered.artifacts)
|
|
1878
|
+
builder.append(artifact);
|
|
1879
|
+
// After every body, and before the entry: a host's required definition can
|
|
1880
|
+
// name anything this unit declared, and nothing this unit emits depends on
|
|
1881
|
+
// one, so the last position with no ordering constraint is the honest one.
|
|
1882
|
+
if (isolate)
|
|
1883
|
+
builder.append(plain(namespaceClose));
|
|
1884
|
+
for (const definition of runtimeDefinitions)
|
|
1885
|
+
builder.append(plain(definition));
|
|
1886
|
+
if (entry !== null)
|
|
1887
|
+
builder.append(plain(entry));
|
|
1888
|
+
const source = spliceUnionAliases(render(builder.seal()));
|
|
1889
|
+
return {
|
|
1890
|
+
source,
|
|
1891
|
+
units: [{ role: 'unit', fileName: `${input.unitBaseName}.cpp`, sourceFile: null, source }],
|
|
1892
|
+
refused: Object.freeze([]),
|
|
1893
|
+
printerDrift
|
|
1894
|
+
};
|
|
1895
|
+
}
|
|
1896
|
+
// The per-file layout. Three kinds of file, and the rule for what goes where
|
|
1897
|
+
// is C++'s own: a DECLARATION may appear in every unit, so it goes in the
|
|
1898
|
+
// header; a DEFINITION with external linkage may appear in exactly one, so it
|
|
1899
|
+
// goes in the unit that owns it -- a body's or a class's own file, or the
|
|
1900
|
+
// program unit for what belongs to no file (storage, dispatch members, the
|
|
1901
|
+
// host-required definitions, the entry). Record field tables belong to no
|
|
1902
|
+
// source declaration and live in the program unit. Class field tables live
|
|
1903
|
+
// with their class. JSON overloads and symbol keys remain inline.
|
|
1904
|
+
const headerName = `${input.unitBaseName}.hpp`;
|
|
1905
|
+
const include = `#include "${headerName}"`;
|
|
1906
|
+
// The prelude is a header of its own so a build can precompile it as the
|
|
1907
|
+
// RUNTIME layer and chain the program's header on top. It has to be this
|
|
1908
|
+
// text and not `generated_support.hpp`: the hosts' preambles come before
|
|
1909
|
+
// `gea_runtime.h` and decide what it declares (`GEA_HOST_DECLARED` turns its
|
|
1910
|
+
// engine stand-ins off), so a PCH built from a header without them declares
|
|
1911
|
+
// stand-ins that then collide with the engine's own types in every unit.
|
|
1912
|
+
const runtimeHeaderName = `${input.unitBaseName}.runtime.hpp`;
|
|
1913
|
+
const runtimeHeader = createCppDocumentBuilder();
|
|
1914
|
+
runtimeHeader.append(plain('#pragma once'));
|
|
1915
|
+
runtimeHeader.append(plain(prelude));
|
|
1916
|
+
const header = createCppDocumentBuilder();
|
|
1917
|
+
header.append(plain('#pragma once'));
|
|
1918
|
+
header.append(plain(`#include "${runtimeHeaderName}"`));
|
|
1919
|
+
if (isolate) {
|
|
1920
|
+
for (const declaration of externs)
|
|
1921
|
+
header.append(plain(declaration.text));
|
|
1922
|
+
for (const definition of absent)
|
|
1923
|
+
header.append(plain(definition.declaration));
|
|
1924
|
+
header.append(plain(namespaceOpen));
|
|
1925
|
+
}
|
|
1926
|
+
header.append(plain(unionAliasMarker));
|
|
1927
|
+
appendStructDeclarations(header);
|
|
1928
|
+
for (const spelling of classStatics)
|
|
1929
|
+
header.append(plain(spelling.declaration));
|
|
1930
|
+
for (const text of jsonUsing)
|
|
1931
|
+
header.append(plain(text));
|
|
1932
|
+
for (const declaration of jsonStructs.declarations)
|
|
1933
|
+
header.append(plain(declaration));
|
|
1934
|
+
if (!isolate) {
|
|
1935
|
+
for (const declaration of externs)
|
|
1936
|
+
header.append(plain(declaration.text));
|
|
1937
|
+
for (const definition of absent)
|
|
1938
|
+
header.append(plain(definition.declaration));
|
|
1939
|
+
}
|
|
1940
|
+
for (const spelling of globals)
|
|
1941
|
+
header.append(plain(spelling.declaration));
|
|
1942
|
+
for (const declaration of environments)
|
|
1943
|
+
header.append(plain(declaration));
|
|
1944
|
+
for (const signature of signatures)
|
|
1945
|
+
header.append(plain(signature));
|
|
1946
|
+
for (const helper of selectionHelpers?.values() ?? [])
|
|
1947
|
+
header.append(plain(helper.declaration));
|
|
1948
|
+
for (const definition of commonJs.definitions)
|
|
1949
|
+
header.append(plain(definition));
|
|
1950
|
+
for (const tag of declarationTags)
|
|
1951
|
+
header.append(plain(tag));
|
|
1952
|
+
for (const thunk of thunks.values())
|
|
1953
|
+
header.append(plain(thunk.prototype));
|
|
1954
|
+
for (const construction of constructions) {
|
|
1955
|
+
if (construction.initializerPrototype !== null)
|
|
1956
|
+
header.append(plain(construction.initializerPrototype));
|
|
1957
|
+
for (const prototype of construction.constructPrototypes)
|
|
1958
|
+
header.append(plain(prototype));
|
|
1959
|
+
}
|
|
1960
|
+
for (const definition of symbolKeyDefinitions(symbolKeys))
|
|
1961
|
+
header.append(plain(definition));
|
|
1962
|
+
if (isolate)
|
|
1963
|
+
header.append(plain(namespaceClose));
|
|
1964
|
+
const program = createCppDocumentBuilder();
|
|
1965
|
+
program.append(plain(include));
|
|
1966
|
+
// At global scope whether or not the program is isolated, because that is
|
|
1967
|
+
// where the header declared them: an absent global is a host's name, and a
|
|
1968
|
+
// host's name is never inside the program's namespace.
|
|
1969
|
+
for (const definition of absent)
|
|
1970
|
+
program.append(plain(definition.text));
|
|
1971
|
+
if (isolate)
|
|
1972
|
+
program.append(plain(namespaceOpen));
|
|
1973
|
+
for (const spelling of classStatics)
|
|
1974
|
+
program.append(plain(spelling.definition));
|
|
1975
|
+
for (const spelling of globals)
|
|
1976
|
+
program.append(plain(spelling.definition));
|
|
1977
|
+
for (const helper of selectionHelpers?.values() ?? [])
|
|
1978
|
+
program.append(plain(helper.definition));
|
|
1979
|
+
for (const definition of virtuals.definitions)
|
|
1980
|
+
program.append(plain(definition));
|
|
1981
|
+
for (const definition of prototypeHooks.definitions)
|
|
1982
|
+
program.append(plain(definition));
|
|
1983
|
+
const classStructNames = new Set([...input.classes.values()].map((layout) => cppClassName(layout.declaration)));
|
|
1984
|
+
for (const [structName, definitions] of structs.fieldDefinitionsByStruct) {
|
|
1985
|
+
if (!classStructNames.has(structName))
|
|
1986
|
+
for (const definition of definitions)
|
|
1987
|
+
program.append(plain(definition));
|
|
1988
|
+
}
|
|
1989
|
+
if (isolate)
|
|
1990
|
+
program.append(plain(namespaceClose));
|
|
1991
|
+
for (const definition of runtimeDefinitions)
|
|
1992
|
+
program.append(plain(definition));
|
|
1993
|
+
if (entry !== null)
|
|
1994
|
+
program.append(plain(entry));
|
|
1995
|
+
// Bodies and classes grouped by the file that declared them. The identity is
|
|
1996
|
+
// the grouping key; the file name is only what the unit is called.
|
|
1997
|
+
const groups = new Map();
|
|
1998
|
+
const groupOf = (identity) => {
|
|
1999
|
+
const existing = groups.get(identity);
|
|
2000
|
+
if (existing)
|
|
2001
|
+
return existing;
|
|
2002
|
+
const created = { bodies: [], constructions: [], fieldDefinitions: [] };
|
|
2003
|
+
groups.set(identity, created);
|
|
2004
|
+
return created;
|
|
2005
|
+
};
|
|
2006
|
+
for (const rendered of renderedBodies)
|
|
2007
|
+
groupOf(fileIdentityOf(rendered.body.sourceOwner)).bodies.push(rendered);
|
|
2008
|
+
for (const construction of constructions)
|
|
2009
|
+
groupOf(fileIdentityOf(construction.declaration)).constructions.push(construction);
|
|
2010
|
+
for (const layout of input.classes.values()) {
|
|
2011
|
+
const definitions = structs.fieldDefinitionsByStruct.get(cppClassName(layout.declaration));
|
|
2012
|
+
if (definitions)
|
|
2013
|
+
groupOf(fileIdentityOf(layout.declaration)).fieldDefinitions.push(...definitions);
|
|
2014
|
+
}
|
|
2015
|
+
const files = [...groups.keys()]
|
|
2016
|
+
.map((identity) => ({ identity, displayName: input.sourceFileNames.get(identity) ?? identity }))
|
|
2017
|
+
.sort((left, right) => left.displayName < right.displayName ? -1 : left.displayName > right.displayName ? 1 : left.identity.localeCompare(right.identity));
|
|
2018
|
+
const names = moduleUnitNames(input.unitBaseName, files);
|
|
2019
|
+
const units = [
|
|
2020
|
+
{ role: 'runtime-header', fileName: runtimeHeaderName, sourceFile: null, source: render(runtimeHeader.seal()) },
|
|
2021
|
+
{ role: 'header', fileName: headerName, sourceFile: null, source: spliceUnionAliases(render(header.seal())) },
|
|
2022
|
+
{ role: 'program', fileName: `${input.unitBaseName}.cpp`, sourceFile: null, source: render(program.seal()) }
|
|
2023
|
+
];
|
|
2024
|
+
for (const file of files) {
|
|
2025
|
+
const group = groups.get(file.identity);
|
|
2026
|
+
if (!group)
|
|
2027
|
+
continue;
|
|
2028
|
+
const unit = createCppDocumentBuilder();
|
|
2029
|
+
unit.append(plain(include));
|
|
2030
|
+
if (isolate)
|
|
2031
|
+
unit.append(plain(namespaceOpen));
|
|
2032
|
+
for (const definition of group.fieldDefinitions)
|
|
2033
|
+
unit.append(plain(definition));
|
|
2034
|
+
for (const rendered of group.bodies)
|
|
2035
|
+
for (const definition of rendered.templateObjects)
|
|
2036
|
+
unit.append(plain(definition.text));
|
|
2037
|
+
for (const rendered of group.bodies) {
|
|
2038
|
+
const thunk = thunks.get(rendered.body);
|
|
2039
|
+
if (thunk)
|
|
2040
|
+
unit.append(plain(thunk.definition));
|
|
2041
|
+
}
|
|
2042
|
+
for (const construction of group.constructions)
|
|
2043
|
+
for (const definition of construction.definitions)
|
|
2044
|
+
unit.append(plain(definition));
|
|
2045
|
+
for (const rendered of group.bodies)
|
|
2046
|
+
for (const artifact of rendered.artifacts)
|
|
2047
|
+
unit.append(artifact);
|
|
2048
|
+
if (isolate)
|
|
2049
|
+
unit.append(plain(namespaceClose));
|
|
2050
|
+
units.push({
|
|
2051
|
+
role: 'module',
|
|
2052
|
+
fileName: names.get(file.identity) ?? `${input.unitBaseName}.${file.identity}.cpp`,
|
|
2053
|
+
sourceFile: input.sourceFileNames.get(file.identity) ?? null,
|
|
2054
|
+
source: render(unit.seal())
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
2057
|
+
return {
|
|
2058
|
+
source: null,
|
|
2059
|
+
units: input.layout === 'balanced' ? balanceCppUnits(units, input.unitBaseName) : units,
|
|
2060
|
+
refused: Object.freeze([]),
|
|
2061
|
+
printerDrift
|
|
2062
|
+
};
|
|
2063
|
+
};
|