Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/lib/pyodide/engineCodegen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Engine-specific codegen seam.
*
* Lets an alternate-engine build inject setup code into the generated Python
* *after* the imports and *before* the blocks, without touching the shared
* code generation in pathsimRunner.ts. The default engine (pathsim) needs none,
* so this is a no-op that a re-engined build swaps out (like the worker-side
* engineInstall seam).
*
* Example (fastsim): emit class-level `port()` wraps for toolbox block classes,
* because fastsim's `Connection` only accepts fastsim blocks, so a pathsim
* toolbox block must be ported at the class level before any instance is built.
*/

/** A named block of setup lines emitted after imports, before block creation. */
export interface EngineSetup {
/** Section header, rendered as a `# <header>` comment (with a banner on export). */
header: string;
/** Python source lines for the section body. */
lines: string[];
}

/**
* Engine-specific setup code, given the block import groups (import path → class
* names) collected from the graph. Returns null when the engine needs no setup
* (the default), in which case no section is emitted.
*/
export function generateEngineSetup(
_importGroups: Map<string, Set<string>>
): EngineSetup | null {
return null;
}
25 changes: 24 additions & 1 deletion src/lib/pyodide/pathsimRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { BLOCK_CATEGORY_ORDER } from '$lib/constants/python';
import { isSubsystem, isInterface } from '$lib/nodes/shapes';
import { blockImportPaths } from '$lib/nodes/generated/blocks';
import { ENGINE_MODULE, enginePath } from '$lib/constants/engine';
import { generateEngineSetup } from './engineCodegen';
import { graphStore, findParentSubsystem } from '$lib/stores/graph';
import {
runStreamingSimulation,
Expand Down Expand Up @@ -421,6 +422,14 @@ export function generatePythonCode(
}
lines.push('');

// 1b. Engine-specific setup (e.g. fastsim port() wraps); no-op by default.
const engineSetup = generateEngineSetup(importGroups);
if (engineSetup) {
lines.push(`# ${engineSetup.header}`);
lines.push(...engineSetup.lines);
lines.push('');
}

// 2. Code context (user-defined variables/functions)
if (codeContext.trim()) {
lines.push('# CODE CONTEXT');
Expand Down Expand Up @@ -475,7 +484,10 @@ export function generatePythonCode(
lines.push('# NODE ID MAPPING (for data extraction)');
lines.push('_node_id_map = {');
for (const [nodeId, varName] of nodeVars) {
lines.push(` id(${varName}): "${nodeId}",`);
// _block_key (REPL setup) uses the engine's stable block_id when
// present and falls back to id(), so static entries here stay
// consistent with the mutation-added ones in _apply_mutations.
lines.push(` _block_key(${varName}): "${nodeId}",`);
}
lines.push('}');
lines.push('');
Expand Down Expand Up @@ -599,6 +611,17 @@ function generateFormattedPythonCode(
}
lines.push('');

// Engine-specific setup (e.g. fastsim port() wraps); no-op by default.
const engineSetup = generateEngineSetup(importGroups);
if (engineSetup) {
lines.push(divider);
lines.push(`# ${engineSetup.header}`);
lines.push(divider);
lines.push('');
lines.push(...engineSetup.lines);
lines.push('');
}

// Code context (user-defined variables/functions)
if (codeContext.trim()) {
lines.push(divider);
Expand Down
Loading