@kernlang/python 3.5.9-canary.218.1.77aa9b0c → 4.0.0

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.
@@ -51,6 +51,15 @@ export interface BodyEmitOptions {
51
51
  * the KERN-form `userId` resolves to the snake_cased Python parameter.
52
52
  * Identifiers not in the map pass through unchanged. */
53
53
  symbolMap?: Record<string, string>;
54
+ /** When true, the handler is a class member body: identifier `super`
55
+ * lowers to Python `super()` (so `super.m()` -> `super().m()`) and a
56
+ * direct `super(...)` call lowers to `super().__init__(...)`. Paired with
57
+ * a `symbolMap` entry `this -> self` by the class generator. */
58
+ inClassBody?: boolean;
59
+ /** When true, the handler is specifically a constructor body, so a direct
60
+ * `super(...)` call lowers to `super().__init__(...)`. Outside a constructor
61
+ * `super(...)` is not a parent-constructor call and is left untouched. */
62
+ inConstructor?: boolean;
54
63
  /** Slice 4a review fix (Gemini #5) — how to lower the `?` propagation
55
64
  * hoist's err-branch return:
56
65
  * - 'value' (default for `fn`): `return __k_tN` so the caller sees
@@ -75,6 +84,16 @@ export interface BodyEmitOptions {
75
84
  forIterNext?: boolean;
76
85
  letAssign?: boolean;
77
86
  };
87
+ /** Coercion-slice opt-out for the helper-less Ground/React declarative
88
+ * layer. Defaults to `true` (native KERN bodies + expression unit tests
89
+ * get full JS value→string coercion, injecting helpers function-locally).
90
+ * The Ground generators (`coalesce`/`firstDefined`/`firstTruthy`/`objectMerge`
91
+ * /…) emit module-level statements via `emitPyExpression` and have no
92
+ * channel to define `_kern_fmt`/`__kern_add`/`_KERN_UNDEFINED`, so they pass
93
+ * `false` to keep the pre-slice output (zero regression). Extending coercion
94
+ * to the Ground layer needs module-level (single-definition) helper
95
+ * injection — a separate follow-up. */
96
+ coerceJsValues?: boolean;
78
97
  /** Outer-scope names the body INHERITS — typically function parameters and
79
98
  * module-level globals the wrapper has bound. Pre-populated as the
80
99
  * outermost `localScopes` map so an inner-block `let` that shadows ANY of
@@ -108,6 +127,11 @@ export interface BodyEmitResult {
108
127
  usedPropagation: boolean;
109
128
  helpers: Set<string>;
110
129
  }
130
+ export interface PyExpressionEmitResult {
131
+ code: string;
132
+ imports: Set<string>;
133
+ helpers: Set<string>;
134
+ }
111
135
  interface BodyEmitContext {
112
136
  gensymCounter: number;
113
137
  imports: Set<string>;
@@ -116,6 +140,8 @@ interface BodyEmitContext {
116
140
  * `each` pair-mode). Consumer emits each entry at module scope. */
117
141
  helpers: Set<string>;
118
142
  symbolMap: Record<string, string>;
143
+ inClassBody: boolean;
144
+ inConstructor: boolean;
119
145
  shadowedSymbols: Set<string>;
120
146
  localScopes: Array<Map<string, 'const' | 'let' | 'cell'>>;
121
147
  regexScopes: Array<Map<string, Extract<ValueIR, {
@@ -146,6 +172,65 @@ interface BodyEmitContext {
146
172
  * override pending control flow, so it gets a finally-specific error. */
147
173
  finallyDepth: number;
148
174
  standaloneExpression: boolean;
175
+ /** When true, helper-dependent JS value→string coercion is emitted
176
+ * (`__kern_add`, `_kern_fmt`-wrapped templates, the `_KERN_UNDEFINED`
177
+ * sentinel + sentinel-aware `??`/`typeof`). Native KERN bodies inject the
178
+ * required helpers function-locally, so the default is true. The Ground/
179
+ * React declarative layer (`coalesce`/`firstDefined`/etc.) emits module-
180
+ * level statements through `emitPyExpression` with NO per-statement helper
181
+ * channel, so it opts out and keeps the pre-coercion-slice forms (raw `+`,
182
+ * raw f-string interpolation, `None` for undefined, None-only `??`).
183
+ * See BodyEmitOptions.coerceJsValues. */
184
+ coerceJsValues: boolean;
185
+ /** Slices 0+1 — block-bodied arrow closure lowering. When `emitLambdaPy`
186
+ * lowers a block arrow it pushes a hoisted local `def __kern_closure_N(...)`
187
+ * (a block of source lines) here and returns the def's NAME as the
188
+ * expression string. `emitChildrenPy`'s per-child loop flushes the buffer
189
+ * IMMEDIATELY BEFORE the statement that referenced it (at the current
190
+ * indent), so the def precedes its use even inside if/else/loop bodies. A
191
+ * buffer left non-empty when a handler body finishes is a BUG (defensive
192
+ * throw at the body-emit entry point). */
193
+ pendingHoists: string[][];
194
+ /** Monotonic gensym counter for hoisted closure def names. Separate from
195
+ * `gensymCounter` so closure names stay stable/independent of other
196
+ * gensym usage. */
197
+ closureSeq: number;
198
+ /** Slice-2 loop-variable pinning. Each entry is the INDEX into `localScopes`
199
+ * of a scope that is a loop BODY (an `each`/`for`/`while` body). A captured
200
+ * name is pinned (JS per-iteration capture → Python default arg) IFF its
201
+ * binding resolves at an index `>= loopScopeIndexes[0]` — i.e. at or inside
202
+ * the OUTERMOST enclosing loop body. Bindings declared OUTSIDE every loop
203
+ * (function params, accumulators, a `while` condition var) resolve below
204
+ * `loopScopeIndexes[0]` and stay late-bound (already JS-parity-correct).
205
+ * Pushed on loop-body entry, popped on exit (LIFO, mirrors `localScopes`). */
206
+ loopScopeIndexes: number[];
207
+ /** Slice-2 fix (agon review, claude 0.7) — one frame per active loop body,
208
+ * parallel to `loopScopeIndexes`. `assignLast` maps a bare assign-target
209
+ * name to the LAST top-level child index (within that loop body) whose
210
+ * subtree assigns it; `current` is the child index the loop body is
211
+ * emitting right now. The default-arg pin freezes a capture at def time,
212
+ * but JS captures BY REFERENCE — so a pinned per-iteration binding that is
213
+ * REASSIGNED in a LATER sibling statement diverges (JS sees the mutation,
214
+ * the frozen default does not). Such captures fail closed at emission
215
+ * instead of emitting silently wrong values. Because within-child statement
216
+ * order is NOT tracked (the whole top-level child shares one index), the
217
+ * reject is `>=` (not `>`): a reassignment in the SAME top-level child as the
218
+ * closure also fails closed (it cannot be proven to run before the closure).
219
+ * `assignLast` covers both `assign` (incl. compound/postfix `op=` forms, same
220
+ * node type) and `set` (a bare-name cell write).
221
+ *
222
+ * Mutation-v1 note: this sibling-reassignment check applies ONLY to PINNED
223
+ * candidates (per-iteration loop-locals that pin via a default arg). A
224
+ * free-variable WRITE inside a closure body (`emitBlockClosurePy`'s
225
+ * `nonlocal` path) targets an OUTER binding declared below the outermost
226
+ * loop scope, so it is never a pin candidate and never enters this frame —
227
+ * the `>=` reject cannot misfire on a nonlocal-written capture. (A write to a
228
+ * binding that IS a per-iteration capture is rejected earlier as
229
+ * `closure-pinned-write`, so the two paths stay disjoint.) */
230
+ loopLaterAssignFrames: Array<{
231
+ assignLast: Map<string, number>;
232
+ current: number;
233
+ }>;
149
234
  }
150
235
  /** PR-4 — Python helpers that normalize `each` pair-mode iteration sources.
151
236
  * Co-located with the codegen so the production emitter and the differential
@@ -213,6 +298,7 @@ export declare function emitNativeKernBodyPythonWithImports(handlerNode: IRNode,
213
298
  * `emitPyExprCtx` which threads the live ctx (and therefore the live
214
299
  * imports set) end-to-end. */
215
300
  export declare function emitPyExpression(node: ValueIR, options?: BodyEmitOptions): string;
301
+ export declare function emitPyExpressionWithImports(node: ValueIR, options?: BodyEmitOptions): PyExpressionEmitResult;
216
302
  export declare function lowerBitwiseAndModuloAST(node: ValueIR): ValueIR;
217
303
  export declare function registerHelpers(node: ValueIR, ctx: BodyEmitContext): void;
218
304
  export {};