diff --git a/packages/components/package.json b/packages/components/package.json index 218747b9..e9549700 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -89,6 +89,7 @@ "@types/react": "17.0.43" }, "source": "./src/index.ts", + "browser": "dist/bundle.js", "main": "dist/src/index.js", "types": "dist/src/index.d.ts" } diff --git a/packages/components/src/components/SquiggleChart.tsx b/packages/components/src/components/SquiggleChart.tsx index 7dda92e4..a6bf12af 100644 --- a/packages/components/src/components/SquiggleChart.tsx +++ b/packages/components/src/components/SquiggleChart.tsx @@ -3,10 +3,12 @@ import _ from "lodash"; import styled from "styled-components"; import { run, + runPartial, errorValueToString, squiggleExpression, + bindings, + samplingParams, } from "@quri/squiggle-lang"; -import type { samplingParams } from "@quri/squiggle-lang"; import { NumberShower } from "./NumberShower"; import { DistributionChart } from "./DistributionChart"; import { ErrorBox } from "./ErrorBox"; @@ -148,6 +150,8 @@ export interface SquiggleChartProps { /** CSS width of the element */ width?: number; height?: number; + /** Bindings of previous variables declared */ + bindings?: bindings; } export const SquiggleChart: React.FC = ({ @@ -156,6 +160,7 @@ export const SquiggleChart: React.FC = ({ outputXYPoints = 1000, onChange = () => {}, height = 60, + bindings = {}, width = NaN, }: SquiggleChartProps) => { const target = React.useRef(null); @@ -167,7 +172,7 @@ export const SquiggleChart: React.FC = ({ sampleCount: sampleCount, xyPointLength: outputXYPoints, }; - let expressionResult = run(squiggleString, samplingInputs); + let expressionResult = run(squiggleString, bindings, samplingInputs); let internal: JSX.Element; if (expressionResult.tag === "Ok") { let expression = expressionResult.value; diff --git a/packages/components/src/components/SquiggleEditor.tsx b/packages/components/src/components/SquiggleEditor.tsx index 580db580..f85cf1e8 100644 --- a/packages/components/src/components/SquiggleEditor.tsx +++ b/packages/components/src/components/SquiggleEditor.tsx @@ -3,7 +3,9 @@ import * as ReactDOM from "react-dom"; import { SquiggleChart } from "./SquiggleChart"; import { CodeEditor } from "./CodeEditor"; import styled from "styled-components"; -import type { squiggleExpression } from "@quri/squiggle-lang"; +import type { squiggleExpression, bindings } from "@quri/squiggle-lang"; +import { runPartial, errorValueToString } from "@quri/squiggle-lang"; +import { ErrorBox } from "./ErrorBox"; export interface SquiggleEditorProps { /** The input string for squiggle */ @@ -26,6 +28,8 @@ export interface SquiggleEditorProps { onChange?(expr: squiggleExpression): void; /** The width of the element */ width: number; + /** Previous variable declarations */ + bindings: bindings; } const Input = styled.div` @@ -46,6 +50,7 @@ export let SquiggleEditor: React.FC = ({ diagramCount, onChange, environment, + bindings = {}, }: SquiggleEditorProps) => { let [expression, setExpression] = React.useState(initialSquiggleString); return ( @@ -71,6 +76,7 @@ export let SquiggleEditor: React.FC = ({ diagramCount={diagramCount} environment={environment} onChange={onChange} + bindings={bindings} /> ); @@ -107,3 +113,76 @@ export function renderSquiggleEditorToDom(props: SquiggleEditorProps) { ); return parent; } + +export interface SquigglePartialProps { + /** The input string for squiggle */ + initialSquiggleString?: string; + /** If the output requires monte carlo sampling, the amount of samples */ + sampleCount?: number; + /** The amount of points returned to draw the distribution */ + outputXYPoints?: number; + kernelWidth?: number; + pointDistLength?: number; + /** If the result is a function, where the function starts */ + diagramStart?: number; + /** If the result is a function, where the function ends */ + diagramStop?: number; + /** If the result is a function, how many points along the function it samples */ + diagramCount?: number; + /** when the environment changes. Used again for notebook magic*/ + onChange?(expr: bindings): void; + /** The width of the element */ + width: number; + /** Previously declared variables */ + bindings: bindings; +} + +export let SquigglePartial: React.FC = ({ + initialSquiggleString = "", + onChange, + bindings, +}: SquigglePartialProps) => { + let [expression, setExpression] = React.useState(initialSquiggleString); + let squiggleResult = runPartial(expression, bindings); + if (squiggleResult.tag == "Ok") { + if (onChange) onChange(squiggleResult.value); + } + return ( +
+ + + + {squiggleResult.tag == "Error" ? ( + + {errorValueToString(squiggleResult.value)} + + ) : ( + <> + )} +
+ ); +}; + +export function renderSquigglePartialToDom(props: SquigglePartialProps) { + let parent = document.createElement("div"); + ReactDOM.render( + { + // @ts-ignore + parent.value = bindings; + + parent.dispatchEvent(new CustomEvent("input")); + if (props.onChange) props.onChange(bindings); + }} + />, + parent + ); + return parent; +} diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 364e6dcb..ffd9c8e0 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -1,7 +1,9 @@ export { SquiggleChart } from "./components/SquiggleChart"; export { SquiggleEditor, + SquigglePartial, renderSquiggleEditorToDom, + renderSquigglePartialToDom, } from "./components/SquiggleEditor"; import SquigglePlayground, { renderSquigglePlaygroundToDom, diff --git a/packages/squiggle-lang/__tests__/TS/JS_test.ts b/packages/squiggle-lang/__tests__/TS/JS_test.ts index 43f981eb..33aae7db 100644 --- a/packages/squiggle-lang/__tests__/TS/JS_test.ts +++ b/packages/squiggle-lang/__tests__/TS/JS_test.ts @@ -1,23 +1,5 @@ -import { - run, - Distribution, - resultMap, - squiggleExpression, - errorValueToString, -} from "../../src/js/index"; - -let testRun = (x: string): squiggleExpression => { - let result = run(x, { sampleCount: 100, xyPointLength: 100 }); - expect(result.tag).toEqual("Ok"); - if (result.tag === "Ok") { - return result.value; - } else { - throw Error( - "Expected squiggle expression to evaluate but got error: " + - errorValueToString(result.value) - ); - } -}; +import { Distribution, resultMap } from "../../src/js/index"; +import { testRun } from "./TestHelpers"; function Ok(x: b) { return { tag: "Ok", value: x }; diff --git a/packages/squiggle-lang/__tests__/TS/TestHelpers.ts b/packages/squiggle-lang/__tests__/TS/TestHelpers.ts index 3d4153ef..8ec0c3e1 100644 --- a/packages/squiggle-lang/__tests__/TS/TestHelpers.ts +++ b/packages/squiggle-lang/__tests__/TS/TestHelpers.ts @@ -8,7 +8,7 @@ import { } from "../../src/js/index"; export function testRun(x: string): squiggleExpression { - let squiggleResult = run(x, { sampleCount: 1000, xyPointLength: 100 }); + let squiggleResult = run(x, {}, { sampleCount: 1000, xyPointLength: 100 }); // return squiggleResult.value if (squiggleResult.tag === "Ok") { return squiggleResult.value; diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index bc66ab99..fb67e47a 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -2,7 +2,9 @@ import * as _ from "lodash"; import { genericDist, samplingParams, - evaluate, + evaluateUsingExternalBindings, + evaluatePartialUsingExternalBindings, + externalBindings, expressionValue, errorValue, distributionError, @@ -46,7 +48,7 @@ import { Constructors_pointwiseLogarithm, Constructors_pointwisePower, } from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen"; -export type { samplingParams, errorValue }; +export type { samplingParams, errorValue, externalBindings as bindings }; export let defaultSamplingInputs: samplingParams = { sampleCount: 10000, @@ -96,15 +98,28 @@ export type squiggleExpression = export function run( squiggleString: string, + bindings?: externalBindings, samplingInputs?: samplingParams ): result { + let b = bindings ? bindings : {}; let si: samplingParams = samplingInputs ? samplingInputs : defaultSamplingInputs; - let result: result = evaluate(squiggleString); + + let result: result = + evaluateUsingExternalBindings(squiggleString, b); return resultMap(result, (x) => createTsExport(x, si)); } +// Run Partial. A partial is a block of code that doesn't return a value +export function runPartial( + squiggleString: string, + bindings: externalBindings, + _samplingInputs?: samplingParams +): result { + return evaluatePartialUsingExternalBindings(squiggleString, bindings); +} + function createTsExport( x: expressionValue, sampEnv: samplingParams @@ -166,7 +181,7 @@ function createTsExport( } } -// Helper functions to convert the recsript representations that genType doesn't +// Helper functions to convert the rescript representations that genType doesn't // cover function convertRawToTypescript( result: rescriptExport, diff --git a/packages/squiggle-lang/src/rescript/TypescriptInterface.res b/packages/squiggle-lang/src/rescript/TypescriptInterface.res index c4265178..f2758ba3 100644 --- a/packages/squiggle-lang/src/rescript/TypescriptInterface.res +++ b/packages/squiggle-lang/src/rescript/TypescriptInterface.res @@ -40,6 +40,12 @@ let evaluate = Reducer.evaluate @genType let evaluateUsingExternalBindings = Reducer.evaluateUsingExternalBindings +@genType +let evaluatePartialUsingExternalBindings = Reducer.evaluatePartialUsingExternalBindings + +@genType +type externalBindings = Reducer.externalBindings + @genType type expressionValue = ReducerInterface_ExpressionValue.expressionValue