@scriptc/compiler 0.0.2 → 0.0.4

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.
Files changed (75) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +145 -9
  2. package/dist/backend/cc.d.ts +7 -0
  3. package/dist/backend/cc.js +1 -0
  4. package/dist/backend/cc.js.map +1 -1
  5. package/dist/backend/emission/emit-exprs.js +35 -0
  6. package/dist/backend/emission/emit-exprs.js.map +1 -1
  7. package/dist/backend/emission/emit-shapes.js +1 -0
  8. package/dist/backend/emission/emit-shapes.js.map +1 -1
  9. package/dist/backend/emission/emitter.js +15 -3
  10. package/dist/backend/emission/emitter.js.map +1 -1
  11. package/dist/backend/llvm/emitter.js +65 -11
  12. package/dist/backend/llvm/emitter.js.map +1 -1
  13. package/dist/backend/llvm/shapes.js +1 -0
  14. package/dist/backend/llvm/shapes.js.map +1 -1
  15. package/dist/coverage/surface-manifest.d.ts +22 -0
  16. package/dist/coverage/surface-manifest.js +295 -0
  17. package/dist/coverage/surface-manifest.js.map +1 -0
  18. package/dist/diagnostics/diagnostic.d.ts +16 -0
  19. package/dist/diagnostics/diagnostic.js +26 -2
  20. package/dist/diagnostics/diagnostic.js.map +1 -1
  21. package/dist/frontend/lowering/lib-boundary.js +76 -6
  22. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  23. package/dist/frontend/lowering/lower-builtins.d.ts +37 -4
  24. package/dist/frontend/lowering/lower-builtins.js +240 -6
  25. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  26. package/dist/frontend/lowering/lower-calls.js +122 -32
  27. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  28. package/dist/frontend/lowering/lower-classes.d.ts +34 -2
  29. package/dist/frontend/lowering/lower-classes.js +256 -33
  30. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  31. package/dist/frontend/lowering/lower-containers.js +25 -3
  32. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  33. package/dist/frontend/lowering/lower-exprs.d.ts +10 -0
  34. package/dist/frontend/lowering/lower-exprs.js +410 -9
  35. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  36. package/dist/frontend/lowering/lower-inspect.d.ts +16 -1
  37. package/dist/frontend/lowering/lower-inspect.js +132 -5
  38. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  39. package/dist/frontend/lowering/lower-island.js +24 -3
  40. package/dist/frontend/lowering/lower-island.js.map +1 -1
  41. package/dist/frontend/lowering/lower-modules.d.ts +6 -5
  42. package/dist/frontend/lowering/lower-modules.js +56 -18
  43. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  44. package/dist/frontend/lowering/lower-stmts.js +56 -0
  45. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  46. package/dist/frontend/lowering/lowerer.d.ts +57 -1
  47. package/dist/frontend/lowering/lowerer.js +291 -10
  48. package/dist/frontend/lowering/lowerer.js.map +1 -1
  49. package/dist/frontend/lowering/surfaces.d.ts +9 -2
  50. package/dist/frontend/lowering/surfaces.js +44 -7
  51. package/dist/frontend/lowering/surfaces.js.map +1 -1
  52. package/dist/frontend/npm.js +2 -2
  53. package/dist/frontend/npm.js.map +1 -1
  54. package/dist/frontend/program.js +59 -8
  55. package/dist/frontend/program.js.map +1 -1
  56. package/dist/frontend/resolve.js +120 -5
  57. package/dist/frontend/resolve.js.map +1 -1
  58. package/dist/frontend/shared.d.ts +8 -2
  59. package/dist/frontend/shared.js +22 -6
  60. package/dist/frontend/shared.js.map +1 -1
  61. package/dist/frontend/ts7/checker.js +1 -1
  62. package/dist/frontend/ts7/checker.js.map +1 -1
  63. package/dist/frontend/types.d.ts +25 -1
  64. package/dist/frontend/types.js +121 -7
  65. package/dist/frontend/types.js.map +1 -1
  66. package/dist/index.d.ts +1 -0
  67. package/dist/index.js +5 -1
  68. package/dist/index.js.map +1 -1
  69. package/dist/ir/nodes.d.ts +43 -1
  70. package/dist/ir/nodes.js +41 -0
  71. package/dist/ir/nodes.js.map +1 -1
  72. package/dist/ir/validate.js +38 -6
  73. package/dist/ir/validate.js.map +1 -1
  74. package/package.json +6 -4
  75. package/surface-manifest.json +2117 -0
@@ -9,16 +9,16 @@ import { isJsSourceFile, locOf } from "../program.js";
9
9
  import { isGenericCallableMemberType, typeKey } from "../types.js";
