diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d7de2646..4ec51fe05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ We'll note all notable changes in this file, including bug fixes, enhancements, and all closed issues. Dates are in `YYYY-MM-DD` format and versions are in [semantic versioning](http://semver.org/) format. +## 0.12.2 2024-10-5 + +### Fixed + +- Corrected debugger behavior in the presence of reused values. + ## 0.12.1 2024-09-28 ### Fixed diff --git a/package.json b/package.json index 3aa881eb7..e62e681d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wordplay", - "version": "0.12.0", + "version": "0.12.2", "scripts": { "postinstall": "run-script-os", "postinstall:default": "svelte-kit sync && cp .env.template .env", diff --git a/src/components/annotations/Annotations.svelte b/src/components/annotations/Annotations.svelte index 40ed19f5f..9d94b895a 100644 --- a/src/components/annotations/Annotations.svelte +++ b/src/components/annotations/Annotations.svelte @@ -212,9 +212,7 @@ ); if (firstExpression) { const value = - evaluator.getLatestExpressionValueInEvaluation( - firstExpression, - ); + evaluator.getLatestExpressionValue(firstExpression); if (value) nodeView = document.querySelector( `.value[data-id="${value.id}"]`, diff --git a/src/components/editor/Editor.svelte b/src/components/editor/Editor.svelte index d315de6a4..2961aa813 100644 --- a/src/components/editor/Editor.svelte +++ b/src/components/editor/Editor.svelte @@ -1163,7 +1163,7 @@ .map((expr) => { return { expression: expr, - value: $evaluation.evaluator.getLatestExpressionValueInEvaluation( + value: $evaluation.evaluator.getLatestExpressionValue( expr, ), }; diff --git a/src/components/editor/NodeView.svelte b/src/components/editor/NodeView.svelte index fb4600751..7afeea382 100644 --- a/src/components/editor/NodeView.svelte +++ b/src/components/editor/NodeView.svelte @@ -49,10 +49,7 @@ node instanceof Expression && !node.isEvaluationInvolved() ) - value = - $evaluation.evaluator.getLatestExpressionValueInEvaluation( - node, - ); + value = $evaluation.evaluator.getLatestExpressionValue(node); } const blocks = isBlocks(); diff --git a/src/models/Project.ts b/src/models/Project.ts index c939d9c2d..48958d31d 100644 --- a/src/models/Project.ts +++ b/src/models/Project.ts @@ -478,13 +478,14 @@ export default class Project { /** Return true if the given expression is in this project and depends only on contants. */ isConstant(expression: Expression): boolean { let constant = this.constants.get(expression); - const context = this.getNodeContext(expression); // If we haven't visited this expression yet, compute it. if (constant === undefined) { // Mark this as not constant, assuming (and preventing) cycles. this.constants.set(expression, false); + // Compute whether the expression is constant. + const context = this.getNodeContext(expression); constant = expression.isConstant(context); - // Now actually compute whether it's constant. + // Cache the determination for later. this.constants.set(expression, constant); } return constant; diff --git a/src/nodes/Expression.ts b/src/nodes/Expression.ts index 7d223f316..04c149749 100644 --- a/src/nodes/Expression.ts +++ b/src/nodes/Expression.ts @@ -134,13 +134,14 @@ export default abstract class Expression extends Node { evaluator: Evaluator, ): Markup; - /** Utility function for getting an optional result */ + /** Utility function for getting an optional result */ getValueIfDefined( locales: Locales, context: Context, evaluator: Evaluator, ) { - const value = evaluator.peekValue(); + const value = + evaluator.peekValue() ?? evaluator.getLatestExpressionValue(this); return value ? new ValueRef(value, locales, context) : undefined; } diff --git a/src/runtime/Evaluator.ts b/src/runtime/Evaluator.ts index 1dbdb68a6..d6c4a5a8b 100644 --- a/src/runtime/Evaluator.ts +++ b/src/runtime/Evaluator.ts @@ -710,7 +710,7 @@ export default class Evaluator { return this.getLatestSourceValue(this.project.getMain()); } - /** Evaluate until we're done */ + /** Prepare for evaluation, and finish if playing. */ start(changedStreams?: StreamValue[], limit = true): void { // If we're not done, finish first, if we were interrupted before. if (!this.isDone()) this.finish(); @@ -718,7 +718,7 @@ export default class Evaluator { // First, initialize any stream dependencies // If there are changed streams, construct a set of affected expressions that need to be reevaluated. // We'll reuse previous values for anything not affected. - if (changedStreams && !this.isInPast()) { + if (changedStreams && changedStreams.length > 0) { this.#currentStreamDependencies = new Set(); for (const stream of changedStreams) { const dependencies = this.#streamDependencies.get( @@ -1131,8 +1131,10 @@ export default class Evaluator { // Reset the project to the beginning of time (but preserve stream history, since that's stored in project). this.resetForEvaluation(true, broadcast); - // Start the evaluation fresh. - this.start(); + console.log('Step back to', change); + + // Start the evaluation fresh, using the changed streams if we found any. + this.start(change ? change.changes.map((c) => c.stream) : undefined); // Step until reaching the target step index. while (this.#stepIndex < destinationStep) { diff --git a/src/runtime/Finish.ts b/src/runtime/Finish.ts index 89a5d77af..2c06a0304 100644 --- a/src/runtime/Finish.ts +++ b/src/runtime/Finish.ts @@ -28,6 +28,8 @@ export function finish(evaluator: Evaluator, expr: Expression) { if (shouldSkip(evaluator, expr)) { const priorValue = evaluator.getLatestExpressionValue(expr); if (priorValue !== undefined) { + // Ask the evaluator to remember the value we computed. + // evaluator.rememberExpressionValue(expr, priorValue); // Evaluate any side effects return expr.evaluate(evaluator, priorValue); } diff --git a/src/runtime/Start.ts b/src/runtime/Start.ts index 3ba211df9..232cedfbc 100644 --- a/src/runtime/Start.ts +++ b/src/runtime/Start.ts @@ -36,6 +36,7 @@ export function start(evaluator: Evaluator, expr: Expression) { shouldSkip(evaluator, expr) && evaluator.getLatestExpressionValue(expr) ) { + console.log('Skipping ' + expr.toWordplay()); // Ask the evaluator to jump past this start's corresponding finish. evaluator.jumpPast(expr); } @@ -46,7 +47,7 @@ export function start(evaluator: Evaluator, expr: Expression) { export function shouldSkip(evaluator: Evaluator, expr: Expression) { return ( !expr.isInternal() && - !evaluator.isInPast() && + // !evaluator.isInPast() && (evaluator.project.isConstant(expr) || (evaluator.isReacting() && !evaluator.isEvaluatingReaction() &&