xbintsc 0.3.87 → 0.5.20
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 +23 -11
- package/README.md +11 -9
- package/README.zh-CN.md +7 -7
- package/dist/src/binder/declarations.js +14 -3
- package/dist/src/binder/declarations.js.map +1 -1
- package/dist/src/cli/hints.js +7 -1
- package/dist/src/cli/hints.js.map +1 -1
- package/dist/src/cli/main.js +115 -15
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/cli/watch.d.ts +25 -0
- package/dist/src/cli/watch.js +93 -0
- package/dist/src/cli/watch.js.map +1 -0
- package/dist/src/codegen/generator/calls/access.js +17 -4
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/calls/closures.js +13 -1
- package/dist/src/codegen/generator/calls/closures.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +4 -3
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +8 -0
- package/dist/src/codegen/generator/context.js +22 -3
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/operators.js +17 -15
- package/dist/src/codegen/generator/expressions/operators.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.js +11 -1
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/module.d.ts +0 -1
- package/dist/src/codegen/generator/module.js +10 -17
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/numeric.d.ts +6 -3
- package/dist/src/codegen/generator/numeric.js +54 -11
- package/dist/src/codegen/generator/numeric.js.map +1 -1
- package/dist/src/codegen/generator/state.js +27 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js +2 -7
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
- package/dist/src/codegen/generator/statements/loops.js +48 -16
- package/dist/src/codegen/generator/statements/loops.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +9 -0
- package/dist/src/codegen/generator/tables.js +100 -3
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/diagnostics/diagnostic.d.ts +3 -1
- package/dist/src/diagnostics/diagnostic.js +23 -3
- package/dist/src/diagnostics/diagnostic.js.map +1 -1
- package/dist/src/driver/app-artifacts.d.ts +42 -0
- package/dist/src/driver/app-artifacts.js +53 -0
- package/dist/src/driver/app-artifacts.js.map +1 -0
- package/dist/src/driver/build-key.d.ts +29 -0
- package/dist/src/driver/build-key.js +35 -0
- package/dist/src/driver/build-key.js.map +1 -0
- package/dist/src/driver/bundler/graph.js +61 -12
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +7 -1
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +10 -67
- package/dist/src/driver/compiler.js +94 -230
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +3 -0
- package/dist/src/driver/config.js +8 -0
- package/dist/src/driver/config.js.map +1 -1
- package/dist/src/driver/frontend.d.ts +37 -0
- package/dist/src/driver/frontend.js +92 -0
- package/dist/src/driver/frontend.js.map +1 -0
- package/dist/src/driver/index.d.ts +1 -1
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/options.d.ts +64 -0
- package/dist/src/driver/options.js +9 -0
- package/dist/src/driver/options.js.map +1 -0
- package/dist/src/driver/runtime-objects.d.ts +38 -0
- package/dist/src/driver/runtime-objects.js +111 -0
- package/dist/src/driver/runtime-objects.js.map +1 -0
- package/dist/src/driver/toolchain-provider.d.ts +4 -0
- package/dist/src/driver/toolchain-provider.js +4 -0
- package/dist/src/driver/toolchain-provider.js.map +1 -1
- package/dist/src/driver/toolchain.d.ts +32 -1
- package/dist/src/driver/toolchain.js +115 -11
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/driver/version.d.ts +12 -0
- package/dist/src/driver/version.js +13 -0
- package/dist/src/driver/version.js.map +1 -0
- package/dist/src/driver/win-icon.d.ts +7 -9
- package/dist/src/driver/win-icon.js +37 -35
- package/dist/src/driver/win-icon.js.map +1 -1
- package/dist/src/parser/declarations/classes.js +5 -0
- package/dist/src/parser/declarations/classes.js.map +1 -1
- package/dist/src/parser/declarations/functions.js +13 -1
- package/dist/src/parser/declarations/functions.js.map +1 -1
- package/dist/src/parser/modules.js +8 -3
- package/dist/src/parser/modules.js.map +1 -1
- package/dist/src/parser/parser.d.ts +1 -0
- package/dist/src/parser/parser.js +23 -0
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/tests/cli/check.test.d.ts +6 -0
- package/dist/tests/cli/check.test.js +68 -0
- package/dist/tests/cli/check.test.js.map +1 -0
- package/dist/tests/cli/main.test.js +19 -0
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/cli/watch.test.d.ts +6 -0
- package/dist/tests/cli/watch.test.js +72 -0
- package/dist/tests/cli/watch.test.js.map +1 -0
- package/dist/tests/codegen/closures.test.js +8 -0
- package/dist/tests/codegen/closures.test.js.map +1 -1
- package/dist/tests/codegen/expressions.test.js +15 -3
- package/dist/tests/codegen/expressions.test.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +16 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/diagnostics/diagnostic.test.js +8 -0
- package/dist/tests/diagnostics/diagnostic.test.js.map +1 -1
- package/dist/tests/docs/structure.test.d.ts +1 -0
- package/dist/tests/docs/structure.test.js +92 -0
- package/dist/tests/docs/structure.test.js.map +1 -0
- package/dist/tests/driver/compiler.test.js +6 -0
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/driver/config.test.js +9 -0
- package/dist/tests/driver/config.test.js.map +1 -1
- package/dist/tests/driver/icon.test.js +19 -32
- package/dist/tests/driver/icon.test.js.map +1 -1
- package/dist/tests/driver/invalid-input.test.d.ts +10 -0
- package/dist/tests/driver/invalid-input.test.js +29 -0
- package/dist/tests/driver/invalid-input.test.js.map +1 -0
- package/dist/tests/driver/modules.test.js +42 -3
- package/dist/tests/driver/modules.test.js.map +1 -1
- package/dist/tests/driver/toolchain-provider.test.js +27 -1
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/driver/toolchain.test.js +60 -2
- package/dist/tests/driver/toolchain.test.js.map +1 -1
- package/dist/tests/e2e/array-buffer.test.d.ts +5 -0
- package/dist/tests/e2e/array-buffer.test.js +38 -0
- package/dist/tests/e2e/array-buffer.test.js.map +1 -0
- package/dist/tests/e2e/array-from-iterables.test.d.ts +7 -0
- package/dist/tests/e2e/array-from-iterables.test.js +34 -0
- package/dist/tests/e2e/array-from-iterables.test.js.map +1 -0
- package/dist/tests/e2e/array-symbol-iterator.test.d.ts +8 -0
- package/dist/tests/e2e/array-symbol-iterator.test.js +42 -0
- package/dist/tests/e2e/array-symbol-iterator.test.js.map +1 -0
- package/dist/tests/e2e/async-await.test.d.ts +10 -0
- package/dist/tests/e2e/async-await.test.js +247 -0
- package/dist/tests/e2e/async-await.test.js.map +1 -0
- package/dist/tests/e2e/async-generators.test.d.ts +1 -0
- package/dist/tests/e2e/async-generators.test.js +154 -0
- package/dist/tests/e2e/async-generators.test.js.map +1 -0
- package/dist/tests/e2e/await-ordering.test.d.ts +5 -0
- package/dist/tests/e2e/await-ordering.test.js +37 -0
- package/dist/tests/e2e/await-ordering.test.js.map +1 -0
- package/dist/tests/e2e/compile-builtins.test.js +1 -1
- package/dist/tests/e2e/compile-modules.test.js +7 -0
- package/dist/tests/e2e/compile-modules.test.js.map +1 -1
- package/dist/tests/e2e/date-parse.test.d.ts +8 -0
- package/dist/tests/e2e/date-parse.test.js +38 -0
- package/dist/tests/e2e/date-parse.test.js.map +1 -0
- package/dist/tests/e2e/default-anonymous-exports.test.d.ts +7 -0
- package/dist/tests/e2e/default-anonymous-exports.test.js +23 -0
- package/dist/tests/e2e/default-anonymous-exports.test.js.map +1 -0
- package/dist/tests/e2e/globals-microtask.test.d.ts +9 -0
- package/dist/tests/e2e/globals-microtask.test.js +37 -0
- package/dist/tests/e2e/globals-microtask.test.js.map +1 -0
- package/dist/tests/e2e/gui-media.test.js +8 -1
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/inspect-builtins.test.d.ts +10 -0
- package/dist/tests/e2e/inspect-builtins.test.js +43 -0
- package/dist/tests/e2e/inspect-builtins.test.js.map +1 -0
- package/dist/tests/e2e/json-builtin-objects.test.d.ts +9 -0
- package/dist/tests/e2e/json-builtin-objects.test.js +23 -0
- package/dist/tests/e2e/json-builtin-objects.test.js.map +1 -0
- package/dist/tests/e2e/json-circular.test.d.ts +6 -0
- package/dist/tests/e2e/json-circular.test.js +43 -0
- package/dist/tests/e2e/json-circular.test.js.map +1 -0
- package/dist/tests/e2e/json-parse-reviver.test.d.ts +6 -0
- package/dist/tests/e2e/json-parse-reviver.test.js +29 -0
- package/dist/tests/e2e/json-parse-reviver.test.js.map +1 -0
- package/dist/tests/e2e/json-stringify-replacer.test.d.ts +6 -0
- package/dist/tests/e2e/json-stringify-replacer.test.js +27 -0
- package/dist/tests/e2e/json-stringify-replacer.test.js.map +1 -0
- package/dist/tests/e2e/json-stringify-space.test.d.ts +6 -0
- package/dist/tests/e2e/json-stringify-space.test.js +23 -0
- package/dist/tests/e2e/json-stringify-space.test.js.map +1 -0
- package/dist/tests/e2e/method-dispatch-errors.test.d.ts +9 -0
- package/dist/tests/e2e/method-dispatch-errors.test.js +38 -0
- package/dist/tests/e2e/method-dispatch-errors.test.js.map +1 -0
- package/dist/tests/e2e/native-extensions.test.js +1 -1
- package/dist/tests/e2e/native-extensions.test.js.map +1 -1
- package/dist/tests/e2e/promise-with-resolvers.test.d.ts +5 -0
- package/dist/tests/e2e/promise-with-resolvers.test.js +20 -0
- package/dist/tests/e2e/promise-with-resolvers.test.js.map +1 -0
- package/dist/tests/e2e/property-descriptors.test.d.ts +5 -0
- package/dist/tests/e2e/property-descriptors.test.js +25 -0
- package/dist/tests/e2e/property-descriptors.test.js.map +1 -0
- package/dist/tests/e2e/property-ic.test.d.ts +1 -0
- package/dist/tests/e2e/property-ic.test.js +55 -0
- package/dist/tests/e2e/property-ic.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js +46 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js.map +1 -1
- package/dist/tests/e2e/runtime-errors.test.d.ts +10 -0
- package/dist/tests/e2e/runtime-errors.test.js +52 -0
- package/dist/tests/e2e/runtime-errors.test.js.map +1 -0
- package/dist/tests/e2e/string-utf16.test.d.ts +6 -0
- package/dist/tests/e2e/string-utf16.test.js +133 -0
- package/dist/tests/e2e/string-utf16.test.js.map +1 -0
- package/dist/tests/e2e/structured-clone.test.d.ts +6 -0
- package/dist/tests/e2e/structured-clone.test.js +49 -0
- package/dist/tests/e2e/structured-clone.test.js.map +1 -0
- package/dist/tests/e2e/text-codec.test.d.ts +6 -0
- package/dist/tests/e2e/text-codec.test.js +24 -0
- package/dist/tests/e2e/text-codec.test.js.map +1 -0
- package/dist/tests/e2e/typed-array-views.test.d.ts +6 -0
- package/dist/tests/e2e/typed-array-views.test.js +39 -0
- package/dist/tests/e2e/typed-array-views.test.js.map +1 -0
- package/dist/tests/e2e/url-search-params.test.d.ts +5 -0
- package/dist/tests/e2e/url-search-params.test.js +30 -0
- package/dist/tests/e2e/url-search-params.test.js.map +1 -0
- package/dist/tests/e2e/weak-collections.test.d.ts +1 -0
- package/dist/tests/e2e/weak-collections.test.js +88 -0
- package/dist/tests/e2e/weak-collections.test.js.map +1 -0
- package/dist/tests/parser/declarations.test.js +12 -0
- package/dist/tests/parser/declarations.test.js.map +1 -1
- package/dist/tests/parser/module-syntax.test.js +9 -0
- package/dist/tests/parser/module-syntax.test.js.map +1 -1
- package/dist/tests/parser/parser.test.js +7 -0
- package/dist/tests/parser/parser.test.js.map +1 -1
- package/dist/tests/version.test.js +5 -1
- package/dist/tests/version.test.js.map +1 -1
- package/doc/ai/README.md +4 -3
- package/doc/ai/cli.md +41 -0
- package/doc/ai/contributing.md +26 -21
- package/doc/ai/extensions.md +12 -9
- package/doc/ai/language-support.md +26 -19
- package/doc/ai/troubleshooting.md +15 -12
- package/doc/ai/zh-CN/README.md +3 -2
- package/doc/ai/zh-CN/cli.md +35 -0
- package/doc/ai/zh-CN/contributing.md +19 -18
- package/doc/ai/zh-CN/extensions.md +10 -7
- package/doc/ai/zh-CN/language-support.md +26 -20
- package/doc/ai/zh-CN/troubleshooting.md +12 -10
- package/doc/gui/build.md +13 -4
- package/doc/gui/known-issues.md +9 -5
- package/doc/gui/rendering.md +3 -1
- package/doc/gui.md +4 -3
- package/doc/icon.md +5 -4
- package/doc/implemented/async.md +38 -0
- package/doc/implemented/binder.md +13 -0
- package/doc/implemented/cli.md +47 -0
- package/doc/implemented/codegen.md +33 -0
- package/doc/implemented/collections.md +26 -0
- package/doc/implemented/driver.md +19 -0
- package/doc/implemented/extensions.md +19 -0
- package/doc/implemented/fetch.md +12 -0
- package/doc/implemented/lexer.md +23 -0
- package/doc/implemented/modules.md +28 -0
- package/doc/implemented/node/assert.md +17 -0
- package/doc/implemented/node/buffer.md +29 -0
- package/doc/implemented/node/child-process.md +29 -0
- package/doc/implemented/node/crypto.md +9 -0
- package/doc/implemented/node/dgram.md +15 -0
- package/doc/implemented/node/events.md +37 -0
- package/doc/implemented/node/fs-promises.md +38 -0
- package/doc/implemented/node/fs.md +112 -0
- package/doc/implemented/node/http.md +21 -0
- package/doc/implemented/node/net.md +17 -0
- package/doc/implemented/node/os.md +22 -0
- package/doc/implemented/node/path.md +33 -0
- package/doc/implemented/node/process.md +23 -0
- package/doc/implemented/node/querystring.md +20 -0
- package/doc/implemented/node/stream-promises.md +8 -0
- package/doc/implemented/node/stream.md +19 -0
- package/doc/implemented/node/test.md +10 -0
- package/doc/implemented/node/url.md +8 -0
- package/doc/implemented/node/util.md +25 -0
- package/doc/implemented/node/worker-threads.md +10 -0
- package/doc/implemented/node/zlib.md +8 -0
- package/doc/implemented/node.md +48 -0
- package/doc/implemented/operators.md +38 -0
- package/doc/implemented/parser.md +58 -0
- package/doc/implemented/pipeline.md +28 -0
- package/doc/implemented/runtime-core.md +32 -0
- package/doc/implemented/stdlib.md +78 -0
- package/doc/implemented/strings.md +27 -0
- package/doc/implemented/tests.md +10 -0
- package/doc/implemented/typed-arrays.md +26 -0
- package/doc/implemented/value-model.md +18 -0
- package/doc/implemented.md +54 -352
- package/doc/node-implemented.md +3 -585
- package/doc/node-unimplemented.md +3 -164
- package/doc/requirements.md +23 -8
- package/doc/unimplemented/classes.md +22 -0
- package/doc/unimplemented/deviations.md +27 -0
- package/doc/unimplemented/expressions.md +26 -0
- package/doc/unimplemented/functions.md +21 -0
- package/doc/unimplemented/modules.md +22 -0
- package/doc/unimplemented/node/async.md +17 -0
- package/doc/unimplemented/node/bun.md +9 -0
- package/doc/unimplemented/node/fs-promises.md +16 -0
- package/doc/unimplemented/node/fs.md +31 -0
- package/doc/unimplemented/node/globals.md +23 -0
- package/doc/unimplemented/node/modules.md +21 -0
- package/doc/unimplemented/node.md +21 -0
- package/doc/unimplemented/statements.md +18 -0
- package/doc/unimplemented/stdlib.md +54 -0
- package/doc/unimplemented/toolchain.md +14 -0
- package/doc/unimplemented/types.md +12 -0
- package/doc/unimplemented.md +18 -274
- package/doc/xbintsc.config.schema.json +12 -0
- package/doc/zh-CN/gui/build.md +11 -3
- package/doc/zh-CN/gui/known-issues.md +9 -4
- package/doc/zh-CN/gui/rendering.md +2 -1
- package/doc/zh-CN/gui.md +3 -2
- package/doc/zh-CN/icon.md +5 -4
- package/doc/zh-CN/implemented/async.md +38 -0
- package/doc/zh-CN/implemented/binder.md +13 -0
- package/doc/zh-CN/implemented/cli.md +46 -0
- package/doc/zh-CN/implemented/codegen.md +33 -0
- package/doc/zh-CN/implemented/collections.md +26 -0
- package/doc/zh-CN/implemented/driver.md +19 -0
- package/doc/zh-CN/implemented/extensions.md +19 -0
- package/doc/zh-CN/implemented/fetch.md +12 -0
- package/doc/zh-CN/implemented/lexer.md +23 -0
- package/doc/zh-CN/implemented/modules.md +28 -0
- package/doc/zh-CN/implemented/node/assert.md +17 -0
- package/doc/zh-CN/implemented/node/buffer.md +25 -0
- package/doc/zh-CN/implemented/node/child-process.md +27 -0
- package/doc/zh-CN/implemented/node/crypto.md +9 -0
- package/doc/zh-CN/implemented/node/dgram.md +15 -0
- package/doc/zh-CN/implemented/node/events.md +36 -0
- package/doc/zh-CN/implemented/node/fs-promises.md +27 -0
- package/doc/zh-CN/implemented/node/fs.md +105 -0
- package/doc/zh-CN/implemented/node/http.md +17 -0
- package/doc/zh-CN/implemented/node/net.md +17 -0
- package/doc/zh-CN/implemented/node/os.md +21 -0
- package/doc/zh-CN/implemented/node/path.md +26 -0
- package/doc/zh-CN/implemented/node/process.md +23 -0
- package/doc/zh-CN/implemented/node/querystring.md +20 -0
- package/doc/zh-CN/implemented/node/stream-promises.md +8 -0
- package/doc/zh-CN/implemented/node/stream.md +15 -0
- package/doc/zh-CN/implemented/node/test.md +10 -0
- package/doc/zh-CN/implemented/node/url.md +8 -0
- package/doc/zh-CN/implemented/node/util.md +25 -0
- package/doc/zh-CN/implemented/node/worker-threads.md +9 -0
- package/doc/zh-CN/implemented/node/zlib.md +8 -0
- package/doc/zh-CN/implemented/node.md +45 -0
- package/doc/zh-CN/implemented/operators.md +38 -0
- package/doc/zh-CN/implemented/parser.md +58 -0
- package/doc/zh-CN/implemented/pipeline.md +25 -0
- package/doc/zh-CN/implemented/runtime-core.md +31 -0
- package/doc/zh-CN/implemented/stdlib.md +76 -0
- package/doc/zh-CN/implemented/strings.md +27 -0
- package/doc/zh-CN/implemented/tests.md +10 -0
- package/doc/zh-CN/implemented/typed-arrays.md +26 -0
- package/doc/zh-CN/implemented/value-model.md +18 -0
- package/doc/zh-CN/implemented.md +50 -347
- package/doc/zh-CN/node-implemented.md +4 -531
- package/doc/zh-CN/node-unimplemented.md +4 -139
- package/doc/zh-CN/plan-require-node-modules.md +4 -4
- package/doc/zh-CN/requirements.md +20 -6
- package/doc/zh-CN/unimplemented/classes.md +22 -0
- package/doc/zh-CN/unimplemented/deviations.md +24 -0
- package/doc/zh-CN/unimplemented/expressions.md +24 -0
- package/doc/zh-CN/unimplemented/functions.md +21 -0
- package/doc/zh-CN/unimplemented/modules.md +19 -0
- package/doc/zh-CN/unimplemented/node/async.md +17 -0
- package/doc/zh-CN/unimplemented/node/bun.md +8 -0
- package/doc/zh-CN/unimplemented/node/fs-promises.md +12 -0
- package/doc/zh-CN/unimplemented/node/fs.md +24 -0
- package/doc/zh-CN/unimplemented/node/globals.md +14 -0
- package/doc/zh-CN/unimplemented/node/modules.md +15 -0
- package/doc/zh-CN/unimplemented/node.md +18 -0
- package/doc/zh-CN/unimplemented/statements.md +15 -0
- package/doc/zh-CN/unimplemented/stdlib.md +54 -0
- package/doc/zh-CN/unimplemented/toolchain.md +14 -0
- package/doc/zh-CN/unimplemented/types.md +11 -0
- package/doc/zh-CN/unimplemented.md +14 -236
- package/llms.txt +32 -4
- package/package.json +1 -1
- package/runtime/ext_gui/renderer_shaders.h +2 -2
- package/runtime/ext_gui/stb_image.h +1 -17
- package/runtime/ext_node/child_process/child_process.c +173 -73
- package/runtime/rt.h +47 -0
- package/runtime/rt_internal.h +205 -10
- package/runtime/xt_alloc.c +49 -7
- package/runtime/xt_array_buffer.c +284 -0
- package/runtime/xt_async.c +222 -0
- package/runtime/xt_bigint/helpers.inc +3 -3
- package/runtime/xt_builtins.c +59 -51
- package/runtime/xt_constructors.c +399 -0
- package/runtime/xt_containers/access.inc +195 -14
- package/runtime/xt_containers/arrays.inc +26 -2
- package/runtime/xt_containers/objects.inc +226 -5
- package/runtime/xt_containers/shapes.inc +71 -0
- package/runtime/xt_containers.c +1 -0
- package/runtime/xt_coroutine.c +229 -0
- package/runtime/xt_generator.c +325 -167
- package/runtime/xt_io/inspect.inc +147 -2
- package/runtime/xt_loop.c +35 -4
- package/runtime/xt_performance.c +37 -0
- package/runtime/xt_promise.c +125 -18
- package/runtime/xt_stdlib/arrays.inc +1 -1
- package/runtime/xt_stdlib/dispatch.inc +64 -13
- package/runtime/xt_stdlib/strings.inc +74 -17
- package/runtime/xt_stdlib2/array-statics.inc +28 -3
- package/runtime/xt_stdlib2/arrays.inc +5 -3
- package/runtime/xt_stdlib2/container.inc +5 -0
- package/runtime/xt_stdlib2/date.inc +111 -3
- package/runtime/xt_stdlib2/error.inc +35 -0
- package/runtime/xt_stdlib2/json.inc +353 -33
- package/runtime/xt_stdlib2/number-string-statics.inc +24 -15
- package/runtime/xt_stdlib2/objects.inc +123 -1
- package/runtime/xt_stdlib2/regexp-match.inc +2 -2
- package/runtime/xt_stdlib2/set.inc +7 -1
- package/runtime/xt_stdlib2/strings.inc +70 -40
- package/runtime/xt_structured_clone.c +159 -0
- package/runtime/xt_symbol.c +2 -2
- package/runtime/xt_text_codec.c +69 -0
- package/runtime/xt_typed_array/construction.inc +78 -7
- package/runtime/xt_typed_array/elements.inc +159 -0
- package/runtime/xt_typed_array/methods.inc +21 -5
- package/runtime/xt_typed_array.c +11 -10
- package/runtime/xt_url.c +375 -0
- package/runtime/xt_values/arithmetic.inc +2 -2
- package/runtime/xt_values/constructors.inc +8 -0
- package/runtime/xt_values/conversions.inc +1 -1
- package/runtime/xt_values/strings.inc +19 -3
- package/runtime/xt_values/utf16.inc +340 -0
- package/runtime/xt_values.c +1 -0
- package/runtime/xt_weak.c +281 -0
- package/scripts/build-gui.ts +133 -60
- package/scripts/check-version.ts +3 -3
- package/src/binder/declarations.ts +14 -3
- package/src/cli/hints.ts +8 -1
- package/src/cli/main.ts +119 -18
- package/src/cli/watch.ts +101 -0
- package/src/codegen/generator/calls/access.ts +17 -4
- package/src/codegen/generator/calls/closures.ts +12 -1
- package/src/codegen/generator/calls/invocation.ts +4 -3
- package/src/codegen/generator/context.ts +23 -3
- package/src/codegen/generator/expressions/operators.ts +27 -13
- package/src/codegen/generator/expressions/primary.ts +10 -1
- package/src/codegen/generator/module.ts +10 -19
- package/src/codegen/generator/numeric.ts +85 -11
- package/src/codegen/generator/state.ts +27 -0
- package/src/codegen/generator/statements/control-flow.ts +2 -6
- package/src/codegen/generator/statements/loops.ts +50 -16
- package/src/codegen/generator/tables.ts +110 -3
- package/src/diagnostics/diagnostic.ts +23 -3
- package/src/driver/app-artifacts.ts +77 -0
- package/src/driver/build-key.ts +55 -0
- package/src/driver/bundler/graph.ts +63 -13
- package/src/driver/bundler/merge.ts +4 -1
- package/src/driver/compiler.ts +93 -324
- package/src/driver/config.ts +11 -0
- package/src/driver/frontend.ts +120 -0
- package/src/driver/index.ts +0 -1
- package/src/driver/options.ts +70 -0
- package/src/driver/runtime-objects.ts +133 -0
- package/src/driver/toolchain-provider.ts +4 -0
- package/src/driver/toolchain.ts +154 -10
- package/src/driver/version.ts +12 -0
- package/src/driver/win-icon.ts +36 -36
- package/src/parser/declarations/classes.ts +4 -0
- package/src/parser/declarations/functions.ts +12 -1
- package/src/parser/modules.ts +8 -4
- package/src/parser/parser.ts +28 -0
package/src/cli/watch.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `xbintsc watch` support: fingerprint a source tree and rebuild when it
|
|
3
|
+
* changes.
|
|
4
|
+
*
|
|
5
|
+
* The scan is deliberately polling-based. A self-hosted xbintsc binary has no
|
|
6
|
+
* `fs.watch` backend in the Node extension, and polling works identically on
|
|
7
|
+
* every platform. The tree is the entry file's directory, with build outputs
|
|
8
|
+
* and dependency directories excluded; package sources inside `node_modules`
|
|
9
|
+
* are not watched (run the build once after installing a dependency).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { readFileSync, readdirSync, statSync, type Dirent } from "node:fs";
|
|
13
|
+
import { extname, join, resolve } from "node:path";
|
|
14
|
+
|
|
15
|
+
const WATCHED_EXTENSIONS = new Set([
|
|
16
|
+
".ts",
|
|
17
|
+
".tsx",
|
|
18
|
+
".js",
|
|
19
|
+
".mjs",
|
|
20
|
+
".cjs",
|
|
21
|
+
".json",
|
|
22
|
+
".html",
|
|
23
|
+
".css",
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
const IGNORED_DIRECTORIES = new Set([
|
|
27
|
+
"node_modules",
|
|
28
|
+
".git",
|
|
29
|
+
".github",
|
|
30
|
+
".xbintsc",
|
|
31
|
+
".xbintsc-cache",
|
|
32
|
+
"build",
|
|
33
|
+
"dist",
|
|
34
|
+
"coverage",
|
|
35
|
+
"scratch",
|
|
36
|
+
"target",
|
|
37
|
+
"vendor",
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
/** One string that changes whenever a watched file changes. */
|
|
41
|
+
export function fingerprintTree(root: string): string {
|
|
42
|
+
const entries: string[] = [];
|
|
43
|
+
collect(resolve(root), entries);
|
|
44
|
+
entries.sort();
|
|
45
|
+
return entries.join("|");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function collect(directory: string, out: string[]): void {
|
|
49
|
+
let entries: Dirent[];
|
|
50
|
+
try {
|
|
51
|
+
entries = readdirSync(directory, { withFileTypes: true });
|
|
52
|
+
} catch {
|
|
53
|
+
return; // the directory disappeared between scans
|
|
54
|
+
}
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
const path = join(directory, entry.name);
|
|
57
|
+
if (entry.isDirectory()) {
|
|
58
|
+
if (!IGNORED_DIRECTORIES.has(entry.name)) collect(path, out);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (!entry.isFile()) continue;
|
|
62
|
+
if (!WATCHED_EXTENSIONS.has(extname(entry.name).toLowerCase())) continue;
|
|
63
|
+
try {
|
|
64
|
+
const stat = statSync(path);
|
|
65
|
+
/* mtime resolution is coarse on some filesystems (and on Windows two
|
|
66
|
+
* same-size writes can share a timestamp), so hash the bytes as well. */
|
|
67
|
+
let hash = 2166136261;
|
|
68
|
+
const contents = readFileSync(path);
|
|
69
|
+
for (let i = 0; i < contents.length; i++) {
|
|
70
|
+
hash = Math.imul(hash ^ (contents[i] ?? 0), 16777619);
|
|
71
|
+
}
|
|
72
|
+
out.push(`${path}:${stat.mtimeMs}:${stat.size}:${hash >>> 0}`);
|
|
73
|
+
} catch {
|
|
74
|
+
// A file removed during the scan is picked up by the next iteration.
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface WatchOptions {
|
|
80
|
+
/** Current fingerprint of everything that should trigger a rebuild. */
|
|
81
|
+
readonly scan: () => string;
|
|
82
|
+
/** Called after the fingerprint changes. Must be synchronous. */
|
|
83
|
+
readonly onRebuild: () => void;
|
|
84
|
+
/** Poll interval; defaults to 300 ms. */
|
|
85
|
+
readonly intervalMs?: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Start polling. Returns a stop function. The caller performs the initial
|
|
90
|
+
* build, so this never fires `onRebuild` for the state it starts in.
|
|
91
|
+
*/
|
|
92
|
+
export function startWatching(options: WatchOptions): () => void {
|
|
93
|
+
let previous = options.scan();
|
|
94
|
+
const timer = setInterval(() => {
|
|
95
|
+
const next = options.scan();
|
|
96
|
+
if (next === previous) return;
|
|
97
|
+
previous = next;
|
|
98
|
+
options.onRebuild();
|
|
99
|
+
}, options.intervalMs ?? 300);
|
|
100
|
+
return () => clearInterval(timer);
|
|
101
|
+
}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
type PropertyAccessExpression,
|
|
14
14
|
} from "../../../ast/nodes.js";
|
|
15
15
|
import { i64, numberLiteral, XT_TRUE, XT_UNDEFINED } from "../../values.js";
|
|
16
|
-
import { MATH_CONSTANTS, NAMESPACE_PROPERTIES, NUMBER_CONSTANTS, TYPED_ARRAYS } from "../tables.js";
|
|
16
|
+
import { MATH_CONSTANTS, NAMESPACE_PROPERTIES, NUMBER_CONSTANTS, SYMBOL_WELL_KNOWN, TYPED_ARRAYS } from "../tables.js";
|
|
17
17
|
import type { Generator } from "../generator.js";
|
|
18
18
|
|
|
19
19
|
export interface AccessCallMethods {
|
|
@@ -85,7 +85,12 @@ export const accessCallMethods: AccessCallMethods = {
|
|
|
85
85
|
!this.binding.symbolOfIdentifier.get(node.expression as Identifier)
|
|
86
86
|
) {
|
|
87
87
|
const getter = NAMESPACE_PROPERTIES[(node.expression as Identifier).text];
|
|
88
|
-
|
|
88
|
+
/* `Symbol.iterator` & friends are well-known symbol values, but
|
|
89
|
+
* `Symbol.prototype` / `.name` / `.length` are ordinary properties of
|
|
90
|
+
* the first-class constructor value. */
|
|
91
|
+
const symbolGetter =
|
|
92
|
+
(node.expression as Identifier).text === "Symbol" && SYMBOL_WELL_KNOWN.has(node.name.text);
|
|
93
|
+
if (getter && (getter !== "xt_symbol_get" || symbolGetter)) {
|
|
89
94
|
const key = this.stringValue(node.name.text);
|
|
90
95
|
const result = this.reg();
|
|
91
96
|
this.emit(` ${result} = call i64 @${getter}(i64 ${key})`);
|
|
@@ -138,7 +143,14 @@ export const accessCallMethods: AccessCallMethods = {
|
|
|
138
143
|
const access = (): string => {
|
|
139
144
|
const key = this.emitExpression(node.argumentExpression);
|
|
140
145
|
const result = this.reg();
|
|
141
|
-
|
|
146
|
+
/* Array-index reads are not object property layouts, so skip the IC for
|
|
147
|
+
* a numeric literal; every other key may benefit from it. */
|
|
148
|
+
if (node.argumentExpression.kind === SyntaxKind.NumericLiteral) {
|
|
149
|
+
this.emit(` ${result} = call i64 @xt_get(i64 ${object}, i64 ${key})`);
|
|
150
|
+
} else {
|
|
151
|
+
const cache = this.icCachePointer();
|
|
152
|
+
this.emit(` ${result} = call i64 @xt_get_ic(i64 ${object}, i64 ${key}, i64* ${cache})`);
|
|
153
|
+
}
|
|
142
154
|
return result;
|
|
143
155
|
};
|
|
144
156
|
return node.optional ? this.emitOptional(object, access) : access();
|
|
@@ -153,8 +165,9 @@ export const accessCallMethods: AccessCallMethods = {
|
|
|
153
165
|
return result;
|
|
154
166
|
}
|
|
155
167
|
const key = this.stringValue(name);
|
|
168
|
+
const cache = this.icCachePointer();
|
|
156
169
|
const result = this.reg();
|
|
157
|
-
this.emit(` ${result} = call i64 @
|
|
170
|
+
this.emit(` ${result} = call i64 @xt_get_ic(i64 ${object}, i64 ${key}, i64* ${cache})`);
|
|
158
171
|
return result;
|
|
159
172
|
},
|
|
160
173
|
|
|
@@ -79,6 +79,17 @@ export const closureCallMethods: ClosureCallMethods = {
|
|
|
79
79
|
if (fn.isConstructor && fn.classInfo) name = fn.classInfo.name;
|
|
80
80
|
const nameValue = this.stringValue(name);
|
|
81
81
|
this.emit(` call i64 @xt_function_set_metadata(i64 ${closure}, i64 ${nameValue}, i32 ${arity})`);
|
|
82
|
-
if (fn.isGenerator)
|
|
82
|
+
if (fn.isAsync && fn.isGenerator) {
|
|
83
|
+
/* `async function*`: a generator whose `.next()` returns promises. The
|
|
84
|
+
* runtime needs both flags, so use the combined marker instead of the
|
|
85
|
+
* two separate setters. */
|
|
86
|
+
this.emit(` call i64 @xt_function_set_async_generator(i64 ${closure})`);
|
|
87
|
+
} else if (fn.isGenerator) {
|
|
88
|
+
this.emit(` call i64 @xt_function_set_generator(i64 ${closure})`);
|
|
89
|
+
} else if (fn.isAsync) {
|
|
90
|
+
/* `async` functions run on a coroutine: the runtime must know at call
|
|
91
|
+
* time so it can return a promise and suspend at `await`. */
|
|
92
|
+
this.emit(` call i64 @xt_function_set_async(i64 ${closure})`);
|
|
93
|
+
}
|
|
83
94
|
},
|
|
84
95
|
};
|
|
@@ -109,9 +109,10 @@ export const invocationCallMethods: InvocationCallMethods = {
|
|
|
109
109
|
if (symbol && symbol.kind === SymbolKind.Function) {
|
|
110
110
|
const declaration = symbol.declarations[0];
|
|
111
111
|
const fn = declaration ? this.binding.functionOfNode.get(declaration) : undefined;
|
|
112
|
-
/* Generator functions are not called directly: the call
|
|
113
|
-
* suspended generator
|
|
114
|
-
|
|
112
|
+
/* Generator and `async` functions are not called directly: the call
|
|
113
|
+
* must create a suspended generator / start a coroutine, so fall
|
|
114
|
+
* through to the closure-call path. */
|
|
115
|
+
if (fn && !fn.isGenerator && !fn.isAsync) {
|
|
115
116
|
const args = this.emitArguments(node.arguments);
|
|
116
117
|
const result = this.reg();
|
|
117
118
|
this.emit(
|
|
@@ -64,6 +64,8 @@ export class GeneratorContext {
|
|
|
64
64
|
readonly lineStartsByFile = new Map<string, number[]>();
|
|
65
65
|
stringCounter = 0;
|
|
66
66
|
staticCounter = 0;
|
|
67
|
+
/** Monotonic id for per-property-access inline-cache globals. */
|
|
68
|
+
icCounter = 0;
|
|
67
69
|
/**
|
|
68
70
|
* How many `UnsupportedFeature` diagnostics the function currently being
|
|
69
71
|
* emitted produced. Unsupported constructs can leave the generator with a
|
|
@@ -187,8 +189,8 @@ export class GeneratorContext {
|
|
|
187
189
|
if (!symbols.some((symbol) => this.usedAsValue(symbol))) return;
|
|
188
190
|
this.diagnostics.error(
|
|
189
191
|
DiagnosticCode.ModuleNotFound,
|
|
190
|
-
`module '${specifier}' is not supported:
|
|
191
|
-
"relative
|
|
192
|
+
`module '${specifier}' is not supported: expected a Node built-in ` +
|
|
193
|
+
"(with --ext node), a relative .ts/.js file, or a package in node_modules",
|
|
192
194
|
declaration.moduleSpecifier,
|
|
193
195
|
this.fileNameOf(declaration.moduleSpecifier),
|
|
194
196
|
);
|
|
@@ -309,6 +311,19 @@ export class GeneratorContext {
|
|
|
309
311
|
return ptr;
|
|
310
312
|
}
|
|
311
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Allocate a two-word inline cache for one property-access site and return
|
|
316
|
+
* the `i64*` the runtime fills with (shape, property index). The global is
|
|
317
|
+
* zero-initialised, which the runtime treats as an empty cache.
|
|
318
|
+
*/
|
|
319
|
+
icCachePointer(): string {
|
|
320
|
+
const name = `@ic.${this.icCounter++}`;
|
|
321
|
+
this.globals.push(`${name} = internal global [2 x i64] zeroinitializer`);
|
|
322
|
+
const ptr = this.reg();
|
|
323
|
+
this.emit(` ${ptr} = getelementptr [2 x i64], [2 x i64]* ${name}, i64 0, i64 0`);
|
|
324
|
+
return ptr;
|
|
325
|
+
}
|
|
326
|
+
|
|
312
327
|
/** Lay already-computed values out as a contiguous `i64*` argument buffer. */
|
|
313
328
|
emitValueArguments(values: readonly string[]): { argc: string; ptr: string } {
|
|
314
329
|
if (values.length === 0) return { argc: "0", ptr: "null" };
|
|
@@ -517,10 +532,15 @@ export class GeneratorContext {
|
|
|
517
532
|
|
|
518
533
|
unsupported(node: Node, what: string): void {
|
|
519
534
|
const label = kindName(node.kind);
|
|
535
|
+
const hasName = label !== String(node.kind);
|
|
536
|
+
/* `unsupported(statement, "statement")` is the generic fallback; when the
|
|
537
|
+
* syntax kind has a human name, use it directly instead of appending a
|
|
538
|
+
* redundant "(statement)". */
|
|
539
|
+
const subject = what === "statement" && hasName ? `this ${label}` : `this ${what} (${label})`;
|
|
520
540
|
this.unsupportedCount++;
|
|
521
541
|
this.diagnostics.error(
|
|
522
542
|
DiagnosticCode.UnsupportedFeature,
|
|
523
|
-
`xbintsc does not yet support
|
|
543
|
+
`xbintsc does not yet support ${subject}`,
|
|
524
544
|
node,
|
|
525
545
|
this.fileNameOf(node),
|
|
526
546
|
);
|
|
@@ -24,6 +24,15 @@ function isStringLike(node: Expression): boolean {
|
|
|
24
24
|
return node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NoSubstitutionTemplateLiteral;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/** True for a numeric literal (optionally signed), whose tag check can be skipped. */
|
|
28
|
+
function isNumericLiteral(node: Expression): boolean {
|
|
29
|
+
if (node.kind === SyntaxKind.NumericLiteral) return true;
|
|
30
|
+
if (node.kind !== SyntaxKind.PrefixUnaryExpression) return false;
|
|
31
|
+
const prefix = node as PrefixUnaryExpression;
|
|
32
|
+
if (prefix.operator !== PrefixUnaryOperator.Minus && prefix.operator !== PrefixUnaryOperator.Plus) return false;
|
|
33
|
+
return prefix.operand.kind === SyntaxKind.NumericLiteral;
|
|
34
|
+
}
|
|
35
|
+
|
|
27
36
|
/**
|
|
28
37
|
* The built-in constructor a right-hand `instanceof` operand names, if any.
|
|
29
38
|
* A user binding with the same name shadows it.
|
|
@@ -84,7 +93,15 @@ export const operatorExpressionMethods: OperatorExpressionMethods = {
|
|
|
84
93
|
// `+` concatenates when either side is known to be a string; skip the
|
|
85
94
|
// numeric tag checks for that shape and call the runtime directly.
|
|
86
95
|
const knownStringConcat = operator === "+" && (isStringLike(node.left) || isStringLike(node.right));
|
|
87
|
-
return this.emitBinaryOperation(
|
|
96
|
+
return this.emitBinaryOperation(
|
|
97
|
+
left,
|
|
98
|
+
right,
|
|
99
|
+
operator,
|
|
100
|
+
runtime,
|
|
101
|
+
!knownStringConcat,
|
|
102
|
+
isNumericLiteral(node.left),
|
|
103
|
+
isNumericLiteral(node.right),
|
|
104
|
+
);
|
|
88
105
|
},
|
|
89
106
|
|
|
90
107
|
emitShortCircuit(node: BinaryExpression, kind: "and" | "or" | "nullish"): string {
|
|
@@ -95,15 +112,9 @@ export const operatorExpressionMethods: OperatorExpressionMethods = {
|
|
|
95
112
|
const endLabel = this.label("sc.end");
|
|
96
113
|
let condition: string;
|
|
97
114
|
if (kind === "and") {
|
|
98
|
-
|
|
99
|
-
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${left})`);
|
|
100
|
-
condition = this.reg();
|
|
101
|
-
this.emit(` ${condition} = icmp ne i32 ${truthy}, 0`);
|
|
115
|
+
condition = this.emitTruthiness(left, node.left);
|
|
102
116
|
} else if (kind === "or") {
|
|
103
|
-
const
|
|
104
|
-
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${left})`);
|
|
105
|
-
const isTruthy = this.reg();
|
|
106
|
-
this.emit(` ${isTruthy} = icmp ne i32 ${truthy}, 0`);
|
|
117
|
+
const isTruthy = this.emitTruthiness(left, node.left);
|
|
107
118
|
condition = this.reg();
|
|
108
119
|
this.emit(` ${condition} = xor i1 ${isTruthy}, true`);
|
|
109
120
|
} else {
|
|
@@ -128,10 +139,7 @@ export const operatorExpressionMethods: OperatorExpressionMethods = {
|
|
|
128
139
|
emitConditional(node: ConditionalExpression): string {
|
|
129
140
|
const result = this.alloca();
|
|
130
141
|
const condition = this.emitExpression(node.condition);
|
|
131
|
-
const
|
|
132
|
-
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${condition})`);
|
|
133
|
-
const nonzero = this.reg();
|
|
134
|
-
this.emit(` ${nonzero} = icmp ne i32 ${truthy}, 0`);
|
|
142
|
+
const nonzero = this.emitTruthiness(condition, node.condition);
|
|
135
143
|
const trueLabel = this.label("cond.true");
|
|
136
144
|
const falseLabel = this.label("cond.false");
|
|
137
145
|
const endLabel = this.label("cond.end");
|
|
@@ -195,6 +203,9 @@ export const operatorExpressionMethods: OperatorExpressionMethods = {
|
|
|
195
203
|
one,
|
|
196
204
|
node.operator === PrefixUnaryOperator.PlusPlus ? "+" : "-",
|
|
197
205
|
fn,
|
|
206
|
+
true,
|
|
207
|
+
false,
|
|
208
|
+
true,
|
|
198
209
|
);
|
|
199
210
|
this.emitAssignmentTarget(node.operand, next);
|
|
200
211
|
return next;
|
|
@@ -214,6 +225,9 @@ export const operatorExpressionMethods: OperatorExpressionMethods = {
|
|
|
214
225
|
one,
|
|
215
226
|
node.operator === PostfixUnaryOperator.PlusPlus ? "+" : "-",
|
|
216
227
|
fn,
|
|
228
|
+
true,
|
|
229
|
+
false,
|
|
230
|
+
true,
|
|
217
231
|
);
|
|
218
232
|
this.emitAssignmentTarget(node.operand, next);
|
|
219
233
|
return current;
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
import { SymbolKind, type SymbolInfo } from "../../../binder/binder.js";
|
|
29
29
|
import { DiagnosticCode } from "../../../diagnostics/diagnostic.js";
|
|
30
30
|
import { i64, numberLiteral, XT_FALSE, XT_NULL, XT_TRUE, XT_UNDEFINED } from "../../values.js";
|
|
31
|
-
import { BUILTIN_FUNCTION_VALUES, CTOR_FUNCTIONS, ERROR_CONSTRUCTORS } from "../tables.js";
|
|
31
|
+
import { BUILTIN_FUNCTION_VALUES, CTOR_FUNCTIONS, ERROR_CONSTRUCTORS, FIRST_CLASS_CONSTRUCTORS } from "../tables.js";
|
|
32
32
|
import type { Generator } from "../generator.js";
|
|
33
33
|
|
|
34
34
|
export interface PrimaryExpressionMethods {
|
|
@@ -218,6 +218,11 @@ export const primaryExpressionMethods: PrimaryExpressionMethods = {
|
|
|
218
218
|
return rest;
|
|
219
219
|
}
|
|
220
220
|
default: {
|
|
221
|
+
if (FIRST_CLASS_CONSTRUCTORS.has(identifier.text)) {
|
|
222
|
+
// `const A = Array`, `arr.filter(Boolean)`, `new (Map)()`: the
|
|
223
|
+
// constructor is an ordinary function value backed by the runtime.
|
|
224
|
+
return this.runtimeCall("xt_builtin_constructor", [this.stringValue(identifier.text)]);
|
|
225
|
+
}
|
|
221
226
|
const builtinValue = BUILTIN_FUNCTION_VALUES[identifier.text];
|
|
222
227
|
if (builtinValue) {
|
|
223
228
|
// A global like `Boolean` used as a value (`arr.filter(Boolean)`):
|
|
@@ -240,6 +245,10 @@ export const primaryExpressionMethods: PrimaryExpressionMethods = {
|
|
|
240
245
|
this.reportRequireUse(identifier);
|
|
241
246
|
return i64(XT_UNDEFINED);
|
|
242
247
|
}
|
|
248
|
+
/* The parser's recovery node for a missing expression. The syntax
|
|
249
|
+
* error has already been reported; "Cannot find name '<error>'" is
|
|
250
|
+
* pure noise on top of it. */
|
|
251
|
+
if (identifier.text === "<error>") return i64(XT_UNDEFINED);
|
|
243
252
|
this.diagnostics.error(
|
|
244
253
|
DiagnosticCode.CannotFindName,
|
|
245
254
|
`Cannot find name '${identifier.text}'`,
|
|
@@ -41,7 +41,6 @@ export interface ModuleMethods {
|
|
|
41
41
|
emitFunctionReturn(this: Generator, value: string): void;
|
|
42
42
|
emitMain(this: Generator): void;
|
|
43
43
|
functionName(this: Generator, fn: FunctionInfo): string;
|
|
44
|
-
wrapAsync(this: Generator, value: string): string;
|
|
45
44
|
classGlobal(this: Generator, classInfo: ClassInfo): string;
|
|
46
45
|
emitClassReference(this: Generator, classInfo: ClassInfo): string;
|
|
47
46
|
emitClassSetup(this: Generator, classInfo: ClassInfo): void;
|
|
@@ -101,13 +100,6 @@ export const moduleMethods: ModuleMethods = {
|
|
|
101
100
|
|
|
102
101
|
emitFunction(fn: FunctionInfo): void {
|
|
103
102
|
this.unsupportedCount = 0;
|
|
104
|
-
// `async function*` would need an async iterator and a promise-returning
|
|
105
|
-
// `.next()`; the generator/async lowering below would silently produce a
|
|
106
|
-
// synchronous generator instead, so reject it rather than miscompile.
|
|
107
|
-
if (fn.isAsync && fn.isGenerator) {
|
|
108
|
-
this.unsupported(fn.node, "async generator function");
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
103
|
const name = this.functionName(fn);
|
|
112
104
|
const debugSubprogram = this.debugSubprogramFor(fn);
|
|
113
105
|
const state: FunctionState = {
|
|
@@ -124,7 +116,11 @@ export const moduleMethods: ModuleMethods = {
|
|
|
124
116
|
finallyStack: [],
|
|
125
117
|
escapePointers: [],
|
|
126
118
|
usesTry: false,
|
|
127
|
-
|
|
119
|
+
/* Generator and async bodies run on a private coroutine stack that can be
|
|
120
|
+
* suspended in the middle of a call. Their shadow frame would then sit on
|
|
121
|
+
* the shadow stack while the caller unwinds its own, so leave them out of
|
|
122
|
+
* `Error.stack` frames (nesting calls inside them are still recorded). */
|
|
123
|
+
trackFrames: !fn.isGenerator && !fn.isAsync,
|
|
128
124
|
...(debugSubprogram ? { debugSubprogram } : {}),
|
|
129
125
|
};
|
|
130
126
|
this.current = state;
|
|
@@ -254,15 +250,17 @@ export const moduleMethods: ModuleMethods = {
|
|
|
254
250
|
this.emitStatements(this.sourceFile.statements);
|
|
255
251
|
} else if (fn.node.kind === SyntaxKind.ArrowFunction && (fn.node as ArrowFunction).body.kind !== SyntaxKind.Block) {
|
|
256
252
|
const value = this.emitExpression((fn.node as ArrowFunction).body as Expression);
|
|
257
|
-
this.emitFunctionReturn(
|
|
253
|
+
this.emitFunctionReturn(value);
|
|
258
254
|
} else {
|
|
259
255
|
const body = (fn.node as { body: Block }).body;
|
|
260
256
|
if (body) this.emitStatements(body.statements);
|
|
261
257
|
}
|
|
262
258
|
|
|
263
259
|
if (!this.current.terminated) {
|
|
264
|
-
|
|
265
|
-
|
|
260
|
+
/* An `async` body returns its value plainly: the runtime's async
|
|
261
|
+
* coroutine settles the returned promise (and adopts a returned
|
|
262
|
+
* promise), so wrapping here would add a redundant promise. */
|
|
263
|
+
this.emitFunctionReturn(i64(XT_UNDEFINED));
|
|
266
264
|
}
|
|
267
265
|
|
|
268
266
|
const escapes = state.usesTry
|
|
@@ -327,13 +325,6 @@ export const moduleMethods: ModuleMethods = {
|
|
|
327
325
|
this.terminate(`ret i64 ${value}`);
|
|
328
326
|
},
|
|
329
327
|
|
|
330
|
-
/** Wrap a returned value in a resolved promise (for `async` functions). */
|
|
331
|
-
wrapAsync(value: string): string {
|
|
332
|
-
const result = this.reg();
|
|
333
|
-
this.emit(` ${result} = call i64 @xt_promise_resolve(i64 ${value})`);
|
|
334
|
-
return result;
|
|
335
|
-
},
|
|
336
|
-
|
|
337
328
|
classGlobal(classInfo: ClassInfo): string {
|
|
338
329
|
const existing = this.classGlobals.get(classInfo.id);
|
|
339
330
|
if (existing) return existing;
|
|
@@ -12,9 +12,41 @@
|
|
|
12
12
|
* mask and the operation is `bitcast` → `fadd`/`fcmp` → `bitcast`.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
import {
|
|
16
|
+
BinaryOperator,
|
|
17
|
+
PrefixUnaryOperator,
|
|
18
|
+
SyntaxKind,
|
|
19
|
+
type BinaryExpression,
|
|
20
|
+
type Expression,
|
|
21
|
+
type PrefixUnaryExpression,
|
|
22
|
+
} from "../../ast/nodes.js";
|
|
15
23
|
import { i64, XT_FALSE, XT_NUMBER_MASK, XT_TRUE } from "../values.js";
|
|
16
24
|
import type { Generator } from "./generator.js";
|
|
17
25
|
|
|
26
|
+
/** Operators whose runtime result is always `XT_TRUE` / `XT_FALSE`. */
|
|
27
|
+
const BOOLEAN_BINARY: ReadonlySet<string> = new Set([
|
|
28
|
+
BinaryOperator.LessThan,
|
|
29
|
+
BinaryOperator.LessThanEquals,
|
|
30
|
+
BinaryOperator.GreaterThan,
|
|
31
|
+
BinaryOperator.GreaterThanEquals,
|
|
32
|
+
BinaryOperator.EqualsEquals,
|
|
33
|
+
BinaryOperator.ExclamationEquals,
|
|
34
|
+
BinaryOperator.EqualsEqualsEquals,
|
|
35
|
+
BinaryOperator.ExclamationEqualsEquals,
|
|
36
|
+
BinaryOperator.In,
|
|
37
|
+
BinaryOperator.InstanceOf,
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
/** True when the expression's value is a boolean tag, not an arbitrary value. */
|
|
41
|
+
function isBooleanValue(node: Expression): boolean {
|
|
42
|
+
if (node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword) return true;
|
|
43
|
+
if (node.kind === SyntaxKind.BinaryExpression) {
|
|
44
|
+
return BOOLEAN_BINARY.has((node as BinaryExpression).operator as string);
|
|
45
|
+
}
|
|
46
|
+
return node.kind === SyntaxKind.PrefixUnaryExpression &&
|
|
47
|
+
(node as PrefixUnaryExpression).operator === PrefixUnaryOperator.Exclamation;
|
|
48
|
+
}
|
|
49
|
+
|
|
18
50
|
export interface NumericMethods {
|
|
19
51
|
/**
|
|
20
52
|
* Emit `left <operator> right`, using an inline double fast path when both
|
|
@@ -27,11 +59,31 @@ export interface NumericMethods {
|
|
|
27
59
|
operator: string,
|
|
28
60
|
runtime: string,
|
|
29
61
|
allowFastPath?: boolean,
|
|
62
|
+
leftKnownNumber?: boolean,
|
|
63
|
+
rightKnownNumber?: boolean,
|
|
64
|
+
): string;
|
|
65
|
+
emitNumericBinary(
|
|
66
|
+
this: Generator,
|
|
67
|
+
left: string,
|
|
68
|
+
right: string,
|
|
69
|
+
instruction: string,
|
|
70
|
+
runtime: string,
|
|
71
|
+
leftKnownNumber?: boolean,
|
|
72
|
+
rightKnownNumber?: boolean,
|
|
73
|
+
): string;
|
|
74
|
+
emitNumericComparison(
|
|
75
|
+
this: Generator,
|
|
76
|
+
left: string,
|
|
77
|
+
right: string,
|
|
78
|
+
predicate: string,
|
|
79
|
+
runtime: string,
|
|
80
|
+
leftKnownNumber?: boolean,
|
|
81
|
+
rightKnownNumber?: boolean,
|
|
30
82
|
): string;
|
|
31
|
-
emitNumericBinary(this: Generator, left: string, right: string, instruction: string, runtime: string): string;
|
|
32
|
-
emitNumericComparison(this: Generator, left: string, right: string, predicate: string, runtime: string): string;
|
|
33
83
|
/** Emit an i1 SSA value that is true when `value` is an unboxed double. */
|
|
34
84
|
isNumberValue(this: Generator, value: string): string;
|
|
85
|
+
/** Emit an i1 branch condition, folding boolean producers to a tag compare. */
|
|
86
|
+
emitTruthiness(this: Generator, value: string, expression?: Expression): string;
|
|
35
87
|
}
|
|
36
88
|
|
|
37
89
|
/** Canonical quiet NaN; the runtime uses the same pattern in `xt_from_double`. */
|
|
@@ -57,12 +109,16 @@ const NUMERIC_COMPARISON: Record<string, string | undefined> = {
|
|
|
57
109
|
};
|
|
58
110
|
|
|
59
111
|
export const numericMethods: NumericMethods = {
|
|
60
|
-
emitBinaryOperation(left, right, operator, runtime, allowFastPath = true) {
|
|
112
|
+
emitBinaryOperation(left, right, operator, runtime, allowFastPath = true, leftKnownNumber = false, rightKnownNumber = false) {
|
|
61
113
|
if (allowFastPath) {
|
|
62
114
|
const instruction = NUMERIC_ARITHMETIC[operator];
|
|
63
|
-
if (instruction)
|
|
115
|
+
if (instruction) {
|
|
116
|
+
return this.emitNumericBinary(left, right, instruction, runtime, leftKnownNumber, rightKnownNumber);
|
|
117
|
+
}
|
|
64
118
|
const predicate = NUMERIC_COMPARISON[operator];
|
|
65
|
-
if (predicate)
|
|
119
|
+
if (predicate) {
|
|
120
|
+
return this.emitNumericComparison(left, right, predicate, runtime, leftKnownNumber, rightKnownNumber);
|
|
121
|
+
}
|
|
66
122
|
}
|
|
67
123
|
const result = this.reg();
|
|
68
124
|
this.emit(` ${result} = call i64 @${runtime}(i64 ${left}, i64 ${right})`);
|
|
@@ -78,10 +134,10 @@ export const numericMethods: NumericMethods = {
|
|
|
78
134
|
return result;
|
|
79
135
|
},
|
|
80
136
|
|
|
81
|
-
emitNumericBinary(left, right, instruction, runtime) {
|
|
137
|
+
emitNumericBinary(left, right, instruction, runtime, leftKnownNumber = false, rightKnownNumber = false) {
|
|
82
138
|
const result = this.alloca();
|
|
83
|
-
const leftIsNumber = this.isNumberValue(left);
|
|
84
|
-
const rightIsNumber = this.isNumberValue(right);
|
|
139
|
+
const leftIsNumber = leftKnownNumber ? "true" : this.isNumberValue(left);
|
|
140
|
+
const rightIsNumber = rightKnownNumber ? "true" : this.isNumberValue(right);
|
|
85
141
|
const bothNumbers = this.reg();
|
|
86
142
|
this.emit(` ${bothNumbers} = and i1 ${leftIsNumber}, ${rightIsNumber}`);
|
|
87
143
|
const fast = this.label("num.fast");
|
|
@@ -119,10 +175,10 @@ export const numericMethods: NumericMethods = {
|
|
|
119
175
|
return value;
|
|
120
176
|
},
|
|
121
177
|
|
|
122
|
-
emitNumericComparison(left, right, predicate, runtime) {
|
|
178
|
+
emitNumericComparison(left, right, predicate, runtime, leftKnownNumber = false, rightKnownNumber = false) {
|
|
123
179
|
const result = this.alloca();
|
|
124
|
-
const leftIsNumber = this.isNumberValue(left);
|
|
125
|
-
const rightIsNumber = this.isNumberValue(right);
|
|
180
|
+
const leftIsNumber = leftKnownNumber ? "true" : this.isNumberValue(left);
|
|
181
|
+
const rightIsNumber = rightKnownNumber ? "true" : this.isNumberValue(right);
|
|
126
182
|
const bothNumbers = this.reg();
|
|
127
183
|
this.emit(` ${bothNumbers} = and i1 ${leftIsNumber}, ${rightIsNumber}`);
|
|
128
184
|
const fast = this.label("cmp.fast");
|
|
@@ -155,4 +211,22 @@ export const numericMethods: NumericMethods = {
|
|
|
155
211
|
this.emit(` ${merged} = load i64, i64* ${result}`);
|
|
156
212
|
return merged;
|
|
157
213
|
},
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* A comparison, `in`/`instanceof` or `!` already evaluates to a boolean tag,
|
|
217
|
+
* so its truthiness is a tag compare instead of an `xt_truthy` call. This is
|
|
218
|
+
* the hot condition in `for (let i = 0; i < n; i++)` loops.
|
|
219
|
+
*/
|
|
220
|
+
emitTruthiness(value, expression) {
|
|
221
|
+
if (expression && isBooleanValue(expression)) {
|
|
222
|
+
const result = this.reg();
|
|
223
|
+
this.emit(` ${result} = icmp eq i64 ${value}, ${i64(XT_TRUE)}`);
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
const truthy = this.reg();
|
|
227
|
+
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${value})`);
|
|
228
|
+
const result = this.reg();
|
|
229
|
+
this.emit(` ${result} = icmp ne i32 ${truthy}, 0`);
|
|
230
|
+
return result;
|
|
231
|
+
},
|
|
158
232
|
};
|
|
@@ -104,6 +104,10 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
104
104
|
"declare i64 @xt_closure_new(i8*, i32, i64*)",
|
|
105
105
|
"declare i64 @xt_function_set_metadata(i64, i64, i32)",
|
|
106
106
|
"declare i64 @xt_function_set_generator(i64)",
|
|
107
|
+
"declare i64 @xt_function_set_async(i64)",
|
|
108
|
+
"declare i64 @xt_function_set_async_generator(i64)",
|
|
109
|
+
"declare i64 @xt_async_iter_open(i64)",
|
|
110
|
+
"declare i64 @xt_async_iter_next(i64)",
|
|
107
111
|
"declare i64 @xt_closure_call(i64, i32, i64*)",
|
|
108
112
|
"declare i64 @xt_closure_env(i64, i32)",
|
|
109
113
|
"declare i64 @xt_call_with_this(i64, i64, i32, i64*)",
|
|
@@ -111,6 +115,9 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
111
115
|
"declare i64 @xt_new(i64, i32, i64*)",
|
|
112
116
|
"declare i64 @xt_instance_of(i64, i64)",
|
|
113
117
|
"declare i64 @xt_instance_of_builtin(i64, i32)",
|
|
118
|
+
"declare i64 @xt_builtin_constructor(i64)",
|
|
119
|
+
"declare i64 @xt_array_ctor(i32, i64*)",
|
|
120
|
+
"declare i64 @xt_object_ctor(i32, i64*)",
|
|
114
121
|
"declare i64 @xt_function_set_prototype(i64, i64)",
|
|
115
122
|
"declare i64 @xt_function_get_prototype(i64)",
|
|
116
123
|
"declare i64 @xt_object_new_with_proto(i64)",
|
|
@@ -176,8 +183,17 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
176
183
|
"declare i64 @xt_process_get(i64)",
|
|
177
184
|
"declare i64 @xt_map_ctor(i32, i64*)",
|
|
178
185
|
"declare i64 @xt_set_ctor(i32, i64*)",
|
|
186
|
+
"declare i64 @xt_weak_map_ctor(i32, i64*)",
|
|
187
|
+
"declare i64 @xt_weak_set_ctor(i32, i64*)",
|
|
188
|
+
"declare i64 @xt_weak_ref_ctor(i32, i64*)",
|
|
189
|
+
"declare i64 @xt_text_encoder_ctor(i32, i64*)",
|
|
190
|
+
"declare i64 @xt_text_decoder_ctor(i32, i64*)",
|
|
179
191
|
"declare i64 @xt_date_ctor(i32, i64*)",
|
|
180
192
|
"declare i64 @xt_regexp_ctor(i32, i64*)",
|
|
193
|
+
"declare i64 @xt_url_search_params_ctor(i32, i64*)",
|
|
194
|
+
"declare i64 @xt_array_buffer_ctor(i32, i64*)",
|
|
195
|
+
"declare i64 @xt_array_buffer_static(i64, i32, i64*)",
|
|
196
|
+
"declare i64 @xt_data_view_ctor(i32, i64*)",
|
|
181
197
|
"declare i64 @xt_error_ctor(i32, i64*)",
|
|
182
198
|
"declare i64 @xt_type_error_ctor(i32, i64*)",
|
|
183
199
|
"declare i64 @xt_range_error_ctor(i32, i64*)",
|
|
@@ -260,6 +276,12 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
260
276
|
"declare i64 @xt_clear_timeout(i32, i64*)",
|
|
261
277
|
"declare i64 @xt_set_interval(i32, i64*)",
|
|
262
278
|
"declare i64 @xt_clear_interval(i32, i64*)",
|
|
279
|
+
"declare i64 @xt_set_immediate(i32, i64*)",
|
|
280
|
+
"declare i64 @xt_clear_immediate(i32, i64*)",
|
|
281
|
+
"declare i64 @xt_queue_microtask(i32, i64*)",
|
|
282
|
+
"declare i64 @xt_performance_get(i64)",
|
|
283
|
+
"declare i64 @xt_performance_call(i64, i32, i64*)",
|
|
284
|
+
"declare i64 @xt_structured_clone(i32, i64*)",
|
|
263
285
|
"declare i64 @xt_fetch(i32, i64*)",
|
|
264
286
|
"declare i64 @xt_number_ctor(i32, i64*)",
|
|
265
287
|
"declare i64 @xt_bigint_ctor(i32, i64*)",
|
|
@@ -296,6 +318,10 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
296
318
|
"declare i64 @xt_builtin_value_clearTimeout(i64, i64, i32, i64*)",
|
|
297
319
|
"declare i64 @xt_builtin_value_setInterval(i64, i64, i32, i64*)",
|
|
298
320
|
"declare i64 @xt_builtin_value_clearInterval(i64, i64, i32, i64*)",
|
|
321
|
+
"declare i64 @xt_builtin_value_setImmediate(i64, i64, i32, i64*)",
|
|
322
|
+
"declare i64 @xt_builtin_value_clearImmediate(i64, i64, i32, i64*)",
|
|
323
|
+
"declare i64 @xt_builtin_value_queueMicrotask(i64, i64, i32, i64*)",
|
|
324
|
+
"declare i64 @xt_builtin_value_structuredClone(i64, i64, i32, i64*)",
|
|
299
325
|
"declare i64 @xt_builtin_value_fetch(i64, i64, i32, i64*)",
|
|
300
326
|
"declare i64 @xt_builtin_value_number(i64, i64, i32, i64*)",
|
|
301
327
|
"declare i64 @xt_builtin_value_string(i64, i64, i32, i64*)",
|
|
@@ -306,6 +332,7 @@ export const RUNTIME_DECLARATIONS: readonly string[] = [
|
|
|
306
332
|
"declare i64 @xt_symbol_static(i64, i32, i64*)",
|
|
307
333
|
"declare i64 @xt_symbol_get(i64)",
|
|
308
334
|
"declare i64 @xt_get(i64, i64)",
|
|
335
|
+
"declare i64 @xt_get_ic(i64, i64, i64*)",
|
|
309
336
|
"declare i64 @xt_set(i64, i64, i64)",
|
|
310
337
|
"declare i64 @xt_box_new(i64)",
|
|
311
338
|
"declare i64 @xt_box_get(i64)",
|
|
@@ -71,10 +71,7 @@ export const controlFlowStatementMethods: ControlFlowStatementMethods = {
|
|
|
71
71
|
const elseLabel = statement.elseStatement ? this.label("if.else") : undefined;
|
|
72
72
|
const endLabel = this.label("if.end");
|
|
73
73
|
const condition = this.emitExpression(statement.condition);
|
|
74
|
-
const
|
|
75
|
-
this.emit(` ${truthy} = call i32 @xt_truthy(i64 ${condition})`);
|
|
76
|
-
const nonzero = this.reg();
|
|
77
|
-
this.emit(` ${nonzero} = icmp ne i32 ${truthy}, 0`);
|
|
74
|
+
const nonzero = this.emitTruthiness(condition, statement.condition);
|
|
78
75
|
this.terminate(`br i1 ${nonzero}, label %${thenLabel}, label %${elseLabel ?? endLabel}`);
|
|
79
76
|
|
|
80
77
|
this.startBlock(thenLabel);
|
|
@@ -250,8 +247,7 @@ export const controlFlowStatementMethods: ControlFlowStatementMethods = {
|
|
|
250
247
|
},
|
|
251
248
|
|
|
252
249
|
emitReturn(statement: ReturnStatement): void {
|
|
253
|
-
|
|
254
|
-
if (this.current.fn.isAsync) value = this.wrapAsync(value);
|
|
250
|
+
const value = statement.expression ? this.emitExpression(statement.expression) : i64(XT_UNDEFINED);
|
|
255
251
|
this.runFinallysBeforeExit(0);
|
|
256
252
|
if (this.current.terminated) return;
|
|
257
253
|
this.popTryFramesTo(0);
|