10
10
  import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, newFnCtx } from "./lowerer.js";
11
11
  import { enforceLibBoundary } from "./lib-boundary.js";
12
- import { builtinFenceHintOf, builtinModuleFnOf, NARROW_FIRST } from "./surfaces.js";
12
+ import { builtinFenceHintOf, builtinModuleFnOf } from "./surfaces.js";
13
13
  import { requiresDynamicDiag } from "../../diagnostics/diagnostic.js";
14
14
  import { mixinFnShapeOf } from "./lower-mixins.js";
15
15
  import { bufEncoding, dynStringReceiver, lowerArrayFromCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerRegexMethodCall, lowerStringMethodCall, lowerTupleReadMethodCall } from "./lower-containers.js";
16
- import { lowerChildStreamMethodCall, lowerDirentMethodCall, lowerProcStreamMethodCall, lowerReflectApplyCall, lowerWatcherMethodCall } from "./lower-builtins.js";
16
+ import { lowerChildStreamMethodCall, lowerDirentMethodCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectApplyCall, lowerWatcherMethodCall } from "./lower-builtins.js";
17
17
  import { lowerPromiseAllTupleCall, lowerPromiseRejectCall, probeLower, templateRawTextOf } from "./lower-exprs.js";
18
18
  import { httpClientFnBindingOf, isStreamUndefCallExpr, lowerHttpClientFnCall } from "./lower-server.js";
19
19
  import { EMITTER_API_MEMBERS, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall } from "./lower-classes.js";
20
20
  import { emitterRooted, lowerEmitterMethodCall } from "./lower-emitter.js";
21
- import { lowerFormatCall } from "./lower-inspect.js";
21
+ import { lowerConsoleInspectArg, lowerFormatCall } from "./lower-inspect.js";
22
22
  import { STREAM_API_MEMBERS, lowerStreamMethodCall, lowerStreamModuleCall, lowerStreamStaticCall, streamSidesOf } from "./lower-stream.js";
23
23
  import { ambientNsRootOf, ambientUndefReadType, ambientUndefVarRootOf, ambientUndefinedFnSymbolOf, contextualUndefReadType, fenceEarlyAliasUse, fenceEarlyNsMemberRef, nsMemberIdentOf, nsPathPrefix, nsUndefRead } from "./lower-namespaces.js";
24
24
  import { declSymbolOf } from "./lower-modules.js";
@@ -730,9 +730,13 @@ export function collectGenericSignature(L, decl) {
730
730
  }
731
731
  // Only NAME syntax is checkable here; optional/default/rest shapes are
732
732
  // computed per call site from the resolved signature (lowerGenericCall).
733
+ // Binding-PATTERN parameters (`retry<T>(fn, { retries = 3 } = {})`)
734
+ // pass: declareParams desugars patterns per instance exactly as it
735
+ // does for non-generic functions.
733
736
  for (const param of decl.parameters) {
734
- if (!ts.isIdentifier(param.name))
737
+ if (!ts.isIdentifier(param.name) && !ts.isObjectBindingPattern(param.name) && !ts.isArrayBindingPattern(param.name)) {
735
738
  L.unsupported("SC1031", param);
739
+ }
736
740
  }
737
741
  const nameText = decl.name?.text ?? "%default"; // nameless = the default export (checked by collectSignatureInner)
738
742
  const symbol = declSymbolOf(L, decl);
@@ -2235,14 +2239,16 @@ export function lowerCall(L, expr) {
2235
2239
  }
2236
2240
  const consoleMember = L.consoleCallMember(expr);
