diff --git a/packages/components/src/components/SquiggleViewer/utils.ts b/packages/components/src/components/SquiggleViewer/utils.ts index 229a0e5a3f..4991672b99 100644 --- a/packages/components/src/components/SquiggleViewer/utils.ts +++ b/packages/components/src/components/SquiggleViewer/utils.ts @@ -60,25 +60,25 @@ export function useGetSubvalueByPath() { }); for (const subValuePath of subValuePaths) { - const pathItem = subValuePath.lastItem()!; // We know it's not empty, because includeRoot is false. + const pathEdge = subValuePath.lastItem()!; // We know it's not empty, because includeRoot is false. const currentTag = currentValue.tag; - const pathItemType = pathItem.value.type; + const pathEdgeType = pathEdge.value.type; let nextValue: SqValue | undefined; - if (currentTag === "Array" && pathItemType === "arrayIndex") { - nextValue = currentValue.value.getValues()[pathItem.value.value]; - } else if (currentTag === "Dict" && pathItemType === "dictKey") { - nextValue = currentValue.value.get(pathItem.value.value); + if (currentTag === "Array" && pathEdgeType === "arrayIndex") { + nextValue = currentValue.value.getValues()[pathEdge.value.value]; + } else if (currentTag === "Dict" && pathEdgeType === "dictKey") { + nextValue = currentValue.value.get(pathEdge.value.value); } else if ( currentTag === "TableChart" && - pathItemType === "cellAddress" + pathEdgeType === "cellAddress" ) { // Maybe it would be better to get the environment in a different way. const environment = context.project.getEnvironment(); const item = currentValue.value.item( - pathItem.value.value.row, - pathItem.value.value.column, + pathEdge.value.value.row, + pathEdge.value.value.column, environment ); if (item.ok) { @@ -86,7 +86,7 @@ export function useGetSubvalueByPath() { } else { return; } - } else if (pathItem.type === "calculator") { + } else if (pathEdge.type === "calculator") { // The previous path item is the one that is the parent of the calculator result. // This is the one that we use in the ViewerContext to store information about the calculator. const calculatorState = itemStore.getCalculator(subValuePath); diff --git a/packages/components/src/stories/SquiggleChart.stories.tsx b/packages/components/src/stories/SquiggleChart.stories.tsx index c3294be7f4..40ac596310 100644 --- a/packages/components/src/stories/SquiggleChart.stories.tsx +++ b/packages/components/src/stories/SquiggleChart.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; -import { SqPathItem, SqValuePath } from "@quri/squiggle-lang"; +import { SqValuePath, SqValuePathEdge } from "@quri/squiggle-lang"; import { SquiggleChart } from "../components/SquiggleChart.js"; @@ -50,7 +50,7 @@ export const RootPathOverride: Story = { code: "{foo: 35 to 50, bar: [1,2,3]}", rootPathOverride: new SqValuePath({ root: "result", - items: [SqPathItem.fromDictKey("bar")], + items: [SqValuePathEdge.fromDictKey("bar")], }), }, }; diff --git a/packages/components/src/stories/SquiggleChart/Basic.stories.tsx b/packages/components/src/stories/SquiggleChart/Basic.stories.tsx index e0ed530f03..f05457606a 100644 --- a/packages/components/src/stories/SquiggleChart/Basic.stories.tsx +++ b/packages/components/src/stories/SquiggleChart/Basic.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; -import { SqPathItem, SqValuePath } from "@quri/squiggle-lang"; +import { SqValuePath, SqValuePathEdge } from "@quri/squiggle-lang"; import { SquiggleChart } from "../../components/SquiggleChart.js"; @@ -43,7 +43,10 @@ export const WithPathOverride: Story = { `, rootPathOverride: new SqValuePath({ root: "bindings", - items: [SqPathItem.fromDictKey("foo"), SqPathItem.fromDictKey("bar")], + items: [ + SqValuePathEdge.fromDictKey("foo"), + SqValuePathEdge.fromDictKey("bar"), + ], }), }, }; diff --git a/packages/squiggle-lang/__tests__/SqValue/SqValuePath_test.ts b/packages/squiggle-lang/__tests__/SqValue/SqValuePath_test.ts index 02cd8783d9..29fdee7a2c 100644 --- a/packages/squiggle-lang/__tests__/SqValue/SqValuePath_test.ts +++ b/packages/squiggle-lang/__tests__/SqValue/SqValuePath_test.ts @@ -1,8 +1,8 @@ -import { SqPathItem, SqValuePath } from "../../src/index.js"; +import { SqValuePath, SqValuePathEdge } from "../../src/index.js"; -describe("SqPathItem", () => { +describe("SqValuePathEdge", () => { test("fromDictKey creates a string item", () => { - const item = SqPathItem.fromDictKey("test"); + const item = SqValuePathEdge.fromDictKey("test"); expect(item.value).toEqual({ type: "dictKey", value: "test" }); }); }); @@ -11,10 +11,10 @@ describe("SqValuePath", () => { const path = new SqValuePath({ root: "bindings", items: [ - SqPathItem.fromDictKey("foo"), - SqPathItem.fromArrayIndex(2), - SqPathItem.fromCalculator(), - SqPathItem.fromCellAddress(1, 2), + SqValuePathEdge.fromDictKey("foo"), + SqValuePathEdge.fromArrayIndex(2), + SqValuePathEdge.fromCalculator(), + SqValuePathEdge.fromCellAddress(1, 2), ], }); @@ -22,10 +22,10 @@ describe("SqValuePath", () => { const path2 = new SqValuePath({ root: "bindings", items: [ - SqPathItem.fromDictKey("foo"), - SqPathItem.fromArrayIndex(2), - SqPathItem.fromCalculator(), - SqPathItem.fromCellAddress(1, 2), + SqValuePathEdge.fromDictKey("foo"), + SqValuePathEdge.fromArrayIndex(2), + SqValuePathEdge.fromCalculator(), + SqValuePathEdge.fromCellAddress(1, 2), ], }); expect(path.isEqual(path2)).toBe(true); @@ -34,9 +34,9 @@ describe("SqValuePath", () => { test("extend()", () => { const path = new SqValuePath({ root: "bindings", - items: [SqPathItem.fromDictKey("foo")], + items: [SqValuePathEdge.fromDictKey("foo")], }); - const extendedPath = path.extend(SqPathItem.fromArrayIndex(2)); + const extendedPath = path.extend(SqValuePathEdge.fromArrayIndex(2)); expect(extendedPath.items.length).toBe(2); expect(extendedPath.items[1].value).toEqual({ type: "arrayIndex", @@ -48,11 +48,14 @@ describe("SqValuePath", () => { test("path fully contains a shorter path", () => { const basePath = new SqValuePath({ root: "bindings", - items: [SqPathItem.fromDictKey("foo"), SqPathItem.fromArrayIndex(2)], + items: [ + SqValuePathEdge.fromDictKey("foo"), + SqValuePathEdge.fromArrayIndex(2), + ], }); const subPath = new SqValuePath({ root: "bindings", - items: [SqPathItem.fromDictKey("foo")], + items: [SqValuePathEdge.fromDictKey("foo")], }); expect(basePath.contains(subPath)).toBe(true); }); @@ -60,20 +63,20 @@ describe("SqValuePath", () => { test("path does not contain longer path", () => { const basePath = new SqValuePath({ root: "bindings", - items: [SqPathItem.fromDictKey("foo")], + items: [SqValuePathEdge.fromDictKey("foo")], }); - const longerPath = basePath.extend(SqPathItem.fromArrayIndex(2)); + const longerPath = basePath.extend(SqValuePathEdge.fromArrayIndex(2)); expect(basePath.contains(longerPath)).toBe(false); }); test("path does not contain different path", () => { const path1 = new SqValuePath({ root: "bindings", - items: [SqPathItem.fromDictKey("foo")], + items: [SqValuePathEdge.fromDictKey("foo")], }); const path2 = new SqValuePath({ root: "imports", - items: [SqPathItem.fromDictKey("bar")], + items: [SqValuePathEdge.fromDictKey("bar")], }); expect(path1.contains(path2)).toBe(false); }); @@ -81,7 +84,7 @@ describe("SqValuePath", () => { test("path contains empty path (with same root)", () => { const nonEmptyPath = new SqValuePath({ root: "exports", - items: [SqPathItem.fromCalculator()], + items: [SqValuePathEdge.fromCalculator()], }); const emptyPath = new SqValuePath({ root: "exports", @@ -93,11 +96,11 @@ describe("SqValuePath", () => { test("equal paths contain each other", () => { const path1 = new SqValuePath({ root: "bindings", - items: [SqPathItem.fromDictKey("test")], + items: [SqValuePathEdge.fromDictKey("test")], }); const path2 = new SqValuePath({ root: "bindings", - items: [SqPathItem.fromDictKey("test")], + items: [SqValuePathEdge.fromDictKey("test")], }); expect(path1.contains(path2)).toBe(true); expect(path2.contains(path1)).toBe(true); diff --git a/packages/squiggle-lang/src/index.ts b/packages/squiggle-lang/src/index.ts index b7d69300dc..928f1c9f6a 100644 --- a/packages/squiggle-lang/src/index.ts +++ b/packages/squiggle-lang/src/index.ts @@ -60,11 +60,7 @@ export { SqTableChart } from "./public/SqValue/SqTableChart.js"; export { SqCalculator } from "./public/SqValue/SqCalculator.js"; export { SqDict } from "./public/SqValue/SqDict.js"; export { SqScale } from "./public/SqValue/SqScale.js"; -export { - type PathItem, - SqPathItem, - SqValuePath, -} from "./public/SqValuePath.js"; +export { SqValuePath, SqValuePathEdge } from "./public/SqValuePath.js"; export { parse } from "./public/parse.js"; export { fmap as resultMap, type result } from "./utility/result.js"; diff --git a/packages/squiggle-lang/src/public/SqValue/SqArray.ts b/packages/squiggle-lang/src/public/SqValue/SqArray.ts index 6dab6e76f0..6b58c65f37 100644 --- a/packages/squiggle-lang/src/public/SqValue/SqArray.ts +++ b/packages/squiggle-lang/src/public/SqValue/SqArray.ts @@ -1,6 +1,6 @@ import { Value } from "../../value/index.js"; import { SqValueContext } from "../SqValueContext.js"; -import { SqPathItem } from "../SqValuePath.js"; +import { SqValuePathEdge } from "../SqValuePath.js"; import { wrapValue } from "./index.js"; export class SqArray { @@ -11,7 +11,7 @@ export class SqArray { getValues() { return this._value.map((v, i) => - wrapValue(v, this.context?.extend(SqPathItem.fromArrayIndex(i))) + wrapValue(v, this.context?.extend(SqValuePathEdge.fromArrayIndex(i))) ); } } diff --git a/packages/squiggle-lang/src/public/SqValue/SqCalculator.ts b/packages/squiggle-lang/src/public/SqValue/SqCalculator.ts index e6504341de..437a4f951b 100644 --- a/packages/squiggle-lang/src/public/SqValue/SqCalculator.ts +++ b/packages/squiggle-lang/src/public/SqValue/SqCalculator.ts @@ -3,7 +3,7 @@ import * as Result from "../../utility/result.js"; import { Calculator } from "../../value/VCalculator.js"; import { SqError, SqOtherError } from "../SqError.js"; import { SqValueContext } from "../SqValueContext.js"; -import { SqPathItem } from "../SqValuePath.js"; +import { SqValuePathEdge } from "../SqValuePath.js"; import { SqValue, wrapValue } from "./index.js"; import { SqInput, wrapInput } from "./SqInput.js"; import { SqLambda } from "./SqLambda.js"; @@ -18,7 +18,7 @@ export class SqCalculator { const sqLambda = new SqLambda(this._value.fn, undefined); const response = sqLambda.call(_arguments, env); - const newContext = this.context?.extend(SqPathItem.fromCalculator()); + const newContext = this.context?.extend(SqValuePathEdge.fromCalculator()); if (!newContext) { return Result.Err( diff --git a/packages/squiggle-lang/src/public/SqValue/SqDict.ts b/packages/squiggle-lang/src/public/SqValue/SqDict.ts index 16d80e6a43..af58684349 100644 --- a/packages/squiggle-lang/src/public/SqValue/SqDict.ts +++ b/packages/squiggle-lang/src/public/SqValue/SqDict.ts @@ -1,7 +1,7 @@ import { VDict } from "../../value/VDict.js"; import { vString } from "../../value/VString.js"; import { SqValueContext } from "../SqValueContext.js"; -import { SqPathItem } from "../SqValuePath.js"; +import { SqValuePathEdge } from "../SqValuePath.js"; import { SqDictValue, SqValue, wrapValue } from "./index.js"; export class SqDict { @@ -15,7 +15,7 @@ export class SqDict { ([key, v]) => [ key, - wrapValue(v, this.context?.extend(SqPathItem.fromDictKey(key))), + wrapValue(v, this.context?.extend(SqValuePathEdge.fromDictKey(key))), ] as const ); } @@ -25,7 +25,10 @@ export class SqDict { if (value === undefined) { return undefined; } - return wrapValue(value, this.context?.extend(SqPathItem.fromDictKey(key))); + return wrapValue( + value, + this.context?.extend(SqValuePathEdge.fromDictKey(key)) + ); } toString() { diff --git a/packages/squiggle-lang/src/public/SqValue/SqPlot.ts b/packages/squiggle-lang/src/public/SqValue/SqPlot.ts index 0ac89b3aa4..1524487de1 100644 --- a/packages/squiggle-lang/src/public/SqValue/SqPlot.ts +++ b/packages/squiggle-lang/src/public/SqValue/SqPlot.ts @@ -6,7 +6,7 @@ import * as Result from "../../utility/result.js"; import { Plot, vPlot } from "../../value/VPlot.js"; import { SqError, SqOtherError } from "../SqError.js"; import { SqValueContext } from "../SqValueContext.js"; -import { SqPathItem } from "../SqValuePath.js"; +import { SqValuePathEdge } from "../SqValuePath.js"; import { SqPlotValue } from "./index.js"; import { SqDistribution, @@ -160,7 +160,7 @@ export class SqNumericFnPlot extends SqAbstractPlot<"numericFn"> { this.context ? this.createdProgrammatically ? this.context - : this.context.extend(SqPathItem.fromDictKey("fn")) + : this.context.extend(SqValuePathEdge.fromDictKey("fn")) : undefined ); } @@ -228,7 +228,7 @@ export class SqDistFnPlot extends SqAbstractPlot<"distFn"> { this.context ? this.createdProgrammatically ? this.context - : this.context.extend(SqPathItem.fromDictKey("fn")) + : this.context.extend(SqValuePathEdge.fromDictKey("fn")) : undefined ); } @@ -315,7 +315,7 @@ export class SqRelativeValuesPlot extends SqAbstractPlot<"relativeValues"> { get fn(): SqLambda { return new SqLambda( this._value.fn, - this.context?.extend(SqPathItem.fromDictKey("fn")) + this.context?.extend(SqValuePathEdge.fromDictKey("fn")) ); } } diff --git a/packages/squiggle-lang/src/public/SqValue/SqTableChart.ts b/packages/squiggle-lang/src/public/SqValue/SqTableChart.ts index d5f9787867..5127ee844b 100644 --- a/packages/squiggle-lang/src/public/SqValue/SqTableChart.ts +++ b/packages/squiggle-lang/src/public/SqValue/SqTableChart.ts @@ -4,7 +4,7 @@ import * as Result from "../../utility/result.js"; import { TableChart } from "../../value/VTableChart.js"; import { SqError, SqOtherError } from "../SqError.js"; import { SqValueContext } from "../SqValueContext.js"; -import { SqPathItem } from "../SqValuePath.js"; +import { SqValuePathEdge } from "../SqValuePath.js"; import { SqValue, wrapValue } from "./index.js"; import { SqLambda } from "./SqLambda.js"; @@ -22,7 +22,7 @@ const getItem = ( ): Result.result => { const response = fn.call([element], env); const newContext: SqValueContext | undefined = context?.extend( - SqPathItem.fromCellAddress(row, column) + SqValuePathEdge.fromCellAddress(row, column) ); if (response.ok && context) { diff --git a/packages/squiggle-lang/src/public/SqValueContext.ts b/packages/squiggle-lang/src/public/SqValueContext.ts index be32f99e11..492b52600d 100644 --- a/packages/squiggle-lang/src/public/SqValueContext.ts +++ b/packages/squiggle-lang/src/public/SqValueContext.ts @@ -1,7 +1,7 @@ import { AST, ASTNode } from "../ast/parse.js"; import { isBindingStatement } from "../ast/utils.js"; import { SqProject } from "./SqProject/index.js"; -import { SqPathItem, SqValuePath } from "./SqValuePath.js"; +import { SqValuePath, SqValuePathEdge } from "./SqValuePath.js"; export class SqValueContext { public project: SqProject; @@ -37,13 +37,13 @@ export class SqValueContext { this.path = props.path; } - extend(item: SqPathItem): SqValueContext { + extend(item: SqValuePathEdge): SqValueContext { let ast = this.valueAst; - const pathItem = item.value; + const pathEdge = item.value; let newAst: ASTNode | undefined; const itemisNotTableIndexOrCalculator = - pathItem.type !== "cellAddress" && pathItem.type !== "calculator"; + pathEdge.type !== "cellAddress" && pathEdge.type !== "calculator"; if (this.valueAstIsPrecise && itemisNotTableIndexOrCalculator) { // now we can try to look for the next nested valueAst @@ -66,20 +66,20 @@ export class SqValueContext { switch (ast.type) { case "Program": { - if (this.path.root === "bindings" && pathItem.type === "dictKey") { - newAst = ast.symbols[pathItem.value]; + if (this.path.root === "bindings" && pathEdge.type === "dictKey") { + newAst = ast.symbols[pathEdge.value]; break; } break; } case "Dict": - if (pathItem.type === "dictKey") { - newAst = ast.symbols[pathItem.value]; + if (pathEdge.type === "dictKey") { + newAst = ast.symbols[pathEdge.value]; } break; case "Array": - if (pathItem.type === "arrayIndex") { - const element = ast.elements[pathItem.value]; + if (pathEdge.type === "arrayIndex") { + const element = ast.elements[pathEdge.value]; if (element) { newAst = element; } diff --git a/packages/squiggle-lang/src/public/SqValuePath.ts b/packages/squiggle-lang/src/public/SqValuePath.ts index c4be0d742b..6234626e1b 100644 --- a/packages/squiggle-lang/src/public/SqValuePath.ts +++ b/packages/squiggle-lang/src/public/SqValuePath.ts @@ -3,7 +3,7 @@ import { locationContains } from "../ast/utils.js"; export type RootPathItem = "result" | "bindings" | "imports" | "exports"; -export type PathItem = +export type ValuePathEdge = | { type: "dictKey"; value: string } | { type: "arrayIndex"; value: number } | { type: "cellAddress"; value: { row: number; column: number } } @@ -12,12 +12,12 @@ export type PathItem = }; function isCellAddressPathItem( - item: PathItem + item: ValuePathEdge ): item is { type: "cellAddress"; value: { row: number; column: number } } { return item.type === "cellAddress"; } -function pathItemIsEqual(a: PathItem, b: PathItem): boolean { +function pathItemIsEqual(a: ValuePathEdge, b: ValuePathEdge): boolean { if (a.type !== b.type) { return false; } @@ -37,26 +37,26 @@ function pathItemIsEqual(a: PathItem, b: PathItem): boolean { } } -export class SqPathItem { - private constructor(public value: PathItem) {} - static fromDictKey(str: string): SqPathItem { - return new SqPathItem({ type: "dictKey", value: str }); +export class SqValuePathEdge { + private constructor(public value: ValuePathEdge) {} + static fromDictKey(str: string): SqValuePathEdge { + return new SqValuePathEdge({ type: "dictKey", value: str }); } - static fromArrayIndex(num: number): SqPathItem { - return new SqPathItem({ type: "arrayIndex", value: num }); + static fromArrayIndex(num: number): SqValuePathEdge { + return new SqValuePathEdge({ type: "arrayIndex", value: num }); } - static fromCalculator(): SqPathItem { - return new SqPathItem({ type: "calculator" }); + static fromCalculator(): SqValuePathEdge { + return new SqValuePathEdge({ type: "calculator" }); } - static fromCellAddress(row: number, column: number): SqPathItem { - return new SqPathItem({ type: "cellAddress", value: { row, column } }); + static fromCellAddress(row: number, column: number): SqValuePathEdge { + return new SqValuePathEdge({ type: "cellAddress", value: { row, column } }); } get type() { return this.value.type; } - isEqual(other: SqPathItem) { + isEqual(other: SqValuePathEdge) { return pathItemIsEqual(this.value, other.value); } @@ -90,8 +90,8 @@ export class SqPathItem { } // There might be a better place for this to go, nearer to the ASTNode type. -function astOffsetToPathItems(ast: ASTNode, offset: number): SqPathItem[] { - function buildRemainingPathItems(ast: ASTNode): SqPathItem[] { +function astOffsetToPathItems(ast: ASTNode, offset: number): SqValuePathEdge[] { + function buildRemainingPathItems(ast: ASTNode): SqValuePathEdge[] { switch (ast.type) { case "Program": { for (const statement of ast.statements) { @@ -121,11 +121,11 @@ function astOffsetToPathItems(ast: ASTNode, offset: number): SqPathItem[] { pair.key.type === "String" // only string keys are supported ) { return [ - SqPathItem.fromDictKey(pair.key.value), + SqValuePathEdge.fromDictKey(pair.key.value), ...buildRemainingPathItems(pair.value), ]; } else if (pair.type === "Identifier") { - return [SqPathItem.fromDictKey(pair.value)]; // this is a final node, no need to buildRemainingPathItems recursively + return [SqValuePathEdge.fromDictKey(pair.value)]; // this is a final node, no need to buildRemainingPathItems recursively } } return []; @@ -135,7 +135,7 @@ function astOffsetToPathItems(ast: ASTNode, offset: number): SqPathItem[] { const element = ast.elements[i]; if (locationContains(element.location, offset)) { return [ - SqPathItem.fromArrayIndex(i), + SqValuePathEdge.fromArrayIndex(i), ...buildRemainingPathItems(element), ]; } @@ -144,13 +144,13 @@ function astOffsetToPathItems(ast: ASTNode, offset: number): SqPathItem[] { } case "LetStatement": { return [ - SqPathItem.fromDictKey(ast.variable.value), + SqValuePathEdge.fromDictKey(ast.variable.value), ...buildRemainingPathItems(ast.value), ]; } case "DefunStatement": { return [ - SqPathItem.fromDictKey(ast.variable.value), + SqValuePathEdge.fromDictKey(ast.variable.value), ...buildRemainingPathItems(ast.value), ]; } @@ -170,9 +170,9 @@ function astOffsetToPathItems(ast: ASTNode, offset: number): SqPathItem[] { export class SqValuePath { public root: RootPathItem; - public items: SqPathItem[]; + public items: SqValuePathEdge[]; - constructor(props: { root: RootPathItem; items: SqPathItem[] }) { + constructor(props: { root: RootPathItem; items: SqValuePathEdge[] }) { this.root = props.root; this.items = props.items; } @@ -194,11 +194,11 @@ export class SqValuePath { return this.items.length === 0; } - lastItem(): SqPathItem | undefined { + lastItem(): SqValuePathEdge | undefined { return this.items[this.items.length - 1]; } - extend(item: SqPathItem) { + extend(item: SqValuePathEdge) { return new SqValuePath({ root: this.root, items: [...this.items, item],