xbintsc 0.5.23 → 0.5.32
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/AGENTS.md +11 -2
- package/README.md +47 -16
- package/README.zh-CN.md +21 -2
- package/dist/scripts/support-matrix.d.ts +18 -0
- package/dist/scripts/support-matrix.js +141 -0
- package/dist/scripts/support-matrix.js.map +1 -0
- package/dist/src/ast/common.d.ts +2 -2
- package/dist/src/ast/declarations.d.ts +7 -1
- package/dist/src/ast/expressions.d.ts +5 -0
- package/dist/src/ast/kinds.d.ts +2 -0
- package/dist/src/ast/kinds.js +2 -0
- package/dist/src/ast/kinds.js.map +1 -1
- package/dist/src/binder/binder.d.ts +2 -1
- package/dist/src/binder/binder.js +2 -0
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/binder/declarations.d.ts +9 -0
- package/dist/src/binder/declarations.js +64 -0
- package/dist/src/binder/declarations.js.map +1 -1
- package/dist/src/binder/references.js +99 -4
- package/dist/src/binder/references.js.map +1 -1
- package/dist/src/binder/types.d.ts +32 -0
- package/dist/src/binder/types.js.map +1 -1
- package/dist/src/canonical.d.ts +29 -0
- package/dist/src/canonical.js +35 -0
- package/dist/src/canonical.js.map +1 -0
- package/dist/src/checker/assignability.d.ts +13 -0
- package/dist/src/checker/assignability.js +146 -0
- package/dist/src/checker/assignability.js.map +1 -0
- package/dist/src/checker/calls.d.ts +13 -0
- package/dist/src/checker/calls.js +127 -0
- package/dist/src/checker/calls.js.map +1 -0
- package/dist/src/checker/checker.d.ts +26 -0
- package/dist/src/checker/checker.js +31 -0
- package/dist/src/checker/checker.js.map +1 -0
- package/dist/src/checker/declarations.d.ts +9 -0
- package/dist/src/checker/declarations.js +15 -0
- package/dist/src/checker/declarations.js.map +1 -0
- package/dist/src/checker/flow.d.ts +21 -0
- package/dist/src/checker/flow.js +241 -0
- package/dist/src/checker/flow.js.map +1 -0
- package/dist/src/checker/globals.d.ts +9 -0
- package/dist/src/checker/globals.js +29 -0
- package/dist/src/checker/globals.js.map +1 -0
- package/dist/src/checker/source.d.ts +38 -0
- package/dist/src/checker/source.js +48 -0
- package/dist/src/checker/source.js.map +1 -0
- package/dist/src/checker/type-infer.d.ts +18 -0
- package/dist/src/checker/type-infer.js +173 -0
- package/dist/src/checker/type-infer.js.map +1 -0
- package/dist/src/checker/type-model.d.ts +73 -0
- package/dist/src/checker/type-model.js +151 -0
- package/dist/src/checker/type-model.js.map +1 -0
- package/dist/src/checker/type-system.d.ts +58 -0
- package/dist/src/checker/type-system.js +569 -0
- package/dist/src/checker/type-system.js.map +1 -0
- package/dist/src/checker/typecheck-types.d.ts +22 -0
- package/dist/src/checker/typecheck-types.js +109 -0
- package/dist/src/checker/typecheck-types.js.map +1 -0
- package/dist/src/checker/typecheck.d.ts +62 -0
- package/dist/src/checker/typecheck.js +574 -0
- package/dist/src/checker/typecheck.js.map +1 -0
- package/dist/src/checker/undefined.d.ts +14 -0
- package/dist/src/checker/undefined.js +32 -0
- package/dist/src/checker/undefined.js.map +1 -0
- package/dist/src/checker/walk.d.ts +10 -0
- package/dist/src/checker/walk.js +15 -0
- package/dist/src/checker/walk.js.map +1 -0
- package/dist/src/cli/help.d.ts +7 -0
- package/dist/src/cli/help.js +64 -0
- package/dist/src/cli/help.js.map +1 -0
- package/dist/src/cli/hints.js +2 -1
- package/dist/src/cli/hints.js.map +1 -1
- package/dist/src/cli/main.js +12 -48
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.js +8 -8
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +9 -4
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/calls/super.d.ts +9 -1
- package/dist/src/codegen/generator/calls/super.js +56 -5
- package/dist/src/codegen/generator/calls/super.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +13 -2
- package/dist/src/codegen/generator/context.js +25 -19
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/debug.js +2 -1
- package/dist/src/codegen/generator/debug.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.d.ts +4 -1
- package/dist/src/codegen/generator/expressions/primary.js +68 -8
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/generator.js +11 -1
- package/dist/src/codegen/generator/generator.js.map +1 -1
- package/dist/src/codegen/generator/module.d.ts +3 -0
- package/dist/src/codegen/generator/module.js +116 -26
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.d.ts +11 -1
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/variables.js +26 -7
- package/dist/src/codegen/generator/statements/variables.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +2 -0
- package/dist/src/codegen/generator/tables.js +4 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/build-key.d.ts +2 -0
- package/dist/src/driver/build-key.js +1 -0
- package/dist/src/driver/build-key.js.map +1 -1
- package/dist/src/driver/bundler/graph.js +5 -1
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +16 -1
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/bundler/types.d.ts +12 -0
- package/dist/src/driver/compiler.d.ts +1 -1
- package/dist/src/driver/compiler.js +3 -0
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/fingerprint.js +2 -1
- package/dist/src/driver/fingerprint.js.map +1 -1
- package/dist/src/driver/frontend.d.ts +8 -6
- package/dist/src/driver/frontend.js +4 -0
- package/dist/src/driver/frontend.js.map +1 -1
- package/dist/src/driver/options.d.ts +6 -0
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/gui/css.d.ts +26 -0
- package/dist/src/extensions/gui/css.js +100 -0
- package/dist/src/extensions/gui/css.js.map +1 -0
- package/dist/src/extensions/gui/html.js +28 -7
- package/dist/src/extensions/gui/html.js.map +1 -1
- package/dist/src/extensions/gui/index.js +79 -2
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/gui/three.d.ts +16 -0
- package/dist/src/extensions/gui/three.js +22 -0
- package/dist/src/extensions/gui/three.js.map +1 -0
- package/dist/src/extensions/media/index.d.ts +6 -5
- package/dist/src/extensions/media/index.js +12 -14
- package/dist/src/extensions/media/index.js.map +1 -1
- package/dist/src/extensions/registry.d.ts +38 -0
- package/dist/src/extensions/registry.js +10 -0
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/declarations/classes.js +7 -0
- package/dist/src/parser/declarations/classes.js.map +1 -1
- package/dist/src/parser/expressions.js +14 -1
- package/dist/src/parser/expressions.js.map +1 -1
- package/dist/src/parser/literals.js +6 -2
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/tests/binder/binder.test.js +29 -0
- package/dist/tests/binder/binder.test.js.map +1 -1
- package/dist/tests/canonical.test.d.ts +1 -0
- package/dist/tests/canonical.test.js +19 -0
- package/dist/tests/canonical.test.js.map +1 -0
- package/dist/tests/checker/checker.test.d.ts +1 -0
- package/dist/tests/checker/checker.test.js +245 -0
- package/dist/tests/checker/checker.test.js.map +1 -0
- package/dist/tests/cli/check.test.js +20 -0
- package/dist/tests/cli/check.test.js.map +1 -1
- package/dist/tests/conformance/matrix.test.d.ts +6 -0
- package/dist/tests/conformance/matrix.test.js +23 -0
- package/dist/tests/conformance/matrix.test.js.map +1 -0
- package/dist/tests/conformance/test262/manifest.d.ts +115 -0
- package/dist/tests/conformance/test262/manifest.js +257 -0
- package/dist/tests/conformance/test262/manifest.js.map +1 -0
- package/dist/tests/conformance/test262.test.d.ts +11 -0
- package/dist/tests/conformance/test262.test.js +74 -0
- package/dist/tests/conformance/test262.test.js.map +1 -0
- package/dist/tests/docs/structure.test.js +9 -11
- package/dist/tests/docs/structure.test.js.map +1 -1
- package/dist/tests/e2e/child-process.test.js +3 -2
- package/dist/tests/e2e/child-process.test.js.map +1 -1
- package/dist/tests/e2e/compile-builtins.test.js +45 -0
- package/dist/tests/e2e/compile-builtins.test.js.map +1 -1
- package/dist/tests/e2e/compile-objects-classes.test.js +77 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/differential-syntax.test.d.ts +5 -0
- package/dist/tests/e2e/differential-syntax.test.js +95 -0
- package/dist/tests/e2e/differential-syntax.test.js.map +1 -0
- package/dist/tests/e2e/differential-values.test.js +15 -0
- package/dist/tests/e2e/differential-values.test.js.map +1 -1
- package/dist/tests/e2e/gui-browser.test.d.ts +13 -0
- package/dist/tests/e2e/gui-browser.test.js +163 -0
- package/dist/tests/e2e/gui-browser.test.js.map +1 -0
- package/dist/tests/e2e/gui-effects.test.d.ts +6 -0
- package/dist/tests/e2e/gui-effects.test.js +262 -0
- package/dist/tests/e2e/gui-effects.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-browser.test.js +2 -2
- package/dist/tests/e2e/gui-example-browser.test.js.map +1 -1
- package/dist/tests/e2e/gui-example-canvas.test.js +5 -4
- package/dist/tests/e2e/gui-example-canvas.test.js.map +1 -1
- package/dist/tests/e2e/gui-example-svg.test.js +4 -3
- package/dist/tests/e2e/gui-example-svg.test.js.map +1 -1
- package/dist/tests/e2e/gui-example-webgl.test.d.ts +10 -0
- package/dist/tests/e2e/gui-example-webgl.test.js +75 -0
- package/dist/tests/e2e/gui-example-webgl.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-webgl2.test.d.ts +8 -0
- package/dist/tests/e2e/gui-example-webgl2.test.js +72 -0
- package/dist/tests/e2e/gui-example-webgl2.test.js.map +1 -0
- package/dist/tests/e2e/gui-example.test.js +4 -3
- package/dist/tests/e2e/gui-example.test.js.map +1 -1
- package/dist/tests/e2e/gui-helpers.js +4 -3
- package/dist/tests/e2e/gui-helpers.js.map +1 -1
- package/dist/tests/e2e/gui-layout.test.js +48 -0
- package/dist/tests/e2e/gui-layout.test.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.js +10 -8
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl.test.d.ts +11 -0
- package/dist/tests/e2e/gui-webgl.test.js +179 -0
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2.test.js +238 -0
- package/dist/tests/e2e/gui-webgl2.test.js.map +1 -0
- package/dist/tests/e2e/harness.d.ts +9 -0
- package/dist/tests/e2e/harness.js +14 -2
- package/dist/tests/e2e/harness.js.map +1 -1
- package/dist/tests/e2e/native-extensions.test.js +2 -1
- package/dist/tests/e2e/native-extensions.test.js.map +1 -1
- package/dist/tests/e2e/property-descriptors.test.js +20 -0
- package/dist/tests/e2e/property-descriptors.test.js.map +1 -1
- package/dist/tests/e2e/unicode-output.test.js +5 -3
- package/dist/tests/e2e/unicode-output.test.js.map +1 -1
- package/dist/tests/e2e/weak-collections.test.js +16 -2
- package/dist/tests/e2e/weak-collections.test.js.map +1 -1
- package/dist/tests/extensions/gui.test.js +41 -0
- package/dist/tests/extensions/gui.test.js.map +1 -1
- package/dist/tests/extensions/media.test.js +7 -3
- package/dist/tests/extensions/media.test.js.map +1 -1
- package/dist/tests/helpers.d.ts +1 -0
- package/dist/tests/helpers.js +1 -0
- package/dist/tests/helpers.js.map +1 -1
- package/dist/tests/parser/declarations.test.js +20 -0
- package/dist/tests/parser/declarations.test.js.map +1 -1
- package/dist/tests/parser/expressions.test.js +36 -0
- package/dist/tests/parser/expressions.test.js.map +1 -1
- package/dist/tests/platform.d.ts +32 -0
- package/dist/tests/platform.js +40 -0
- package/dist/tests/platform.js.map +1 -0
- package/dist/tests/platform.test.d.ts +12 -0
- package/dist/tests/platform.test.js +51 -0
- package/dist/tests/platform.test.js.map +1 -0
- package/dist/tests/version.test.js +4 -4
- package/dist/tests/version.test.js.map +1 -1
- package/doc/ai/README.md +10 -4
- package/doc/ai/build-recipe.md +1 -0
- package/doc/ai/cli.md +17 -5
- package/doc/ai/contributing.md +59 -2
- package/doc/ai/extensions.md +38 -7
- package/doc/ai/language-support.md +25 -16
- package/doc/ai/troubleshooting.md +12 -8
- package/doc/ai/zh-CN/README.md +9 -4
- package/doc/ai/zh-CN/build-recipe.md +1 -0
- package/doc/ai/zh-CN/cli.md +13 -3
- package/doc/ai/zh-CN/contributing.md +49 -3
- package/doc/ai/zh-CN/extensions.md +33 -6
- package/doc/ai/zh-CN/language-support.md +23 -14
- package/doc/ai/zh-CN/troubleshooting.md +10 -6
- package/doc/gui/api.md +47 -1
- package/doc/gui/build.md +72 -16
- package/doc/gui/canvas.md +11 -3
- package/doc/gui/dom.md +33 -18
- package/doc/gui/known-issues.md +58 -15
- package/doc/gui/layout.md +18 -0
- package/doc/gui/media.md +17 -13
- package/doc/gui/rendering.md +50 -3
- package/doc/gui/runtime.md +18 -0
- package/doc/gui/webgl.md +256 -0
- package/doc/gui-scripts.md +7 -0
- package/doc/gui.md +108 -17
- package/doc/implemented/binder.md +2 -0
- package/doc/implemented/checker.md +117 -0
- package/doc/implemented/cli.md +13 -1
- package/doc/implemented/codegen.md +3 -2
- package/doc/implemented/driver.md +2 -2
- package/doc/implemented/operators.md +2 -1
- package/doc/implemented/parser.md +3 -2
- package/doc/implemented/pipeline.md +8 -1
- package/doc/implemented/stdlib.md +2 -1
- package/doc/implemented/tests.md +3 -1
- package/doc/implemented.md +2 -0
- package/doc/npm-package.md +419 -0
- package/doc/requirements.md +22 -10
- package/doc/support-matrix.md +83 -0
- package/doc/unimplemented/classes.md +3 -0
- package/doc/unimplemented/deviations.md +3 -2
- package/doc/unimplemented/toolchain.md +1 -1
- package/doc/unimplemented/types.md +24 -8
- package/doc/unimplemented.md +1 -1
- package/doc/zh-CN/gui/api.md +43 -1
- package/doc/zh-CN/gui/build.md +64 -15
- package/doc/zh-CN/gui/canvas.md +9 -2
- package/doc/zh-CN/gui/dom.md +20 -7
- package/doc/zh-CN/gui/known-issues.md +46 -13
- package/doc/zh-CN/gui/layout.md +14 -0
- package/doc/zh-CN/gui/media.md +15 -11
- package/doc/zh-CN/gui/rendering.md +41 -4
- package/doc/zh-CN/gui/runtime.md +16 -0
- package/doc/zh-CN/gui/webgl.md +115 -0
- package/doc/zh-CN/gui-scripts.md +5 -0
- package/doc/zh-CN/gui.md +89 -14
- package/doc/zh-CN/implemented/binder.md +2 -0
- package/doc/zh-CN/implemented/checker.md +99 -0
- package/doc/zh-CN/implemented/cli.md +12 -1
- package/doc/zh-CN/implemented/codegen.md +3 -2
- package/doc/zh-CN/implemented/driver.md +2 -2
- package/doc/zh-CN/implemented/operators.md +1 -1
- package/doc/zh-CN/implemented/parser.md +3 -2
- package/doc/zh-CN/implemented/pipeline.md +3 -1
- package/doc/zh-CN/implemented/stdlib.md +2 -1
- package/doc/zh-CN/implemented/tests.md +3 -1
- package/doc/zh-CN/implemented.md +2 -0
- package/doc/zh-CN/npm-package.md +394 -0
- package/doc/zh-CN/post/announce.md +47 -47
- package/doc/zh-CN/requirements.md +16 -7
- package/doc/zh-CN/support-matrix.md +82 -0
- package/doc/zh-CN/unimplemented/classes.md +3 -0
- package/doc/zh-CN/unimplemented/deviations.md +3 -2
- package/doc/zh-CN/unimplemented/toolchain.md +1 -1
- package/doc/zh-CN/unimplemented/types.md +16 -6
- package/doc/zh-CN/unimplemented.md +1 -1
- package/llms.txt +6 -1
- package/package.json +2 -1
- package/runtime/ext_gui/audio.cpp +316 -0
- package/runtime/ext_gui/browser.cpp +573 -0
- package/runtime/ext_gui/browser_escape.cpp +85 -0
- package/runtime/ext_gui/browser_loop.cpp +83 -0
- package/runtime/ext_gui/canvas.cpp +12 -21
- package/runtime/ext_gui/canvas_internal.h +10 -0
- package/runtime/ext_gui/canvas_raster.cpp +79 -1
- package/runtime/ext_gui/clip_values.cpp +246 -0
- package/runtime/ext_gui/css.cpp +94 -0
- package/runtime/ext_gui/css.h +22 -1
- package/runtime/ext_gui/css_match.cpp +3 -0
- package/runtime/ext_gui/css_selector.cpp +9 -0
- package/runtime/ext_gui/css_sheet.cpp +89 -45
- package/runtime/ext_gui/document.cpp +4 -1
- package/runtime/ext_gui/document.h +2 -0
- package/runtime/ext_gui/dom.h +16 -0
- package/runtime/ext_gui/dom_api.cpp +37 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +17 -80
- package/runtime/ext_gui/dom_api_canvas_extra.cpp +130 -1
- package/runtime/ext_gui/dom_api_canvas_pending.cpp +41 -0
- package/runtime/ext_gui/dom_api_document.cpp +96 -5
- package/runtime/ext_gui/dom_api_events.cpp +20 -0
- package/runtime/ext_gui/dom_api_internal.h +278 -0
- package/runtime/ext_gui/dom_api_proto.cpp +6 -0
- package/runtime/ext_gui/dom_api_webgl.cpp +376 -0
- package/runtime/ext_gui/dom_api_webgl2.cpp +434 -0
- package/runtime/ext_gui/dom_api_webgl2_draw.cpp +269 -0
- package/runtime/ext_gui/dom_api_webgl_buffer.cpp +212 -0
- package/runtime/ext_gui/dom_api_webgl_rt.h +30 -0
- package/runtime/ext_gui/dom_api_webgl_shader.cpp +443 -0
- package/runtime/ext_gui/dom_api_webgl_state.cpp +444 -0
- package/runtime/ext_gui/dom_api_webgl_texture.cpp +445 -0
- package/runtime/ext_gui/effect_values.cpp +312 -0
- package/runtime/ext_gui/gradient_values.cpp +476 -0
- package/runtime/ext_gui/grid_values.cpp +230 -0
- package/runtime/ext_gui/gui.cpp +90 -23
- package/runtime/ext_gui/gui_canvas.cpp +50 -2
- package/runtime/ext_gui/gui_engine.h +71 -0
- package/runtime/ext_gui/gui_events.cpp +4 -1
- package/runtime/ext_gui/gui_media.cpp +1 -1
- package/runtime/ext_gui/gui_webgl.cpp +83 -0
- package/runtime/ext_gui/layout.cpp +21 -0
- package/runtime/ext_gui/layout_flow.cpp +81 -4
- package/runtime/ext_gui/layout_flow_internal.h +31 -0
- package/runtime/ext_gui/layout_grid.cpp +374 -0
- package/runtime/ext_gui/media.h +1 -1
- package/runtime/ext_gui/media_api.h +2 -2
- package/runtime/ext_gui/media_query.cpp +211 -0
- package/runtime/ext_gui/paint.cpp +111 -77
- package/runtime/ext_gui/paint.h +33 -3
- package/runtime/ext_gui/paint_background.cpp +229 -0
- package/runtime/ext_gui/paint_clip.cpp +268 -0
- package/runtime/ext_gui/paint_effects.cpp +324 -0
- package/runtime/ext_gui/paint_internal.h +85 -0
- package/runtime/ext_gui/renderer.cpp +8 -31
- package/runtime/ext_gui/renderer_clip.cpp +196 -0
- package/runtime/ext_gui/renderer_image.cpp +13 -8
- package/runtime/ext_gui/renderer_internal.h +15 -8
- package/runtime/ext_gui/renderer_text.cpp +6 -31
- package/runtime/ext_gui/style.cpp +343 -20
- package/runtime/ext_gui/style.h +144 -3
- package/runtime/ext_gui/style_print.cpp +134 -1
- package/runtime/ext_gui/style_values.cpp +152 -126
- package/runtime/ext_gui/style_values_internal.h +35 -0
- package/runtime/ext_gui/webgl.h +466 -0
- package/runtime/ext_gui/webgl2_constants.h +274 -0
- package/runtime/ext_gui/webgl_buffer.cpp +565 -0
- package/runtime/ext_gui/webgl_constants.h +317 -0
- package/runtime/ext_gui/webgl_context.cpp +466 -0
- package/runtime/ext_gui/webgl_draw.cpp +495 -0
- package/runtime/ext_gui/webgl_glsl.h +125 -0
- package/runtime/ext_gui/webgl_glsl_compile.cpp +431 -0
- package/runtime/ext_gui/webgl_glsl_rewrite.cpp +349 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +581 -0
- package/runtime/ext_gui/webgl_msl.cpp +62 -0
- package/runtime/ext_gui/webgl_msl.h +33 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +274 -0
- package/runtime/ext_gui/webgl_program_internal.h +18 -0
- package/runtime/ext_gui/webgl_shader.cpp +582 -0
- package/runtime/ext_gui/webgl_texture.cpp +293 -0
- package/runtime/ext_gui/webgl_uniform.cpp +167 -0
- package/runtime/ext_gui/webgl_webgl2.cpp +224 -0
- package/runtime/ext_gui/window.cpp +9 -0
- package/runtime/ext_media/media.cpp +1 -1
- package/runtime/ext_media/media_bridge.c +9 -3
- package/runtime/ext_node/path/path.c +7 -7
- package/runtime/ext_node/url/url.c +4 -2
- package/runtime/rt.h +15 -0
- package/runtime/rt_internal.h +1 -0
- package/runtime/xt_constructors.c +2 -1
- package/runtime/xt_containers/access.inc +8 -0
- package/runtime/xt_containers/objects.inc +22 -2
- package/runtime/xt_io/exception.inc +4 -2
- package/runtime/xt_regex/api.inc +2 -0
- package/runtime/xt_regex/matcher.inc +16 -3
- package/runtime/xt_regex/parser.inc +8 -2
- package/runtime/xt_regex/types.inc +3 -0
- package/runtime/xt_stdlib/math.inc +62 -0
- package/runtime/xt_stdlib2/date.inc +7 -1
- package/runtime/xt_stdlib2/objects.inc +14 -0
- package/runtime/xt_stdlib2/regexp-match.inc +60 -21
- package/runtime/xt_stdlib2/regexp.inc +1 -0
- package/runtime/xt_typed_array.c +1 -1
- package/scripts/build-gui.ts +90 -3
- package/scripts/build-media.ts +323 -58
- package/scripts/setup-vs-toolchain.ps1 +152 -0
- package/scripts/support-matrix.ts +167 -0
- package/src/ast/common.ts +2 -0
- package/src/ast/declarations.ts +12 -1
- package/src/ast/expressions.ts +6 -0
- package/src/ast/kinds.ts +2 -0
- package/src/binder/binder.ts +3 -0
- package/src/binder/declarations.ts +70 -0
- package/src/binder/references.ts +97 -4
- package/src/binder/types.ts +30 -0
- package/src/canonical.ts +37 -0
- package/src/checker/assignability.ts +134 -0
- package/src/checker/calls.ts +135 -0
- package/src/checker/checker.ts +47 -0
- package/src/checker/declarations.ts +26 -0
- package/src/checker/flow.ts +236 -0
- package/src/checker/globals.ts +40 -0
- package/src/checker/source.ts +53 -0
- package/src/checker/type-infer.ts +185 -0
- package/src/checker/type-model.ts +212 -0
- package/src/checker/type-system.ts +578 -0
- package/src/checker/typecheck-types.ts +112 -0
- package/src/checker/typecheck.ts +586 -0
- package/src/checker/undefined.ts +43 -0
- package/src/checker/walk.ts +16 -0
- package/src/cli/help.ts +65 -0
- package/src/cli/hints.ts +2 -1
- package/src/cli/main.ts +12 -49
- package/src/codegen/generator/calls/access.ts +8 -8
- package/src/codegen/generator/calls/invocation.ts +8 -5
- package/src/codegen/generator/calls/super.ts +67 -5
- package/src/codegen/generator/context.ts +31 -19
- package/src/codegen/generator/debug.ts +2 -1
- package/src/codegen/generator/expressions/primary.ts +84 -13
- package/src/codegen/generator/generator.ts +11 -1
- package/src/codegen/generator/module.ts +115 -24
- package/src/codegen/generator/state.ts +11 -1
- package/src/codegen/generator/statements/variables.ts +26 -6
- package/src/codegen/generator/tables.ts +5 -0
- package/src/driver/build-key.ts +3 -0
- package/src/driver/bundler/graph.ts +6 -2
- package/src/driver/bundler/merge.ts +14 -1
- package/src/driver/bundler/types.ts +13 -0
- package/src/driver/compiler.ts +4 -1
- package/src/driver/fingerprint.ts +2 -1
- package/src/driver/frontend.ts +13 -2
- package/src/driver/options.ts +6 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/css.ts +113 -0
- package/src/extensions/gui/html.ts +31 -11
- package/src/extensions/gui/index.ts +81 -2
- package/src/extensions/gui/three.ts +25 -0
- package/src/extensions/media/index.ts +13 -16
- package/src/extensions/registry.ts +48 -0
- package/src/index.ts +1 -0
- package/src/parser/declarations/classes.ts +7 -0
- package/src/parser/expressions.ts +13 -1
- package/src/parser/literals.ts +6 -2
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The type-aware half of the checker: declaration/assignment/return/argument
|
|
3
|
+
* assignability, property existence on annotated and inferred shapes, and the
|
|
4
|
+
* small amount of flow narrowing that makes those checks useful inside an
|
|
5
|
+
* `if (value !== null)` block.
|
|
6
|
+
*
|
|
7
|
+
* Every decision is conservative. When the model cannot name a type it uses
|
|
8
|
+
* `any`, and `any` is compatible with everything; a diagnostic is only emitted
|
|
9
|
+
* for a definite mismatch.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
SyntaxKind,
|
|
14
|
+
type ArrowFunction,
|
|
15
|
+
type BinaryExpression,
|
|
16
|
+
type Block,
|
|
17
|
+
type CallExpression,
|
|
18
|
+
type ClassDeclaration,
|
|
19
|
+
type ConditionalExpression,
|
|
20
|
+
type Expression,
|
|
21
|
+
type ForOfStatement,
|
|
22
|
+
type ForStatement,
|
|
23
|
+
type FunctionDeclaration,
|
|
24
|
+
type FunctionExpression,
|
|
25
|
+
type Identifier,
|
|
26
|
+
type IfStatement,
|
|
27
|
+
type NewExpression,
|
|
28
|
+
type ObjectLiteralExpression,
|
|
29
|
+
type PropertyAccessExpression,
|
|
30
|
+
type ReturnStatement,
|
|
31
|
+
type SourceFileNode,
|
|
32
|
+
type Statement,
|
|
33
|
+
type TryStatement,
|
|
34
|
+
|
|
35
|
+
type VariableDeclarationList,
|
|
36
|
+
type VariableStatement,
|
|
37
|
+
} from "../ast/nodes.js";
|
|
38
|
+
import type { BindResult } from "../binder/binder.js";
|
|
39
|
+
import { DiagnosticCode, type DiagnosticBag } from "../diagnostics/diagnostic.js";
|
|
40
|
+
import { isAssignable, isDefinitelyNotCallable } from "./assignability.js";
|
|
41
|
+
import { Flow, narrow, withoutNullish } from "./flow.js";
|
|
42
|
+
import { ANY, printType, primitive, unionOf, unwrap, widenType, type Type } from "./type-model.js";
|
|
43
|
+
import { TypeResolver } from "./type-system.js";
|
|
44
|
+
import { typeCheckerMembers, type TypeCheckerMembers } from "./typecheck-types.js";
|
|
45
|
+
import { fileNameOf, isUntypedNode } from "./source.js";
|
|
46
|
+
|
|
47
|
+
export interface CheckContext {
|
|
48
|
+
readonly returnType: Type;
|
|
49
|
+
readonly thisType?: Type;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Check declarations, assignments, returns, call arguments and property reads
|
|
54
|
+
* against the type model. Runs after the simpler passes; it only adds
|
|
55
|
+
* `TypeMismatch`, `NotCallable` and `PropertyNotFound` diagnostics.
|
|
56
|
+
*/
|
|
57
|
+
export function checkTypes(
|
|
58
|
+
sourceFile: SourceFileNode,
|
|
59
|
+
binding: BindResult,
|
|
60
|
+
diagnostics: DiagnosticBag,
|
|
61
|
+
): void {
|
|
62
|
+
new TypeChecker(sourceFile, binding, diagnostics).run();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class TypeChecker {
|
|
66
|
+
readonly resolver: TypeResolver;
|
|
67
|
+
|
|
68
|
+
constructor(
|
|
69
|
+
readonly sourceFile: SourceFileNode,
|
|
70
|
+
readonly binding: BindResult,
|
|
71
|
+
readonly diagnostics: DiagnosticBag,
|
|
72
|
+
) {
|
|
73
|
+
this.resolver = new TypeResolver(sourceFile, binding);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
run(): void {
|
|
77
|
+
this.checkStatements(this.sourceFile.statements, new Flow(), { returnType: ANY });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// -- statements ----------------------------------------------------------
|
|
81
|
+
|
|
82
|
+
private checkStatements(statements: readonly Statement[], flow: Flow, context: CheckContext): void {
|
|
83
|
+
for (const statement of statements) this.checkStatement(statement, flow, context);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private checkStatement(statement: Statement, flow: Flow, context: CheckContext): void {
|
|
87
|
+
if (isUntypedNode(this.sourceFile, statement)) return;
|
|
88
|
+
switch (statement.kind) {
|
|
89
|
+
case SyntaxKind.VariableStatement:
|
|
90
|
+
this.checkVariableList((statement as VariableStatement).declarationList, flow, context);
|
|
91
|
+
return;
|
|
92
|
+
case SyntaxKind.ExpressionStatement:
|
|
93
|
+
this.checkExpression((statement as unknown as { expression: Expression }).expression, flow, context);
|
|
94
|
+
return;
|
|
95
|
+
case SyntaxKind.ReturnStatement: {
|
|
96
|
+
const returned = (statement as ReturnStatement).expression;
|
|
97
|
+
if (returned) this.checkAssignable(returned, context.returnType, flow, context);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
case SyntaxKind.IfStatement: {
|
|
101
|
+
const condition = (statement as IfStatement).condition;
|
|
102
|
+
this.checkExpression(condition, flow, context);
|
|
103
|
+
this.checkStatement((statement as IfStatement).thenStatement, narrow(condition, true, flow, this.resolver), context);
|
|
104
|
+
const otherwise = (statement as IfStatement).elseStatement;
|
|
105
|
+
if (otherwise) this.checkStatement(otherwise, narrow(condition, false, flow, this.resolver), context);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
case SyntaxKind.Block:
|
|
109
|
+
this.checkStatements((statement as Block).statements, new Flow(flow), context);
|
|
110
|
+
return;
|
|
111
|
+
case SyntaxKind.FunctionDeclaration:
|
|
112
|
+
this.checkFunction(statement as FunctionDeclaration, flow, context.thisType);
|
|
113
|
+
return;
|
|
114
|
+
case SyntaxKind.ClassDeclaration:
|
|
115
|
+
this.checkClass(statement as ClassDeclaration, flow);
|
|
116
|
+
return;
|
|
117
|
+
case SyntaxKind.ForStatement: {
|
|
118
|
+
const loop = statement as ForStatement;
|
|
119
|
+
const loopFlow = new Flow(flow);
|
|
120
|
+
if (loop.initializer) {
|
|
121
|
+
if (loop.initializer.kind === SyntaxKind.VariableDeclarationList) {
|
|
122
|
+
this.checkVariableList(loop.initializer as VariableDeclarationList, loopFlow, context);
|
|
123
|
+
} else {
|
|
124
|
+
this.checkExpression(loop.initializer as Expression, loopFlow, context);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (loop.condition) this.checkExpression(loop.condition, loopFlow, context);
|
|
128
|
+
if (loop.incrementor) this.checkExpression(loop.incrementor, loopFlow, context);
|
|
129
|
+
this.checkStatement(loop.statement, loopFlow, context);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
case SyntaxKind.ForOfStatement:
|
|
133
|
+
this.checkForOf(statement as ForOfStatement, flow, context);
|
|
134
|
+
return;
|
|
135
|
+
case SyntaxKind.ForInStatement: {
|
|
136
|
+
const loop = statement as unknown as { initializer: VariableDeclarationList | Expression; statement: Statement };
|
|
137
|
+
if (loop.initializer.kind === SyntaxKind.VariableDeclarationList) {
|
|
138
|
+
const declaration = loop.initializer.declarations[0];
|
|
139
|
+
const symbol = declaration ? this.binding.symbolOfDeclaration.get(declaration) : undefined;
|
|
140
|
+
if (symbol && declaration?.name.kind === SyntaxKind.Identifier) this.resolver.setSymbolType(symbol.id, primitive("string"));
|
|
141
|
+
}
|
|
142
|
+
this.checkStatement(loop.statement, new Flow(flow), context);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
case SyntaxKind.WhileStatement:
|
|
146
|
+
case SyntaxKind.DoStatement: {
|
|
147
|
+
const loop = statement as unknown as { condition: Expression; statement: Statement };
|
|
148
|
+
this.checkExpression(loop.condition, new Flow(flow), context);
|
|
149
|
+
this.checkStatement(loop.statement, new Flow(flow), context);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
case SyntaxKind.TryStatement: {
|
|
153
|
+
const attempt = statement as TryStatement;
|
|
154
|
+
this.checkStatements(attempt.tryBlock.statements, new Flow(flow), context);
|
|
155
|
+
if (attempt.catchClause) {
|
|
156
|
+
const catchSymbol = attempt.catchClause.variable
|
|
157
|
+
? this.binding.symbolOfDeclaration.get(attempt.catchClause.variable)
|
|
158
|
+
: undefined;
|
|
159
|
+
if (catchSymbol) this.resolver.setSymbolType(catchSymbol.id, ANY);
|
|
160
|
+
this.checkStatements(attempt.catchClause.block.statements, new Flow(flow), context);
|
|
161
|
+
}
|
|
162
|
+
if (attempt.finallyBlock) this.checkStatements(attempt.finallyBlock.statements, new Flow(flow), context);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
case SyntaxKind.SwitchStatement: {
|
|
166
|
+
const switchStatement = statement as unknown as { expression: Expression; clauses: { expression?: Expression; statements: Statement[] }[] };
|
|
167
|
+
this.checkExpression(switchStatement.expression, flow, context);
|
|
168
|
+
for (const clause of switchStatement.clauses) {
|
|
169
|
+
if (clause.expression) this.checkExpression(clause.expression, flow, context);
|
|
170
|
+
this.checkStatements(clause.statements, new Flow(flow), context);
|
|
171
|
+
}
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
case SyntaxKind.ThrowStatement:
|
|
175
|
+
this.checkExpression((statement as unknown as { expression: Expression }).expression, flow, context);
|
|
176
|
+
return;
|
|
177
|
+
case SyntaxKind.LabeledStatement:
|
|
178
|
+
this.checkStatement((statement as unknown as { statement: Statement }).statement, flow, context);
|
|
179
|
+
return;
|
|
180
|
+
case SyntaxKind.ExportAssignment:
|
|
181
|
+
this.checkExpression((statement as unknown as { expression: Expression }).expression, flow, context);
|
|
182
|
+
return;
|
|
183
|
+
default:
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private checkVariableList(list: VariableDeclarationList, flow: Flow, context: CheckContext): void {
|
|
189
|
+
for (const declaration of list.declarations) {
|
|
190
|
+
const symbol = this.binding.symbolOfDeclaration.get(declaration);
|
|
191
|
+
const annotation = declaration.type ? this.resolver.resolve(declaration.type) : undefined;
|
|
192
|
+
const isSimple = declaration.name.kind === SyntaxKind.Identifier;
|
|
193
|
+
if (declaration.initializer) {
|
|
194
|
+
if (annotation && isSimple) this.checkAssignable(declaration.initializer, annotation, flow, context);
|
|
195
|
+
else this.checkExpression(declaration.initializer, flow, context);
|
|
196
|
+
}
|
|
197
|
+
if (!symbol || declaration.name.kind !== SyntaxKind.Identifier) continue;
|
|
198
|
+
const inferred = annotation ?? (declaration.initializer ? this.resolver.inferExpression(declaration.initializer, (candidate) => this.lookup(candidate.id, flow)) : ANY);
|
|
199
|
+
// `let x = 1` has type number, not the literal 1; `const` keeps the literal.
|
|
200
|
+
const widened = list.declarationKind === "const" ? inferred : this.widen(inferred);
|
|
201
|
+
this.resolver.setSymbolType(symbol.id, widened);
|
|
202
|
+
// An alias can mutate the original through a path this pass cannot
|
|
203
|
+
// follow, so the original shape is no longer trusted.
|
|
204
|
+
const initializer = declaration.initializer ? unwrap(declaration.initializer) : undefined;
|
|
205
|
+
if (initializer?.kind === SyntaxKind.Identifier) {
|
|
206
|
+
const source = this.binding.symbolOfIdentifier.get(initializer as Identifier);
|
|
207
|
+
if (source && this.lookup(source.id, flow).kind === "object") this.resolver.setSymbolType(source.id, ANY);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** `let`/`var` widen literal and array-literal types (`let x = 1` is number). */
|
|
213
|
+
private widen(type: Type): Type {
|
|
214
|
+
return widenType(type);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private checkForOf(loop: ForOfStatement, flow: Flow, context: CheckContext): void {
|
|
218
|
+
const iterated = this.checkExpression(loop.expression, flow, context);
|
|
219
|
+
let element: Type = ANY;
|
|
220
|
+
if (iterated.kind === "array") element = iterated.element;
|
|
221
|
+
else if (iterated.kind === "tuple") element = unionOf(iterated.elements);
|
|
222
|
+
else if (iterated.kind === "primitive" && iterated.name === "string") element = primitive("string");
|
|
223
|
+
if (loop.initializer.kind === SyntaxKind.VariableDeclarationList) {
|
|
224
|
+
const declaration = loop.initializer.declarations[0];
|
|
225
|
+
const symbol = declaration ? this.binding.symbolOfDeclaration.get(declaration) : undefined;
|
|
226
|
+
if (symbol && declaration?.name.kind === SyntaxKind.Identifier) {
|
|
227
|
+
const annotated = declaration.type ? this.resolver.resolve(declaration.type) : undefined;
|
|
228
|
+
this.resolver.setSymbolType(symbol.id, annotated ?? element);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
this.checkStatement(loop.statement, new Flow(flow), context);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private checkFunction(node: FunctionDeclaration, flow: Flow, thisType: Type | undefined): void {
|
|
235
|
+
const returnType = node.returnType ? this.resolver.resolve(node.returnType) : ANY;
|
|
236
|
+
const child = new Flow(flow);
|
|
237
|
+
for (const parameter of node.parameters) {
|
|
238
|
+
const symbol = this.binding.symbolOfDeclaration.get(parameter);
|
|
239
|
+
if (symbol) this.resolver.setSymbolType(symbol.id, parameter.type ? this.resolver.resolve(parameter.type) : ANY);
|
|
240
|
+
}
|
|
241
|
+
const context: CheckContext = { returnType, ...(thisType ? { thisType } : {}) };
|
|
242
|
+
if (!node.body) return;
|
|
243
|
+
this.checkStatements(node.body.statements, child, context);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
private checkClass(node: ClassDeclaration, flow: Flow): void {
|
|
247
|
+
const thisType = this.resolver.classInstanceType(node);
|
|
248
|
+
for (const member of node.members) {
|
|
249
|
+
if (member.kind === SyntaxKind.ClassStaticBlockDeclaration) {
|
|
250
|
+
const block = member as unknown as { body: Block };
|
|
251
|
+
this.checkStatements(block.body.statements, new Flow(flow), { returnType: ANY });
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (member.kind === SyntaxKind.PropertyDeclaration) {
|
|
255
|
+
const property = member as unknown as { type?: import("../ast/nodes.js").TypeNode; initializer?: Expression };
|
|
256
|
+
if (!property.initializer) continue;
|
|
257
|
+
if (property.type) this.checkAssignable(property.initializer, this.resolver.resolve(property.type), new Flow(flow), { returnType: ANY, thisType });
|
|
258
|
+
else this.checkExpression(property.initializer, new Flow(flow), { returnType: ANY, thisType });
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
if (member.kind === SyntaxKind.MethodDeclaration || member.kind === SyntaxKind.ConstructorDeclaration) {
|
|
262
|
+
const method = member as unknown as { body?: Block; returnType?: import("../ast/nodes.js").TypeNode; parameters: import("../ast/nodes.js").Parameter[]; modifiers: { modifierKind: string }[] };
|
|
263
|
+
const isStatic = method.modifiers.some((modifier) => modifier.modifierKind === "static");
|
|
264
|
+
if (!method.body) continue;
|
|
265
|
+
const child = new Flow(flow);
|
|
266
|
+
for (const parameter of method.parameters) {
|
|
267
|
+
const symbol = this.binding.symbolOfDeclaration.get(parameter);
|
|
268
|
+
if (symbol) this.resolver.setSymbolType(symbol.id, parameter.type ? this.resolver.resolve(parameter.type) : ANY);
|
|
269
|
+
}
|
|
270
|
+
const context: CheckContext = {
|
|
271
|
+
returnType: method.returnType ? this.resolver.resolve(method.returnType) : ANY,
|
|
272
|
+
...(isStatic ? {} : { thisType }),
|
|
273
|
+
};
|
|
274
|
+
this.checkStatements(method.body.statements, child, context);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// -- expressions ---------------------------------------------------------
|
|
280
|
+
|
|
281
|
+
lookup(symbolId: number, flow: Flow): Type {
|
|
282
|
+
return flow.typeOf(symbolId) ?? this.resolver.typeOfSymbolId(symbolId) ?? ANY;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
private checkAssignable(expression: Expression, target: Type, flow: Flow, context: CheckContext): Type {
|
|
286
|
+
if (target.kind === "any") return this.checkExpression(expression, flow, context);
|
|
287
|
+
const source = this.checkExpression(expression, flow, context);
|
|
288
|
+
if (!isAssignable(source, target) && !isUntypedNode(this.sourceFile, expression)) {
|
|
289
|
+
this.report(
|
|
290
|
+
DiagnosticCode.TypeMismatch,
|
|
291
|
+
`Type '${printType(source)}' is not assignable to type '${printType(target)}'.`,
|
|
292
|
+
expression,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
return source;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
private report(code: DiagnosticCode, message: string, node: Expression): void {
|
|
299
|
+
this.diagnostics.error(code, message, node, fileNameOf(this.sourceFile, node));
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
checkExpression(expression: Expression, flow: Flow, context: CheckContext): Type {
|
|
303
|
+
if (isUntypedNode(this.sourceFile, expression)) return ANY;
|
|
304
|
+
switch (expression.kind) {
|
|
305
|
+
case SyntaxKind.NumericLiteral:
|
|
306
|
+
case SyntaxKind.StringLiteral:
|
|
307
|
+
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
|
308
|
+
case SyntaxKind.BigIntLiteral:
|
|
309
|
+
case SyntaxKind.TrueKeyword:
|
|
310
|
+
case SyntaxKind.FalseKeyword:
|
|
311
|
+
case SyntaxKind.NullKeyword:
|
|
312
|
+
case SyntaxKind.UndefinedKeyword:
|
|
313
|
+
return this.resolver.inferExpression(expression, (symbol) => this.lookup(symbol.id, flow));
|
|
314
|
+
case SyntaxKind.Identifier: {
|
|
315
|
+
const symbol = this.binding.symbolOfIdentifier.get(expression as Identifier);
|
|
316
|
+
return symbol ? this.lookup(symbol.id, flow) : ANY;
|
|
317
|
+
}
|
|
318
|
+
case SyntaxKind.ThisKeyword:
|
|
319
|
+
return context.thisType ?? ANY;
|
|
320
|
+
case SyntaxKind.PropertyAccessExpression: {
|
|
321
|
+
const access = expression as PropertyAccessExpression;
|
|
322
|
+
const base = this.checkExpression(access.expression, flow, context);
|
|
323
|
+
if (access.name.kind !== SyntaxKind.Identifier) return ANY;
|
|
324
|
+
const name = (access.name as Identifier).text;
|
|
325
|
+
const found = this.lookupProperty(base, name);
|
|
326
|
+
if (found.missing) {
|
|
327
|
+
this.report(DiagnosticCode.PropertyNotFound, `Property '${name}' does not exist on ${printType(base)}.`, access);
|
|
328
|
+
}
|
|
329
|
+
return found.type;
|
|
330
|
+
}
|
|
331
|
+
case SyntaxKind.ElementAccessExpression: {
|
|
332
|
+
const access = expression as unknown as { expression: Expression; argumentExpression: Expression };
|
|
333
|
+
const base = this.checkExpression(access.expression, flow, context);
|
|
334
|
+
this.checkExpression(access.argumentExpression, flow, context);
|
|
335
|
+
const index = unwrap(access.argumentExpression);
|
|
336
|
+
// A symbol or computed key is not an array index (`arr[Symbol.iterator]`).
|
|
337
|
+
if (index.kind !== SyntaxKind.NumericLiteral) return ANY;
|
|
338
|
+
if (base.kind === "array") return base.element;
|
|
339
|
+
if (base.kind === "tuple") return base.elements[(index as unknown as { value: number }).value] ?? ANY;
|
|
340
|
+
return ANY;
|
|
341
|
+
}
|
|
342
|
+
case SyntaxKind.CallExpression:
|
|
343
|
+
return this.checkCall(expression as CallExpression, flow, context);
|
|
344
|
+
case SyntaxKind.NewExpression: {
|
|
345
|
+
const call = expression as NewExpression;
|
|
346
|
+
for (const argument of call.arguments) this.checkExpression(argument, flow, context);
|
|
347
|
+
return this.resolver.inferExpression(call, (symbol) => this.lookup(symbol.id, flow));
|
|
348
|
+
}
|
|
349
|
+
case SyntaxKind.BinaryExpression:
|
|
350
|
+
return this.checkBinary(expression as BinaryExpression, flow, context);
|
|
351
|
+
case SyntaxKind.ConditionalExpression: {
|
|
352
|
+
const conditional = expression as ConditionalExpression;
|
|
353
|
+
this.checkExpression(conditional.condition, flow, context);
|
|
354
|
+
const whenTrue = this.checkExpression(conditional.whenTrue, narrow(conditional.condition, true, flow, this.resolver), context);
|
|
355
|
+
const whenFalse = this.checkExpression(conditional.whenFalse, narrow(conditional.condition, false, flow, this.resolver), context);
|
|
356
|
+
return unionOf([whenTrue, whenFalse]);
|
|
357
|
+
}
|
|
358
|
+
case SyntaxKind.SequenceExpression: {
|
|
359
|
+
const sequence = expression as unknown as { expressions: Expression[] };
|
|
360
|
+
let type: Type = ANY;
|
|
361
|
+
for (const item of sequence.expressions) type = this.checkExpression(item, flow, context);
|
|
362
|
+
return type;
|
|
363
|
+
}
|
|
364
|
+
case SyntaxKind.ObjectLiteralExpression:
|
|
365
|
+
return this.checkObjectLiteral(expression as ObjectLiteralExpression, flow, context);
|
|
366
|
+
case SyntaxKind.ArrayLiteralExpression: {
|
|
367
|
+
const elements = (expression as unknown as { elements: Expression[] }).elements;
|
|
368
|
+
const types = elements.map((element) => {
|
|
369
|
+
if (element.kind !== SyntaxKind.SpreadElement) return this.checkExpression(element, flow, context);
|
|
370
|
+
const spread = this.checkExpression((element as unknown as { expression: Expression }).expression, flow, context);
|
|
371
|
+
return spread.kind === "array" ? spread.element : ANY;
|
|
372
|
+
});
|
|
373
|
+
return { kind: "array", element: unionOf(types) };
|
|
374
|
+
}
|
|
375
|
+
case SyntaxKind.ArrowFunction:
|
|
376
|
+
this.checkFunctionLike(expression as ArrowFunction, flow, context);
|
|
377
|
+
return this.resolver.inferExpression(expression, (symbol) => this.lookup(symbol.id, flow));
|
|
378
|
+
case SyntaxKind.FunctionExpression:
|
|
379
|
+
this.checkFunctionLike(expression as FunctionExpression, flow, context);
|
|
380
|
+
return this.resolver.inferExpression(expression, (symbol) => this.lookup(symbol.id, flow));
|
|
381
|
+
case SyntaxKind.AsExpression:
|
|
382
|
+
this.checkExpression((expression as unknown as { expression: Expression }).expression, flow, context);
|
|
383
|
+
return this.resolver.resolve((expression as unknown as { type: import("../ast/nodes.js").TypeNode }).type);
|
|
384
|
+
case SyntaxKind.SatisfiesExpression:
|
|
385
|
+
case SyntaxKind.ParenthesizedExpression:
|
|
386
|
+
return this.checkExpression((expression as unknown as { expression: Expression }).expression, flow, context);
|
|
387
|
+
case SyntaxKind.NonNullExpression:
|
|
388
|
+
return withoutNullish(this.checkExpression((expression as unknown as { expression: Expression }).expression, flow, context));
|
|
389
|
+
case SyntaxKind.TypeOfExpression:
|
|
390
|
+
this.checkExpression((expression as unknown as { expression: Expression }).expression, flow, context);
|
|
391
|
+
return primitive("string");
|
|
392
|
+
case SyntaxKind.VoidExpression: {
|
|
393
|
+
const operand = (expression as unknown as { expression?: Expression }).expression;
|
|
394
|
+
if (operand) this.checkExpression(operand, flow, context);
|
|
395
|
+
return primitive("undefined");
|
|
396
|
+
}
|
|
397
|
+
case SyntaxKind.PrefixUnaryExpression: {
|
|
398
|
+
const unary = expression as unknown as { operator: string; operand: Expression };
|
|
399
|
+
this.checkExpression(unary.operand, flow, context);
|
|
400
|
+
if (unary.operator === "!") return primitive("boolean");
|
|
401
|
+
if (unary.operator === "typeof") return primitive("string");
|
|
402
|
+
return primitive("number");
|
|
403
|
+
}
|
|
404
|
+
case SyntaxKind.PostfixUnaryExpression:
|
|
405
|
+
this.checkExpression((expression as unknown as { operand: Expression }).operand, flow, context);
|
|
406
|
+
return primitive("number");
|
|
407
|
+
case SyntaxKind.AwaitExpression:
|
|
408
|
+
this.checkExpression((expression as unknown as { expression: Expression }).expression, flow, context);
|
|
409
|
+
return ANY;
|
|
410
|
+
case SyntaxKind.TemplateLiteral: {
|
|
411
|
+
for (const span of (expression as unknown as { spans: { expression: Expression }[] }).spans) this.checkExpression(span.expression, flow, context);
|
|
412
|
+
return primitive("string");
|
|
413
|
+
}
|
|
414
|
+
case SyntaxKind.TaggedTemplateExpression: {
|
|
415
|
+
const tagged = expression as unknown as { tag: Expression; template: Expression };
|
|
416
|
+
this.checkExpression(tagged.tag, flow, context);
|
|
417
|
+
this.checkExpression(tagged.template, flow, context);
|
|
418
|
+
return ANY;
|
|
419
|
+
}
|
|
420
|
+
case SyntaxKind.DeleteExpression:
|
|
421
|
+
this.checkExpression((expression as unknown as { expression: Expression }).expression, flow, context);
|
|
422
|
+
return primitive("boolean");
|
|
423
|
+
case SyntaxKind.SpreadElement:
|
|
424
|
+
return this.checkExpression((expression as unknown as { expression: Expression }).expression, flow, context);
|
|
425
|
+
default:
|
|
426
|
+
return ANY;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private checkObjectLiteral(literal: ObjectLiteralExpression, flow: Flow, context: CheckContext): Type {
|
|
431
|
+
for (const property of literal.properties) {
|
|
432
|
+
if (property.kind === SyntaxKind.PropertyAssignment) {
|
|
433
|
+
this.checkExpression((property as unknown as { initializer: Expression }).initializer, flow, context);
|
|
434
|
+
} else if (property.kind === SyntaxKind.ShorthandPropertyAssignment) {
|
|
435
|
+
this.checkExpression((property as unknown as { name: Identifier }).name, flow, context);
|
|
436
|
+
} else if (property.kind === SyntaxKind.SpreadElement) {
|
|
437
|
+
this.checkExpression((property as unknown as { expression: Expression }).expression, flow, context);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return this.resolver.inferExpression(literal, (symbol) => this.lookup(symbol.id, flow));
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
private checkFunctionLike(node: ArrowFunction | FunctionExpression, flow: Flow, context: CheckContext): void {
|
|
444
|
+
const returnType = node.returnType ? this.resolver.resolve(node.returnType) : ANY;
|
|
445
|
+
const child = new Flow(flow);
|
|
446
|
+
for (const parameter of node.parameters) {
|
|
447
|
+
const symbol = this.binding.symbolOfDeclaration.get(parameter);
|
|
448
|
+
if (symbol) this.resolver.setSymbolType(symbol.id, parameter.type ? this.resolver.resolve(parameter.type) : ANY);
|
|
449
|
+
}
|
|
450
|
+
const inner: CheckContext = { returnType, ...(context.thisType ? { thisType: context.thisType } : {}) };
|
|
451
|
+
if (node.body.kind === SyntaxKind.Block) this.checkStatements((node.body as Block).statements, child, inner);
|
|
452
|
+
else this.checkAssignable(node.body as Expression, returnType, child, inner);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
private checkBinary(binary: BinaryExpression, flow: Flow, context: CheckContext): Type {
|
|
456
|
+
const assignment = (binary.operator as string) === "=";
|
|
457
|
+
if (assignment) {
|
|
458
|
+
const pattern = unwrap(binary.left);
|
|
459
|
+
// A destructuring assignment target is a pattern, not an object value.
|
|
460
|
+
if (pattern.kind === SyntaxKind.ObjectLiteralExpression || pattern.kind === SyntaxKind.ArrayLiteralExpression) {
|
|
461
|
+
return this.checkExpression(binary.right, flow, context);
|
|
462
|
+
}
|
|
463
|
+
const target = this.checkAssignmentTarget(binary.left, flow, context);
|
|
464
|
+
const value = this.checkExpression(binary.right, flow, context);
|
|
465
|
+
if (!isAssignable(value, target) && !isUntypedNode(this.sourceFile, binary.right)) {
|
|
466
|
+
this.report(DiagnosticCode.TypeMismatch, `Type '${printType(value)}' is not assignable to type '${printType(target)}'.`, binary.right);
|
|
467
|
+
}
|
|
468
|
+
return value;
|
|
469
|
+
}
|
|
470
|
+
if (binary.operator === "&&" || binary.operator === "||") {
|
|
471
|
+
const left = this.checkExpression(binary.left, flow, context);
|
|
472
|
+
const rightFlow = narrow(binary.left, binary.operator === "&&", flow, this.resolver);
|
|
473
|
+
const right = this.checkExpression(binary.right, rightFlow, context);
|
|
474
|
+
return unionOf([left, right]);
|
|
475
|
+
}
|
|
476
|
+
if (binary.operator === "??") {
|
|
477
|
+
const left = this.checkExpression(binary.left, flow, context);
|
|
478
|
+
const right = this.checkExpression(binary.right, narrow(binary.left, true, flow, this.resolver), context);
|
|
479
|
+
return unionOf([withoutNullish(left), right]);
|
|
480
|
+
}
|
|
481
|
+
this.checkExpression(binary.left, flow, context);
|
|
482
|
+
this.checkExpression(binary.right, flow, context);
|
|
483
|
+
return this.resolver.inferExpression(binary, (symbol) => this.lookup(symbol.id, flow));
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* The type a value is assigned into. A missing property is not reported on a
|
|
488
|
+
* write: xbintsc programs legitimately grow an object after its literal
|
|
489
|
+
* (`const o = {}; o.a = 1`), so the shape is opened instead.
|
|
490
|
+
*/
|
|
491
|
+
private checkAssignmentTarget(expression: Expression, flow: Flow, context: CheckContext): Type {
|
|
492
|
+
const target = unwrap(expression);
|
|
493
|
+
if (target.kind === SyntaxKind.Identifier) {
|
|
494
|
+
const symbol = this.binding.symbolOfIdentifier.get(target as Identifier);
|
|
495
|
+
return symbol ? this.lookup(symbol.id, flow) : ANY;
|
|
496
|
+
}
|
|
497
|
+
if (target.kind === SyntaxKind.PropertyAccessExpression) {
|
|
498
|
+
const access = target as PropertyAccessExpression;
|
|
499
|
+
const base = this.checkExpression(access.expression, flow, context);
|
|
500
|
+
if (access.name.kind !== SyntaxKind.Identifier) return ANY;
|
|
501
|
+
const found = this.lookupProperty(base, (access.name as Identifier).text);
|
|
502
|
+
if (!found.missing) return found.type;
|
|
503
|
+
const baseIdentifier = unwrap(access.expression);
|
|
504
|
+
if (baseIdentifier.kind === SyntaxKind.Identifier) {
|
|
505
|
+
const symbol = this.binding.symbolOfIdentifier.get(baseIdentifier as Identifier);
|
|
506
|
+
if (symbol) this.resolver.setSymbolType(symbol.id, ANY);
|
|
507
|
+
}
|
|
508
|
+
return ANY;
|
|
509
|
+
}
|
|
510
|
+
if (target.kind === SyntaxKind.ElementAccessExpression) {
|
|
511
|
+
const access = target as unknown as { expression: Expression; argumentExpression: Expression };
|
|
512
|
+
const base = this.checkExpression(access.expression, flow, context);
|
|
513
|
+
this.checkExpression(access.argumentExpression, flow, context);
|
|
514
|
+
return base.kind === "array" ? base.element : ANY;
|
|
515
|
+
}
|
|
516
|
+
return ANY;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
private checkCall(call: CallExpression, flow: Flow, context: CheckContext): Type {
|
|
520
|
+
this.openMutatedArguments(call, flow);
|
|
521
|
+
const callee = this.checkExpression(call.expression, flow, context);
|
|
522
|
+
if (isDefinitelyNotCallable(callee)) {
|
|
523
|
+
this.report(DiagnosticCode.NotCallable, `This expression is not callable; its type is '${printType(callee)}'.`, call.expression);
|
|
524
|
+
for (const argument of call.arguments) this.checkExpression(argument, flow, context);
|
|
525
|
+
return ANY;
|
|
526
|
+
}
|
|
527
|
+
if (callee.kind !== "function") {
|
|
528
|
+
for (const argument of call.arguments) this.checkExpression(argument, flow, context);
|
|
529
|
+
return ANY;
|
|
530
|
+
}
|
|
531
|
+
const substitutions = this.inferTypeArguments(callee, call, flow, context);
|
|
532
|
+
for (let index = 0; index < call.arguments.length; index++) {
|
|
533
|
+
const argument = call.arguments[index]!;
|
|
534
|
+
if (argument.kind === SyntaxKind.SpreadElement) {
|
|
535
|
+
this.checkExpression((argument as unknown as { expression: Expression }).expression, flow, context);
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const last = callee.parameters[callee.parameters.length - 1];
|
|
539
|
+
const parameter = index < callee.parameters.length - 1 ? callee.parameters[index] : last;
|
|
540
|
+
const argumentType = this.checkExpression(argument, flow, context);
|
|
541
|
+
if (!parameter) continue;
|
|
542
|
+
const restElement = parameter.rest && parameter.type.kind === "array" ? parameter.type.element : parameter.type;
|
|
543
|
+
const expected = this.substitute(restElement, substitutions);
|
|
544
|
+
if (!isAssignable(argumentType, expected) && !isUntypedNode(this.sourceFile, argument)) {
|
|
545
|
+
this.report(
|
|
546
|
+
DiagnosticCode.TypeMismatch,
|
|
547
|
+
`Argument of type '${printType(argumentType)}' is not assignable to parameter of type '${printType(expected)}'.`,
|
|
548
|
+
argument,
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return this.substitute(callee.returnType, substitutions);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** Calls can mutate an object argument; open its shape when they might. */
|
|
556
|
+
private openMutatedArguments(call: CallExpression, flow: Flow): void {
|
|
557
|
+
if (!this.callMayMutate(call)) return;
|
|
558
|
+
for (const argument of call.arguments) {
|
|
559
|
+
const target = unwrap(argument);
|
|
560
|
+
if (target.kind !== SyntaxKind.Identifier) continue;
|
|
561
|
+
const symbol = this.binding.symbolOfIdentifier.get(target as Identifier);
|
|
562
|
+
if (!symbol) continue;
|
|
563
|
+
if (this.lookup(symbol.id, flow).kind === "object") this.resolver.setSymbolType(symbol.id, ANY);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
private callMayMutate(call: CallExpression): boolean {
|
|
568
|
+
const callee = unwrap(call.expression);
|
|
569
|
+
if (callee.kind !== SyntaxKind.PropertyAccessExpression) return true;
|
|
570
|
+
const access = callee as PropertyAccessExpression;
|
|
571
|
+
if (access.expression.kind !== SyntaxKind.Identifier || access.name.kind !== SyntaxKind.Identifier) return true;
|
|
572
|
+
const owner = (access.expression as Identifier).text;
|
|
573
|
+
const method = (access.name as Identifier).text;
|
|
574
|
+
if (owner === "console" || owner === "String" || owner === "Number" || owner === "Boolean") return false;
|
|
575
|
+
if (owner === "JSON" && method === "stringify") return false;
|
|
576
|
+
if (owner === "Array" && method === "isArray") return false;
|
|
577
|
+
return !(
|
|
578
|
+
owner === "Object" &&
|
|
579
|
+
["keys", "values", "entries", "getOwnPropertyNames", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors", "getPrototypeOf", "isFrozen", "isSealed", "isExtensible", "hasOwn"].includes(method)
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
585
|
+
export interface TypeChecker extends TypeCheckerMembers {}
|
|
586
|
+
Object.assign(TypeChecker.prototype, typeCheckerMembers);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unresolved names: an identifier that is neither a declaration in any
|
|
3
|
+
* enclosing scope nor a runtime global.
|
|
4
|
+
*
|
|
5
|
+
* The binder already collects exactly this set (`BindResult.unresolved`); the
|
|
6
|
+
* checker only decides which entries are legitimate globals and reports the
|
|
7
|
+
* rest. Keeping the decision here (instead of in code generation) means a name
|
|
8
|
+
* error no longer depends on the identifier being lowered — dead code and
|
|
9
|
+
* unreachable branches are checked too.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { SourceFileNode } from "../ast/nodes.js";
|
|
13
|
+
import type { BindResult } from "../binder/binder.js";
|
|
14
|
+
import { DiagnosticCode, type DiagnosticBag } from "../diagnostics/diagnostic.js";
|
|
15
|
+
import { isKnownGlobalName } from "./globals.js";
|
|
16
|
+
import { fileNameOf, isDependencyNode } from "./source.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Names that are unresolved by design: `import.meta` is lowered through a
|
|
20
|
+
* namespace getter, `require` gets a dedicated "use ESM import" diagnostic
|
|
21
|
+
* from code generation, and `<error>` is the parser's recovery node.
|
|
22
|
+
*/
|
|
23
|
+
const SPECIAL_NAMES: ReadonlySet<string> = new Set(["import.meta", "require", "<error>"]);
|
|
24
|
+
|
|
25
|
+
export function checkUnresolvedNames(
|
|
26
|
+
sourceFile: SourceFileNode,
|
|
27
|
+
binding: BindResult,
|
|
28
|
+
diagnostics: DiagnosticBag,
|
|
29
|
+
extensionBuiltins?: ReadonlySet<string>,
|
|
30
|
+
): void {
|
|
31
|
+
for (const identifier of binding.unresolved) {
|
|
32
|
+
if (isDependencyNode(sourceFile, identifier)) continue;
|
|
33
|
+
const name = identifier.text;
|
|
34
|
+
if (SPECIAL_NAMES.has(name)) continue;
|
|
35
|
+
if (isKnownGlobalName(name, extensionBuiltins)) continue;
|
|
36
|
+
diagnostics.error(
|
|
37
|
+
DiagnosticCode.CannotFindName,
|
|
38
|
+
`Cannot find name '${name}'`,
|
|
39
|
+
identifier,
|
|
40
|
+
fileNameOf(sourceFile, identifier),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A depth-first walk over the AST.
|
|
3
|
+
*
|
|
4
|
+
* `childNodes` is the binder's generic child accessor: it visits every field
|
|
5
|
+
* that looks like a node, including type annotations and operator tokens. That
|
|
6
|
+
* is fine for the checks here — they only react to a handful of expression
|
|
7
|
+
* kinds, and tokens carry a string `kind` while AST nodes carry a numeric one.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Node } from "../ast/nodes.js";
|
|
11
|
+
import { childNodes } from "../binder/helpers.js";
|
|
12
|
+
|
|
13
|
+
export function walk(node: Node, visit: (node: Node) => void): void {
|
|
14
|
+
visit(node);
|
|
15
|
+
for (const child of childNodes(node)) walk(child, visit);
|
|
16
|
+
}
|