2237
2241
  if (consoleMember !== null) {
2238
- // console.log writes stdout; console.error and console.warn are one
2239
- // stream in Node (warn IS error) and write stderr with the exact same
2240
- // formatting. The ambient signature accepts (number | string |
2241
- // boolean)[], which a union of those arms satisfies — so tsc lets
2242
- // `console.log(u)` through and the fence lives here. A NARROWED use
2243
- // already lowered to the arm via maybeNarrow; only genuinely-union
2244
- // args are rejected.
2242
+ // console.log/info/debug write stdout; console.error and console.warn
2243
+ // are one stream in Node (warn IS error, info and debug ARE log) and
2244
+ // write stderr with the exact same formatting. Node's formatter is
2245
+ // formatWithOptions: string arguments print verbatim, numbers and
2246
+ // booleans directly, and EVERYTHING else through util.inspect at the
2247
+ // rest-args depth 2 — which the static inspect machinery renders
2248
+ // here (arrays, records, unions, Maps/Sets, undefined/null, ...);
2249
+ // shapes inspect cannot render keep honest per-argument fences.
2245
2250
  const surface = `console.${consoleMember}`;
2251
+ const stdoutMember = consoleMember === "log" || consoleMember === "info" || consoleMember === "debug";
2246
2252
  // A LITERAL format string with %-specifiers and further arguments
2247
2253
  // (`console.log('Mismatched %s function calls. Expected %s, actual
2248
2254
  // %d.', name, seg, n)` — test/common's exit report): Node's console
@@ -2256,7 +2262,7 @@ export function lowerCall(L, expr) {
2256
2262
  const formatted = lowerFormatCall(L, expr, loc, false);
2257
2263
  return {
2258
2264
  kind: "intrinsic",
2259
- name: consoleMember === "log" ? "console.log" : "console.error",
2265
+ name: stdoutMember ? "console.log" : "console.error",
2260
2266
  args: [formatted],
2261
2267
  type: VOID,
2262
2268
  loc,
@@ -2270,9 +2276,6 @@ export function lowerCall(L, expr) {
2270
2276
  // are ToString (Node-exact), casts are validated: both honest.
2271
2277
  L.unsupported("SC1090", a, `${surface} of 'any' values (wrap it: ${surface}(\`\${v}\`), or validate with 'as <type>' first)`);
2272
2278
  }
2273
- if (lowered.type.kind === "union") {
2274
- L.unsupported("SC1090", a, `union-typed ${surface} arguments (${NARROW_FIRST})`);
2275
- }
2276
2279
  // Checked-dynamic values carry their own shape, so the runtime
2277
2280
  // renders them exactly like Node's console formatter renders a
2278
2281
  // non-format argument: strings VERBATIM, everything else through
@@ -2311,19 +2314,22 @@ export function lowerCall(L, expr) {
2311
2314
  loc,
2312
2315
  };
2313
2316
  }
2314
- // With the fallback console the signature already restricts args to
2315
- // number | string | boolean (anything else is a type error); with
2316
- // @types/node's console.log(...any[]) everything typechecks, so the
2317
- // fence moves here.
2318
- if (lowered.type.kind !== "f64" && lowered.type.kind !== "string" && lowered.type.kind !== "bool") {
2319
- L.unsupported("SC1090", a, `${surface} of '${L.fmt(lowered.type)}' values ` +
2320
- `(only number, string, and boolean arguments lower)`);
2317
+ // number/string/boolean ride the ScrLogArg protocol directly (the
2318
+ // runtime formats them Node-exactly — including -0).
2319
+ if (lowered.type.kind === "f64" || lowered.type.kind === "string" || lowered.type.kind === "bool") {
2320
+ return lowered;
2321
2321
  }
2322
- return lowered;
2322
+ // Everything else renders through the static inspect machinery at
2323
+ // the rest-args depth 2 (formatWithOptions): arrays, records,
2324
+ // unions (a string arm prints VERBATIM — the console.log vs
2325
+ // inspect distinction, per arm), Maps/Sets, plain undefined/null,
2326
+ // regexes, symbols, error values, Buffers. Shapes inspect cannot
2327
+ // render fence honestly with the reason.
2328
+ return lowerConsoleInspectArg(L, a, lowered, surface, loc);
2323
2329
  });
2324
2330
  return {
2325
2331
  kind: "intrinsic",
2326
- name: consoleMember === "log" ? "console.log" : "console.error",
2332
+ name: stdoutMember ? "console.log" : "console.error",
2327
2333
  args,
2328
2334
  type: VOID,
2329
2335
  loc,
@@ -2551,6 +2557,17 @@ export function lowerCall(L, expr) {
2551
2557
  if (ts.isPropertyAccessExpression(expr.expression) &&
2552
2558
  L.isIslandExpr(expr.expression.expression)) {
2553
2559
  const receiver = L.lowerExpr(expr.expression.expression);
2560
+ // A checker-`any` receiver whose VALUE lives in the DOM (a
2561
+ // checked-dynamic local behind the any-typed spelling — the JS
2562
+ // WeakSet placeholder, rest-args arrays): the checked-dynamic
2563
+ // method machinery owns it — receiver-kind dispatch, stored-member
2564
+ // calls, honest fences — never an engine op over a dyn value.
2565
+ if (receiver.type.kind === "dyn") {
2566
+ const served = lowerDynReceiverMethodCall(L, expr, expr.expression);
2567
+ if (served)
2568
+ return served;
2569
+ L.unsupported("SC1100", expr, `'.${expr.expression.name.text}()' calls through 'unknown'-valued receivers in dynamically-executed positions`);
2570
+ }
2554
2571
  const args = expr.arguments.map((a) => L.jsvalIn(L.lowerExpr(a), a));
2555
2572
  const result = {
2556
2573
  kind: "jsOp", op: "callMethod", name: expr.expression.name.text,
@@ -2560,6 +2577,20 @@ export function lowerCall(L, expr) {
2560
2577
  }
2561
2578
  if (L.isIslandExpr(expr.expression)) {
2562
2579
  const callee = L.lowerExpr(expr.expression);
2580
+ // A checker-`any` callee that LOWERED checked-dynamic (a dyn member
2581
+ // chain's stored function): the DOM's own call — dynCall reads and
2582
+ // calls the stored member with Node's is-not-a-function TypeError
2583
+ // on refusal. Island-typed arguments meet the boundary pass's
2584
+ // dynCall rule (no jsval→DOM bridge exists — the named fence).
2585
+ if (callee.type.kind === "dyn") {
2586
+ const args = expr.arguments.map((a) => L.lowerExprExpecting(a, DYN));
2587
+ const calleeName = ts.isPropertyAccessExpression(expr.expression)
2588
+ ? expr.expression.getText()
2589
+ : ts.isIdentifier(expr.expression)
2590
+ ? expr.expression.text
2591
+ : "value";
2592
+ return { kind: "dynCall", callee, calleeName, args, type: DYN, loc };
2593
+ }
2563
2594
  const args = expr.arguments.map((a) => L.jsvalIn(L.lowerExpr(a), a));
2564
2595
  const result = { kind: "jsOp", op: "callFn", args: [callee, ...args], type: JSVAL, loc };
2565
2596
  return islandPrimitiveExit(L, expr, result);
@@ -2934,7 +2965,7 @@ export function lowerCall(L, expr) {
2934
2965
  if (nsMember) {
2935
2966
  // A builtin RE-EXPORT FACADE member (`import * as assert from
2936
2967
  // "./facade.js"` over `export { ok } from "node:assert"` —
2937
- // prettier's universal/assert): builtinMemberOf's alias chase
2968
+ // a universal re-export facade): builtinMemberOf's alias chase
2938
2969
  // resolves the builtin module/member, and the spokes own the call
2939
2970
  // exactly as a direct builtin import. Ordinary user-module
2940
2971
  // members answer null there and resolve below.
@@ -3037,6 +3068,10 @@ export function lowerCall(L, expr) {
3037
3068
  // as named builtin imports — before anything below tries to lower
3038
3069
  // the namespace object itself as a receiver.
3039
3070
  L.lowerNamespaceBuiltinCall(expr, expr.expression) ??
3071
+ // The node:perf_hooks spoke: performance.now() and its
3072
+ // .bind(performance) function value over the runtime's
3073
+ // process-start-anchored monotonic clock.
3074
+ lowerPerfHooksCall(L, expr, expr.expression) ??
3040
3075
  // The composed crypto pattern (randomBytes(n).toString(enc))
3041
3076
  // — its receiver is a Buffer-typed CALL no other lowering claims.
3042
3077
  L.lowerCryptoComposedCall(expr, expr.expression) ??
@@ -5648,8 +5683,15 @@ function lowerObjectStaticCall(L, call, access) {
5648
5683
  }
5649
5684
  else if (others.length === 1) {
5650
5685
  vt = others[0];
5651
- const narrowTag = L.armTag(f.type.unionId, vt);
5652
- value = { kind: "unionNarrow", unionId: f.type.unionId, tag: narrowTag, value: raw, type: vt, loc };
5686
+ // A UNIT other arm (`null | undefined` fields — the mixed-
5687
+ // defaults spread idiom; undefined was filtered above, so
5688
+ // the unit is null): units carry no payload, so the guarded
5689
+ // push writes the unit LITERAL — unionNarrow to a unit arm
5690
+ // (and unionWrap of a narrowed unit) is malformed IR; the
5691
+ // literal is the one legal unit spelling.
5692
+ value = isUnitType(vt)
5693
+ ? { kind: "unitLit", unit: "null", type: vt, loc }
5694
+ : { kind: "unionNarrow", unionId: f.type.unionId, tag: L.armTag(f.type.unionId, vt), value: raw, type: vt, loc };
5653
5695
  }
5654
5696
  else {
5655
5697
  L.unsupported("SC1090", call, `Object.${member} over '${L.fmt(argIr)}' (field '${f.name}' is a multi-arm union that ` +
@@ -5740,6 +5782,7 @@ export function lowerFunction(L, decl) {
5740
5782
  ctx.isAsync = sig.isAsync === true;
5741
5783
  if (sig.generator !== undefined)
5742
5784
  ctx.generator = sig.generator;
5785
+ const diagsBefore = L.diags.length;
5743
5786
  L.fnStack.push(ctx);
5744
5787
  try {
5745
5788
  const { params, prologue } = L.declareParams(decl.parameters, sig.params);
@@ -5773,11 +5816,57 @@ export function lowerFunction(L, decl) {
5773
5816
  }
5774
5817
  catch (e) {
5775
5818
  // A poison OUTSIDE the per-statement catches (a parameter DEFAULT
5776
- // whose initializer is fenced): the diagnostic is already recorded —
5777
- // the function skips, like a signature-blocked one, instead of
5778
- // killing the whole analysis.
5819
+ // whose initializer is fenced, a parameter PATTERN over a class
5820
+ // that never lowered): the diagnostic is already recorded — the
5821
+ // function skips, like a signature-blocked one, instead of killing
5822
+ // the whole analysis.
5779
5823
  if (!(e instanceof PoisonError))
5780
5824
  throw e;
5825
+ // JS sources defer function-level poisons like statement fences
5826
+ // (the sentence-walker idiom `({ parent: sentenceNode })` over the
5827
+ // #private-fenced AstPath): the function compiles as its OWN
5828
+ // runtimeFence — CALLING it throws the first captured diagnostic
5829
+ // at the declaration's position — so a reachable-but-broken
5830
+ // signature stops the RUN at its own site instead of the build.
5831
+ // ICEs (SC9001) stay compile errors, exactly like lowerStmts.
5832
+ if (isJsSourceFile(decl.getSourceFile()) &&
5833
+ L.diagSink === null &&
5834
+ L.diags.length > diagsBefore &&
5835
+ !L.diags.slice(diagsBefore).some((d) => d.code === "SC9001")) {
5836
+ const captured = L.diags.splice(diagsBefore);
5837
+ L.runtimeFences.push(...captured);
5838
+ // An ABI type naming a class that never REGISTERED (the sentence-
5839
+ // walker idiom's path type — the #private fence) is fine to emit:
5840
+ // callers CAN lower calls to this symbol (a same-typed param
5841
+ // passes straight through — no construction needed), so the fence
5842
+ // function must exist, and run()'s unregistered-class sweep
5843
+ // rewrites every such slot to the inert f64 placeholder before
5844
+ // emission — caller and fence stay ABI-consistent.
5845
+ const first = captured[0];
5846
+ const loc = locOf(decl);
5847
+ const pos = ts.getLineAndCharacterOfPosition(L.program.getSourceFile(first.loc.file) ?? decl.getSourceFile(), first.loc.start);
5848
+ const params = sig.params.map((p, i) => ({ localId: `%pf${i}`, name: `%pf${i}`, type: p.type }));
5849
+ const fn = {
5850
+ name: sig.name,
5851
+ params,
5852
+ returnType: bodyReturn,
5853
+ locals: params.map((p) => ({ id: p.localId, name: p.name, type: p.type, mutable: false })),
5854
+ body: [
5855
+ {
5856
+ kind: "runtimeFence",
5857
+ code: first.code,
5858
+ message: `${first.message} [${first.code} at ${first.loc.file}:${pos.line + 1}]`,
5859
+ loc,
5860
+ },
5861
+ ],
5862
+ loc,
5863
+ };
5864
+ if (sig.isAsync)
5865
+ fn.async = true;
5866
+ if (sig.generator !== undefined)
5867
+ fn.generator = sig.generator;
5868
+ return fn;
5869
+ }
5781
5870
  return null;
5782
5871
  }
5783
5872
  finally {
@@ -6069,10 +6158,11 @@ export function bindingGenericFnInfoOf(L, decl, fnNode) {
6069
6158
  }
6070
6159
  // Only NAME syntax is checkable here; optional/default/rest shapes are
6071
6160
  // computed per instantiation from the resolved signature — exactly
6072
- // collectGenericSignature's rule.
6161
+ // collectGenericSignature's rule, binding patterns included.
6073
6162
  for (const param of fnNode.parameters) {
6074
- if (!ts.isIdentifier(param.name))
6163
+ if (!ts.isIdentifier(param.name) && !ts.isObjectBindingPattern(param.name) && !ts.isArrayBindingPattern(param.name)) {
6075
6164
  L.unsupported("SC1031", param);
6165
+ }
6076
6166
  }
6077
6167
  const stmt = decl.parent.parent; // declarator → list → statement (nsPathPrefix wants the statement)
6078
6168
  const info = {