From 64ad3b5b91aad7bd056b84361a80f81fac27f1df Mon Sep 17 00:00:00 2001 From: Terence Teo Date: Mon, 6 Apr 2026 23:27:43 +0800 Subject: [PATCH 01/14] StreamVis drawing arrows --- src/createContext.ts | 4 ++++ src/cse-machine/closure.ts | 1 + src/cse-machine/interpreter.ts | 29 ++++++++++++++++++++++++++++- src/cse-machine/utils.ts | 11 +++++++++++ src/types.ts | 6 ++++++ src/utils/testing/mocks.ts | 1 + 6 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/createContext.ts b/src/createContext.ts index 5fb347fae..ece102dbb 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -95,6 +95,8 @@ const createEmptyRuntime = () => ({ envStepsTotal: 0, breakpointSteps: [], changepointSteps: [], + streamLineage: new Map(), + streamsPointSteps: [] }); const createEmptyDebugger = () => ({ @@ -140,6 +142,8 @@ export const createEmptyContext = ( runtime: createEmptyRuntime(), numberOfOuterEnvironments: 1, prelude: null, + pendingStreamFnStack: [], + streamLineage: new Map(), debugger: createEmptyDebugger(), nativeStorage: createNativeStorage(), executionMethod: 'auto', diff --git a/src/cse-machine/closure.ts b/src/cse-machine/closure.ts index 73845529c..9001dc6d3 100644 --- a/src/cse-machine/closure.ts +++ b/src/cse-machine/closure.ts @@ -31,6 +31,7 @@ const closureToJS = (value: Closure, context: Context) => { nodes: [...context.runtime.nodes], breakpointSteps: [...context.runtime.breakpointSteps], changepointSteps: [...context.runtime.changepointSteps], + streamsPointSteps: [...context.runtime.streamsPointSteps], debuggerOn: false, }, }; diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index 9b3b8bf14..ec7eed663 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -1,5 +1,5 @@ /** - * This interpreter implements an explicit-control evaluator. + * This interpreter implements an explicit-control evaluator. * * Heavily adapted from https://github.com/source-academy/JSpike/ * and the legacy interpreter @@ -60,6 +60,7 @@ import { declareIdentifier, defineVariable, envChanging, + envChangingStreams, getVariable, handleArrayCreation, handleRuntimeError, @@ -359,6 +360,25 @@ export function* generateCSEMachineStateStream( context.runtime.changepointSteps.push(steps + 1); } + if (!isPrelude && envChangingStreams(command, context)) { + // same as !isPrelude && envChanging(command) check above + // but this checks if next instruction on control is a pair() function + // Usage: streams visualiser + context.runtime.streamsPointSteps.push(steps + 1) + } + const evalResult = context.runtime.stash?.peek(); + const mostRecentControlHeight = context.pendingStreamFnStack[context.pendingStreamFnStack.length -1]?.[1] + + if(Array.isArray(evalResult) && evalResult.length == 2 && mostRecentControlHeight != undefined && context.runtime.control?.size() == parseInt(mostRecentControlHeight) - 1) { + const mostRecentNullaryFnId = context.pendingStreamFnStack.pop()?.[0] + if (mostRecentNullaryFnId != undefined){ + if (!context.streamLineage.get(mostRecentNullaryFnId)) { + context.streamLineage.set(mostRecentNullaryFnId, []) + } + context.streamLineage.get(mostRecentNullaryFnId)?.push((evalResult as any).id) + } + } + control.pop(); if (isNode(command)) { context.runtime.nodes.shift(); @@ -834,6 +854,13 @@ const cmdEvaluators: CommandEvaluators = { context.runtime.environments.unshift(func.environment); } + // Streams Visualisation: + // If CALL0, push the nullary fn to pendingStreamFnStack + // (to map which nullary fn produces which pairs; for nested nullary fn) + if (func.node.params.length === 0) { + context.pendingStreamFnStack.push([func.id, context.runtime.control !== null ? context.runtime.control.size().toString() : "0"]) + } + // Handle special case if function is simple if (isSimpleFunction(func.node)) { // Closures convert ArrowExpressionStatements to BlockStatements diff --git a/src/cse-machine/utils.ts b/src/cse-machine/utils.ts index d3c32b462..95084fede 100644 --- a/src/cse-machine/utils.ts +++ b/src/cse-machine/utils.ts @@ -255,6 +255,17 @@ export const envChanging = (command: ControlItem): boolean => { } }; +export const envChangingStreams = (command: ControlItem, context: Context): boolean => { + if (isInstr(command)) { + const evalResult = context.runtime.stash?.peek(); + const mostRecentControlHeight = context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1] + if (Array.isArray(evalResult) && evalResult.length == 2 && mostRecentControlHeight != undefined && context.runtime.control?.size() == parseInt(mostRecentControlHeight) - 1) { + return true + } + } + return false +} + // TODO: This type guard does not seem to be doing what it thinks its doing /** * To determine if the function is simple. diff --git a/src/types.ts b/src/types.ts index 0b0ea6323..4079643c3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -63,8 +63,14 @@ export interface Context { envStepsTotal: number; breakpointSteps: number[]; changepointSteps: number[]; + streamsPointSteps: number[] }; + // STREAM VISUALISATION + streamLineage: Map + + pendingStreamFnStack: (string[] | undefined)[] + numberOfOuterEnvironments: number; prelude: string | null; diff --git a/src/utils/testing/mocks.ts b/src/utils/testing/mocks.ts index dad633e2f..7753c3646 100644 --- a/src/utils/testing/mocks.ts +++ b/src/utils/testing/mocks.ts @@ -61,6 +61,7 @@ export function mockRuntimeContext(): Context { envStepsTotal: 0, breakpointSteps: [], changepointSteps: [], + streamsPointSteps: [] }; return context; } From 73e080460f1792d40d8a90018887ddc05ab08be5 Mon Sep 17 00:00:00 2001 From: TristanTayYuHng <33745288+TristanTayYuHng@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:37:10 +0800 Subject: [PATCH 02/14] added gemini suggestions --- src/createContext.ts | 1 - src/cse-machine/interpreter.ts | 6 +++--- src/cse-machine/utils.ts | 2 +- src/types.ts | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/createContext.ts b/src/createContext.ts index ece102dbb..4b292a58c 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -95,7 +95,6 @@ const createEmptyRuntime = () => ({ envStepsTotal: 0, breakpointSteps: [], changepointSteps: [], - streamLineage: new Map(), streamsPointSteps: [] }); diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index ec7eed663..09c282d46 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -367,9 +367,9 @@ export function* generateCSEMachineStateStream( context.runtime.streamsPointSteps.push(steps + 1) } const evalResult = context.runtime.stash?.peek(); - const mostRecentControlHeight = context.pendingStreamFnStack[context.pendingStreamFnStack.length -1]?.[1] + const mostRecentControlHeight = context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1] - if(Array.isArray(evalResult) && evalResult.length == 2 && mostRecentControlHeight != undefined && context.runtime.control?.size() == parseInt(mostRecentControlHeight) - 1) { + if(Array.isArray(evalResult) && evalResult.length == 2 && mostRecentControlHeight != undefined && context.runtime.control?.size() == mostRecentControlHeight - 1) { const mostRecentNullaryFnId = context.pendingStreamFnStack.pop()?.[0] if (mostRecentNullaryFnId != undefined){ if (!context.streamLineage.get(mostRecentNullaryFnId)) { @@ -858,7 +858,7 @@ const cmdEvaluators: CommandEvaluators = { // If CALL0, push the nullary fn to pendingStreamFnStack // (to map which nullary fn produces which pairs; for nested nullary fn) if (func.node.params.length === 0) { - context.pendingStreamFnStack.push([func.id, context.runtime.control !== null ? context.runtime.control.size().toString() : "0"]) + context.pendingStreamFnStack.push([func.id, context.runtime.control !== null ? context.runtime.control.size() : 0]) } // Handle special case if function is simple diff --git a/src/cse-machine/utils.ts b/src/cse-machine/utils.ts index 95084fede..17a33ed42 100644 --- a/src/cse-machine/utils.ts +++ b/src/cse-machine/utils.ts @@ -259,7 +259,7 @@ export const envChangingStreams = (command: ControlItem, context: Context): bool if (isInstr(command)) { const evalResult = context.runtime.stash?.peek(); const mostRecentControlHeight = context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1] - if (Array.isArray(evalResult) && evalResult.length == 2 && mostRecentControlHeight != undefined && context.runtime.control?.size() == parseInt(mostRecentControlHeight) - 1) { + if (Array.isArray(evalResult) && evalResult.length == 2 && mostRecentControlHeight != undefined && context.runtime.control?.size() == mostRecentControlHeight - 1) { return true } } diff --git a/src/types.ts b/src/types.ts index 4079643c3..abe65ced7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -69,7 +69,7 @@ export interface Context { // STREAM VISUALISATION streamLineage: Map - pendingStreamFnStack: (string[] | undefined)[] + pendingStreamFnStack: [string, number][] numberOfOuterEnvironments: number; From a77832a45c363f9d93f0e5dad5233786ad0fb9cf Mon Sep 17 00:00:00 2001 From: TristanTayYuHng <33745288+TristanTayYuHng@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:43:43 +0800 Subject: [PATCH 03/14] More gemini fixes, apologies for spam --- src/cse-machine/interpreter.ts | 4 ++-- src/cse-machine/utils.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index 09c282d46..d33e7d794 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -369,9 +369,9 @@ export function* generateCSEMachineStateStream( const evalResult = context.runtime.stash?.peek(); const mostRecentControlHeight = context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1] - if(Array.isArray(evalResult) && evalResult.length == 2 && mostRecentControlHeight != undefined && context.runtime.control?.size() == mostRecentControlHeight - 1) { + if (Array.isArray(evalResult) && evalResult.length === 2 && mostRecentControlHeight !== undefined && context.runtime.control?.size() === mostRecentControlHeight - 1) { const mostRecentNullaryFnId = context.pendingStreamFnStack.pop()?.[0] - if (mostRecentNullaryFnId != undefined){ + if (mostRecentNullaryFnId !== undefined){ if (!context.streamLineage.get(mostRecentNullaryFnId)) { context.streamLineage.set(mostRecentNullaryFnId, []) } diff --git a/src/cse-machine/utils.ts b/src/cse-machine/utils.ts index 17a33ed42..7f6d27cad 100644 --- a/src/cse-machine/utils.ts +++ b/src/cse-machine/utils.ts @@ -259,7 +259,7 @@ export const envChangingStreams = (command: ControlItem, context: Context): bool if (isInstr(command)) { const evalResult = context.runtime.stash?.peek(); const mostRecentControlHeight = context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1] - if (Array.isArray(evalResult) && evalResult.length == 2 && mostRecentControlHeight != undefined && context.runtime.control?.size() == mostRecentControlHeight - 1) { + if (Array.isArray(evalResult) && evalResult.length === 2 && mostRecentControlHeight !== undefined && context.runtime.control?.size() === mostRecentControlHeight - 1) { return true } } From 71c2d31789c8a8ff4d999b44ff37b602cce393af Mon Sep 17 00:00:00 2001 From: TristanTayYuHng <33745288+TristanTayYuHng@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:55:01 +0800 Subject: [PATCH 04/14] Yarn format --- src/createContext.ts | 2 +- src/cse-machine/interpreter.ts | 35 +++++++++++++++++++++------------- src/cse-machine/utils.ts | 16 +++++++++++----- src/types.ts | 6 +++--- 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/createContext.ts b/src/createContext.ts index 4b292a58c..998d2ffc8 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -95,7 +95,7 @@ const createEmptyRuntime = () => ({ envStepsTotal: 0, breakpointSteps: [], changepointSteps: [], - streamsPointSteps: [] + streamsPointSteps: [], }); const createEmptyDebugger = () => ({ diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index d33e7d794..ea422879f 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -1,5 +1,5 @@ /** - * This interpreter implements an explicit-control evaluator. + * This interpreter implements an explicit-control evaluator. * * Heavily adapted from https://github.com/source-academy/JSpike/ * and the legacy interpreter @@ -360,24 +360,30 @@ export function* generateCSEMachineStateStream( context.runtime.changepointSteps.push(steps + 1); } - if (!isPrelude && envChangingStreams(command, context)) { + if (!isPrelude && envChangingStreams(command, context)) { // same as !isPrelude && envChanging(command) check above // but this checks if next instruction on control is a pair() function // Usage: streams visualiser - context.runtime.streamsPointSteps.push(steps + 1) + context.runtime.streamsPointSteps.push(steps + 1); } const evalResult = context.runtime.stash?.peek(); - const mostRecentControlHeight = context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1] + const mostRecentControlHeight = + context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1]; - if (Array.isArray(evalResult) && evalResult.length === 2 && mostRecentControlHeight !== undefined && context.runtime.control?.size() === mostRecentControlHeight - 1) { - const mostRecentNullaryFnId = context.pendingStreamFnStack.pop()?.[0] - if (mostRecentNullaryFnId !== undefined){ + if ( + Array.isArray(evalResult) && + evalResult.length === 2 && + mostRecentControlHeight !== undefined && + context.runtime.control?.size() === mostRecentControlHeight - 1 + ) { + const mostRecentNullaryFnId = context.pendingStreamFnStack.pop()?.[0]; + if (mostRecentNullaryFnId !== undefined) { if (!context.streamLineage.get(mostRecentNullaryFnId)) { - context.streamLineage.set(mostRecentNullaryFnId, []) + context.streamLineage.set(mostRecentNullaryFnId, []); } - context.streamLineage.get(mostRecentNullaryFnId)?.push((evalResult as any).id) + context.streamLineage.get(mostRecentNullaryFnId)?.push((evalResult as any).id); } - } + } control.pop(); if (isNode(command)) { @@ -855,11 +861,14 @@ const cmdEvaluators: CommandEvaluators = { } // Streams Visualisation: - // If CALL0, push the nullary fn to pendingStreamFnStack + // If CALL0, push the nullary fn to pendingStreamFnStack // (to map which nullary fn produces which pairs; for nested nullary fn) if (func.node.params.length === 0) { - context.pendingStreamFnStack.push([func.id, context.runtime.control !== null ? context.runtime.control.size() : 0]) - } + context.pendingStreamFnStack.push([ + func.id, + context.runtime.control !== null ? context.runtime.control.size() : 0, + ]); + } // Handle special case if function is simple if (isSimpleFunction(func.node)) { diff --git a/src/cse-machine/utils.ts b/src/cse-machine/utils.ts index 7f6d27cad..6bca4e227 100644 --- a/src/cse-machine/utils.ts +++ b/src/cse-machine/utils.ts @@ -258,13 +258,19 @@ export const envChanging = (command: ControlItem): boolean => { export const envChangingStreams = (command: ControlItem, context: Context): boolean => { if (isInstr(command)) { const evalResult = context.runtime.stash?.peek(); - const mostRecentControlHeight = context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1] - if (Array.isArray(evalResult) && evalResult.length === 2 && mostRecentControlHeight !== undefined && context.runtime.control?.size() === mostRecentControlHeight - 1) { - return true + const mostRecentControlHeight = + context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1]; + if ( + Array.isArray(evalResult) && + evalResult.length === 2 && + mostRecentControlHeight !== undefined && + context.runtime.control?.size() === mostRecentControlHeight - 1 + ) { + return true; } } - return false -} + return false; +}; // TODO: This type guard does not seem to be doing what it thinks its doing /** diff --git a/src/types.ts b/src/types.ts index abe65ced7..916f45ab0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -63,13 +63,13 @@ export interface Context { envStepsTotal: number; breakpointSteps: number[]; changepointSteps: number[]; - streamsPointSteps: number[] + streamsPointSteps: number[]; }; // STREAM VISUALISATION - streamLineage: Map + streamLineage: Map; - pendingStreamFnStack: [string, number][] + pendingStreamFnStack: [string, number][]; numberOfOuterEnvironments: number; From 464c7ca21cb63a352f89ab1e311f1dc7951a68bc Mon Sep 17 00:00:00 2001 From: TristanTayYuHng <33745288+TristanTayYuHng@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:57:16 +0800 Subject: [PATCH 05/14] Yarn format --- src/utils/testing/mocks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/testing/mocks.ts b/src/utils/testing/mocks.ts index 7753c3646..fac6637c4 100644 --- a/src/utils/testing/mocks.ts +++ b/src/utils/testing/mocks.ts @@ -61,7 +61,7 @@ export function mockRuntimeContext(): Context { envStepsTotal: 0, breakpointSteps: [], changepointSteps: [], - streamsPointSteps: [] + streamsPointSteps: [], }; return context; } From eabfb64fd5dc539fdd78b5f347f02cead2fb5261 Mon Sep 17 00:00:00 2001 From: Terence Teo Date: Thu, 9 Apr 2026 09:24:22 +0800 Subject: [PATCH 06/14] removed envChangingStreams --- src/cse-machine/interpreter.ts | 9 +-------- src/cse-machine/utils.ts | 17 +---------------- 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index ea422879f..a61d7bebe 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -60,7 +60,6 @@ import { declareIdentifier, defineVariable, envChanging, - envChangingStreams, getVariable, handleArrayCreation, handleRuntimeError, @@ -359,13 +358,7 @@ export function* generateCSEMachineStateStream( // Hence, next step will change the environment context.runtime.changepointSteps.push(steps + 1); } - - if (!isPrelude && envChangingStreams(command, context)) { - // same as !isPrelude && envChanging(command) check above - // but this checks if next instruction on control is a pair() function - // Usage: streams visualiser - context.runtime.streamsPointSteps.push(steps + 1); - } + const evalResult = context.runtime.stash?.peek(); const mostRecentControlHeight = context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1]; diff --git a/src/cse-machine/utils.ts b/src/cse-machine/utils.ts index 6bca4e227..64e195a7e 100644 --- a/src/cse-machine/utils.ts +++ b/src/cse-machine/utils.ts @@ -255,22 +255,7 @@ export const envChanging = (command: ControlItem): boolean => { } }; -export const envChangingStreams = (command: ControlItem, context: Context): boolean => { - if (isInstr(command)) { - const evalResult = context.runtime.stash?.peek(); - const mostRecentControlHeight = - context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1]; - if ( - Array.isArray(evalResult) && - evalResult.length === 2 && - mostRecentControlHeight !== undefined && - context.runtime.control?.size() === mostRecentControlHeight - 1 - ) { - return true; - } - } - return false; -}; + // TODO: This type guard does not seem to be doing what it thinks its doing /** From d7b569f92ffc68577d3cf3503ec6607aaadc8518 Mon Sep 17 00:00:00 2001 From: TristanTayYuHng <33745288+TristanTayYuHng@users.noreply.github.com> Date: Thu, 9 Apr 2026 20:50:52 +0800 Subject: [PATCH 07/14] simplified js-slang for mvp --- src/alt-langs/scheme/scm-slang | 1 + src/createContext.ts | 3 +-- src/cse-machine/closure.ts | 1 - src/types.ts | 1 - src/utils/testing/mocks.ts | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) create mode 160000 src/alt-langs/scheme/scm-slang diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang new file mode 160000 index 000000000..3cd7cbc5a --- /dev/null +++ b/src/alt-langs/scheme/scm-slang @@ -0,0 +1 @@ +Subproject commit 3cd7cbc5aef2a0b20ee77e2d1a41d1408758775e diff --git a/src/createContext.ts b/src/createContext.ts index 998d2ffc8..c42916fa4 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -94,8 +94,7 @@ const createEmptyRuntime = () => ({ envSteps: -1, envStepsTotal: 0, breakpointSteps: [], - changepointSteps: [], - streamsPointSteps: [], + changepointSteps: [] }); const createEmptyDebugger = () => ({ diff --git a/src/cse-machine/closure.ts b/src/cse-machine/closure.ts index 9001dc6d3..73845529c 100644 --- a/src/cse-machine/closure.ts +++ b/src/cse-machine/closure.ts @@ -31,7 +31,6 @@ const closureToJS = (value: Closure, context: Context) => { nodes: [...context.runtime.nodes], breakpointSteps: [...context.runtime.breakpointSteps], changepointSteps: [...context.runtime.changepointSteps], - streamsPointSteps: [...context.runtime.streamsPointSteps], debuggerOn: false, }, }; diff --git a/src/types.ts b/src/types.ts index 916f45ab0..85c35106c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -63,7 +63,6 @@ export interface Context { envStepsTotal: number; breakpointSteps: number[]; changepointSteps: number[]; - streamsPointSteps: number[]; }; // STREAM VISUALISATION diff --git a/src/utils/testing/mocks.ts b/src/utils/testing/mocks.ts index fac6637c4..dad633e2f 100644 --- a/src/utils/testing/mocks.ts +++ b/src/utils/testing/mocks.ts @@ -61,7 +61,6 @@ export function mockRuntimeContext(): Context { envStepsTotal: 0, breakpointSteps: [], changepointSteps: [], - streamsPointSteps: [], }; return context; } From 9ece1e0cf25de68327d188bc60f8f1c2efb6d68e Mon Sep 17 00:00:00 2001 From: TristanTayYuHng <33745288+TristanTayYuHng@users.noreply.github.com> Date: Thu, 9 Apr 2026 20:53:00 +0800 Subject: [PATCH 08/14] fixed some submodul update issue --- src/py-slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py-slang b/src/py-slang index 9a3eceb6b..c5fc711d7 160000 --- a/src/py-slang +++ b/src/py-slang @@ -1 +1 @@ -Subproject commit 9a3eceb6b03b077b6c187b068f80b74136aa5c53 +Subproject commit c5fc711d7fa7974d78b2b95f85c6dcabb8f8c691 From 2d7d178ca59c9646bf8f75d6cdec7fd9a71954a9 Mon Sep 17 00:00:00 2001 From: TristanTayYuHng <33745288+TristanTayYuHng@users.noreply.github.com> Date: Thu, 9 Apr 2026 21:20:46 +0800 Subject: [PATCH 09/14] Remove orphaned scm-slang submodule --- src/alt-langs/scheme/scm-slang | 1 - 1 file changed, 1 deletion(-) delete mode 160000 src/alt-langs/scheme/scm-slang diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang deleted file mode 160000 index 3cd7cbc5a..000000000 --- a/src/alt-langs/scheme/scm-slang +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3cd7cbc5aef2a0b20ee77e2d1a41d1408758775e From 5b1f38583d8430bbfffdb20ef2de8ff76205b67a Mon Sep 17 00:00:00 2001 From: TristanTayYuHng <33745288+TristanTayYuHng@users.noreply.github.com> Date: Fri, 10 Apr 2026 18:21:34 +0800 Subject: [PATCH 10/14] fix py-slang --- src/py-slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py-slang b/src/py-slang index c5fc711d7..9c30dba1d 160000 --- a/src/py-slang +++ b/src/py-slang @@ -1 +1 @@ -Subproject commit c5fc711d7fa7974d78b2b95f85c6dcabb8f8c691 +Subproject commit 9c30dba1d96095c826375a48d0a84eed757a39f6 From a19e188b4301ef00ec3aa8cf8d175a9f5599ac49 Mon Sep 17 00:00:00 2001 From: TristanTayYuHng <33745288+TristanTayYuHng@users.noreply.github.com> Date: Fri, 10 Apr 2026 18:30:15 +0800 Subject: [PATCH 11/14] fix py-slang --- src/py-slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py-slang b/src/py-slang index 9c30dba1d..9a3eceb6b 160000 --- a/src/py-slang +++ b/src/py-slang @@ -1 +1 @@ -Subproject commit 9c30dba1d96095c826375a48d0a84eed757a39f6 +Subproject commit 9a3eceb6b03b077b6c187b068f80b74136aa5c53 From c05d79ec1d2b41f48fc88b20818f1e7f6b764f78 Mon Sep 17 00:00:00 2001 From: TristanTayYuHng <33745288+TristanTayYuHng@users.noreply.github.com> Date: Fri, 10 Apr 2026 18:35:08 +0800 Subject: [PATCH 12/14] yarn format --- src/createContext.ts | 2 +- src/cse-machine/interpreter.ts | 2 +- src/cse-machine/utils.ts | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/createContext.ts b/src/createContext.ts index c42916fa4..0494f19ae 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -94,7 +94,7 @@ const createEmptyRuntime = () => ({ envSteps: -1, envStepsTotal: 0, breakpointSteps: [], - changepointSteps: [] + changepointSteps: [], }); const createEmptyDebugger = () => ({ diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index a61d7bebe..96fb4d4bb 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -358,7 +358,7 @@ export function* generateCSEMachineStateStream( // Hence, next step will change the environment context.runtime.changepointSteps.push(steps + 1); } - + const evalResult = context.runtime.stash?.peek(); const mostRecentControlHeight = context.pendingStreamFnStack[context.pendingStreamFnStack.length - 1]?.[1]; diff --git a/src/cse-machine/utils.ts b/src/cse-machine/utils.ts index 64e195a7e..d3c32b462 100644 --- a/src/cse-machine/utils.ts +++ b/src/cse-machine/utils.ts @@ -255,8 +255,6 @@ export const envChanging = (command: ControlItem): boolean => { } }; - - // TODO: This type guard does not seem to be doing what it thinks its doing /** * To determine if the function is simple. From 7508606f7676e3cda907c3b8fd87df6a06569b51 Mon Sep 17 00:00:00 2001 From: DaRealTristan Date: Tue, 14 Apr 2026 20:06:21 +0800 Subject: [PATCH 13/14] Added tests for streamLineage --- .../cse-machine-runtime-context.test.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/cse-machine/__tests__/cse-machine-runtime-context.test.ts b/src/cse-machine/__tests__/cse-machine-runtime-context.test.ts index 1c4d85506..1481d7a20 100644 --- a/src/cse-machine/__tests__/cse-machine-runtime-context.test.ts +++ b/src/cse-machine/__tests__/cse-machine-runtime-context.test.ts @@ -210,3 +210,43 @@ test('Avoid unnescessary environment instruction 4', () => { expect(state.control.getNumEnvDependentItems()).toMatchSnapshot(); } }); + +test('CSE Machine correctly updates streamLineage with simple streams', async () => { + const context = await getContextFrom( + stripIndent` + const s1 = pair(1, () => pair(2, () => pair(3, () => null))); + eval_stream(s1, 3); + `, + 172, + ); + + expect(context.streamLineage.size).toEqual(2); +}); + +test('CSE Machine correctly updates streamLineage with self-referential streams', async () => { + const context = await getContextFrom( + stripIndent` + const s1 = pair(1, () => s1); + eval_stream(s1, 3); + `, + 164, + ); + + expect((context.streamLineage.values().next().value as Array).length).toEqual(2); +}); + +test('CSE Machine does not update streamLineage when nullary function does not return a stream', async () => { + const context = await getContextFrom( + stripIndent` + const s1 = pair(1, () => [0, 1, 2, () => 1]); + stream_tail(s1); + const s2 = pair(1, x => s2); + tail(s2)(1); + const s3 = pair(1, () => 2); + stream_tail(s3); + `, + 115, + ); + + expect(context.streamLineage.size).toEqual(0); +}); \ No newline at end of file From ec3e8307f8b82d96c1d45edde356808fffeb56ed Mon Sep 17 00:00:00 2001 From: DaRealTristan Date: Tue, 14 Apr 2026 20:14:24 +0800 Subject: [PATCH 14/14] yarn format --- .../__tests__/cse-machine-runtime-context.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cse-machine/__tests__/cse-machine-runtime-context.test.ts b/src/cse-machine/__tests__/cse-machine-runtime-context.test.ts index 1481d7a20..90a943bed 100644 --- a/src/cse-machine/__tests__/cse-machine-runtime-context.test.ts +++ b/src/cse-machine/__tests__/cse-machine-runtime-context.test.ts @@ -219,7 +219,7 @@ test('CSE Machine correctly updates streamLineage with simple streams', async () `, 172, ); - + expect(context.streamLineage.size).toEqual(2); }); @@ -231,7 +231,7 @@ test('CSE Machine correctly updates streamLineage with self-referential streams' `, 164, ); - + expect((context.streamLineage.values().next().value as Array).length).toEqual(2); }); @@ -247,6 +247,6 @@ test('CSE Machine does not update streamLineage when nullary function does not r `, 115, ); - + expect(context.streamLineage.size).toEqual(0); -}); \ No newline at end of file +});