Skip to content

Commit 7b8512a

Browse files
authored
Merge pull request #313 from pathsim/refactor/engine-codegen-seam
Codegen: engine setup seam + consistent _block_key
2 parents e9d4913 + 45e8972 commit 7b8512a

2 files changed

Lines changed: 56 additions & 1 deletion

File tree

src/lib/pyodide/engineCodegen.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Engine-specific codegen seam.
3+
*
4+
* Lets an alternate-engine build inject setup code into the generated Python
5+
* *after* the imports and *before* the blocks, without touching the shared
6+
* code generation in pathsimRunner.ts. The default engine (pathsim) needs none,
7+
* so this is a no-op that a re-engined build swaps out (like the worker-side
8+
* engineInstall seam).
9+
*
10+
* Example (fastsim): emit class-level `port()` wraps for toolbox block classes,
11+
* because fastsim's `Connection` only accepts fastsim blocks, so a pathsim
12+
* toolbox block must be ported at the class level before any instance is built.
13+
*/
14+
15+
/** A named block of setup lines emitted after imports, before block creation. */
16+
export interface EngineSetup {
17+
/** Section header, rendered as a `# <header>` comment (with a banner on export). */
18+
header: string;
19+
/** Python source lines for the section body. */
20+
lines: string[];
21+
}
22+
23+
/**
24+
* Engine-specific setup code, given the block import groups (import path → class
25+
* names) collected from the graph. Returns null when the engine needs no setup
26+
* (the default), in which case no section is emitted.
27+
*/
28+
export function generateEngineSetup(
29+
_importGroups: Map<string, Set<string>>
30+
): EngineSetup | null {
31+
return null;
32+
}

src/lib/pyodide/pathsimRunner.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { BLOCK_CATEGORY_ORDER } from '$lib/constants/python';
1313
import { isSubsystem, isInterface } from '$lib/nodes/shapes';
1414
import { blockImportPaths } from '$lib/nodes/generated/blocks';
1515
import { ENGINE_MODULE, enginePath } from '$lib/constants/engine';
16+
import { generateEngineSetup } from './engineCodegen';
1617
import { graphStore, findParentSubsystem } from '$lib/stores/graph';
1718
import {
1819
runStreamingSimulation,
@@ -421,6 +422,14 @@ export function generatePythonCode(
421422
}
422423
lines.push('');
423424

425+
// 1b. Engine-specific setup (e.g. fastsim port() wraps); no-op by default.
426+
const engineSetup = generateEngineSetup(importGroups);
427+
if (engineSetup) {
428+
lines.push(`# ${engineSetup.header}`);
429+
lines.push(...engineSetup.lines);
430+
lines.push('');
431+
}
432+
424433
// 2. Code context (user-defined variables/functions)
425434
if (codeContext.trim()) {
426435
lines.push('# CODE CONTEXT');
@@ -475,7 +484,10 @@ export function generatePythonCode(
475484
lines.push('# NODE ID MAPPING (for data extraction)');
476485
lines.push('_node_id_map = {');
477486
for (const [nodeId, varName] of nodeVars) {
478-
lines.push(` id(${varName}): "${nodeId}",`);
487+
// _block_key (REPL setup) uses the engine's stable block_id when
488+
// present and falls back to id(), so static entries here stay
489+
// consistent with the mutation-added ones in _apply_mutations.
490+
lines.push(` _block_key(${varName}): "${nodeId}",`);
479491
}
480492
lines.push('}');
481493
lines.push('');
@@ -599,6 +611,17 @@ function generateFormattedPythonCode(
599611
}
600612
lines.push('');
601613

614+
// Engine-specific setup (e.g. fastsim port() wraps); no-op by default.
615+
const engineSetup = generateEngineSetup(importGroups);
616+
if (engineSetup) {
617+
lines.push(divider);
618+
lines.push(`# ${engineSetup.header}`);
619+
lines.push(divider);
620+
lines.push('');
621+
lines.push(...engineSetup.lines);
622+
lines.push('');
623+
}
624+
602625
// Code context (user-defined variables/functions)
603626
if (codeContext.trim()) {
604627
lines.push(divider);

0 commit comments

Comments
 (0)