@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
|
@@ -6,953 +6,9 @@
|
|
|
6
6
|
* - Integer casts only from IrCastExpression (not inferred from expectedType)
|
|
7
7
|
* - Binary ops: int op int = int, double op anything = double (C# semantics)
|
|
8
8
|
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import { lowerAssignmentPattern } from "../patterns.js";
|
|
15
|
-
/**
|
|
16
|
-
* Check if an expression has proven Int32 type from the numeric proof pass.
|
|
17
|
-
* Mirrors the same check in access.ts for consistency.
|
|
18
|
-
*/
|
|
19
|
-
const hasInt32Proof = (expr) => {
|
|
20
|
-
if (expr.inferredType?.kind === "primitiveType" &&
|
|
21
|
-
expr.inferredType.name === "int") {
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
if (expr.inferredType?.kind === "referenceType" &&
|
|
25
|
-
expr.inferredType.name === "int") {
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
return false;
|
|
29
|
-
};
|
|
30
|
-
/**
|
|
31
|
-
* Get operator precedence for proper parenthesization
|
|
32
|
-
*/
|
|
33
|
-
const getPrecedence = (operator) => {
|
|
34
|
-
const precedences = {
|
|
35
|
-
"||": 5,
|
|
36
|
-
// C# precedence: `??` binds less tightly than `||` / `&&` but more tightly than `?:`.
|
|
37
|
-
"??": 4,
|
|
38
|
-
"&&": 6,
|
|
39
|
-
"|": 7,
|
|
40
|
-
"^": 8,
|
|
41
|
-
"&": 9,
|
|
42
|
-
"==": 10,
|
|
43
|
-
"!=": 10,
|
|
44
|
-
"===": 10,
|
|
45
|
-
"!==": 10,
|
|
46
|
-
"<": 11,
|
|
47
|
-
">": 11,
|
|
48
|
-
"<=": 11,
|
|
49
|
-
">=": 11,
|
|
50
|
-
instanceof: 11,
|
|
51
|
-
in: 11,
|
|
52
|
-
"<<": 12,
|
|
53
|
-
">>": 12,
|
|
54
|
-
">>>": 12,
|
|
55
|
-
"+": 13,
|
|
56
|
-
"-": 13,
|
|
57
|
-
"*": 14,
|
|
58
|
-
"/": 14,
|
|
59
|
-
"%": 14,
|
|
60
|
-
"**": 15,
|
|
61
|
-
};
|
|
62
|
-
return precedences[operator] ?? 16;
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* Check if an expression has char type (either from string indexer or a variable typed as char).
|
|
66
|
-
* In C#, string[int] returns char, not string like in TypeScript.
|
|
67
|
-
* The IR now correctly sets inferredType to char for string indexer access.
|
|
68
|
-
*/
|
|
69
|
-
const isCharTyped = (expr) => {
|
|
70
|
-
return ((expr.inferredType?.kind === "primitiveType" &&
|
|
71
|
-
expr.inferredType.name === "char") ||
|
|
72
|
-
(expr.inferredType?.kind === "referenceType" &&
|
|
73
|
-
expr.inferredType.name === "char"));
|
|
74
|
-
};
|
|
75
|
-
const stripNullishFromType = (type) => {
|
|
76
|
-
if (!type)
|
|
77
|
-
return undefined;
|
|
78
|
-
if (type.kind !== "unionType")
|
|
79
|
-
return type;
|
|
80
|
-
const nonNullish = type.types.filter((t) => !(t.kind === "primitiveType" &&
|
|
81
|
-
(t.name === "null" || t.name === "undefined")));
|
|
82
|
-
if (nonNullish.length === 1) {
|
|
83
|
-
const only = nonNullish[0];
|
|
84
|
-
return only ? stripNullishFromType(only) : undefined;
|
|
85
|
-
}
|
|
86
|
-
return type;
|
|
87
|
-
};
|
|
88
|
-
const isStringTyped = (expr) => {
|
|
89
|
-
const type = stripNullishFromType(expr.inferredType);
|
|
90
|
-
if (!type)
|
|
91
|
-
return false;
|
|
92
|
-
if (type.kind === "primitiveType")
|
|
93
|
-
return type.name === "string";
|
|
94
|
-
if (type.kind === "referenceType")
|
|
95
|
-
return type.name === "string";
|
|
96
|
-
if (type.kind === "intersectionType") {
|
|
97
|
-
return type.types.some((part) => (part.kind === "primitiveType" && part.name === "string") ||
|
|
98
|
-
(part.kind === "referenceType" && part.name === "string"));
|
|
99
|
-
}
|
|
100
|
-
return false;
|
|
101
|
-
};
|
|
102
|
-
/**
|
|
103
|
-
* Check if an expression is a single-character string literal.
|
|
104
|
-
* Returns the character if so, undefined otherwise.
|
|
105
|
-
*/
|
|
106
|
-
const getSingleCharLiteral = (expr) => {
|
|
107
|
-
if (expr.kind !== "literal")
|
|
108
|
-
return undefined;
|
|
109
|
-
if (typeof expr.value !== "string")
|
|
110
|
-
return undefined;
|
|
111
|
-
if (expr.value.length !== 1)
|
|
112
|
-
return undefined;
|
|
113
|
-
return expr.value;
|
|
114
|
-
};
|
|
115
|
-
/**
|
|
116
|
-
* Escape a character for use in a C# char literal.
|
|
117
|
-
* Handles special characters like quotes, backslash, newline, etc.
|
|
118
|
-
*/
|
|
119
|
-
const escapeCharLiteral = (char) => {
|
|
120
|
-
switch (char) {
|
|
121
|
-
case "'":
|
|
122
|
-
return "\\'";
|
|
123
|
-
case "\\":
|
|
124
|
-
return "\\\\";
|
|
125
|
-
case "\n":
|
|
126
|
-
return "\\n";
|
|
127
|
-
case "\r":
|
|
128
|
-
return "\\r";
|
|
129
|
-
case "\t":
|
|
130
|
-
return "\\t";
|
|
131
|
-
case "\0":
|
|
132
|
-
return "\\0";
|
|
133
|
-
default:
|
|
134
|
-
return char;
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
/**
|
|
138
|
-
* Emit a binary operator expression
|
|
139
|
-
*
|
|
140
|
-
* NEW NUMERIC SPEC: No contextual type propagation for numeric literals.
|
|
141
|
-
* Literals use their raw lexeme - C# will naturally handle int + int = int,
|
|
142
|
-
* int + double = double, etc.
|
|
143
|
-
*
|
|
144
|
-
* Explicit casts come from IrCastExpression nodes (generated by type-checker
|
|
145
|
-
* when user intent allows int → double coercion).
|
|
146
|
-
*
|
|
147
|
-
* STRING INDEXER FIX: In C#, string[int] returns char, not string.
|
|
148
|
-
* When comparing a string indexer result with a single-character string literal,
|
|
149
|
-
* we emit the string as a char literal to avoid CS0019 (char == string).
|
|
150
|
-
*
|
|
151
|
-
* @param expr - The binary expression
|
|
152
|
-
* @param context - Emitter context
|
|
153
|
-
* @param _expectedType - Unused under new spec (kept for API compatibility)
|
|
154
|
-
*/
|
|
155
|
-
export const emitBinary = (expr, context, _expectedType) => {
|
|
156
|
-
// Map JavaScript operators to C# operators
|
|
157
|
-
const operatorMap = {
|
|
158
|
-
"===": "==",
|
|
159
|
-
"!==": "!=",
|
|
160
|
-
"==": "==", // Loose equality - needs special handling
|
|
161
|
-
"!=": "!=", // Loose inequality - needs special handling
|
|
162
|
-
instanceof: "is",
|
|
163
|
-
in: "/* in */", // Needs special handling
|
|
164
|
-
};
|
|
165
|
-
const op = operatorMap[expr.operator] ?? expr.operator;
|
|
166
|
-
const parentPrecedence = getPrecedence(expr.operator);
|
|
167
|
-
// Handle `"prop" in x` (union narrowing / dictionary membership)
|
|
168
|
-
if (expr.operator === "in") {
|
|
169
|
-
// LHS must be a string literal for deterministic lowering.
|
|
170
|
-
if (expr.left.kind !== "literal" || typeof expr.left.value !== "string") {
|
|
171
|
-
throw new Error("ICE: Unsupported `in` operator form. Left-hand side must be a string literal.");
|
|
172
|
-
}
|
|
173
|
-
const rhsType = expr.right.inferredType;
|
|
174
|
-
if (!rhsType) {
|
|
175
|
-
throw new Error("ICE: `in` operator RHS missing inferredType.");
|
|
176
|
-
}
|
|
177
|
-
const [rhsFrag, rhsCtx] = emitExpression(expr.right, context);
|
|
178
|
-
const rhsText = rhsFrag.text;
|
|
179
|
-
const resolvedRhs = resolveTypeAlias(stripNullish(rhsType), rhsCtx);
|
|
180
|
-
// Union<T1..Tn>: `"error" in auth` → auth.IsN() (where member N has the prop)
|
|
181
|
-
if (resolvedRhs.kind === "unionType") {
|
|
182
|
-
const propName = expr.left.value;
|
|
183
|
-
const matchingMembers = [];
|
|
184
|
-
for (let i = 0; i < resolvedRhs.types.length; i++) {
|
|
185
|
-
const member = resolvedRhs.types[i];
|
|
186
|
-
if (!member || member.kind !== "referenceType")
|
|
187
|
-
continue;
|
|
188
|
-
const localInfo = rhsCtx.localTypes?.get(member.name);
|
|
189
|
-
if (localInfo?.kind === "interface") {
|
|
190
|
-
const props = getAllPropertySignatures(member, rhsCtx);
|
|
191
|
-
if (props?.some((p) => p.name === propName)) {
|
|
192
|
-
matchingMembers.push(i + 1);
|
|
193
|
-
}
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
196
|
-
if (localInfo?.kind === "class") {
|
|
197
|
-
if (localInfo.members.some((m) => (m.kind === "propertyDeclaration" ||
|
|
198
|
-
m.kind === "methodDeclaration") &&
|
|
199
|
-
m.name === propName)) {
|
|
200
|
-
matchingMembers.push(i + 1);
|
|
201
|
-
}
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
// Cross-module union members: consult the batch type-member index.
|
|
205
|
-
// This enables `"prop" in x` narrowing even when the union member types
|
|
206
|
-
// are declared in a different TS module.
|
|
207
|
-
const candidates = [];
|
|
208
|
-
const stripGlobalPrefix = (name) => name.startsWith("global::") ? name.slice("global::".length) : name;
|
|
209
|
-
if (member.resolvedClrType) {
|
|
210
|
-
candidates.push(stripGlobalPrefix(member.resolvedClrType));
|
|
211
|
-
}
|
|
212
|
-
if (member.name.includes(".")) {
|
|
213
|
-
candidates.push(member.name);
|
|
214
|
-
}
|
|
215
|
-
if (!member.name.includes(".") && rhsCtx.options.typeMemberIndex) {
|
|
216
|
-
const matches = [];
|
|
217
|
-
for (const fqn of rhsCtx.options.typeMemberIndex.keys()) {
|
|
218
|
-
if (fqn.endsWith(`.${member.name}`) ||
|
|
219
|
-
fqn.endsWith(`.${member.name}__Alias`)) {
|
|
220
|
-
matches.push(fqn);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
if (matches.length === 1) {
|
|
224
|
-
candidates.push(matches[0]);
|
|
225
|
-
}
|
|
226
|
-
else if (matches.length > 1) {
|
|
227
|
-
const list = matches.sort().join(", ");
|
|
228
|
-
throw new Error(`ICE: Ambiguous union member type '${member.name}' for \`in\` narrowing. Candidates: ${list}`);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
// Single-file fallback (no batch indexes): assume same namespace.
|
|
232
|
-
if (rhsCtx.moduleNamespace) {
|
|
233
|
-
candidates.push(`${rhsCtx.moduleNamespace}.${member.name}`);
|
|
234
|
-
candidates.push(`${rhsCtx.moduleNamespace}.${member.name}__Alias`);
|
|
235
|
-
}
|
|
236
|
-
const hasMember = candidates.some((fqn) => {
|
|
237
|
-
const perType = rhsCtx.options.typeMemberIndex?.get(fqn);
|
|
238
|
-
return perType?.has(propName) ?? false;
|
|
239
|
-
});
|
|
240
|
-
if (hasMember) {
|
|
241
|
-
matchingMembers.push(i + 1);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
if (matchingMembers.length === 0) {
|
|
245
|
-
return [{ text: "false", precedence: parentPrecedence }, rhsCtx];
|
|
246
|
-
}
|
|
247
|
-
const checks = matchingMembers
|
|
248
|
-
.map((n) => `${rhsText}.Is${n}()`)
|
|
249
|
-
.join(" || ");
|
|
250
|
-
// Lowering emits an `||` chain; wrap to preserve grouping in any surrounding expression.
|
|
251
|
-
return [{ text: `(${checks})`, precedence: 16 }, rhsCtx];
|
|
252
|
-
}
|
|
253
|
-
// Dictionary<K,V>: `"k" in dict` → dict.ContainsKey("k")
|
|
254
|
-
if (resolvedRhs.kind === "dictionaryType") {
|
|
255
|
-
const keyType = stripNullish(resolvedRhs.keyType);
|
|
256
|
-
const isStringKey = (keyType.kind === "primitiveType" && keyType.name === "string") ||
|
|
257
|
-
(keyType.kind === "referenceType" && keyType.name === "string");
|
|
258
|
-
if (!isStringKey) {
|
|
259
|
-
throw new Error("ICE: Unsupported `in` operator on dictionary with non-string keys.");
|
|
260
|
-
}
|
|
261
|
-
const [keyFrag, keyCtx] = emitExpression(expr.left, rhsCtx);
|
|
262
|
-
const text = `${rhsText}.ContainsKey(${keyFrag.text})`;
|
|
263
|
-
return [{ text, precedence: parentPrecedence }, keyCtx];
|
|
264
|
-
}
|
|
265
|
-
throw new Error("ICE: Unsupported `in` operator. Only union shape guards and Dictionary<string, T> membership are supported.");
|
|
266
|
-
}
|
|
267
|
-
// Handle instanceof operator specially
|
|
268
|
-
if (expr.operator === "instanceof") {
|
|
269
|
-
const [leftFrag, leftContext] = emitExpression(expr.left, context);
|
|
270
|
-
const [rightFrag, rightContext] = emitExpression(expr.right, leftContext);
|
|
271
|
-
const text = `${leftFrag.text} is ${rightFrag.text}`;
|
|
272
|
-
return [{ text, precedence: parentPrecedence }, rightContext];
|
|
273
|
-
}
|
|
274
|
-
// CHAR VS STRING COMPARISON FIX:
|
|
275
|
-
// In C#, string[int] returns char, but in TypeScript it returns string.
|
|
276
|
-
// The IR now sets inferredType to char for string indexer access.
|
|
277
|
-
// When comparing a char-typed expression with a single-character string literal,
|
|
278
|
-
// emit the string as a char literal to avoid CS0019 (operator == cannot be applied to char and string).
|
|
279
|
-
const isComparisonOp = op === "==" ||
|
|
280
|
-
op === "!=" ||
|
|
281
|
-
op === "<" ||
|
|
282
|
-
op === ">" ||
|
|
283
|
-
op === "<=" ||
|
|
284
|
-
op === ">=";
|
|
285
|
-
if (isComparisonOp) {
|
|
286
|
-
const leftIsChar = isCharTyped(expr.left);
|
|
287
|
-
const rightIsChar = isCharTyped(expr.right);
|
|
288
|
-
const leftSingleChar = getSingleCharLiteral(expr.left);
|
|
289
|
-
const rightSingleChar = getSingleCharLiteral(expr.right);
|
|
290
|
-
// Case 1: left is char-typed, right is single-char literal → emit right as char
|
|
291
|
-
if (leftIsChar && rightSingleChar !== undefined) {
|
|
292
|
-
const [leftFrag, leftContext] = emitExpression(expr.left, context);
|
|
293
|
-
// Emit as char literal instead of string literal
|
|
294
|
-
const charLiteral = `'${escapeCharLiteral(rightSingleChar)}'`;
|
|
295
|
-
const text = `${leftFrag.text} ${op} ${charLiteral}`;
|
|
296
|
-
return [{ text, precedence: parentPrecedence }, leftContext];
|
|
297
|
-
}
|
|
298
|
-
// Case 2: right is char-typed, left is single-char literal → emit left as char
|
|
299
|
-
if (rightIsChar && leftSingleChar !== undefined) {
|
|
300
|
-
const [rightFrag, rightContext] = emitExpression(expr.right, context);
|
|
301
|
-
// Emit as char literal instead of string literal
|
|
302
|
-
const charLiteral = `'${escapeCharLiteral(leftSingleChar)}'`;
|
|
303
|
-
const text = `${charLiteral} ${op} ${rightFrag.text}`;
|
|
304
|
-
return [{ text, precedence: parentPrecedence }, rightContext];
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
// C# does not support relational operators directly on strings.
|
|
308
|
-
// TypeScript's lexicographic ordering maps to ordinal string comparison.
|
|
309
|
-
if (isComparisonOp &&
|
|
310
|
-
(op === "<" || op === ">" || op === "<=" || op === ">=") &&
|
|
311
|
-
isStringTyped(expr.left) &&
|
|
312
|
-
isStringTyped(expr.right)) {
|
|
313
|
-
const [leftFrag, leftContext] = emitExpression(expr.left, context);
|
|
314
|
-
const [rightFrag, rightContext] = emitExpression(expr.right, leftContext);
|
|
315
|
-
const compareExpr = `global::System.String.CompareOrdinal(${leftFrag.text}, ${rightFrag.text})`;
|
|
316
|
-
const text = `${compareExpr} ${op} 0`;
|
|
317
|
-
return [{ text, precedence: getPrecedence(expr.operator) }, rightContext];
|
|
318
|
-
}
|
|
319
|
-
// NULLISH COMPARISONS:
|
|
320
|
-
//
|
|
321
|
-
// Prefer `== null` / `!= null` for normal reference/nullable types so the result
|
|
322
|
-
// is expression-tree friendly (EF Core query providers do not support pattern matching).
|
|
323
|
-
//
|
|
324
|
-
// For unconstrained generics (T), `== null` is not always valid, so we instead cast
|
|
325
|
-
// to `object` to force reference-equality semantics and avoid operator overloads:
|
|
326
|
-
// ((object)x) == null
|
|
327
|
-
// This also avoids emitting pattern matching (`is null`) which is rejected inside
|
|
328
|
-
// expression trees (EF Core query providers).
|
|
329
|
-
//
|
|
330
|
-
// TypeScript: x === undefined → C#: x == null
|
|
331
|
-
// TypeScript: x !== undefined → C#: x != null
|
|
332
|
-
// TypeScript: x === null → C#: x == null
|
|
333
|
-
// TypeScript: x !== null → C#: x != null
|
|
334
|
-
const isNullishLiteral = (e) => (e.kind === "literal" && (e.value === undefined || e.value === null)) ||
|
|
335
|
-
(e.kind === "identifier" && (e.name === "undefined" || e.name === "null"));
|
|
336
|
-
const leftIsNullish = isNullishLiteral(expr.left);
|
|
337
|
-
const rightIsNullish = isNullishLiteral(expr.right);
|
|
338
|
-
const isNullishComparison = isComparisonOp &&
|
|
339
|
-
(op === "==" || op === "!=") &&
|
|
340
|
-
(leftIsNullish || rightIsNullish);
|
|
341
|
-
if (isNullishComparison) {
|
|
342
|
-
// One side is null/undefined literal, emit the other side as a C# null check.
|
|
343
|
-
// Clear narrowedBindings so we emit the raw identifier (not .Value)
|
|
344
|
-
const nonNullishExpr = leftIsNullish ? expr.right : expr.left;
|
|
345
|
-
const nullishExpr = leftIsNullish ? expr.left : expr.right;
|
|
346
|
-
const isUndefinedLiteral = (nullishExpr.kind === "literal" && nullishExpr.value === undefined) ||
|
|
347
|
-
(nullishExpr.kind === "identifier" && nullishExpr.name === "undefined");
|
|
348
|
-
// JS dictionary-style access (`dict[key]`) with undefined comparison should
|
|
349
|
-
// model key existence, not CLR value-type nullability.
|
|
350
|
-
//
|
|
351
|
-
// dict[key] === undefined -> !dict.ContainsKey(key)
|
|
352
|
-
// dict[key] !== undefined -> dict.ContainsKey(key)
|
|
353
|
-
//
|
|
354
|
-
// This prevents miscompiles like folding `dict[key] !== undefined` to `true`
|
|
355
|
-
// when value type is non-nullable, and preserves delete/lookup behavior.
|
|
356
|
-
if (isUndefinedLiteral &&
|
|
357
|
-
nonNullishExpr.kind === "memberAccess" &&
|
|
358
|
-
nonNullishExpr.isComputed &&
|
|
359
|
-
typeof nonNullishExpr.property !== "string" &&
|
|
360
|
-
(nonNullishExpr.accessKind === "dictionary" ||
|
|
361
|
-
nonNullishExpr.object.inferredType?.kind === "dictionaryType")) {
|
|
362
|
-
const nonNullishContext = { ...context, narrowedBindings: undefined };
|
|
363
|
-
const [dictFrag, dictContext] = emitExpression(nonNullishExpr.object, nonNullishContext);
|
|
364
|
-
const [keyFrag, keyContext] = emitExpression(nonNullishExpr.property, dictContext);
|
|
365
|
-
const containsExpr = `(${dictFrag.text}).ContainsKey(${keyFrag.text})`;
|
|
366
|
-
const text = op === "==" ? `!${containsExpr}` : containsExpr;
|
|
367
|
-
return [{ text, precedence: getPrecedence(expr.operator) }, keyContext];
|
|
368
|
-
}
|
|
369
|
-
const nonNullishContext = { ...context, narrowedBindings: undefined };
|
|
370
|
-
const [nonNullishFrag, resultContext] = emitExpression(nonNullishExpr, nonNullishContext);
|
|
371
|
-
const inferred = nonNullishExpr.inferredType;
|
|
372
|
-
const base = inferred ? stripNullish(inferred) : undefined;
|
|
373
|
-
const bareTypeParamName = (() => {
|
|
374
|
-
if (!base)
|
|
375
|
-
return undefined;
|
|
376
|
-
if (base.kind === "typeParameterType")
|
|
377
|
-
return base.name;
|
|
378
|
-
if (base.kind === "referenceType" &&
|
|
379
|
-
(resultContext.typeParameters?.has(base.name) ?? false) &&
|
|
380
|
-
(!base.typeArguments || base.typeArguments.length === 0)) {
|
|
381
|
-
return base.name;
|
|
382
|
-
}
|
|
383
|
-
return undefined;
|
|
384
|
-
})();
|
|
385
|
-
const isDefiniteNonUnionValueType = inferred !== undefined &&
|
|
386
|
-
inferred.kind !== "unionType" &&
|
|
387
|
-
isDefinitelyValueType(inferred);
|
|
388
|
-
const typeParamConstraint = bareTypeParamName !== undefined
|
|
389
|
-
? (resultContext.typeParamConstraints?.get(bareTypeParamName) ??
|
|
390
|
-
"unconstrained")
|
|
391
|
-
: undefined;
|
|
392
|
-
const needsObjectCastForTypeParam = bareTypeParamName !== undefined &&
|
|
393
|
-
(typeParamConstraint === "unconstrained" ||
|
|
394
|
-
typeParamConstraint === "struct");
|
|
395
|
-
const needsObjectCastForValueType = isDefiniteNonUnionValueType;
|
|
396
|
-
const nullOp = op === "==" ? "== null" : "!= null";
|
|
397
|
-
const nullOperandText = (() => {
|
|
398
|
-
switch (nonNullishExpr.kind) {
|
|
399
|
-
case "identifier":
|
|
400
|
-
case "memberAccess":
|
|
401
|
-
case "call":
|
|
402
|
-
case "new":
|
|
403
|
-
case "this":
|
|
404
|
-
case "literal":
|
|
405
|
-
return nonNullishFrag.text;
|
|
406
|
-
default:
|
|
407
|
-
return `(${nonNullishFrag.text})`;
|
|
408
|
-
}
|
|
409
|
-
})();
|
|
410
|
-
const text = needsObjectCastForTypeParam || needsObjectCastForValueType
|
|
411
|
-
? `((global::System.Object)(${nonNullishFrag.text})) ${nullOp}`
|
|
412
|
-
: `${nullOperandText} ${nullOp}`;
|
|
413
|
-
return [{ text, precedence: getPrecedence(expr.operator) }, resultContext];
|
|
414
|
-
}
|
|
415
|
-
// Standard emission path
|
|
416
|
-
// Emit operands without contextual type propagation
|
|
417
|
-
// Literals will emit using their raw lexeme (42 vs 42.0)
|
|
418
|
-
const [leftFrag, leftContext] = emitExpression(expr.left, context);
|
|
419
|
-
const [rightFrag, rightContext] = emitExpression(expr.right, leftContext);
|
|
420
|
-
// Wrap child expressions in parentheses if their precedence is lower than parent
|
|
421
|
-
// This preserves grouping: (x + y) * z should not become x + y * z
|
|
422
|
-
const leftText = leftFrag.precedence !== undefined && leftFrag.precedence < parentPrecedence
|
|
423
|
-
? `(${leftFrag.text})`
|
|
424
|
-
: leftFrag.text;
|
|
425
|
-
// For right operand, also wrap if precedence is equal (right-to-left associativity issue)
|
|
426
|
-
// Example: a - (b - c) should not become a - b - c
|
|
427
|
-
const rightText = rightFrag.precedence !== undefined &&
|
|
428
|
-
rightFrag.precedence <= parentPrecedence
|
|
429
|
-
? `(${rightFrag.text})`
|
|
430
|
-
: rightFrag.text;
|
|
431
|
-
const text = `${leftText} ${op} ${rightText}`;
|
|
432
|
-
return [{ text, precedence: getPrecedence(expr.operator) }, rightContext];
|
|
433
|
-
};
|
|
434
|
-
/**
|
|
435
|
-
* Check if an IR type is boolean
|
|
436
|
-
*/
|
|
437
|
-
const isBooleanType = (type) => {
|
|
438
|
-
if (!type)
|
|
439
|
-
return false;
|
|
440
|
-
return type.kind === "primitiveType" && type.name === "boolean";
|
|
441
|
-
};
|
|
442
|
-
/**
|
|
443
|
-
* Emit a logical operator expression (&&, ||, ??)
|
|
444
|
-
*
|
|
445
|
-
* In TypeScript, || is used both for:
|
|
446
|
-
* 1. Boolean OR (when operands are booleans)
|
|
447
|
-
* 2. Nullish coalescing fallback (when left operand is nullable)
|
|
448
|
-
*
|
|
449
|
-
* In C#:
|
|
450
|
-
* - || only works with booleans
|
|
451
|
-
* - ?? is used for nullish coalescing
|
|
452
|
-
*
|
|
453
|
-
* We check if || is used with non-boolean operands and emit ?? instead.
|
|
454
|
-
*/
|
|
455
|
-
export const emitLogical = (expr, context) => {
|
|
456
|
-
const [leftFrag, leftContext] = emitExpression(expr.left, context);
|
|
457
|
-
// If || is used with non-boolean left operand, use ?? instead for nullish coalescing
|
|
458
|
-
const operator = expr.operator === "||" && !isBooleanType(expr.left.inferredType)
|
|
459
|
-
? "??"
|
|
460
|
-
: expr.operator;
|
|
461
|
-
const parentPrecedence = getPrecedence(operator);
|
|
462
|
-
// If the left operand is a non-nullable value type, `??` is invalid in C# and the
|
|
463
|
-
// fallback is unreachable. Emit only the left operand.
|
|
464
|
-
if (operator === "??" &&
|
|
465
|
-
expr.left.inferredType &&
|
|
466
|
-
expr.left.inferredType.kind !== "unionType" &&
|
|
467
|
-
isDefinitelyValueType(expr.left.inferredType) &&
|
|
468
|
-
// Conditional access (`?.` / `?[`) produces nullable value types in C# even when the
|
|
469
|
-
// underlying member type is non-nullable (e.g., `string?.Length` → `int?`).
|
|
470
|
-
// In that case the fallback is still meaningful and must be preserved.
|
|
471
|
-
!leftFrag.text.includes("?.") &&
|
|
472
|
-
!leftFrag.text.includes("?[")) {
|
|
473
|
-
return [leftFrag, leftContext];
|
|
474
|
-
}
|
|
475
|
-
const [rightFrag, rightContext] = emitExpression(expr.right, leftContext);
|
|
476
|
-
const leftText = leftFrag.precedence !== undefined && leftFrag.precedence < parentPrecedence
|
|
477
|
-
? `(${leftFrag.text})`
|
|
478
|
-
: leftFrag.text;
|
|
479
|
-
const rightText = rightFrag.precedence !== undefined &&
|
|
480
|
-
rightFrag.precedence <= parentPrecedence
|
|
481
|
-
? `(${rightFrag.text})`
|
|
482
|
-
: rightFrag.text;
|
|
483
|
-
const text = `${leftText} ${operator} ${rightText}`;
|
|
484
|
-
return [{ text, precedence: getPrecedence(operator) }, rightContext];
|
|
485
|
-
};
|
|
486
|
-
/**
|
|
487
|
-
* Emit a unary operator expression (-, +, !, ~, typeof, void, delete)
|
|
488
|
-
*
|
|
489
|
-
* NEW NUMERIC SPEC: No contextual type propagation for numeric literals.
|
|
490
|
-
* Explicit casts come from IrCastExpression nodes.
|
|
491
|
-
*
|
|
492
|
-
* @param expr - The unary expression
|
|
493
|
-
* @param context - Emitter context
|
|
494
|
-
* @param _expectedType - Unused under new spec (kept for API compatibility)
|
|
495
|
-
*/
|
|
496
|
-
export const emitUnary = (expr, context, expectedType) => {
|
|
497
|
-
// In TypeScript, `!x` applies JS ToBoolean semantics to *any* operand.
|
|
498
|
-
// In C#, `!` only works on booleans, so we must coerce to a boolean condition.
|
|
499
|
-
if (expr.operator === "!") {
|
|
500
|
-
const [condText, condCtx] = emitBooleanCondition(expr.expression, (e, ctx) => emitExpression(e, ctx), context);
|
|
501
|
-
const text = `!(${condText})`;
|
|
502
|
-
return [{ text, precedence: 15 }, condCtx];
|
|
503
|
-
}
|
|
504
|
-
if (expr.operator === "delete") {
|
|
505
|
-
// JavaScript `delete obj[key]` maps to dictionary key removal in CLR:
|
|
506
|
-
// delete dict[key] -> dict.Remove(key)
|
|
507
|
-
// For unsupported targets we keep the existing no-op emission for now.
|
|
508
|
-
const target = expr.expression;
|
|
509
|
-
if (target.kind === "memberAccess" &&
|
|
510
|
-
target.isComputed &&
|
|
511
|
-
typeof target.property !== "string" &&
|
|
512
|
-
(target.accessKind === "dictionary" ||
|
|
513
|
-
target.object.inferredType?.kind === "dictionaryType")) {
|
|
514
|
-
const [objectFrag, objectContext] = emitExpression(target.object, context);
|
|
515
|
-
const [keyFrag, keyContext] = emitExpression(target.property, objectContext);
|
|
516
|
-
const text = `${objectFrag.text}.Remove(${keyFrag.text})`;
|
|
517
|
-
return [{ text }, keyContext];
|
|
518
|
-
}
|
|
519
|
-
const [targetFrag, newContext] = emitExpression(target, context);
|
|
520
|
-
const text = `/* delete ${targetFrag.text} */`;
|
|
521
|
-
return [{ text }, newContext];
|
|
522
|
-
}
|
|
523
|
-
const [operandFrag, newContext] = emitExpression(expr.expression, context);
|
|
524
|
-
if (expr.operator === "typeof") {
|
|
525
|
-
// typeof becomes global::Tsonic.Runtime.Operators.typeof()
|
|
526
|
-
const text = `global::Tsonic.Runtime.Operators.@typeof(${operandFrag.text})`;
|
|
527
|
-
return [{ text }, newContext];
|
|
528
|
-
}
|
|
529
|
-
if (expr.operator === "void") {
|
|
530
|
-
// `void expr` evaluates `expr` and yields `undefined`.
|
|
531
|
-
//
|
|
532
|
-
// In expression position we must produce a value, so use an IIFE:
|
|
533
|
-
// (() => { <eval expr>; return default(<T>); })()
|
|
534
|
-
//
|
|
535
|
-
// In statement position, emitExpressionStatement handles this separately
|
|
536
|
-
// (so we don't pay this cost for the common `void x;` marker).
|
|
537
|
-
const operand = expr.expression;
|
|
538
|
-
// If the operand is a literal null/undefined, evaluation is a no-op and can be skipped.
|
|
539
|
-
// This avoids generating invalid discard assignments like `_ = default;`.
|
|
540
|
-
const isNoopOperand = (operand.kind === "literal" &&
|
|
541
|
-
(operand.value === undefined || operand.value === null)) ||
|
|
542
|
-
(operand.kind === "identifier" &&
|
|
543
|
-
(operand.name === "undefined" || operand.name === "null"));
|
|
544
|
-
let currentContext = newContext;
|
|
545
|
-
const effectiveExpectedType = expectedType &&
|
|
546
|
-
expectedType.kind !== "voidType" &&
|
|
547
|
-
expectedType.kind !== "neverType"
|
|
548
|
-
? expectedType
|
|
549
|
-
: undefined;
|
|
550
|
-
let returnTypeText = "object?";
|
|
551
|
-
let defaultText = "default";
|
|
552
|
-
if (effectiveExpectedType) {
|
|
553
|
-
try {
|
|
554
|
-
const [typeText, next] = emitType(effectiveExpectedType, currentContext);
|
|
555
|
-
currentContext = next;
|
|
556
|
-
returnTypeText = typeText;
|
|
557
|
-
defaultText = `default(${typeText})`;
|
|
558
|
-
}
|
|
559
|
-
catch {
|
|
560
|
-
// Fall back to object? + default literal.
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
const operandStatement = (() => {
|
|
564
|
-
if (isNoopOperand)
|
|
565
|
-
return "";
|
|
566
|
-
// If the operand is already a valid statement-expression (call/new/assignment/
|
|
567
|
-
// update/await), emit it directly. Otherwise, use a discard assignment.
|
|
568
|
-
if (operand.kind === "call" ||
|
|
569
|
-
operand.kind === "new" ||
|
|
570
|
-
operand.kind === "assignment" ||
|
|
571
|
-
operand.kind === "update" ||
|
|
572
|
-
operand.kind === "await") {
|
|
573
|
-
return `${operandFrag.text}; `;
|
|
574
|
-
}
|
|
575
|
-
return `_ = ${operandFrag.text}; `;
|
|
576
|
-
})();
|
|
577
|
-
if (operand.kind === "await") {
|
|
578
|
-
if (!currentContext.isAsync) {
|
|
579
|
-
throw new Error("ICE: `void await <expr>` reached emitter in a non-async context.");
|
|
580
|
-
}
|
|
581
|
-
const taskReturnType = `global::System.Threading.Tasks.Task<${returnTypeText}>`;
|
|
582
|
-
const text = `await ((global::System.Func<${taskReturnType}>)(async () => { ${operandStatement}return ${defaultText}; }))()`;
|
|
583
|
-
return [{ text }, currentContext];
|
|
584
|
-
}
|
|
585
|
-
const text = `((global::System.Func<${returnTypeText}>)(() => { ${operandStatement}return ${defaultText}; }))()`;
|
|
586
|
-
return [{ text }, currentContext];
|
|
587
|
-
}
|
|
588
|
-
const text = `${expr.operator}${operandFrag.text}`;
|
|
589
|
-
return [{ text, precedence: 15 }, newContext];
|
|
590
|
-
};
|
|
591
|
-
/**
|
|
592
|
-
* Emit an update operator expression (++, --)
|
|
593
|
-
*/
|
|
594
|
-
export const emitUpdate = (expr, context) => {
|
|
595
|
-
// Narrowing maps (instanceof / nullable / union) apply to *reads*, not writes.
|
|
596
|
-
// For update operators, the operand is written, so we must not rewrite the target
|
|
597
|
-
// identifier to a narrowed binding (e.g., C# pattern var).
|
|
598
|
-
const operandCtx = expr.expression.kind === "identifier" &&
|
|
599
|
-
context.narrowedBindings?.has(expr.expression.name)
|
|
600
|
-
? (() => {
|
|
601
|
-
const next = new Map(context.narrowedBindings);
|
|
602
|
-
next.delete(expr.expression.name);
|
|
603
|
-
return { ...context, narrowedBindings: next };
|
|
604
|
-
})()
|
|
605
|
-
: context;
|
|
606
|
-
const [operandFrag, ctx] = emitExpression(expr.expression, operandCtx);
|
|
607
|
-
const newContext = operandCtx !== context
|
|
608
|
-
? { ...ctx, narrowedBindings: context.narrowedBindings }
|
|
609
|
-
: ctx;
|
|
610
|
-
const text = expr.prefix
|
|
611
|
-
? `${expr.operator}${operandFrag.text}`
|
|
612
|
-
: `${operandFrag.text}${expr.operator}`;
|
|
613
|
-
return [{ text, precedence: 15 }, newContext];
|
|
614
|
-
};
|
|
615
|
-
/**
|
|
616
|
-
* Emit an assignment expression (=, +=, -=, etc.)
|
|
617
|
-
*
|
|
618
|
-
* Passes the LHS type as expected type to RHS, enabling proper integer
|
|
619
|
-
* literal emission for cases like `this.value = this.value + 1`.
|
|
620
|
-
*/
|
|
621
|
-
export const emitAssignment = (expr, context) => {
|
|
622
|
-
// Array element assignment uses native CLR indexer
|
|
623
|
-
// HARD GATE: Index must be proven Int32 (validated by proof pass)
|
|
624
|
-
if (expr.operator === "=" &&
|
|
625
|
-
"kind" in expr.left &&
|
|
626
|
-
expr.left.kind === "memberAccess" &&
|
|
627
|
-
expr.left.isComputed &&
|
|
628
|
-
expr.left.object.inferredType?.kind === "arrayType") {
|
|
629
|
-
const leftExpr = expr.left;
|
|
630
|
-
const indexExpr = leftExpr.property;
|
|
631
|
-
if (!hasInt32Proof(indexExpr)) {
|
|
632
|
-
// ICE: Unproven index should have been caught by proof pass (TSN5107)
|
|
633
|
-
throw new Error(`Internal Compiler Error: Array index must be proven Int32. ` +
|
|
634
|
-
`This should have been caught by the numeric proof pass (TSN5107).`);
|
|
635
|
-
}
|
|
636
|
-
const [objectFrag, objectContext] = emitExpression(leftExpr.object, context);
|
|
637
|
-
const [indexFrag, indexContext] = emitExpression(indexExpr, objectContext);
|
|
638
|
-
const [rightFrag, rightContext] = emitExpression(expr.right, indexContext);
|
|
639
|
-
// Use native CLR indexer
|
|
640
|
-
const text = `${objectFrag.text}[${indexFrag.text}] = ${rightFrag.text}`;
|
|
641
|
-
return [{ text, precedence: 2 }, rightContext];
|
|
642
|
-
}
|
|
643
|
-
// Left side can be an expression or a pattern (for destructuring)
|
|
644
|
-
const isPattern = "kind" in expr.left &&
|
|
645
|
-
(expr.left.kind === "identifierPattern" ||
|
|
646
|
-
expr.left.kind === "arrayPattern" ||
|
|
647
|
-
expr.left.kind === "objectPattern");
|
|
648
|
-
// Handle destructuring assignment patterns
|
|
649
|
-
if (isPattern && expr.operator === "=") {
|
|
650
|
-
const pattern = expr.left;
|
|
651
|
-
// Emit the RHS first
|
|
652
|
-
const [rightFrag, rightContext] = emitExpression(expr.right, context);
|
|
653
|
-
// Use lowerAssignmentPattern to generate the destructuring expression
|
|
654
|
-
const result = lowerAssignmentPattern(pattern, rightFrag.text, expr.right.inferredType, rightContext);
|
|
655
|
-
return [{ text: result.expression, precedence: 2 }, result.context];
|
|
656
|
-
}
|
|
657
|
-
// Standard assignment (expression on left side)
|
|
658
|
-
let leftText;
|
|
659
|
-
let leftContext;
|
|
660
|
-
let leftType;
|
|
661
|
-
if (isPattern) {
|
|
662
|
-
// Identifier pattern with compound assignment (+=, etc.)
|
|
663
|
-
const pattern = expr.left;
|
|
664
|
-
if (pattern.kind === "identifierPattern") {
|
|
665
|
-
leftText = emitRemappedLocalName(pattern.name, context);
|
|
666
|
-
leftContext = context;
|
|
667
|
-
leftType = pattern.type;
|
|
668
|
-
}
|
|
669
|
-
else {
|
|
670
|
-
// Compound assignment to array/object pattern - not valid in JS
|
|
671
|
-
leftText = "/* invalid compound destructuring */";
|
|
672
|
-
leftContext = context;
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
else {
|
|
676
|
-
const leftExpr = expr.left;
|
|
677
|
-
// Narrowing maps (instanceof / nullable / union) apply to *reads*, not writes.
|
|
678
|
-
// For assignment, the LHS is written, so we must not rewrite identifier targets
|
|
679
|
-
// to narrowed bindings (e.g., C# pattern vars).
|
|
680
|
-
const leftCtx = leftExpr.kind === "identifier" &&
|
|
681
|
-
context.narrowedBindings?.has(leftExpr.name)
|
|
682
|
-
? (() => {
|
|
683
|
-
const next = new Map(context.narrowedBindings);
|
|
684
|
-
next.delete(leftExpr.name);
|
|
685
|
-
return { ...context, narrowedBindings: next };
|
|
686
|
-
})()
|
|
687
|
-
: context;
|
|
688
|
-
const [leftFrag, ctx] = emitExpression(leftExpr, leftCtx);
|
|
689
|
-
leftText = leftFrag.text;
|
|
690
|
-
// Restore narrowing for RHS emission (reads) when we suppressed it for the LHS.
|
|
691
|
-
leftContext =
|
|
692
|
-
leftCtx !== context
|
|
693
|
-
? { ...ctx, narrowedBindings: context.narrowedBindings }
|
|
694
|
-
: ctx;
|
|
695
|
-
leftType = leftExpr.inferredType;
|
|
696
|
-
}
|
|
697
|
-
// Pass LHS type as expected type to RHS for proper integer handling
|
|
698
|
-
const [rightFrag, rightContext] = emitExpression(expr.right, leftContext, leftType);
|
|
699
|
-
const text = `${leftText} ${expr.operator} ${rightFrag.text}`;
|
|
700
|
-
return [{ text, precedence: 2 }, rightContext];
|
|
701
|
-
};
|
|
702
|
-
const resolveLocalTypesForReference = (type, context) => {
|
|
703
|
-
const lookupName = type.name.includes(".")
|
|
704
|
-
? (type.name.split(".").pop() ?? type.name)
|
|
705
|
-
: type.name;
|
|
706
|
-
if (context.localTypes?.has(lookupName)) {
|
|
707
|
-
return context.localTypes;
|
|
708
|
-
}
|
|
709
|
-
const moduleMap = context.options.moduleMap;
|
|
710
|
-
if (!moduleMap)
|
|
711
|
-
return undefined;
|
|
712
|
-
const matches = [];
|
|
713
|
-
for (const m of moduleMap.values()) {
|
|
714
|
-
if (!m.localTypes)
|
|
715
|
-
continue;
|
|
716
|
-
if (m.localTypes.has(lookupName)) {
|
|
717
|
-
matches.push({ namespace: m.namespace, localTypes: m.localTypes });
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
if (matches.length === 0)
|
|
721
|
-
return undefined;
|
|
722
|
-
if (matches.length === 1)
|
|
723
|
-
return matches[0].localTypes;
|
|
724
|
-
const fqn = type.resolvedClrType ?? (type.name.includes(".") ? type.name : undefined);
|
|
725
|
-
if (fqn && fqn.includes(".")) {
|
|
726
|
-
const ns = fqn.slice(0, fqn.lastIndexOf("."));
|
|
727
|
-
const filtered = matches.filter((m) => m.namespace === ns);
|
|
728
|
-
if (filtered.length === 1)
|
|
729
|
-
return filtered[0].localTypes;
|
|
730
|
-
}
|
|
731
|
-
return undefined;
|
|
732
|
-
};
|
|
733
|
-
const tryGetLiteralSet = (type, context) => {
|
|
734
|
-
const resolved = resolveTypeAlias(type, context);
|
|
735
|
-
if (resolved.kind === "literalType") {
|
|
736
|
-
return new Set([resolved.value]);
|
|
737
|
-
}
|
|
738
|
-
if (resolved.kind === "unionType") {
|
|
739
|
-
const out = new Set();
|
|
740
|
-
for (const t of resolved.types) {
|
|
741
|
-
const r = resolveTypeAlias(t, context);
|
|
742
|
-
if (r.kind !== "literalType")
|
|
743
|
-
return undefined;
|
|
744
|
-
out.add(r.value);
|
|
745
|
-
}
|
|
746
|
-
return out;
|
|
747
|
-
}
|
|
748
|
-
return undefined;
|
|
749
|
-
};
|
|
750
|
-
const tryResolveTernaryGuard = (condition, context) => {
|
|
751
|
-
// Check for direct call: isUser(x)
|
|
752
|
-
const resolveFromCall = (call) => {
|
|
753
|
-
const narrowing = call.narrowing;
|
|
754
|
-
if (!narrowing || narrowing.kind !== "typePredicate")
|
|
755
|
-
return undefined;
|
|
756
|
-
const arg = call.arguments[narrowing.argIndex];
|
|
757
|
-
if (!arg ||
|
|
758
|
-
("kind" in arg && arg.kind === "spread") ||
|
|
759
|
-
arg.kind !== "identifier") {
|
|
760
|
-
return undefined;
|
|
761
|
-
}
|
|
762
|
-
const originalName = arg.name;
|
|
763
|
-
const unionSourceType = arg.inferredType;
|
|
764
|
-
if (!unionSourceType)
|
|
765
|
-
return undefined;
|
|
766
|
-
const resolved = resolveTypeAlias(stripNullish(unionSourceType), context);
|
|
767
|
-
if (resolved.kind !== "unionType")
|
|
768
|
-
return undefined;
|
|
769
|
-
const idx = findUnionMemberIndex(resolved, narrowing.targetType, context);
|
|
770
|
-
if (idx === undefined)
|
|
771
|
-
return undefined;
|
|
772
|
-
return {
|
|
773
|
-
originalName,
|
|
774
|
-
memberN: idx + 1,
|
|
775
|
-
escapedOrig: emitRemappedLocalName(originalName, context),
|
|
776
|
-
polarity: "positive",
|
|
777
|
-
};
|
|
778
|
-
};
|
|
779
|
-
// Direct call: isUser(x) -> narrow whenTrue
|
|
780
|
-
if (condition.kind === "call") {
|
|
781
|
-
return resolveFromCall(condition);
|
|
782
|
-
}
|
|
783
|
-
// Discriminant literal equality: x.kind === "circle"
|
|
784
|
-
const resolveFromDiscriminantEquality = (expr) => {
|
|
785
|
-
// Normalize `!(x.prop === lit)` to `x.prop !== lit` (and vice versa) by flipping polarity.
|
|
786
|
-
if (expr.kind === "unary" && expr.operator === "!") {
|
|
787
|
-
const inner = resolveFromDiscriminantEquality(expr.expression);
|
|
788
|
-
if (!inner)
|
|
789
|
-
return undefined;
|
|
790
|
-
return {
|
|
791
|
-
...inner,
|
|
792
|
-
polarity: inner.polarity === "positive" ? "negative" : "positive",
|
|
793
|
-
};
|
|
794
|
-
}
|
|
795
|
-
if (expr.kind !== "binary")
|
|
796
|
-
return undefined;
|
|
797
|
-
if (expr.operator !== "===" &&
|
|
798
|
-
expr.operator !== "!==" &&
|
|
799
|
-
expr.operator !== "==" &&
|
|
800
|
-
expr.operator !== "!=") {
|
|
801
|
-
return undefined;
|
|
802
|
-
}
|
|
803
|
-
const extract = (left, right) => {
|
|
804
|
-
if (left.kind !== "memberAccess")
|
|
805
|
-
return undefined;
|
|
806
|
-
if (left.isOptional)
|
|
807
|
-
return undefined;
|
|
808
|
-
if (left.isComputed)
|
|
809
|
-
return undefined;
|
|
810
|
-
if (left.object.kind !== "identifier")
|
|
811
|
-
return undefined;
|
|
812
|
-
if (typeof left.property !== "string")
|
|
813
|
-
return undefined;
|
|
814
|
-
if (right.kind !== "literal")
|
|
815
|
-
return undefined;
|
|
816
|
-
if (typeof right.value !== "string" &&
|
|
817
|
-
typeof right.value !== "number" &&
|
|
818
|
-
typeof right.value !== "boolean") {
|
|
819
|
-
return undefined;
|
|
820
|
-
}
|
|
821
|
-
return {
|
|
822
|
-
receiver: left.object,
|
|
823
|
-
propertyName: left.property,
|
|
824
|
-
literal: right.value,
|
|
825
|
-
};
|
|
826
|
-
};
|
|
827
|
-
const direct = extract(expr.left, expr.right);
|
|
828
|
-
const swapped = direct ? undefined : extract(expr.right, expr.left);
|
|
829
|
-
const match = direct ?? swapped;
|
|
830
|
-
if (!match)
|
|
831
|
-
return undefined;
|
|
832
|
-
const { receiver, propertyName, literal } = match;
|
|
833
|
-
const originalName = receiver.name;
|
|
834
|
-
if (context.narrowedBindings?.has(originalName))
|
|
835
|
-
return undefined;
|
|
836
|
-
const unionSourceType = receiver.inferredType;
|
|
837
|
-
if (!unionSourceType)
|
|
838
|
-
return undefined;
|
|
839
|
-
const resolved = resolveTypeAlias(stripNullish(unionSourceType), context);
|
|
840
|
-
if (resolved.kind !== "unionType")
|
|
841
|
-
return undefined;
|
|
842
|
-
const unionArity = resolved.types.length;
|
|
843
|
-
if (unionArity < 2 || unionArity > 8)
|
|
844
|
-
return undefined;
|
|
845
|
-
const matchingMembers = [];
|
|
846
|
-
for (let i = 0; i < resolved.types.length; i++) {
|
|
847
|
-
const member = resolved.types[i];
|
|
848
|
-
if (!member)
|
|
849
|
-
continue;
|
|
850
|
-
let propType;
|
|
851
|
-
if (member.kind === "objectType") {
|
|
852
|
-
const prop = member.members.find((m) => m.kind === "propertySignature" && m.name === propertyName);
|
|
853
|
-
propType = prop?.type;
|
|
854
|
-
}
|
|
855
|
-
else if (member.kind === "referenceType") {
|
|
856
|
-
const localTypes = resolveLocalTypesForReference(member, context);
|
|
857
|
-
if (!localTypes)
|
|
858
|
-
continue;
|
|
859
|
-
const lookupName = member.name.includes(".")
|
|
860
|
-
? (member.name.split(".").pop() ?? member.name)
|
|
861
|
-
: member.name;
|
|
862
|
-
propType = getPropertyType({ ...member, name: lookupName }, propertyName, { ...context, localTypes });
|
|
863
|
-
}
|
|
864
|
-
else {
|
|
865
|
-
continue;
|
|
866
|
-
}
|
|
867
|
-
if (!propType)
|
|
868
|
-
continue;
|
|
869
|
-
const literals = tryGetLiteralSet(propType, context);
|
|
870
|
-
if (!literals)
|
|
871
|
-
continue;
|
|
872
|
-
if (literals.has(literal)) {
|
|
873
|
-
matchingMembers.push(i + 1);
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
if (matchingMembers.length !== 1)
|
|
877
|
-
return undefined;
|
|
878
|
-
const memberN = matchingMembers[0];
|
|
879
|
-
if (!memberN)
|
|
880
|
-
return undefined;
|
|
881
|
-
const isInequality = expr.operator === "!==" || expr.operator === "!=";
|
|
882
|
-
return {
|
|
883
|
-
originalName,
|
|
884
|
-
memberN,
|
|
885
|
-
escapedOrig: emitRemappedLocalName(originalName, context),
|
|
886
|
-
polarity: isInequality ? "negative" : "positive",
|
|
887
|
-
};
|
|
888
|
-
};
|
|
889
|
-
const discr = resolveFromDiscriminantEquality(condition);
|
|
890
|
-
if (discr)
|
|
891
|
-
return discr;
|
|
892
|
-
// Negated call: !isUser(x) -> narrow whenFalse
|
|
893
|
-
if (condition.kind === "unary" &&
|
|
894
|
-
condition.operator === "!" &&
|
|
895
|
-
condition.expression.kind === "call") {
|
|
896
|
-
const guard = resolveFromCall(condition.expression);
|
|
897
|
-
if (guard) {
|
|
898
|
-
return { ...guard, polarity: "negative" };
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
return undefined;
|
|
902
|
-
};
|
|
903
|
-
/**
|
|
904
|
-
* Emit a conditional (ternary) expression
|
|
905
|
-
*
|
|
906
|
-
* Supports type predicate narrowing:
|
|
907
|
-
* - `isUser(x) ? x.name : "anon"` → `x.Is1() ? (x.As1()).name : "anon"`
|
|
908
|
-
* - `!isUser(x) ? "anon" : x.name` → `!x.Is1() ? "anon" : (x.As1()).name`
|
|
909
|
-
*
|
|
910
|
-
* @param expr - The conditional expression
|
|
911
|
-
* @param context - Emitter context
|
|
912
|
-
* @param expectedType - Optional expected type (for null → default in generic contexts)
|
|
913
|
-
*/
|
|
914
|
-
export const emitConditional = (expr, context, expectedType) => {
|
|
915
|
-
// When no contextual expectedType is provided (e.g., `var x = cond ? a : b`),
|
|
916
|
-
// use the conditional expression's own inferred type to guide null/undefined → default
|
|
917
|
-
// conversions and keep C# type inference consistent with TS.
|
|
918
|
-
const branchExpectedType = expectedType ?? expr.inferredType;
|
|
919
|
-
// Try to detect type predicate guard in condition
|
|
920
|
-
const guard = tryResolveTernaryGuard(expr.condition, context);
|
|
921
|
-
if (guard) {
|
|
922
|
-
const { originalName, memberN, escapedOrig, polarity } = guard;
|
|
923
|
-
// Build condition text
|
|
924
|
-
const condText = polarity === "positive"
|
|
925
|
-
? `${escapedOrig}.Is${memberN}()`
|
|
926
|
-
: `!${escapedOrig}.Is${memberN}()`;
|
|
927
|
-
// Create inline narrowing binding: x -> (x.AsN())
|
|
928
|
-
const inlineExpr = `(${escapedOrig}.As${memberN}())`;
|
|
929
|
-
const narrowedMap = new Map(context.narrowedBindings ?? []);
|
|
930
|
-
narrowedMap.set(originalName, { kind: "expr", exprText: inlineExpr });
|
|
931
|
-
const narrowedContext = {
|
|
932
|
-
...context,
|
|
933
|
-
narrowedBindings: narrowedMap,
|
|
934
|
-
};
|
|
935
|
-
// Apply narrowing to the appropriate branch
|
|
936
|
-
const [trueFrag, trueContext] = polarity === "positive"
|
|
937
|
-
? emitExpression(expr.whenTrue, narrowedContext, branchExpectedType)
|
|
938
|
-
: emitExpression(expr.whenTrue, context, branchExpectedType);
|
|
939
|
-
const [falseFrag, falseContext] = polarity === "negative"
|
|
940
|
-
? emitExpression(expr.whenFalse, narrowedContext, branchExpectedType)
|
|
941
|
-
: emitExpression(expr.whenFalse, trueContext, branchExpectedType);
|
|
942
|
-
const text = `${condText} ? ${trueFrag.text} : ${falseFrag.text}`;
|
|
943
|
-
// Return context WITHOUT narrowing (don't leak)
|
|
944
|
-
const finalContext = {
|
|
945
|
-
...falseContext,
|
|
946
|
-
narrowedBindings: context.narrowedBindings,
|
|
947
|
-
};
|
|
948
|
-
return [{ text, precedence: 3 }, finalContext];
|
|
949
|
-
}
|
|
950
|
-
// Standard ternary emission (no narrowing)
|
|
951
|
-
const [condText, condContext] = emitBooleanCondition(expr.condition, (e, ctx) => emitExpression(e, ctx), context);
|
|
952
|
-
// Pass expectedType (or inferred type) to both branches for null/undefined → default conversion
|
|
953
|
-
const [trueFrag, trueContext] = emitExpression(expr.whenTrue, condContext, branchExpectedType);
|
|
954
|
-
const [falseFrag, falseContext] = emitExpression(expr.whenFalse, trueContext, branchExpectedType);
|
|
955
|
-
const text = `${condText} ? ${trueFrag.text} : ${falseFrag.text}`;
|
|
956
|
-
return [{ text, precedence: 3 }, falseContext];
|
|
957
|
-
};
|
|
9
|
+
export { emitBinary } from "./operators/binary-emitter.js";
|
|
10
|
+
export { emitLogical } from "./operators/logical-emitter.js";
|
|
11
|
+
export { emitUnary, emitUpdate } from "./operators/unary-emitter.js";
|
|
12
|
+
export { emitAssignment } from "./operators/assignment-emitter.js";
|
|
13
|
+
export { emitConditional } from "./operators/conditional-emitter.js";
|
|
958
14
|
//# sourceMappingURL=operators.js.map
|