From e6f6ceee6c009f5f9ccc8dff8e94f8cefe58ea03 Mon Sep 17 00:00:00 2001 From: Andrew Michael McNutt Date: Sun, 19 Jan 2025 18:46:54 -0700 Subject: [PATCH] make some stuff work/break some other stuff --- .../src/lib/SmallStepEvaluator.test.ts | 25 +++++- .../SmallStepEvaluator.test.ts.snap | 82 +++++++++++++++++++ .../lil-buddy/src/lib/small-step-evaluator.ts | 73 +++++++++++------ .../linting/summary-nodes/DispatchNode.svelte | 28 ++++++- .../linting/summary-nodes/InlineNode.svelte | 46 ++++++++++- 5 files changed, 221 insertions(+), 33 deletions(-) diff --git a/apps/lil-buddy/src/lib/SmallStepEvaluator.test.ts b/apps/lil-buddy/src/lib/SmallStepEvaluator.test.ts index 5291f47..04f1ff0 100644 --- a/apps/lil-buddy/src/lib/SmallStepEvaluator.test.ts +++ b/apps/lil-buddy/src/lib/SmallStepEvaluator.test.ts @@ -1,6 +1,6 @@ import { expect, test } from "vitest"; import { makePalFromString } from "color-buddy-palette"; -import { GenerateAST } from "color-buddy-palette-lint"; +import { GenerateAST, PREBUILT_LINTS } from "color-buddy-palette-lint"; import { generateEvaluations } from "./small-step-evaluator"; const defaultPal = makePalFromString(["red", "green"]); @@ -42,3 +42,26 @@ test("Agg Test", () => { const result = generateEvaluations(ast, {}, defaultPal); expect(result).toMatchSnapshot(); }); + +test("Fair Test", () => { + const fair = { + "<": { + left: { extent: { sort: "colors", varb: "x", func: { "lch.l": "x" } } }, + right: 50, + }, + }; + const ast = (GenerateAST(fair as any).value as any).children[0] as any; + const result = generateEvaluations(ast, {}, defaultPal); + expect(result).toMatchSnapshot(); +}); + +// test("All Test", () => { +// for (const test in PREBUILT_LINTS) { +// const lint = PREBUILT_LINTS[test as keyof typeof PREBUILT_LINTS]; +// console.log(lint); +// const lintProgram = JSON.parse(lint.program); +// const ast = (GenerateAST(lintProgram).value as any).children[0] as any; +// const result = generateEvaluations(ast, {}, defaultPal); +// expect(result).toMatchSnapshot(); +// } +// }); diff --git a/apps/lil-buddy/src/lib/__snapshots__/SmallStepEvaluator.test.ts.snap b/apps/lil-buddy/src/lib/__snapshots__/SmallStepEvaluator.test.ts.snap index 6565d01..be4f671 100644 --- a/apps/lil-buddy/src/lib/__snapshots__/SmallStepEvaluator.test.ts.snap +++ b/apps/lil-buddy/src/lib/__snapshots__/SmallStepEvaluator.test.ts.snap @@ -42,6 +42,88 @@ exports[`Agg Test 1`] = ` ] `; +exports[`Fair Test 1`] = ` +[ + LLExpression { + "nodeType": "expression", + "value": LLPredicate { + "left": LLAggregate { + "children": LLMap { + "children": LLVariable { + "nodeType": "variable", + "value": "colors", + }, + "func": LLValueFunction { + "input": LLVariable { + "nodeType": "variable", + "value": "x", + }, + "nodeType": "valueFunction", + "params": {}, + "type": "lch.l", + }, + "nodeType": "map", + "type": "sort", + "varb": "x", + }, + "nodeType": "aggregate", + "type": "extent", + }, + "nodeType": "predicate", + "right": LLNumber { + "nodeType": "number", + "value": 50, + }, + "threshold": undefined, + "type": "<", + }, + }, + LLPredicate { + "left": LLAggregate { + "children": LLValueArray { + "children": [ + LLNumber { + "nodeType": "number", + "value": 46.278, + }, + LLNumber { + "nodeType": "number", + "value": 54.291, + }, + ], + "nodeType": "array", + }, + "nodeType": "aggregate", + "type": "extent", + }, + "nodeType": "predicate", + "right": LLNumber { + "nodeType": "number", + "value": 50, + }, + "threshold": undefined, + "type": "<", + }, + LLPredicate { + "left": LLNumber { + "nodeType": "number", + "value": 8.012999999999998, + }, + "nodeType": "predicate", + "right": LLNumber { + "nodeType": "number", + "value": 50, + }, + "threshold": undefined, + "type": "<", + }, + LLBool { + "nodeType": "bool", + "value": true, + }, +] +`; + exports[`SmallStepEvaluator works 1`] = ` [ LLExpression { diff --git a/apps/lil-buddy/src/lib/small-step-evaluator.ts b/apps/lil-buddy/src/lib/small-step-evaluator.ts index 6cb6eca..de914ff 100644 --- a/apps/lil-buddy/src/lib/small-step-evaluator.ts +++ b/apps/lil-buddy/src/lib/small-step-evaluator.ts @@ -15,7 +15,8 @@ export function evaluateNode( (acc, [key, value]) => acc.set(key, toVal(value)), new Environment(pal, {}, opts, {}) ); - return node.evaluate(newEnv); + const result = node.evaluate(newEnv); + return result; } function isValue(node: any) { @@ -31,6 +32,8 @@ function isValue(node: any) { case "variable": case undefined: return true; + case "array": + return node.children.every(isValue); default: return false; } @@ -41,17 +44,23 @@ function subTreeIsPureOp(node: any): boolean { case "numberOp": case "predicate": return isValue(node.left) && isValue(node.right); - case "conjunction": + case "aggregate": + case "array": + case "map": + // special thing for conjunction if (node.type === "not") { return isValue(node.children[0]); } - return node.children.every((x: any) => subTreeIsPureOp(x)); - case "aggregate": - case "array": if (node.children?.nodeType === "variable") { return true; } - return node.children.every((x: any) => subTreeIsPureOp(x)); + const children = node.children; + if (Array.isArray(children)) { + return children.every((x: any) => isValue(x)); + } else { + // for variables and such + return isValue(children); + } case "node": case "expression": return subTreeIsPureOp(node.value); @@ -64,7 +73,7 @@ function subTreeIsPureOp(node: any): boolean { case "valueFunction": return isValue(node.input); case "quantifier": - case "map": + throw new Error("Quantifiers should not be evaluated here", node); default: return false; } @@ -80,7 +89,12 @@ function traverseAndMaybeExecute( const thisIsPureOp = subTreeIsPureOp(node); if (thisIsPureOp) { const result = evaluateNode(node, inducedVariables, pal).result; - const astResult = LLTypes.LLValue.tryToConstruct(result, {} as any); + let astResult; + if (Array.isArray(result)) { + astResult = LLTypes.LLValueArray.tryToConstruct(result, {} as any); + } else { + astResult = LLTypes.LLValue.tryToConstruct(result, {} as any); + } return { result: astResult, didEval: true }; } let updatedNode = node.copy(); @@ -102,7 +116,7 @@ function traverseAndMaybeExecute( inducedVariables, pal ); - if (rightTraverse) { + if (rightTraverse.didEval) { updatedNode.right = rightTraverse.result; return { result: updatedNode, didEval: true }; } @@ -110,28 +124,36 @@ function traverseAndMaybeExecute( case "conjunction": case "array": case "aggregate": - const newChildren = []; - let found = false; - for (let idx = 0; idx < updatedNode.children.length; idx++) { - if (found) { - newChildren.push(updatedNode.children[idx]); - continue; + case "map": + const children = updatedNode.children; + if (Array.isArray(children)) { + const newChildren = []; + let found = false; + for (let idx = 0; idx < updatedNode.children.length; idx++) { + if (found) { + newChildren.push(updatedNode.children[idx]); + continue; + } + const child = updatedNode.children[idx]; + const childResult = traverseAndMaybeExecute( + child, + inducedVariables, + pal + ); + newChildren.push(childResult.result); + found = childResult.didEval; } - const child = updatedNode.children[idx]; + updatedNode.children = newChildren; + return { result: updatedNode, didEval: found }; + } else { const childResult = traverseAndMaybeExecute( - child, + updatedNode.children, inducedVariables, pal ); - newChildren.push(childResult.result); - found = childResult.didEval; + updatedNode.children = childResult.result; + return { result: updatedNode, didEval: childResult.didEval }; } - // let found = false - // updatedNode.children = updatedNode.children.map(x => { - - // }) - updatedNode.children = newChildren; - return { result: updatedNode, didEval: found }; case "node": case "expression": return traverseAndMaybeExecute(node.value, inducedVariables, pal); @@ -154,7 +176,6 @@ function traverseAndMaybeExecute( case "quantifier": throw new Error("Quantifiers should not be evaluated here", node); - case "map": default: console.log(node.nodeType, " not implemented yet", node); throw new Error(`${node.nodeType} not implemented yet`, node); diff --git a/apps/lil-buddy/src/linting/summary-nodes/DispatchNode.svelte b/apps/lil-buddy/src/linting/summary-nodes/DispatchNode.svelte index 0a9bc7d..15d55a7 100644 --- a/apps/lil-buddy/src/linting/summary-nodes/DispatchNode.svelte +++ b/apps/lil-buddy/src/linting/summary-nodes/DispatchNode.svelte @@ -2,7 +2,7 @@ import type { Palette, Color } from "color-buddy-palette"; import InlineNode from "./InlineNode.svelte"; import QuantifierNode from "./QuantifierNode.svelte"; - import { getPredNodes } from "./visual-summary-utils"; + import { getPredNodes, handleEval } from "./visual-summary-utils"; export let node: any; export let pal: Palette; @@ -11,12 +11,32 @@ $: predicateNodes = getPredNodes(node, inducedVariables, pal) as any[]; $: isNotNode = node.nodeType === "conjunction" && node.type === "not"; + function shouldComputeResult(node: any) { + const conjTypes = new Set(["and", "or"]); + return node.nodeType === "conjunction" && conjTypes.has(node.type); + } {#if node.nodeType == "conjunction" && !isNotNode} - {#each node.children as child} - - {/each} +
+
+ {#if node.type !== "id"} +
{node.type}
+ {/if} + {#each node.children as child} +
+ +
+ {/each} +
+ {#if shouldComputeResult(node)} +
→{handleEval(node, inducedVariables, pal).result}
+ {/if} +
{:else if node.nodeType === "expression"} {:else if predicateNodes.length} diff --git a/apps/lil-buddy/src/linting/summary-nodes/InlineNode.svelte b/apps/lil-buddy/src/linting/summary-nodes/InlineNode.svelte index ff0b9ca..db60cd9 100644 --- a/apps/lil-buddy/src/linting/summary-nodes/InlineNode.svelte +++ b/apps/lil-buddy/src/linting/summary-nodes/InlineNode.svelte @@ -20,8 +20,15 @@ NOT + {:else if node.nodeType === "conjunction"} +
+
{node.type}
+ {#each node.children as child} + + {/each} +
{:else if node.nodeType === "number"} -
{node.value}
+
{Math.round(node.value * 1000) / 1000}
{:else if node.nodeType === "variable"} {#if inducedVariables[node.value]}
{node.type} {"("} - {#if node.children?.nodeType === "variable"} + {#if Array.isArray(node.children)} + {#each node.children as child} + + {#if child !== node.children[node.children.length - 1]} + {","} + {/if} + {/each} + {:else} + {/if} + {")"} +
+ {:else if node.nodeType === "array"} +
+ {"["} + {#if Array.isArray(node.children)} + {#each node.children as child} + + {#if child !== node.children[node.children.length - 1]} + {","} + {/if} + {/each} {:else} + + {/if} + {"]"} +
+ {:else if node.nodeType === "map"} +
+ {node.type} + {"("} + {#if Array.isArray(node.children)} {#each node.children as child} {#if child !== node.children[node.children.length - 1]} {","} {/if} {/each} + {:else} + {/if} + {","} +
{node.varb}
+ {"=>"} + {")"}
{:else if node.nodeType === "expression"}