@tsonic/emitter 0.0.62 → 0.0.64
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/dist/.tsbuildinfo +1 -1
- package/dist/adapter-generator.d.ts +5 -15
- package/dist/adapter-generator.d.ts.map +1 -1
- package/dist/adapter-generator.js +60 -53
- package/dist/adapter-generator.js.map +1 -1
- package/dist/contracts/backend-adapter.d.ts +36 -0
- package/dist/contracts/backend-adapter.d.ts.map +1 -0
- package/dist/contracts/backend-adapter.js +9 -0
- package/dist/contracts/backend-adapter.js.map +1 -0
- package/dist/contracts/emitter-contract.d.ts +54 -0
- package/dist/contracts/emitter-contract.d.ts.map +1 -0
- package/dist/contracts/emitter-contract.js +8 -0
- package/dist/contracts/emitter-contract.js.map +1 -0
- package/dist/contracts/import-classifier.d.ts +36 -0
- package/dist/contracts/import-classifier.d.ts.map +1 -0
- package/dist/contracts/import-classifier.js +9 -0
- package/dist/contracts/import-classifier.js.map +1 -0
- package/dist/core/{attributes.d.ts → format/attributes.d.ts} +9 -14
- package/dist/core/format/attributes.d.ts.map +1 -0
- package/dist/core/format/attributes.js +190 -0
- package/dist/core/format/attributes.js.map +1 -0
- package/dist/core/format/attributes.test.d.ts.map +1 -0
- package/dist/core/{attributes.test.js → format/attributes.test.js} +70 -32
- package/dist/core/format/attributes.test.js.map +1 -0
- package/dist/core/format/backend-ast/index.d.ts +7 -0
- package/dist/core/format/backend-ast/index.d.ts.map +1 -0
- package/dist/core/format/backend-ast/index.js +6 -0
- package/dist/core/format/backend-ast/index.js.map +1 -0
- package/dist/core/format/backend-ast/printer.d.ts +33 -0
- package/dist/core/format/backend-ast/printer.d.ts.map +1 -0
- package/dist/core/format/backend-ast/printer.js +1151 -0
- package/dist/core/format/backend-ast/printer.js.map +1 -0
- package/dist/core/format/backend-ast/types.d.ts +504 -0
- package/dist/core/format/backend-ast/types.d.ts.map +1 -0
- package/dist/core/format/backend-ast/types.js +13 -0
- package/dist/core/format/backend-ast/types.js.map +1 -0
- package/dist/core/format/backend-ast/utils.d.ts +26 -0
- package/dist/core/format/backend-ast/utils.d.ts.map +1 -0
- package/dist/core/format/backend-ast/utils.js +65 -0
- package/dist/core/format/backend-ast/utils.js.map +1 -0
- package/dist/core/{exports.d.ts → format/exports.d.ts} +2 -2
- package/dist/core/format/exports.d.ts.map +1 -0
- package/dist/core/format/exports.js +22 -0
- package/dist/core/format/exports.js.map +1 -0
- package/dist/core/format/index.d.ts +9 -0
- package/dist/core/format/index.d.ts.map +1 -0
- package/dist/core/format/index.js +9 -0
- package/dist/core/format/index.js.map +1 -0
- package/dist/core/{local-names.d.ts → format/local-names.d.ts} +1 -1
- package/dist/core/format/local-names.d.ts.map +1 -0
- package/dist/core/{local-names.js → format/local-names.js} +1 -1
- package/dist/core/format/local-names.js.map +1 -0
- package/dist/core/format/module-emitter/assembly.d.ts +27 -0
- package/dist/core/format/module-emitter/assembly.d.ts.map +1 -0
- package/dist/core/format/module-emitter/assembly.js +44 -0
- package/dist/core/format/module-emitter/assembly.js.map +1 -0
- package/dist/core/{module-emitter → format/module-emitter}/header.d.ts +1 -1
- package/dist/core/format/module-emitter/header.d.ts.map +1 -0
- package/dist/core/{module-emitter → format/module-emitter}/header.js +1 -1
- package/dist/core/format/module-emitter/header.js.map +1 -0
- package/dist/core/format/module-emitter/index.d.ts.map +1 -0
- package/dist/core/format/module-emitter/index.js.map +1 -0
- package/dist/core/format/module-emitter/namespace.d.ts +21 -0
- package/dist/core/format/module-emitter/namespace.d.ts.map +1 -0
- package/dist/core/format/module-emitter/namespace.js +58 -0
- package/dist/core/format/module-emitter/namespace.js.map +1 -0
- package/dist/core/{module-emitter → format/module-emitter}/orchestrator.d.ts +1 -1
- package/dist/core/format/module-emitter/orchestrator.d.ts.map +1 -0
- package/dist/core/{module-emitter → format/module-emitter}/orchestrator.js +19 -19
- package/dist/core/format/module-emitter/orchestrator.js.map +1 -0
- package/dist/core/format/module-emitter/separation.d.ts.map +1 -0
- package/dist/core/format/module-emitter/separation.js.map +1 -0
- package/dist/core/{module-emitter → format/module-emitter}/static-container.d.ts +8 -3
- package/dist/core/format/module-emitter/static-container.d.ts.map +1 -0
- package/dist/core/format/module-emitter/static-container.js +202 -0
- package/dist/core/format/module-emitter/static-container.js.map +1 -0
- package/dist/core/format/module-emitter.d.ts.map +1 -0
- package/dist/core/format/module-emitter.js.map +1 -0
- package/dist/core/{options.d.ts → format/options.d.ts} +1 -1
- package/dist/core/format/options.d.ts.map +1 -0
- package/dist/core/format/options.js.map +1 -0
- package/dist/core/index.d.ts +2 -7
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -7
- package/dist/core/index.js.map +1 -1
- package/dist/core/semantic/boolean-context.d.ts +44 -0
- package/dist/core/semantic/boolean-context.d.ts.map +1 -0
- package/dist/core/semantic/boolean-context.js +717 -0
- package/dist/core/semantic/boolean-context.js.map +1 -0
- package/dist/core/semantic/boolean-context.test.d.ts.map +1 -0
- package/dist/core/{boolean-context.test.js → semantic/boolean-context.test.js} +86 -109
- package/dist/core/semantic/boolean-context.test.js.map +1 -0
- package/dist/core/{imports.d.ts → semantic/imports.d.ts} +1 -5
- package/dist/core/semantic/imports.d.ts.map +1 -0
- package/dist/core/{imports.js → semantic/imports.js} +56 -74
- package/dist/core/semantic/imports.js.map +1 -0
- package/dist/core/semantic/imports.test.d.ts.map +1 -0
- package/dist/core/semantic/imports.test.js +229 -0
- package/dist/core/semantic/imports.test.js.map +1 -0
- package/dist/core/semantic/index.d.ts +15 -0
- package/dist/core/semantic/index.d.ts.map +1 -0
- package/dist/core/semantic/index.js +15 -0
- package/dist/core/semantic/index.js.map +1 -0
- package/dist/core/{local-types.d.ts → semantic/local-types.d.ts} +1 -1
- package/dist/core/semantic/local-types.d.ts.map +1 -0
- package/dist/core/semantic/local-types.js.map +1 -0
- package/dist/core/{module-map.d.ts → semantic/module-map.d.ts} +1 -1
- package/dist/core/semantic/module-map.d.ts.map +1 -0
- package/dist/core/semantic/module-map.js.map +1 -0
- package/dist/core/semantic/module-map.test.d.ts.map +1 -0
- package/dist/core/semantic/module-map.test.js.map +1 -0
- package/dist/core/semantic/naming-collisions.d.ts.map +1 -0
- package/dist/core/{naming-collisions.js → semantic/naming-collisions.js} +1 -1
- package/dist/core/semantic/naming-collisions.js.map +1 -0
- package/dist/core/{type-alias-index.d.ts → semantic/type-alias-index.d.ts} +1 -1
- package/dist/core/semantic/type-alias-index.d.ts.map +1 -0
- package/dist/core/semantic/type-alias-index.js.map +1 -0
- package/dist/core/semantic/type-compatibility.d.ts.map +1 -0
- package/dist/core/semantic/type-compatibility.js.map +1 -0
- package/dist/core/{type-member-index.d.ts → semantic/type-member-index.d.ts} +1 -1
- package/dist/core/semantic/type-member-index.d.ts.map +1 -0
- package/dist/core/semantic/type-member-index.js.map +1 -0
- package/dist/core/semantic/type-params.d.ts.map +1 -0
- package/dist/core/semantic/type-params.js.map +1 -0
- package/dist/core/{type-resolution.d.ts → semantic/type-resolution.d.ts} +3 -6
- package/dist/core/semantic/type-resolution.d.ts.map +1 -0
- package/dist/core/{type-resolution.js → semantic/type-resolution.js} +15 -25
- package/dist/core/semantic/type-resolution.js.map +1 -0
- package/dist/core/semantic/type-resolution.test.d.ts.map +1 -0
- package/dist/core/{type-resolution.test.js → semantic/type-resolution.test.js} +11 -19
- package/dist/core/semantic/type-resolution.test.js.map +1 -0
- package/dist/core/semantic/unsafe.d.ts.map +1 -0
- package/dist/core/semantic/unsafe.js.map +1 -0
- package/dist/emitter-types/core.d.ts +6 -12
- package/dist/emitter-types/core.d.ts.map +1 -1
- package/dist/emitter-types/index.d.ts +1 -1
- package/dist/emitter-types/index.d.ts.map +1 -1
- package/dist/emitter-types/index.js.map +1 -1
- package/dist/emitter.d.ts +1 -1
- package/dist/emitter.d.ts.map +1 -1
- package/dist/emitter.js +9 -8
- package/dist/emitter.js.map +1 -1
- package/dist/expression-emitter.d.ts +10 -5
- package/dist/expression-emitter.d.ts.map +1 -1
- package/dist/expression-emitter.js +333 -117
- package/dist/expression-emitter.js.map +1 -1
- package/dist/expressions/access.d.ts +4 -3
- package/dist/expressions/access.d.ts.map +1 -1
- package/dist/expressions/access.js +252 -102
- package/dist/expressions/access.js.map +1 -1
- package/dist/expressions/calls/call-analysis.d.ts +86 -0
- package/dist/expressions/calls/call-analysis.d.ts.map +1 -0
- package/dist/expressions/calls/call-analysis.js +284 -0
- package/dist/expressions/calls/call-analysis.js.map +1 -0
- package/dist/expressions/calls/call-emitter.d.ts +13 -0
- package/dist/expressions/calls/call-emitter.d.ts.map +1 -0
- package/dist/expressions/calls/call-emitter.js +1048 -0
- package/dist/expressions/calls/call-emitter.js.map +1 -0
- package/dist/expressions/calls/new-emitter.d.ts +13 -0
- package/dist/expressions/calls/new-emitter.d.ts.map +1 -0
- package/dist/expressions/calls/new-emitter.js +641 -0
- package/dist/expressions/calls/new-emitter.js.map +1 -0
- package/dist/expressions/calls.d.ts +2 -14
- package/dist/expressions/calls.d.ts.map +1 -1
- package/dist/expressions/calls.js +2 -909
- package/dist/expressions/calls.js.map +1 -1
- package/dist/expressions/collections.d.ts +6 -16
- package/dist/expressions/collections.d.ts.map +1 -1
- package/dist/expressions/collections.js +318 -217
- package/dist/expressions/collections.js.map +1 -1
- package/dist/expressions/functions.d.ts +6 -5
- package/dist/expressions/functions.d.ts.map +1 -1
- package/dist/expressions/functions.js +57 -62
- package/dist/expressions/functions.js.map +1 -1
- package/dist/expressions/identifiers.d.ts +11 -6
- package/dist/expressions/identifiers.d.ts.map +1 -1
- package/dist/expressions/identifiers.js +76 -25
- package/dist/expressions/identifiers.js.map +1 -1
- package/dist/expressions/index.d.ts +1 -1
- package/dist/expressions/index.d.ts.map +1 -1
- package/dist/expressions/index.js +1 -1
- package/dist/expressions/index.js.map +1 -1
- package/dist/expressions/index.test.js +605 -0
- package/dist/expressions/index.test.js.map +1 -1
- package/dist/expressions/literals.d.ts +4 -3
- package/dist/expressions/literals.d.ts.map +1 -1
- package/dist/expressions/literals.js +25 -17
- package/dist/expressions/literals.js.map +1 -1
- package/dist/expressions/literals.test.js +18 -18
- package/dist/expressions/literals.test.js.map +1 -1
- package/dist/expressions/operators/assignment-emitter.d.ts +16 -0
- package/dist/expressions/operators/assignment-emitter.d.ts.map +1 -0
- package/dist/expressions/operators/assignment-emitter.js +118 -0
- package/dist/expressions/operators/assignment-emitter.js.map +1 -0
- package/dist/expressions/operators/binary-emitter.d.ts +33 -0
- package/dist/expressions/operators/binary-emitter.d.ts.map +1 -0
- package/dist/expressions/operators/binary-emitter.js +398 -0
- package/dist/expressions/operators/binary-emitter.js.map +1 -0
- package/dist/expressions/operators/conditional-emitter.d.ts +17 -0
- package/dist/expressions/operators/conditional-emitter.d.ts.map +1 -0
- package/dist/expressions/operators/conditional-emitter.js +306 -0
- package/dist/expressions/operators/conditional-emitter.js.map +1 -0
- package/dist/expressions/operators/helpers.d.ts +37 -0
- package/dist/expressions/operators/helpers.d.ts.map +1 -0
- package/dist/expressions/operators/helpers.js +136 -0
- package/dist/expressions/operators/helpers.js.map +1 -0
- package/dist/expressions/operators/logical-emitter.d.ts +23 -0
- package/dist/expressions/operators/logical-emitter.d.ts.map +1 -0
- package/dist/expressions/operators/logical-emitter.js +73 -0
- package/dist/expressions/operators/logical-emitter.js.map +1 -0
- package/dist/expressions/operators/unary-emitter.d.ts +30 -0
- package/dist/expressions/operators/unary-emitter.d.ts.map +1 -0
- package/dist/expressions/operators/unary-emitter.js +244 -0
- package/dist/expressions/operators/unary-emitter.js.map +1 -0
- package/dist/expressions/operators.d.ts +5 -81
- package/dist/expressions/operators.d.ts.map +1 -1
- package/dist/expressions/operators.js +5 -949
- package/dist/expressions/operators.js.map +1 -1
- package/dist/expressions/other.d.ts +15 -11
- package/dist/expressions/other.d.ts.map +1 -1
- package/dist/expressions/other.js +51 -36
- package/dist/expressions/other.js.map +1 -1
- package/dist/expressions/precedence.test.js +1 -1
- package/dist/expressions/precedence.test.js.map +1 -1
- package/dist/generator-exchange.d.ts +10 -3
- package/dist/generator-exchange.d.ts.map +1 -1
- package/dist/generator-exchange.js +57 -54
- package/dist/generator-exchange.js.map +1 -1
- package/dist/generator-wrapper.d.ts +17 -65
- package/dist/generator-wrapper.d.ts.map +1 -1
- package/dist/generator-wrapper.js +396 -220
- package/dist/generator-wrapper.js.map +1 -1
- package/dist/generator-wrapper.test.js +22 -14
- package/dist/generator-wrapper.test.js.map +1 -1
- package/dist/integration.test.js +169 -1
- package/dist/integration.test.js.map +1 -1
- package/dist/patterns.d.ts +18 -88
- package/dist/patterns.d.ts.map +1 -1
- package/dist/patterns.js +540 -304
- package/dist/patterns.js.map +1 -1
- package/dist/patterns.test.js +5 -4
- package/dist/patterns.test.js.map +1 -1
- package/dist/specialization/generation.d.ts +7 -3
- package/dist/specialization/generation.d.ts.map +1 -1
- package/dist/specialization/generation.js +31 -15
- package/dist/specialization/generation.js.map +1 -1
- package/dist/specialization/type-aliases.test.js +47 -2
- package/dist/specialization/type-aliases.test.js.map +1 -1
- package/dist/statement-emitter.d.ts +15 -4
- package/dist/statement-emitter.d.ts.map +1 -1
- package/dist/statement-emitter.js +54 -47
- package/dist/statement-emitter.js.map +1 -1
- package/dist/statements/blocks.d.ts +24 -16
- package/dist/statements/blocks.d.ts.map +1 -1
- package/dist/statements/blocks.js +242 -65
- package/dist/statements/blocks.js.map +1 -1
- package/dist/statements/classes/index.d.ts +1 -1
- package/dist/statements/classes/index.d.ts.map +1 -1
- package/dist/statements/classes/index.js +1 -1
- package/dist/statements/classes/index.js.map +1 -1
- package/dist/statements/classes/inline-types.d.ts +4 -3
- package/dist/statements/classes/inline-types.d.ts.map +1 -1
- package/dist/statements/classes/inline-types.js +21 -21
- package/dist/statements/classes/inline-types.js.map +1 -1
- package/dist/statements/classes/members/constructors.d.ts +4 -3
- package/dist/statements/classes/members/constructors.d.ts.map +1 -1
- package/dist/statements/classes/members/constructors.js +57 -58
- package/dist/statements/classes/members/constructors.js.map +1 -1
- package/dist/statements/classes/members/methods.d.ts +4 -3
- package/dist/statements/classes/members/methods.d.ts.map +1 -1
- package/dist/statements/classes/members/methods.js +106 -101
- package/dist/statements/classes/members/methods.js.map +1 -1
- package/dist/statements/classes/members/orchestrator.d.ts +4 -3
- package/dist/statements/classes/members/orchestrator.d.ts.map +1 -1
- package/dist/statements/classes/members/orchestrator.js +2 -2
- package/dist/statements/classes/members/orchestrator.js.map +1 -1
- package/dist/statements/classes/members/properties.d.ts +4 -3
- package/dist/statements/classes/members/properties.d.ts.map +1 -1
- package/dist/statements/classes/members/properties.js +105 -88
- package/dist/statements/classes/members/properties.js.map +1 -1
- package/dist/statements/classes/members/shadowing.test.js +7 -2
- package/dist/statements/classes/members/shadowing.test.js.map +1 -1
- package/dist/statements/classes/members/static-readonly-properties.test.js +4 -1
- package/dist/statements/classes/members/static-readonly-properties.test.js.map +1 -1
- package/dist/statements/classes/parameters.d.ts +8 -10
- package/dist/statements/classes/parameters.d.ts.map +1 -1
- package/dist/statements/classes/parameters.js +30 -26
- package/dist/statements/classes/parameters.js.map +1 -1
- package/dist/statements/classes/properties.d.ts +4 -3
- package/dist/statements/classes/properties.d.ts.map +1 -1
- package/dist/statements/classes/properties.js +76 -50
- package/dist/statements/classes/properties.js.map +1 -1
- package/dist/statements/classes.d.ts +1 -1
- package/dist/statements/classes.d.ts.map +1 -1
- package/dist/statements/classes.js +1 -1
- package/dist/statements/classes.js.map +1 -1
- package/dist/statements/control/conditionals/guard-analysis.d.ts +169 -0
- package/dist/statements/control/conditionals/guard-analysis.d.ts.map +1 -0
- package/dist/statements/control/conditionals/guard-analysis.js +591 -0
- package/dist/statements/control/conditionals/guard-analysis.js.map +1 -0
- package/dist/statements/control/conditionals/if-emitter.d.ts +14 -0
- package/dist/statements/control/conditionals/if-emitter.d.ts.map +1 -0
- package/dist/statements/control/conditionals/if-emitter.js +725 -0
- package/dist/statements/control/conditionals/if-emitter.js.map +1 -0
- package/dist/statements/control/conditionals/switch-emitter.d.ts +13 -0
- package/dist/statements/control/conditionals/switch-emitter.d.ts.map +1 -0
- package/dist/statements/control/conditionals/switch-emitter.js +60 -0
- package/dist/statements/control/conditionals/switch-emitter.js.map +1 -0
- package/dist/statements/control/conditionals.d.ts +3 -15
- package/dist/statements/control/conditionals.d.ts.map +1 -1
- package/dist/statements/control/conditionals.js +3 -1152
- package/dist/statements/control/conditionals.js.map +1 -1
- package/dist/statements/control/exceptions.d.ts +8 -6
- package/dist/statements/control/exceptions.d.ts.map +1 -1
- package/dist/statements/control/exceptions.js +35 -23
- package/dist/statements/control/exceptions.js.map +1 -1
- package/dist/statements/control/index.d.ts +3 -3
- package/dist/statements/control/index.d.ts.map +1 -1
- package/dist/statements/control/index.js +3 -3
- package/dist/statements/control/index.js.map +1 -1
- package/dist/statements/control/loops.d.ts +14 -12
- package/dist/statements/control/loops.d.ts.map +1 -1
- package/dist/statements/control/loops.js +147 -82
- package/dist/statements/control/loops.js.map +1 -1
- package/dist/statements/control.d.ts +1 -1
- package/dist/statements/control.d.ts.map +1 -1
- package/dist/statements/control.js +1 -1
- package/dist/statements/control.js.map +1 -1
- package/dist/statements/declarations/classes.d.ts +7 -3
- package/dist/statements/declarations/classes.d.ts.map +1 -1
- package/dist/statements/declarations/classes.js +107 -83
- package/dist/statements/declarations/classes.js.map +1 -1
- package/dist/statements/declarations/enums.d.ts +4 -3
- package/dist/statements/declarations/enums.d.ts.map +1 -1
- package/dist/statements/declarations/enums.js +16 -15
- package/dist/statements/declarations/enums.js.map +1 -1
- package/dist/statements/declarations/functions.d.ts +18 -2
- package/dist/statements/declarations/functions.d.ts.map +1 -1
- package/dist/statements/declarations/functions.js +633 -162
- package/dist/statements/declarations/functions.js.map +1 -1
- package/dist/statements/declarations/index.d.ts +2 -2
- package/dist/statements/declarations/index.d.ts.map +1 -1
- package/dist/statements/declarations/index.js +2 -2
- package/dist/statements/declarations/index.js.map +1 -1
- package/dist/statements/declarations/interfaces.d.ts +7 -3
- package/dist/statements/declarations/interfaces.d.ts.map +1 -1
- package/dist/statements/declarations/interfaces.js +138 -105
- package/dist/statements/declarations/interfaces.js.map +1 -1
- package/dist/statements/declarations/type-aliases.d.ts +7 -3
- package/dist/statements/declarations/type-aliases.d.ts.map +1 -1
- package/dist/statements/declarations/type-aliases.js +122 -82
- package/dist/statements/declarations/type-aliases.js.map +1 -1
- package/dist/statements/declarations/variables.d.ts +12 -2
- package/dist/statements/declarations/variables.d.ts.map +1 -1
- package/dist/statements/declarations/variables.js +541 -428
- package/dist/statements/declarations/variables.js.map +1 -1
- package/dist/statements/declarations.d.ts +1 -1
- package/dist/statements/declarations.d.ts.map +1 -1
- package/dist/statements/declarations.js +1 -1
- package/dist/statements/declarations.js.map +1 -1
- package/dist/statements/index.d.ts +3 -3
- package/dist/statements/index.d.ts.map +1 -1
- package/dist/statements/index.js +5 -5
- package/dist/statements/index.js.map +1 -1
- package/dist/statements/index.test.js +307 -0
- package/dist/statements/index.test.js.map +1 -1
- package/dist/type-emitter.d.ts +1 -1
- package/dist/type-emitter.d.ts.map +1 -1
- package/dist/type-emitter.js +1 -1
- package/dist/type-emitter.js.map +1 -1
- package/dist/types/arrays.d.ts +3 -2
- package/dist/types/arrays.d.ts.map +1 -1
- package/dist/types/arrays.js +7 -5
- package/dist/types/arrays.js.map +1 -1
- package/dist/types/dictionaries.d.ts +6 -3
- package/dist/types/dictionaries.d.ts.map +1 -1
- package/dist/types/dictionaries.js +22 -10
- package/dist/types/dictionaries.js.map +1 -1
- package/dist/types/emitter.d.ts +8 -2
- package/dist/types/emitter.d.ts.map +1 -1
- package/dist/types/emitter.js +20 -6
- package/dist/types/emitter.js.map +1 -1
- package/dist/types/functions.d.ts +3 -2
- package/dist/types/functions.d.ts.map +1 -1
- package/dist/types/functions.js +36 -13
- package/dist/types/functions.js.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -2
- package/dist/types/index.js.map +1 -1
- package/dist/types/index.test.js +137 -0
- package/dist/types/index.test.js.map +1 -1
- package/dist/types/intersections.d.ts +3 -2
- package/dist/types/intersections.d.ts.map +1 -1
- package/dist/types/intersections.js +2 -2
- package/dist/types/intersections.js.map +1 -1
- package/dist/types/literals.d.ts +9 -2
- package/dist/types/literals.d.ts.map +1 -1
- package/dist/types/literals.js +11 -5
- package/dist/types/literals.js.map +1 -1
- package/dist/types/objects.d.ts +3 -2
- package/dist/types/objects.d.ts.map +1 -1
- package/dist/types/objects.js +1 -1
- package/dist/types/objects.js.map +1 -1
- package/dist/types/parameters.d.ts +6 -5
- package/dist/types/parameters.d.ts.map +1 -1
- package/dist/types/parameters.js +88 -29
- package/dist/types/parameters.js.map +1 -1
- package/dist/types/parameters.test.js +9 -4
- package/dist/types/parameters.test.js.map +1 -1
- package/dist/types/primitives.d.ts +5 -4
- package/dist/types/primitives.d.ts.map +1 -1
- package/dist/types/primitives.js +14 -13
- package/dist/types/primitives.js.map +1 -1
- package/dist/types/references.d.ts +3 -2
- package/dist/types/references.d.ts.map +1 -1
- package/dist/types/references.js +135 -111
- package/dist/types/references.js.map +1 -1
- package/dist/types/tuples.d.ts +3 -2
- package/dist/types/tuples.d.ts.map +1 -1
- package/dist/types/tuples.js +25 -11
- package/dist/types/tuples.js.map +1 -1
- package/dist/types/unions.d.ts +3 -2
- package/dist/types/unions.d.ts.map +1 -1
- package/dist/types/unions.js +36 -21
- package/dist/types/unions.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/dist/core/attributes.d.ts.map +0 -1
- package/dist/core/attributes.js +0 -141
- package/dist/core/attributes.js.map +0 -1
- package/dist/core/attributes.test.d.ts.map +0 -1
- package/dist/core/attributes.test.js.map +0 -1
- package/dist/core/boolean-context.d.ts +0 -42
- package/dist/core/boolean-context.d.ts.map +0 -1
- package/dist/core/boolean-context.js +0 -442
- package/dist/core/boolean-context.js.map +0 -1
- package/dist/core/boolean-context.test.d.ts.map +0 -1
- package/dist/core/boolean-context.test.js.map +0 -1
- package/dist/core/exports.d.ts.map +0 -1
- package/dist/core/exports.js +0 -28
- package/dist/core/exports.js.map +0 -1
- package/dist/core/imports.d.ts.map +0 -1
- package/dist/core/imports.js.map +0 -1
- package/dist/core/imports.test.d.ts.map +0 -1
- package/dist/core/imports.test.js +0 -79
- package/dist/core/imports.test.js.map +0 -1
- package/dist/core/local-names.d.ts.map +0 -1
- package/dist/core/local-names.js.map +0 -1
- package/dist/core/local-types.d.ts.map +0 -1
- package/dist/core/local-types.js.map +0 -1
- package/dist/core/module-emitter/assembly.d.ts +0 -24
- package/dist/core/module-emitter/assembly.d.ts.map +0 -1
- package/dist/core/module-emitter/assembly.js +0 -69
- package/dist/core/module-emitter/assembly.js.map +0 -1
- package/dist/core/module-emitter/header.d.ts.map +0 -1
- package/dist/core/module-emitter/header.js.map +0 -1
- package/dist/core/module-emitter/index.d.ts.map +0 -1
- package/dist/core/module-emitter/index.js.map +0 -1
- package/dist/core/module-emitter/namespace.d.ts +0 -14
- package/dist/core/module-emitter/namespace.d.ts.map +0 -1
- package/dist/core/module-emitter/namespace.js +0 -26
- package/dist/core/module-emitter/namespace.js.map +0 -1
- package/dist/core/module-emitter/orchestrator.d.ts.map +0 -1
- package/dist/core/module-emitter/orchestrator.js.map +0 -1
- package/dist/core/module-emitter/separation.d.ts.map +0 -1
- package/dist/core/module-emitter/separation.js.map +0 -1
- package/dist/core/module-emitter/static-container.d.ts.map +0 -1
- package/dist/core/module-emitter/static-container.js +0 -139
- package/dist/core/module-emitter/static-container.js.map +0 -1
- package/dist/core/module-emitter.d.ts.map +0 -1
- package/dist/core/module-emitter.js.map +0 -1
- package/dist/core/module-map.d.ts.map +0 -1
- package/dist/core/module-map.js.map +0 -1
- package/dist/core/module-map.test.d.ts.map +0 -1
- package/dist/core/module-map.test.js.map +0 -1
- package/dist/core/naming-collisions.d.ts.map +0 -1
- package/dist/core/naming-collisions.js.map +0 -1
- package/dist/core/options.d.ts.map +0 -1
- package/dist/core/options.js.map +0 -1
- package/dist/core/type-alias-index.d.ts.map +0 -1
- package/dist/core/type-alias-index.js.map +0 -1
- package/dist/core/type-compatibility.d.ts.map +0 -1
- package/dist/core/type-compatibility.js.map +0 -1
- package/dist/core/type-member-index.d.ts.map +0 -1
- package/dist/core/type-member-index.js.map +0 -1
- package/dist/core/type-params.d.ts.map +0 -1
- package/dist/core/type-params.js.map +0 -1
- package/dist/core/type-resolution.d.ts.map +0 -1
- package/dist/core/type-resolution.js.map +0 -1
- package/dist/core/type-resolution.test.d.ts.map +0 -1
- package/dist/core/type-resolution.test.js.map +0 -1
- package/dist/core/unsafe.d.ts.map +0 -1
- package/dist/core/unsafe.js.map +0 -1
- /package/dist/core/{attributes.test.d.ts → format/attributes.test.d.ts} +0 -0
- /package/dist/core/{module-emitter → format/module-emitter}/index.d.ts +0 -0
- /package/dist/core/{module-emitter → format/module-emitter}/index.js +0 -0
- /package/dist/core/{module-emitter → format/module-emitter}/separation.d.ts +0 -0
- /package/dist/core/{module-emitter → format/module-emitter}/separation.js +0 -0
- /package/dist/core/{module-emitter.d.ts → format/module-emitter.d.ts} +0 -0
- /package/dist/core/{module-emitter.js → format/module-emitter.js} +0 -0
- /package/dist/core/{options.js → format/options.js} +0 -0
- /package/dist/core/{boolean-context.test.d.ts → semantic/boolean-context.test.d.ts} +0 -0
- /package/dist/core/{imports.test.d.ts → semantic/imports.test.d.ts} +0 -0
- /package/dist/core/{local-types.js → semantic/local-types.js} +0 -0
- /package/dist/core/{module-map.js → semantic/module-map.js} +0 -0
- /package/dist/core/{module-map.test.d.ts → semantic/module-map.test.d.ts} +0 -0
- /package/dist/core/{module-map.test.js → semantic/module-map.test.js} +0 -0
- /package/dist/core/{naming-collisions.d.ts → semantic/naming-collisions.d.ts} +0 -0
- /package/dist/core/{type-alias-index.js → semantic/type-alias-index.js} +0 -0
- /package/dist/core/{type-compatibility.d.ts → semantic/type-compatibility.d.ts} +0 -0
- /package/dist/core/{type-compatibility.js → semantic/type-compatibility.js} +0 -0
- /package/dist/core/{type-member-index.js → semantic/type-member-index.js} +0 -0
- /package/dist/core/{type-params.d.ts → semantic/type-params.d.ts} +0 -0
- /package/dist/core/{type-params.js → semantic/type-params.js} +0 -0
- /package/dist/core/{type-resolution.test.d.ts → semantic/type-resolution.test.d.ts} +0 -0
- /package/dist/core/{unsafe.d.ts → semantic/unsafe.d.ts} +0 -0
- /package/dist/core/{unsafe.js → semantic/unsafe.js} +0 -0
|
@@ -1,913 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Call and new expression emitters
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { emitType } from "../type-emitter.js";
|
|
7
|
-
import { formatPostfixExpressionText } from "./parentheses.js";
|
|
8
|
-
import { emitMemberAccess } from "./access.js";
|
|
9
|
-
import { containsTypeParameter } from "../core/type-resolution.js";
|
|
10
|
-
/**
|
|
11
|
-
* Ref/out/in parameter handling:
|
|
12
|
-
* The frontend extracts parameter passing modes from resolved signatures
|
|
13
|
-
* and attaches them to IrCallExpression.argumentPassing array.
|
|
14
|
-
* The emitter reads this array and prefixes arguments with ref/out/in keywords.
|
|
15
|
-
*/
|
|
16
|
-
/**
|
|
17
|
-
* Check if an expression is an lvalue (can be passed by reference)
|
|
18
|
-
* Only identifiers and member accesses are lvalues in C#
|
|
19
|
-
*/
|
|
20
|
-
const isLValue = (expr) => {
|
|
21
|
-
return expr.kind === "identifier" || expr.kind === "memberAccess";
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* Check if an expression has an `as out<T>`, `as ref<T>`, or `as inref<T>` cast.
|
|
25
|
-
* Returns the modifier ("out", "ref", "in") or undefined if not a passing modifier cast.
|
|
26
|
-
*
|
|
27
|
-
* When TypeScript code has `value as out<int>`, the frontend converts this to
|
|
28
|
-
* an expression with `inferredType: { kind: "referenceType", name: "out", ... }`.
|
|
29
|
-
*/
|
|
30
|
-
const getPassingModifierFromCast = (expr) => {
|
|
31
|
-
const inferredType = expr.inferredType;
|
|
32
|
-
if (!inferredType || inferredType.kind !== "referenceType") {
|
|
33
|
-
return undefined;
|
|
34
|
-
}
|
|
35
|
-
const typeName = inferredType.name;
|
|
36
|
-
if (typeName === "out")
|
|
37
|
-
return "out";
|
|
38
|
-
if (typeName === "ref")
|
|
39
|
-
return "ref";
|
|
40
|
-
if (typeName === "inref")
|
|
41
|
-
return "in"; // inref maps to C# 'in' keyword
|
|
42
|
-
return undefined;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* Check if a member access expression targets System.Text.Json.JsonSerializer
|
|
46
|
-
*/
|
|
47
|
-
const isJsonSerializerCall = (callee) => {
|
|
48
|
-
if (callee.kind !== "memberAccess")
|
|
49
|
-
return null;
|
|
50
|
-
if (!callee.memberBinding)
|
|
51
|
-
return null;
|
|
52
|
-
const { type, member } = callee.memberBinding;
|
|
53
|
-
// Check if this is System.Text.Json.JsonSerializer
|
|
54
|
-
if (type !== "System.Text.Json.JsonSerializer")
|
|
55
|
-
return null;
|
|
56
|
-
// Check if the member is Serialize or Deserialize
|
|
57
|
-
if (member === "Serialize")
|
|
58
|
-
return { method: "Serialize" };
|
|
59
|
-
if (member === "Deserialize")
|
|
60
|
-
return { method: "Deserialize" };
|
|
61
|
-
return null;
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Check if a call targets global JSON.stringify or JSON.parse
|
|
65
|
-
* These global JSON methods compile to JsonSerializer
|
|
66
|
-
*/
|
|
67
|
-
const isGlobalJsonCall = (callee) => {
|
|
68
|
-
if (callee.kind !== "memberAccess")
|
|
69
|
-
return null;
|
|
70
|
-
// Check if object is the global JSON identifier
|
|
71
|
-
const obj = callee.object;
|
|
72
|
-
if (obj.kind !== "identifier" || obj.name !== "JSON")
|
|
73
|
-
return null;
|
|
74
|
-
// Check property name
|
|
75
|
-
const prop = callee.property;
|
|
76
|
-
if (typeof prop !== "string")
|
|
77
|
-
return null;
|
|
78
|
-
if (prop === "stringify")
|
|
79
|
-
return { method: "Serialize" };
|
|
80
|
-
if (prop === "parse")
|
|
81
|
-
return { method: "Deserialize" };
|
|
82
|
-
return null;
|
|
83
|
-
};
|
|
84
|
-
/**
|
|
85
|
-
* Heuristic: Determine if a member access is an instance-style access (receiver.value)
|
|
86
|
-
* vs a static type reference (Type.Member).
|
|
87
|
-
*
|
|
88
|
-
* This mirrors the logic in emitMemberAccess; extension-method lowering only applies
|
|
89
|
-
* to instance-style member accesses.
|
|
90
|
-
*/
|
|
91
|
-
const isInstanceMemberAccess = (expr, context) => {
|
|
92
|
-
// Imported types (e.g., `Enumerable.Where(...)`) are static receiver expressions,
|
|
93
|
-
// even if TypeScript assigns them an inferredType.
|
|
94
|
-
if (expr.object.kind === "identifier") {
|
|
95
|
-
const importBinding = context.importBindings?.get(expr.object.name);
|
|
96
|
-
if (importBinding?.kind === "type") {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
// If this isn't an import and we don't have a receiver type, default to instance.
|
|
100
|
-
// This matches emitMemberAccess's behavior and prevents local variables from being
|
|
101
|
-
// misclassified as static type receivers (which breaks extension method lowering).
|
|
102
|
-
if (!expr.object.inferredType) {
|
|
103
|
-
return true;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
const objectType = expr.object.inferredType;
|
|
107
|
-
return (objectType?.kind === "referenceType" ||
|
|
108
|
-
objectType?.kind === "arrayType" ||
|
|
109
|
-
objectType?.kind === "intersectionType" ||
|
|
110
|
-
objectType?.kind === "unionType" ||
|
|
111
|
-
objectType?.kind === "primitiveType" ||
|
|
112
|
-
objectType?.kind === "literalType" ||
|
|
113
|
-
objectType?.kind === "typeParameterType" ||
|
|
114
|
-
objectType?.kind === "unknownType");
|
|
115
|
-
};
|
|
116
|
-
/**
|
|
117
|
-
* Whether to emit an extension method call using fluent instance syntax (receiver.Method(...))
|
|
118
|
-
* instead of explicit static invocation (Type.Method(receiver, ...)).
|
|
119
|
-
*
|
|
120
|
-
* Default: prefer static invocation to avoid relying on `using` directives and to avoid
|
|
121
|
-
* accidental binding to an instance member when a type has both an instance method and
|
|
122
|
-
* an extension method with the same name.
|
|
123
|
-
*
|
|
124
|
-
* Exception: certain toolchains (notably EF query precompilation) require the *syntax*
|
|
125
|
-
* of extension-method invocation so the analyzer can locate queries in user code.
|
|
126
|
-
*/
|
|
127
|
-
const shouldEmitFluentExtensionCall = (bindingType, memberName) => {
|
|
128
|
-
// EF Core query precompilation requires fluent/extension syntax specifically for Queryable.
|
|
129
|
-
// Keep Enumerable as explicit static invocation by default to avoid accidental binding to
|
|
130
|
-
// instance methods on custom enumerable types.
|
|
131
|
-
if (bindingType.startsWith("System.Linq.Queryable"))
|
|
132
|
-
return true;
|
|
133
|
-
// EF Core query operators (Include/ThenInclude/AsNoTracking/etc.)
|
|
134
|
-
if (bindingType.startsWith("Microsoft.EntityFrameworkCore."))
|
|
135
|
-
return true;
|
|
136
|
-
// EF Core query precompilation also requires fluent syntax for certain Enumerable terminal ops
|
|
137
|
-
// (e.g., IQueryable<T>.ToList()/ToArray()). When emitted as explicit static calls
|
|
138
|
-
// (Enumerable.ToList(query)), dotnet-ef may not generate interceptors, causing runtime failure
|
|
139
|
-
// under NativeAOT ("Query wasn't precompiled and dynamic code isn't supported").
|
|
140
|
-
if (bindingType.startsWith("System.Linq.Enumerable") &&
|
|
141
|
-
(memberName === "ToList" || memberName === "ToArray")) {
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
return false;
|
|
145
|
-
};
|
|
146
|
-
const getTypeNamespace = (typeName) => {
|
|
147
|
-
const lastDot = typeName.lastIndexOf(".");
|
|
148
|
-
if (lastDot <= 0)
|
|
149
|
-
return undefined;
|
|
150
|
-
return typeName.slice(0, lastDot);
|
|
151
|
-
};
|
|
152
|
-
/**
|
|
153
|
-
* Whether a C# type string is a builtin/keyword type (optionally nullable).
|
|
154
|
-
*
|
|
155
|
-
* These must NOT be qualified with a namespace (e.g. `object`, not `MyNs.object`).
|
|
156
|
-
*/
|
|
157
|
-
const isCSharpBuiltinType = (typeStr) => {
|
|
158
|
-
const base = typeStr.endsWith("?") ? typeStr.slice(0, -1) : typeStr;
|
|
159
|
-
return (base === "string" ||
|
|
160
|
-
base === "int" ||
|
|
161
|
-
base === "long" ||
|
|
162
|
-
base === "short" ||
|
|
163
|
-
base === "byte" ||
|
|
164
|
-
base === "sbyte" ||
|
|
165
|
-
base === "uint" ||
|
|
166
|
-
base === "ulong" ||
|
|
167
|
-
base === "ushort" ||
|
|
168
|
-
base === "float" ||
|
|
169
|
-
base === "double" ||
|
|
170
|
-
base === "decimal" ||
|
|
171
|
-
base === "bool" ||
|
|
172
|
-
base === "char" ||
|
|
173
|
-
base === "object" ||
|
|
174
|
-
base === "void");
|
|
175
|
-
};
|
|
176
|
-
/**
|
|
177
|
-
* Ensure a C# type string has global:: prefix for unambiguous resolution
|
|
178
|
-
*/
|
|
179
|
-
const ensureGlobalPrefix = (typeStr) => {
|
|
180
|
-
// Skip already-prefixed types
|
|
181
|
-
if (typeStr.startsWith("global::")) {
|
|
182
|
-
return typeStr;
|
|
183
|
-
}
|
|
184
|
-
// Handle pointer types (T*). `global::int*` is invalid; qualify the element type only.
|
|
185
|
-
if (typeStr.endsWith("*")) {
|
|
186
|
-
const inner = typeStr.slice(0, -1);
|
|
187
|
-
return `${ensureGlobalPrefix(inner)}*`;
|
|
188
|
-
}
|
|
189
|
-
// Handle arrays (T[], T[,], jagged arrays, ...). `global::string[]` is invalid; qualify
|
|
190
|
-
// the element type only.
|
|
191
|
-
const arrayMatch = /(\[[,\s]*\])$/.exec(typeStr);
|
|
192
|
-
if (arrayMatch) {
|
|
193
|
-
const suffix = arrayMatch[1];
|
|
194
|
-
if (!suffix)
|
|
195
|
-
return typeStr;
|
|
196
|
-
const inner = typeStr.slice(0, -suffix.length);
|
|
197
|
-
return `${ensureGlobalPrefix(inner)}${suffix}`;
|
|
198
|
-
}
|
|
199
|
-
// Skip primitives (and other builtin keyword types) after handling suffix forms.
|
|
200
|
-
if (isCSharpBuiltinType(typeStr)) {
|
|
201
|
-
return typeStr;
|
|
202
|
-
}
|
|
203
|
-
// Handle generic types: List<Foo> -> global::List<global::Foo>
|
|
204
|
-
// For now, just add prefix to the outer type
|
|
205
|
-
// The inner types should already be handled by emitType
|
|
206
|
-
return `global::${typeStr}`;
|
|
207
|
-
};
|
|
208
|
-
/**
|
|
209
|
-
* Register a type with the JSON AOT registry.
|
|
210
|
-
* Ensures types are fully qualified with namespace for the AOT source generator.
|
|
211
|
-
*/
|
|
212
|
-
const registerJsonAotType = (type, context) => {
|
|
213
|
-
if (!type)
|
|
214
|
-
return;
|
|
215
|
-
if (!context.options.jsonAotRegistry)
|
|
216
|
-
return;
|
|
217
|
-
// NativeAOT JSON source generation requires CLOSED types.
|
|
218
|
-
// If the type contains any generic parameters in the current scope (T, U, ...),
|
|
219
|
-
// we cannot emit `[JsonSerializable(typeof(T))]` because `T` is not in scope in the
|
|
220
|
-
// generated context class. Skip registration to keep emission valid.
|
|
221
|
-
if (containsTypeParameter(type, context.typeParameters ?? new Set())) {
|
|
222
|
-
context.options.jsonAotRegistry.needsJsonAot = true;
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const registry = context.options.jsonAotRegistry;
|
|
226
|
-
const [rawTypeStr] = emitType(type, { ...context, qualifyLocalTypes: true });
|
|
227
|
-
const typeStr = rawTypeStr.endsWith("?")
|
|
228
|
-
? rawTypeStr.slice(0, -1)
|
|
229
|
-
: rawTypeStr;
|
|
230
|
-
registry.rootTypes.add(ensureGlobalPrefix(typeStr));
|
|
231
|
-
registry.needsJsonAot = true;
|
|
232
|
-
};
|
|
233
|
-
/**
|
|
234
|
-
* Check if a call expression needs an explicit cast because the inferred type
|
|
235
|
-
* differs from the C# return type. This handles cases like Math.floor() which
|
|
236
|
-
* returns double in C# but is cast to int in TypeScript via `as int`.
|
|
237
|
-
*/
|
|
238
|
-
const needsIntCast = (expr, calleeName) => {
|
|
239
|
-
// Check if the inferred type is int (a reference type from @tsonic/core)
|
|
240
|
-
const inferredType = expr.inferredType;
|
|
241
|
-
if (!inferredType ||
|
|
242
|
-
inferredType.kind !== "referenceType" ||
|
|
243
|
-
inferredType.name !== "int") {
|
|
244
|
-
return false;
|
|
245
|
-
}
|
|
246
|
-
// Check if this is a Math method that returns double
|
|
247
|
-
const mathMethodsReturningDouble = [
|
|
248
|
-
"Math.floor",
|
|
249
|
-
"Math.ceil",
|
|
250
|
-
"Math.round",
|
|
251
|
-
"Math.abs",
|
|
252
|
-
"Math.pow",
|
|
253
|
-
"Math.sqrt",
|
|
254
|
-
"Math.min",
|
|
255
|
-
"Math.max",
|
|
256
|
-
];
|
|
257
|
-
return mathMethodsReturningDouble.some((m) => calleeName === m || calleeName.endsWith(`.${m.split(".").pop()}`));
|
|
258
|
-
};
|
|
259
|
-
/**
|
|
260
|
-
* Emit a JsonSerializer call with NativeAOT-compatible options.
|
|
261
|
-
* Rewrites:
|
|
262
|
-
* JsonSerializer.Serialize(value) → JsonSerializer.Serialize(value, TsonicJson.Options)
|
|
263
|
-
* JsonSerializer.Deserialize<T>(json) → JsonSerializer.Deserialize<T>(json, TsonicJson.Options)
|
|
264
|
-
*/
|
|
265
|
-
const emitJsonSerializerCall = (expr, context, method) => {
|
|
266
|
-
let currentContext = context;
|
|
267
|
-
// Register the type with the JSON AOT registry
|
|
268
|
-
if (method === "Serialize") {
|
|
269
|
-
// For Serialize, get type from first argument's inferredType
|
|
270
|
-
const firstArg = expr.arguments[0];
|
|
271
|
-
if (firstArg && firstArg.kind !== "spread") {
|
|
272
|
-
registerJsonAotType(firstArg.inferredType, context);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
// For Deserialize, get type from type arguments
|
|
277
|
-
const typeArg = expr.typeArguments?.[0];
|
|
278
|
-
if (typeArg) {
|
|
279
|
-
registerJsonAotType(typeArg, context);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
// Emit type arguments for Deserialize<T>
|
|
283
|
-
let typeArgsStr = "";
|
|
284
|
-
if (expr.typeArguments && expr.typeArguments.length > 0) {
|
|
285
|
-
const [typeArgs, typeContext] = emitTypeArguments(expr.typeArguments, currentContext);
|
|
286
|
-
typeArgsStr = typeArgs;
|
|
287
|
-
currentContext = typeContext;
|
|
288
|
-
}
|
|
289
|
-
// Emit arguments
|
|
290
|
-
const args = [];
|
|
291
|
-
for (const arg of expr.arguments) {
|
|
292
|
-
if (arg.kind === "spread") {
|
|
293
|
-
const [spreadFrag, ctx] = emitExpression(arg.expression, currentContext);
|
|
294
|
-
args.push(spreadFrag.text);
|
|
295
|
-
currentContext = ctx;
|
|
296
|
-
}
|
|
297
|
-
else {
|
|
298
|
-
const [argFrag, ctx] = emitExpression(arg, currentContext);
|
|
299
|
-
args.push(argFrag.text);
|
|
300
|
-
currentContext = ctx;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
// Add TsonicJson.Options only when NativeAOT JSON context generation is enabled.
|
|
304
|
-
if (context.options.jsonAotRegistry) {
|
|
305
|
-
args.push("TsonicJson.Options");
|
|
306
|
-
}
|
|
307
|
-
const text = `global::System.Text.Json.JsonSerializer.${method}${typeArgsStr}(${args.join(", ")})`;
|
|
308
|
-
return [{ text }, currentContext];
|
|
309
|
-
};
|
|
310
|
-
/**
|
|
311
|
-
* Emit a function call expression
|
|
312
|
-
*/
|
|
313
|
-
export const emitCall = (expr, context) => {
|
|
314
|
-
// Void promise resolve: emit as zero-arg call when safe.
|
|
315
|
-
// C# Action (zero-arg) cannot accept arguments, so resolve() and resolve(undefined)
|
|
316
|
-
// both map to resolve(). Only strip when there are no arguments or a single
|
|
317
|
-
// `undefined` identifier — other argument forms may have side effects that must
|
|
318
|
-
// not be dropped. Name-based matching is scoped to the executor body; shadowing
|
|
319
|
-
// the resolve name inside the executor is technically possible but extremely rare.
|
|
320
|
-
if (expr.callee.kind === "identifier" &&
|
|
321
|
-
context.voidResolveNames?.has(expr.callee.name)) {
|
|
322
|
-
const isZeroArg = expr.arguments.length === 0;
|
|
323
|
-
const isSingleUndefined = expr.arguments.length === 1 &&
|
|
324
|
-
expr.arguments[0]?.kind === "identifier" &&
|
|
325
|
-
expr.arguments[0].name === "undefined";
|
|
326
|
-
if (isZeroArg || isSingleUndefined) {
|
|
327
|
-
const [calleeFrag, calleeCtx] = emitExpression(expr.callee, context);
|
|
328
|
-
const calleeText = formatPostfixExpressionText(expr.callee, calleeFrag.text);
|
|
329
|
-
return [{ text: `${calleeText}()` }, calleeCtx];
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
// Check for JsonSerializer calls (NativeAOT support)
|
|
333
|
-
const jsonCall = isJsonSerializerCall(expr.callee);
|
|
334
|
-
if (jsonCall) {
|
|
335
|
-
return emitJsonSerializerCall(expr, context, jsonCall.method);
|
|
336
|
-
}
|
|
337
|
-
// Check for global JSON.stringify/parse calls
|
|
338
|
-
// These compile to JsonSerializer.Serialize/Deserialize
|
|
339
|
-
const globalJsonCall = isGlobalJsonCall(expr.callee);
|
|
340
|
-
if (globalJsonCall) {
|
|
341
|
-
return emitJsonSerializerCall(expr, context, globalJsonCall.method);
|
|
342
|
-
}
|
|
343
|
-
// EF Core query precompilation has a known limitation: `query.ToList().ToArray()`
|
|
344
|
-
// fails to precompile (captured locals may be treated as "unknown identifiers").
|
|
345
|
-
// Since `ToList().ToArray()` is equivalent to `ToArray()` for IEnumerable<T>,
|
|
346
|
-
// canonicalize this pattern to `query.ToArray()` so NativeAOT precompilation works.
|
|
347
|
-
if (expr.callee.kind === "memberAccess" &&
|
|
348
|
-
expr.callee.property === "ToArray" &&
|
|
349
|
-
expr.arguments.length === 0 &&
|
|
350
|
-
expr.callee.object.kind === "call") {
|
|
351
|
-
const innerCall = expr.callee.object;
|
|
352
|
-
if (innerCall.callee.kind === "memberAccess" &&
|
|
353
|
-
innerCall.callee.memberBinding?.isExtensionMethod &&
|
|
354
|
-
isInstanceMemberAccess(innerCall.callee, context) &&
|
|
355
|
-
innerCall.callee.memberBinding.type.startsWith("System.Linq.Enumerable") &&
|
|
356
|
-
innerCall.callee.memberBinding.member === "ToList" &&
|
|
357
|
-
innerCall.arguments.length === 0) {
|
|
358
|
-
let currentContext = context;
|
|
359
|
-
// Ensure extension methods are in scope.
|
|
360
|
-
currentContext.usings.add("System.Linq");
|
|
361
|
-
const receiverExpr = innerCall.callee.object;
|
|
362
|
-
const [receiverFrag, receiverCtx] = emitExpression(receiverExpr, currentContext);
|
|
363
|
-
currentContext = receiverCtx;
|
|
364
|
-
const receiverText = formatPostfixExpressionText(receiverExpr, receiverFrag.text);
|
|
365
|
-
const text = `${receiverText}.ToArray()`;
|
|
366
|
-
return [{ text }, currentContext];
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
// Extension method lowering: emit explicit static invocation with receiver as first arg.
|
|
370
|
-
// This avoids relying on C# `using` directives for extension method discovery.
|
|
371
|
-
if (expr.callee.kind === "memberAccess" &&
|
|
372
|
-
expr.callee.memberBinding?.isExtensionMethod &&
|
|
373
|
-
isInstanceMemberAccess(expr.callee, context)) {
|
|
374
|
-
let currentContext = context;
|
|
375
|
-
const binding = expr.callee.memberBinding;
|
|
376
|
-
const receiverExpr = expr.callee.object;
|
|
377
|
-
const [receiverFrag, receiverContext] = emitExpression(receiverExpr, currentContext);
|
|
378
|
-
currentContext = receiverContext;
|
|
379
|
-
// Some ecosystems (notably EF Core query precompilation) require fluent syntax
|
|
380
|
-
// so the tooling can locate queries in syntax trees. For those namespaces,
|
|
381
|
-
// emit `receiver.Method(...)` and add a `using` directive for the namespace.
|
|
382
|
-
if (shouldEmitFluentExtensionCall(binding.type, binding.member)) {
|
|
383
|
-
const ns = getTypeNamespace(binding.type);
|
|
384
|
-
if (ns) {
|
|
385
|
-
currentContext.usings.add(ns);
|
|
386
|
-
}
|
|
387
|
-
// Handle generic type arguments
|
|
388
|
-
let typeArgsStr = "";
|
|
389
|
-
if (expr.typeArguments && expr.typeArguments.length > 0) {
|
|
390
|
-
const [typeArgs, typeContext] = emitTypeArguments(expr.typeArguments, currentContext);
|
|
391
|
-
typeArgsStr = typeArgs;
|
|
392
|
-
currentContext = typeContext;
|
|
393
|
-
}
|
|
394
|
-
// Get parameter types from IR (extracted from resolved signature in frontend)
|
|
395
|
-
const parameterTypes = expr.parameterTypes ?? [];
|
|
396
|
-
const args = [];
|
|
397
|
-
for (let i = 0; i < expr.arguments.length; i++) {
|
|
398
|
-
const arg = expr.arguments[i];
|
|
399
|
-
if (!arg)
|
|
400
|
-
continue;
|
|
401
|
-
const expectedType = parameterTypes[i];
|
|
402
|
-
if (arg.kind === "spread") {
|
|
403
|
-
const [spreadFrag, ctx] = emitExpression(arg.expression, currentContext);
|
|
404
|
-
args.push(`params ${spreadFrag.text}`);
|
|
405
|
-
currentContext = ctx;
|
|
406
|
-
}
|
|
407
|
-
else {
|
|
408
|
-
const castModifier = getPassingModifierFromCast(arg);
|
|
409
|
-
if (castModifier && isLValue(arg)) {
|
|
410
|
-
const [argFrag, ctx] = emitExpression(arg, currentContext);
|
|
411
|
-
args.push(`${castModifier} ${argFrag.text}`);
|
|
412
|
-
currentContext = ctx;
|
|
413
|
-
}
|
|
414
|
-
else {
|
|
415
|
-
const [argFrag, ctx] = emitExpression(arg, currentContext, expectedType);
|
|
416
|
-
const passingMode = expr.argumentPassing?.[i];
|
|
417
|
-
const prefix = passingMode && passingMode !== "value" && isLValue(arg)
|
|
418
|
-
? `${passingMode} `
|
|
419
|
-
: "";
|
|
420
|
-
args.push(`${prefix}${argFrag.text}`);
|
|
421
|
-
currentContext = ctx;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
const receiverText = formatPostfixExpressionText(receiverExpr, receiverFrag.text);
|
|
426
|
-
const op = expr.isOptional ? "?." : ".";
|
|
427
|
-
const baseCallText = `${receiverText}${op}${binding.member}${typeArgsStr}(${args.join(", ")})`;
|
|
428
|
-
const text = needsIntCast(expr, binding.member)
|
|
429
|
-
? `(int)${baseCallText}`
|
|
430
|
-
: baseCallText;
|
|
431
|
-
return [{ text }, currentContext];
|
|
432
|
-
}
|
|
433
|
-
let finalCalleeName = `global::${binding.type}.${binding.member}`;
|
|
434
|
-
// Handle generic type arguments
|
|
435
|
-
let typeArgsStr = "";
|
|
436
|
-
if (expr.typeArguments && expr.typeArguments.length > 0) {
|
|
437
|
-
if (expr.requiresSpecialization) {
|
|
438
|
-
const [specializedName, specContext] = generateSpecializedName(finalCalleeName, expr.typeArguments, currentContext);
|
|
439
|
-
finalCalleeName = specializedName;
|
|
440
|
-
currentContext = specContext;
|
|
441
|
-
}
|
|
442
|
-
else {
|
|
443
|
-
const [typeArgs, typeContext] = emitTypeArguments(expr.typeArguments, currentContext);
|
|
444
|
-
typeArgsStr = typeArgs;
|
|
445
|
-
currentContext = typeContext;
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
const parameterTypes = expr.parameterTypes ?? [];
|
|
449
|
-
const args = [receiverFrag.text];
|
|
450
|
-
for (let i = 0; i < expr.arguments.length; i++) {
|
|
451
|
-
const arg = expr.arguments[i];
|
|
452
|
-
if (!arg)
|
|
453
|
-
continue;
|
|
454
|
-
const expectedType = parameterTypes[i];
|
|
455
|
-
if (arg.kind === "spread") {
|
|
456
|
-
const [spreadFrag, ctx] = emitExpression(arg.expression, currentContext);
|
|
457
|
-
args.push(`params ${spreadFrag.text}`);
|
|
458
|
-
currentContext = ctx;
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
const castModifier = getPassingModifierFromCast(arg);
|
|
462
|
-
if (castModifier && isLValue(arg)) {
|
|
463
|
-
const [argFrag, ctx] = emitExpression(arg, currentContext);
|
|
464
|
-
args.push(`${castModifier} ${argFrag.text}`);
|
|
465
|
-
currentContext = ctx;
|
|
466
|
-
}
|
|
467
|
-
else {
|
|
468
|
-
const [argFrag, ctx] = emitExpression(arg, currentContext, expectedType);
|
|
469
|
-
const passingMode = expr.argumentPassing?.[i];
|
|
470
|
-
const prefix = passingMode && passingMode !== "value" && isLValue(arg)
|
|
471
|
-
? `${passingMode} `
|
|
472
|
-
: "";
|
|
473
|
-
args.push(`${prefix}${argFrag.text}`);
|
|
474
|
-
currentContext = ctx;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
const baseCallText = `${finalCalleeName}${typeArgsStr}(${args.join(", ")})`;
|
|
479
|
-
// JS runtime helpers often return List<T> for array-like results, while the IR
|
|
480
|
-
// models them as native CLR arrays. When the IR expects an array, coerce via
|
|
481
|
-
// Enumerable.ToArray to preserve the IR contract.
|
|
482
|
-
const callText = expr.inferredType?.kind === "arrayType"
|
|
483
|
-
? `global::System.Linq.Enumerable.ToArray(${baseCallText})`
|
|
484
|
-
: baseCallText;
|
|
485
|
-
const text = needsIntCast(expr, finalCalleeName)
|
|
486
|
-
? `(int)${callText}`
|
|
487
|
-
: callText;
|
|
488
|
-
return [{ text }, currentContext];
|
|
489
|
-
}
|
|
490
|
-
// Regular function call
|
|
491
|
-
const [calleeFrag, newContext] = expr.callee.kind === "memberAccess"
|
|
492
|
-
? emitMemberAccess(expr.callee, context, "call")
|
|
493
|
-
: emitExpression(expr.callee, context);
|
|
494
|
-
let currentContext = newContext;
|
|
495
|
-
// Handle generic type arguments
|
|
496
|
-
let typeArgsStr = "";
|
|
497
|
-
let finalCalleeName = calleeFrag.text;
|
|
498
|
-
if (expr.typeArguments && expr.typeArguments.length > 0) {
|
|
499
|
-
if (expr.requiresSpecialization) {
|
|
500
|
-
// Monomorphisation: Generate specialized method name
|
|
501
|
-
// e.g., process<string> → process__string
|
|
502
|
-
const [specializedName, specContext] = generateSpecializedName(calleeFrag.text, expr.typeArguments, currentContext);
|
|
503
|
-
finalCalleeName = specializedName;
|
|
504
|
-
currentContext = specContext;
|
|
505
|
-
}
|
|
506
|
-
else {
|
|
507
|
-
// Emit explicit type arguments for generic call
|
|
508
|
-
// e.g., identity<string>(value)
|
|
509
|
-
const [typeArgs, typeContext] = emitTypeArguments(expr.typeArguments, currentContext);
|
|
510
|
-
typeArgsStr = typeArgs;
|
|
511
|
-
currentContext = typeContext;
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
// Get parameter types from IR (extracted from resolved signature in frontend)
|
|
515
|
-
const parameterTypes = expr.parameterTypes ?? [];
|
|
516
|
-
const args = [];
|
|
517
|
-
for (let i = 0; i < expr.arguments.length; i++) {
|
|
518
|
-
const arg = expr.arguments[i];
|
|
519
|
-
if (!arg)
|
|
520
|
-
continue; // Skip undefined (shouldn't happen in valid IR)
|
|
521
|
-
// Get expected type for this argument from parameter types
|
|
522
|
-
const expectedType = parameterTypes[i];
|
|
523
|
-
if (arg.kind === "spread") {
|
|
524
|
-
// Spread in function call
|
|
525
|
-
const [spreadFrag, ctx] = emitExpression(arg.expression, currentContext);
|
|
526
|
-
args.push(`params ${spreadFrag.text}`);
|
|
527
|
-
currentContext = ctx;
|
|
528
|
-
}
|
|
529
|
-
else {
|
|
530
|
-
// Check if this argument has an explicit `as out<T>` / `as ref<T>` / `as inref<T>` cast
|
|
531
|
-
const castModifier = getPassingModifierFromCast(arg);
|
|
532
|
-
if (castModifier && isLValue(arg)) {
|
|
533
|
-
// Emit the expression without the cast wrapper, with the modifier prefix
|
|
534
|
-
// For `value as out<int>`, emit `out value`
|
|
535
|
-
const [argFrag, ctx] = emitExpression(arg, currentContext);
|
|
536
|
-
args.push(`${castModifier} ${argFrag.text}`);
|
|
537
|
-
currentContext = ctx;
|
|
538
|
-
}
|
|
539
|
-
else {
|
|
540
|
-
const [argFrag, ctx] = emitExpression(arg, currentContext, expectedType);
|
|
541
|
-
// Check if this argument needs ref/out/in prefix from function signature
|
|
542
|
-
// Only add prefix if argument is an lvalue (identifier or member access)
|
|
543
|
-
const passingMode = expr.argumentPassing?.[i];
|
|
544
|
-
const prefix = passingMode && passingMode !== "value" && isLValue(arg)
|
|
545
|
-
? `${passingMode} `
|
|
546
|
-
: "";
|
|
547
|
-
args.push(`${prefix}${argFrag.text}`);
|
|
548
|
-
currentContext = ctx;
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
// For member-access calls, the receiver parenthesization is already handled inside
|
|
553
|
-
// `emitMemberAccess`. Wrapping the full `obj.Member` in parentheses can change meaning
|
|
554
|
-
// in C# (e.g., `(obj.Member)()` attempts to invoke a delegate rather than calling a method).
|
|
555
|
-
const calleeText = expr.callee.kind === "memberAccess"
|
|
556
|
-
? `${finalCalleeName}${typeArgsStr}`
|
|
557
|
-
: formatPostfixExpressionText(expr.callee, `${finalCalleeName}${typeArgsStr}`);
|
|
558
|
-
const callOp = expr.isOptional ? "?." : "";
|
|
559
|
-
const callText = `${calleeText}${callOp}(${args.join(", ")})`;
|
|
560
|
-
// Add cast if needed (e.g., Math.floor returning double but asserted as int)
|
|
561
|
-
const text = needsIntCast(expr, finalCalleeName)
|
|
562
|
-
? `(int)${callText}`
|
|
563
|
-
: callText;
|
|
564
|
-
return [{ text }, currentContext];
|
|
565
|
-
};
|
|
566
|
-
/**
|
|
567
|
-
* Check if a new expression is new List<T>([...]) with an array literal argument
|
|
568
|
-
* This pattern should be emitted as collection initializer: new List<T> { ... }
|
|
569
|
-
*/
|
|
570
|
-
const isListConstructorWithArrayLiteral = (expr) => {
|
|
571
|
-
// Only apply to BCL List<T> so the rewrite is semantics-safe.
|
|
572
|
-
// (We rely on List<T> having a parameterless ctor + Add for collection initializer.)
|
|
573
|
-
const inferredType = expr.inferredType;
|
|
574
|
-
if (inferredType?.kind !== "referenceType") {
|
|
575
|
-
return false;
|
|
576
|
-
}
|
|
577
|
-
const typeId = inferredType.typeId;
|
|
578
|
-
if (!typeId ||
|
|
579
|
-
!typeId.clrName.startsWith("System.Collections.Generic.List")) {
|
|
580
|
-
return false;
|
|
581
|
-
}
|
|
582
|
-
// Must have exactly one type argument
|
|
583
|
-
if (!expr.typeArguments || expr.typeArguments.length !== 1) {
|
|
584
|
-
return false;
|
|
585
|
-
}
|
|
586
|
-
// Check if callee is identifier "List"
|
|
587
|
-
if (expr.callee.kind !== "identifier" || expr.callee.name !== "List") {
|
|
588
|
-
return false;
|
|
589
|
-
}
|
|
590
|
-
// Must have exactly one argument that is an array literal
|
|
591
|
-
if (expr.arguments.length !== 1) {
|
|
592
|
-
return false;
|
|
593
|
-
}
|
|
594
|
-
const arg = expr.arguments[0];
|
|
595
|
-
if (!arg || arg.kind === "spread" || arg.kind !== "array") {
|
|
596
|
-
return false;
|
|
597
|
-
}
|
|
598
|
-
// Collection initializers don't support spreads/holes, so reject them here.
|
|
599
|
-
for (const element of arg.elements) {
|
|
600
|
-
if (!element || element.kind === "spread") {
|
|
601
|
-
return false;
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
return true;
|
|
605
|
-
};
|
|
606
|
-
/**
|
|
607
|
-
* Emit new List<T>([...]) as collection initializer: new List<T> { ... }
|
|
608
|
-
*
|
|
609
|
-
* Examples:
|
|
610
|
-
* new List<int>([1, 2, 3]) → new List<int> { 1, 2, 3 }
|
|
611
|
-
* new List<string>(["a", "b"]) → new List<string> { "a", "b" }
|
|
612
|
-
* new List<User>([u1, u2]) → new List<User> { u1, u2 }
|
|
613
|
-
*/
|
|
614
|
-
const emitListCollectionInitializer = (expr, context) => {
|
|
615
|
-
let currentContext = context;
|
|
616
|
-
const [calleeFrag, calleeContext] = emitExpression(expr.callee, currentContext);
|
|
617
|
-
currentContext = calleeContext;
|
|
618
|
-
// Handle generic type arguments consistently with emitNew()
|
|
619
|
-
let typeArgsStr = "";
|
|
620
|
-
let finalClassName = calleeFrag.text;
|
|
621
|
-
if (expr.typeArguments && expr.typeArguments.length > 0) {
|
|
622
|
-
if (expr.requiresSpecialization) {
|
|
623
|
-
const [specializedName, specContext] = generateSpecializedName(calleeFrag.text, expr.typeArguments, currentContext);
|
|
624
|
-
finalClassName = specializedName;
|
|
625
|
-
currentContext = specContext;
|
|
626
|
-
}
|
|
627
|
-
else {
|
|
628
|
-
const [typeArgs, typeContext] = emitTypeArguments(expr.typeArguments, currentContext);
|
|
629
|
-
typeArgsStr = typeArgs;
|
|
630
|
-
currentContext = typeContext;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
// Get the array literal argument
|
|
634
|
-
const arrayLiteral = expr.arguments[0];
|
|
635
|
-
// Emit each element
|
|
636
|
-
const elements = [];
|
|
637
|
-
for (const element of arrayLiteral.elements) {
|
|
638
|
-
if (element === undefined) {
|
|
639
|
-
continue; // Skip undefined slots (sparse arrays)
|
|
640
|
-
}
|
|
641
|
-
if (element.kind === "spread") {
|
|
642
|
-
// Not supported (guarded by isListConstructorWithArrayLiteral)
|
|
643
|
-
const [fallbackFrag, fallbackContext] = emitNew(expr, currentContext);
|
|
644
|
-
return [fallbackFrag, fallbackContext];
|
|
645
|
-
}
|
|
646
|
-
else {
|
|
647
|
-
const [elemFrag, ctx] = emitExpression(element, currentContext);
|
|
648
|
-
elements.push(elemFrag.text);
|
|
649
|
-
currentContext = ctx;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
// Use collection initializer syntax
|
|
653
|
-
const text = elements.length === 0
|
|
654
|
-
? `new ${finalClassName}${typeArgsStr}()`
|
|
655
|
-
: `new ${finalClassName}${typeArgsStr} { ${elements.join(", ")} }`;
|
|
656
|
-
return [{ text }, currentContext];
|
|
657
|
-
};
|
|
658
|
-
/**
|
|
659
|
-
* Check if a new expression is new Array<T>(size)
|
|
660
|
-
* Returns the element type if it is, undefined otherwise
|
|
661
|
-
*/
|
|
662
|
-
const isArrayConstructorCall = (expr) => {
|
|
663
|
-
// Check if callee is identifier "Array"
|
|
664
|
-
if (expr.callee.kind !== "identifier" || expr.callee.name !== "Array") {
|
|
665
|
-
return false;
|
|
666
|
-
}
|
|
667
|
-
// Must have exactly one type argument
|
|
668
|
-
if (!expr.typeArguments || expr.typeArguments.length !== 1) {
|
|
669
|
-
return false;
|
|
670
|
-
}
|
|
671
|
-
return true;
|
|
672
|
-
};
|
|
673
|
-
/**
|
|
674
|
-
* Emit new Array<T>(size) as new T[size]
|
|
675
|
-
*
|
|
676
|
-
* Examples:
|
|
677
|
-
* new Array<int>(10) → new int[10]
|
|
678
|
-
* new Array<string>(5) → new string[5]
|
|
679
|
-
* new Array<User>(count) → new User[count]
|
|
680
|
-
* new Array<int>() → new int[0]
|
|
681
|
-
*/
|
|
682
|
-
const emitArrayConstructor = (expr, context) => {
|
|
683
|
-
let currentContext = context;
|
|
684
|
-
// Get the element type (verified by isArrayConstructorCall)
|
|
685
|
-
const typeArgs = expr.typeArguments;
|
|
686
|
-
const elementType = typeArgs?.[0];
|
|
687
|
-
if (!elementType) {
|
|
688
|
-
return [{ text: "new object[0]" }, currentContext];
|
|
689
|
-
}
|
|
690
|
-
const [elementTypeStr, typeContext] = emitType(elementType, currentContext);
|
|
691
|
-
currentContext = typeContext;
|
|
692
|
-
// Get the size argument (if any)
|
|
693
|
-
let sizeStr = "0"; // Default to empty array if no size argument
|
|
694
|
-
if (expr.arguments.length > 0) {
|
|
695
|
-
const sizeArg = expr.arguments[0];
|
|
696
|
-
if (sizeArg && sizeArg.kind !== "spread") {
|
|
697
|
-
const [sizeFrag, sizeContext] = emitExpression(sizeArg, currentContext);
|
|
698
|
-
sizeStr = sizeFrag.text;
|
|
699
|
-
currentContext = sizeContext;
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
const text = `new ${elementTypeStr}[${sizeStr}]`;
|
|
703
|
-
return [{ text }, currentContext];
|
|
704
|
-
};
|
|
705
|
-
const isPromiseConstructorCall = (expr) => {
|
|
706
|
-
return expr.callee.kind === "identifier" && expr.callee.name === "Promise";
|
|
707
|
-
};
|
|
708
|
-
const isVoidLikeType = (type) => {
|
|
709
|
-
if (!type)
|
|
710
|
-
return false;
|
|
711
|
-
return (type.kind === "voidType" ||
|
|
712
|
-
(type.kind === "primitiveType" && type.name === "undefined"));
|
|
713
|
-
};
|
|
714
|
-
/**
|
|
715
|
-
* Check if a type contains `void` in a position where it would be emitted
|
|
716
|
-
* as a C# generic type argument (union member, type argument, etc.).
|
|
717
|
-
* C# forbids `void` as a generic type argument, so such types are invalid.
|
|
718
|
-
*/
|
|
719
|
-
const containsVoidInGenericPosition = (type) => {
|
|
720
|
-
if (!type)
|
|
721
|
-
return false;
|
|
722
|
-
if (type.kind === "unionType") {
|
|
723
|
-
return type.types.some((t) => isVoidLikeType(t) || containsVoidInGenericPosition(t));
|
|
724
|
-
}
|
|
725
|
-
if (type.kind === "referenceType" && type.typeArguments) {
|
|
726
|
-
return type.typeArguments.some((t) => isVoidLikeType(t) || containsVoidInGenericPosition(t));
|
|
727
|
-
}
|
|
728
|
-
if (type.kind === "functionType") {
|
|
729
|
-
return (type.parameters.some((p) => containsVoidInGenericPosition(p.type)) ||
|
|
730
|
-
containsVoidInGenericPosition(type.returnType));
|
|
731
|
-
}
|
|
732
|
-
return false;
|
|
733
|
-
};
|
|
734
|
-
const getPromiseValueType = (expr) => {
|
|
735
|
-
const inferred = expr.inferredType;
|
|
736
|
-
if (inferred?.kind === "referenceType") {
|
|
737
|
-
const candidate = inferred.typeArguments?.[0];
|
|
738
|
-
if (candidate && !isVoidLikeType(candidate)) {
|
|
739
|
-
return candidate;
|
|
740
|
-
}
|
|
741
|
-
if (candidate && isVoidLikeType(candidate)) {
|
|
742
|
-
return undefined;
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
const explicit = expr.typeArguments?.[0];
|
|
746
|
-
if (explicit && !isVoidLikeType(explicit)) {
|
|
747
|
-
return explicit;
|
|
748
|
-
}
|
|
749
|
-
return undefined;
|
|
750
|
-
};
|
|
751
|
-
const getExecutorArity = (expr) => {
|
|
752
|
-
const executor = expr.arguments[0];
|
|
753
|
-
if (executor &&
|
|
754
|
-
executor.kind !== "spread" &&
|
|
755
|
-
(executor.kind === "arrowFunction" ||
|
|
756
|
-
executor.kind === "functionExpression")) {
|
|
757
|
-
return executor.parameters.length;
|
|
758
|
-
}
|
|
759
|
-
const executorType = expr.parameterTypes?.[0];
|
|
760
|
-
if (executorType?.kind === "functionType") {
|
|
761
|
-
return executorType.parameters.length;
|
|
762
|
-
}
|
|
763
|
-
return 1;
|
|
764
|
-
};
|
|
765
|
-
const emitPromiseConstructor = (expr, context) => {
|
|
766
|
-
const executor = expr.arguments[0];
|
|
767
|
-
if (!executor || executor.kind === "spread") {
|
|
768
|
-
throw new Error("Unsupported Promise constructor form: expected an executor function argument.");
|
|
769
|
-
}
|
|
770
|
-
let currentContext = context;
|
|
771
|
-
const [taskTypeTextRaw, taskTypeContext] = expr.inferredType
|
|
772
|
-
? emitType(expr.inferredType, currentContext)
|
|
773
|
-
: ["global::System.Threading.Tasks.Task", currentContext];
|
|
774
|
-
currentContext = taskTypeContext;
|
|
775
|
-
const taskTypeText = taskTypeTextRaw.length > 0
|
|
776
|
-
? taskTypeTextRaw
|
|
777
|
-
: "global::System.Threading.Tasks.Task";
|
|
778
|
-
const promiseValueType = getPromiseValueType(expr);
|
|
779
|
-
let valueTypeText = "bool";
|
|
780
|
-
if (promiseValueType) {
|
|
781
|
-
const [valueType, valueTypeContext] = emitType(promiseValueType, currentContext);
|
|
782
|
-
valueTypeText = valueType;
|
|
783
|
-
currentContext = valueTypeContext;
|
|
784
|
-
}
|
|
785
|
-
// For void promises, track the resolve parameter name so call emitter
|
|
786
|
-
// can strip arguments from resolve(undefined) calls (C# Action is zero-arg)
|
|
787
|
-
const resolveParam = !promiseValueType &&
|
|
788
|
-
(executor.kind === "arrowFunction" ||
|
|
789
|
-
executor.kind === "functionExpression")
|
|
790
|
-
? executor.parameters[0]
|
|
791
|
-
: undefined;
|
|
792
|
-
const resolveParamName = resolveParam?.pattern.kind === "identifierPattern"
|
|
793
|
-
? resolveParam.pattern.name
|
|
794
|
-
: undefined;
|
|
795
|
-
const executorEmitContext = resolveParamName
|
|
796
|
-
? { ...currentContext, voidResolveNames: new Set([resolveParamName]) }
|
|
797
|
-
: currentContext;
|
|
798
|
-
// For void promises, the resolve parameter's TS type may be
|
|
799
|
-
// `(value: void | PromiseLike<void>) => void` which emits as `Action<Union<void, Task>>` —
|
|
800
|
-
// invalid in C# (void cannot be a generic type argument). Strip the type annotation only
|
|
801
|
-
// when it contains void-in-generic, letting C# infer from the outer delegate cast.
|
|
802
|
-
// When the type is clean (e.g., `() => void` → `Action`), keep it for clarity.
|
|
803
|
-
const resolveParamHasVoidGeneric = resolveParam?.type?.kind === "functionType" &&
|
|
804
|
-
resolveParam.type.parameters.some((p) => containsVoidInGenericPosition(p.type));
|
|
805
|
-
const emittedExecutor = resolveParamHasVoidGeneric &&
|
|
806
|
-
(executor.kind === "arrowFunction" ||
|
|
807
|
-
executor.kind === "functionExpression")
|
|
808
|
-
? {
|
|
809
|
-
...executor,
|
|
810
|
-
parameters: executor.parameters.map((p, i) => i === 0 ? { ...p, type: undefined } : p),
|
|
811
|
-
}
|
|
812
|
-
: executor;
|
|
813
|
-
const [executorFrag, executorContext] = emitExpression(emittedExecutor, executorEmitContext, expr.parameterTypes?.[0]);
|
|
814
|
-
// Strip voidResolveNames from returned context to prevent leakage into enclosing scope
|
|
815
|
-
currentContext = resolveParamName
|
|
816
|
-
? { ...executorContext, voidResolveNames: undefined }
|
|
817
|
-
: executorContext;
|
|
818
|
-
const executorText = formatPostfixExpressionText(executor, executorFrag.text);
|
|
819
|
-
const executorArity = getExecutorArity(expr);
|
|
820
|
-
const resolveCallbackType = promiseValueType
|
|
821
|
-
? `global::System.Action<${valueTypeText}>`
|
|
822
|
-
: "global::System.Action";
|
|
823
|
-
const executorDelegateType = executorArity >= 2
|
|
824
|
-
? `global::System.Action<${resolveCallbackType}, global::System.Action<object?>>`
|
|
825
|
-
: `global::System.Action<${resolveCallbackType}>`;
|
|
826
|
-
const executorInvokeTarget = `((${executorDelegateType})${executorText})`;
|
|
827
|
-
const invokeArgs = executorArity >= 2
|
|
828
|
-
? "__tsonic_resolve, __tsonic_reject"
|
|
829
|
-
: "__tsonic_resolve";
|
|
830
|
-
const resolveDecl = promiseValueType
|
|
831
|
-
? `global::System.Action<${valueTypeText}> __tsonic_resolve = (value) => __tsonic_tcs.TrySetResult(value);`
|
|
832
|
-
: "global::System.Action __tsonic_resolve = () => __tsonic_tcs.TrySetResult(true);";
|
|
833
|
-
const text = `((global::System.Func<${taskTypeText}>)(() => { ` +
|
|
834
|
-
`var __tsonic_tcs = new global::System.Threading.Tasks.TaskCompletionSource<${valueTypeText}>(); ` +
|
|
835
|
-
`${resolveDecl} ` +
|
|
836
|
-
`global::System.Action<object?> __tsonic_reject = (error) => __tsonic_tcs.TrySetException((error as global::System.Exception) ?? new global::System.Exception(error?.ToString() ?? "Promise rejected")); ` +
|
|
837
|
-
`try { ${executorInvokeTarget}(${invokeArgs}); } catch (global::System.Exception ex) { __tsonic_tcs.TrySetException(ex); } ` +
|
|
838
|
-
`return __tsonic_tcs.Task; }))()`;
|
|
839
|
-
return [{ text }, currentContext];
|
|
840
|
-
};
|
|
841
|
-
/**
|
|
842
|
-
* Emit a new expression
|
|
843
|
-
*/
|
|
844
|
-
export const emitNew = (expr, context) => {
|
|
845
|
-
// Special case: new Array<T>(size) → new T[size]
|
|
846
|
-
if (isArrayConstructorCall(expr)) {
|
|
847
|
-
return emitArrayConstructor(expr, context);
|
|
848
|
-
}
|
|
849
|
-
// Special case: new List<T>([...]) → new List<T> { ... }
|
|
850
|
-
if (isListConstructorWithArrayLiteral(expr)) {
|
|
851
|
-
return emitListCollectionInitializer(expr, context);
|
|
852
|
-
}
|
|
853
|
-
// Promise constructor lowering:
|
|
854
|
-
// new Promise<T>((resolve, reject) => { ... })
|
|
855
|
-
// becomes a TaskCompletionSource<T>-backed Task expression.
|
|
856
|
-
if (isPromiseConstructorCall(expr)) {
|
|
857
|
-
return emitPromiseConstructor(expr, context);
|
|
858
|
-
}
|
|
859
|
-
const [calleeFrag, newContext] = emitExpression(expr.callee, context);
|
|
860
|
-
let currentContext = newContext;
|
|
861
|
-
// Handle generic type arguments
|
|
862
|
-
let typeArgsStr = "";
|
|
863
|
-
let finalClassName = calleeFrag.text;
|
|
864
|
-
if (expr.typeArguments && expr.typeArguments.length > 0) {
|
|
865
|
-
if (expr.requiresSpecialization) {
|
|
866
|
-
// Monomorphisation: Generate specialized class name
|
|
867
|
-
// e.g., new Box<string>() → new Box__string()
|
|
868
|
-
const [specializedName, specContext] = generateSpecializedName(calleeFrag.text, expr.typeArguments, currentContext);
|
|
869
|
-
finalClassName = specializedName;
|
|
870
|
-
currentContext = specContext;
|
|
871
|
-
}
|
|
872
|
-
else {
|
|
873
|
-
// Emit explicit type arguments for generic constructor
|
|
874
|
-
// e.g., new Box<string>(value)
|
|
875
|
-
const [typeArgs, typeContext] = emitTypeArguments(expr.typeArguments, currentContext);
|
|
876
|
-
typeArgsStr = typeArgs;
|
|
877
|
-
currentContext = typeContext;
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
const args = [];
|
|
881
|
-
const parameterTypes = expr.parameterTypes ?? [];
|
|
882
|
-
for (let i = 0; i < expr.arguments.length; i++) {
|
|
883
|
-
const arg = expr.arguments[i];
|
|
884
|
-
if (!arg)
|
|
885
|
-
continue;
|
|
886
|
-
if (arg.kind === "spread") {
|
|
887
|
-
const [spreadFrag, ctx] = emitExpression(arg.expression, currentContext);
|
|
888
|
-
args.push(`params ${spreadFrag.text}`);
|
|
889
|
-
currentContext = ctx;
|
|
890
|
-
}
|
|
891
|
-
else {
|
|
892
|
-
const expectedType = parameterTypes[i];
|
|
893
|
-
const castModifier = getPassingModifierFromCast(arg);
|
|
894
|
-
if (castModifier && isLValue(arg)) {
|
|
895
|
-
const [argFrag, ctx] = emitExpression(arg, currentContext);
|
|
896
|
-
args.push(`${castModifier} ${argFrag.text}`);
|
|
897
|
-
currentContext = ctx;
|
|
898
|
-
}
|
|
899
|
-
else {
|
|
900
|
-
const [argFrag, ctx] = emitExpression(arg, currentContext, expectedType);
|
|
901
|
-
const passingMode = expr.argumentPassing?.[i];
|
|
902
|
-
const prefix = passingMode && passingMode !== "value" && isLValue(arg)
|
|
903
|
-
? `${passingMode} `
|
|
904
|
-
: "";
|
|
905
|
-
args.push(`${prefix}${argFrag.text}`);
|
|
906
|
-
currentContext = ctx;
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
const text = `new ${finalClassName}${typeArgsStr}(${args.join(", ")})`;
|
|
911
|
-
return [{ text }, currentContext];
|
|
912
|
-
};
|
|
4
|
+
export { emitCall } from "./calls/call-emitter.js";
|
|
5
|
+
export { emitNew } from "./calls/new-emitter.js";
|
|
913
6
|
//# sourceMappingURL=calls.js.map
|