JS parameters in squiggle lang
This commit is contained in:
parent
bb8ed5ce4f
commit
d4f929367d
|
@ -1,19 +1,19 @@
|
||||||
{
|
{
|
||||||
"name": "@quri/squiggle-components",
|
"name": "@quri/squiggle-components",
|
||||||
"version": "0.2.14",
|
"version": "0.2.15",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-ace": "10.1.0",
|
|
||||||
"@quri/squiggle-lang": "^0.2.7",
|
"@quri/squiggle-lang": "^0.2.7",
|
||||||
"react-dom": "^18.1.0",
|
|
||||||
"vega": "^5.22.1",
|
|
||||||
"vega-embed": "^6.20.6",
|
|
||||||
"vega-lite": "^5.2.0",
|
|
||||||
"react-vega": "^7.5.0",
|
|
||||||
"react": "^18.1.0",
|
|
||||||
"@react-hook/size": "^2.1.2",
|
"@react-hook/size": "^2.1.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"styled-components": "^5.3.5"
|
"react": "^18.1.0",
|
||||||
|
"react-ace": "10.1.0",
|
||||||
|
"react-dom": "^18.1.0",
|
||||||
|
"react-vega": "^7.5.0",
|
||||||
|
"styled-components": "^5.3.5",
|
||||||
|
"vega": "^5.22.1",
|
||||||
|
"vega-embed": "^6.20.6",
|
||||||
|
"vega-lite": "^5.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-private-property-in-object": "^7.16.7",
|
"@babel/plugin-proposal-private-property-in-object": "^7.16.7",
|
||||||
|
@ -25,27 +25,26 @@
|
||||||
"@storybook/node-logger": "^6.4.22",
|
"@storybook/node-logger": "^6.4.22",
|
||||||
"@storybook/preset-create-react-app": "^4.1.0",
|
"@storybook/preset-create-react-app": "^4.1.0",
|
||||||
"@storybook/react": "^6.4.22",
|
"@storybook/react": "^6.4.22",
|
||||||
"@types/styled-components": "^5.1.24",
|
|
||||||
"@types/webpack": "^5.28.0",
|
|
||||||
"style-loader": "^3.3.1",
|
|
||||||
"ts-loader": "^9.2.9",
|
|
||||||
"webpack": "^5.72.0",
|
|
||||||
"webpack-cli": "^4.9.2",
|
|
||||||
"webpack-dev-server": "^4.8.1",
|
|
||||||
"@testing-library/jest-dom": "^5.16.4",
|
"@testing-library/jest-dom": "^5.16.4",
|
||||||
"@testing-library/react": "^13.1.1",
|
"@testing-library/react": "^13.1.1",
|
||||||
"@testing-library/user-event": "^14.1.1",
|
"@testing-library/user-event": "^14.1.1",
|
||||||
"@types/jest": "^27.4.0",
|
"@types/jest": "^27.4.0",
|
||||||
"web-vitals": "^2.1.4",
|
|
||||||
"@types/lodash": "^4.14.182",
|
"@types/lodash": "^4.14.182",
|
||||||
"@types/node": "^17.0.29",
|
"@types/node": "^17.0.29",
|
||||||
"@types/react": "^18.0.3",
|
"@types/react": "^18.0.3",
|
||||||
"@types/react-dom": "^18.0.2",
|
"@types/react-dom": "^18.0.2",
|
||||||
|
"@types/styled-components": "^5.1.24",
|
||||||
|
"@types/webpack": "^5.28.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
|
"style-loader": "^3.3.1",
|
||||||
|
"ts-loader": "^9.2.9",
|
||||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||||
"typescript": "^4.6.3",
|
"typescript": "^4.6.3",
|
||||||
"webpack-cli": "^4.9.2"
|
"web-vitals": "^2.1.4",
|
||||||
|
"webpack": "^5.72.0",
|
||||||
|
"webpack-cli": "^4.9.2",
|
||||||
|
"webpack-dev-server": "^4.8.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public",
|
"start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public",
|
||||||
|
|
|
@ -68,6 +68,29 @@ describe("Partials", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Parameters", () => {
|
||||||
|
test("Can pass parameters into partials and cells", () => {
|
||||||
|
let bindings = testRunPartial(`y = $x + 2`, {}, { x: 1 }); // y = 3
|
||||||
|
let bindings2 = testRunPartial(`z = $x + y * $a`, bindings, { a: 3 }); // z = 1 + 3 * 3 = 10
|
||||||
|
expect(testRun(`z + $x + $a + y`, bindings2)).toEqual({
|
||||||
|
tag: "number",
|
||||||
|
value: 17,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
test("Complicated deep parameters", () => {
|
||||||
|
expect(
|
||||||
|
testRun(
|
||||||
|
`$x.y[0][0].w + $x.z + $u.v`,
|
||||||
|
{},
|
||||||
|
{ x: { y: [[{ w: 1 }]], z: 2 }, u: { v: 3 } }
|
||||||
|
)
|
||||||
|
).toEqual({
|
||||||
|
tag: "number",
|
||||||
|
value: 6,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("Distribution", () => {
|
describe("Distribution", () => {
|
||||||
//It's important that sampleCount is less than 9. If it's more, than that will create randomness
|
//It's important that sampleCount is less than 9. If it's more, than that will create randomness
|
||||||
//Also, note, the value should be created using makeSampleSetDist() later on.
|
//Also, note, the value should be created using makeSampleSetDist() later on.
|
||||||
|
|
|
@ -6,11 +6,20 @@ import {
|
||||||
errorValueToString,
|
errorValueToString,
|
||||||
} from "../../src/js/index";
|
} from "../../src/js/index";
|
||||||
|
|
||||||
export function testRun(x: string, bindings = {}): squiggleExpression {
|
export function testRun(
|
||||||
let squiggleResult = run(x, bindings, {
|
x: string,
|
||||||
sampleCount: 1000,
|
bindings = {},
|
||||||
xyPointLength: 100,
|
parameters = {}
|
||||||
});
|
): squiggleExpression {
|
||||||
|
let squiggleResult = run(
|
||||||
|
x,
|
||||||
|
bindings,
|
||||||
|
{
|
||||||
|
sampleCount: 1000,
|
||||||
|
xyPointLength: 100,
|
||||||
|
},
|
||||||
|
parameters
|
||||||
|
);
|
||||||
// return squiggleResult.value
|
// return squiggleResult.value
|
||||||
if (squiggleResult.tag === "Ok") {
|
if (squiggleResult.tag === "Ok") {
|
||||||
return squiggleResult.value;
|
return squiggleResult.value;
|
||||||
|
@ -23,11 +32,20 @@ export function testRun(x: string, bindings = {}): squiggleExpression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function testRunPartial(x: string, bindings: bindings = {}): bindings {
|
export function testRunPartial(
|
||||||
let squiggleResult = runPartial(x, bindings, {
|
x: string,
|
||||||
sampleCount: 1000,
|
bindings: bindings = {},
|
||||||
xyPointLength: 100,
|
parameters = {}
|
||||||
});
|
): bindings {
|
||||||
|
let squiggleResult = runPartial(
|
||||||
|
x,
|
||||||
|
bindings,
|
||||||
|
{
|
||||||
|
sampleCount: 1000,
|
||||||
|
xyPointLength: 100,
|
||||||
|
},
|
||||||
|
parameters
|
||||||
|
);
|
||||||
if (squiggleResult.tag === "Ok") {
|
if (squiggleResult.tag === "Ok") {
|
||||||
return squiggleResult.value;
|
return squiggleResult.value;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -99,25 +99,71 @@ export type squiggleExpression =
|
||||||
export function run(
|
export function run(
|
||||||
squiggleString: string,
|
squiggleString: string,
|
||||||
bindings?: externalBindings,
|
bindings?: externalBindings,
|
||||||
samplingInputs?: samplingParams
|
samplingInputs?: samplingParams,
|
||||||
|
parameters?: parameters
|
||||||
): result<squiggleExpression, errorValue> {
|
): result<squiggleExpression, errorValue> {
|
||||||
let b = bindings ? bindings : {};
|
let b = bindings ? bindings : {};
|
||||||
|
let p = parameters ? parameters : {};
|
||||||
let si: samplingParams = samplingInputs
|
let si: samplingParams = samplingInputs
|
||||||
? samplingInputs
|
? samplingInputs
|
||||||
: defaultSamplingInputs;
|
: defaultSamplingInputs;
|
||||||
|
|
||||||
let result: result<expressionValue, errorValue> =
|
let result: result<expressionValue, errorValue> =
|
||||||
evaluateUsingExternalBindings(squiggleString, b);
|
evaluateUsingExternalBindings(squiggleString, mergeParameters(b, p));
|
||||||
return resultMap(result, (x) => createTsExport(x, si));
|
return resultMap(result, (x) => createTsExport(x, si));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run Partial. A partial is a block of code that doesn't return a value
|
// Run Partial. A partial is a block of code that doesn't return a value
|
||||||
export function runPartial(
|
export function runPartial(
|
||||||
squiggleString: string,
|
squiggleString: string,
|
||||||
bindings: externalBindings,
|
bindings?: externalBindings,
|
||||||
_samplingInputs?: samplingParams
|
_samplingInputs?: samplingParams,
|
||||||
|
parameters?: parameters
|
||||||
): result<externalBindings, errorValue> {
|
): result<externalBindings, errorValue> {
|
||||||
return evaluatePartialUsingExternalBindings(squiggleString, bindings);
|
let b = bindings ? bindings : {};
|
||||||
|
let p = parameters ? parameters : {};
|
||||||
|
|
||||||
|
return evaluatePartialUsingExternalBindings(
|
||||||
|
squiggleString,
|
||||||
|
mergeParameters(b, p)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeParameters(
|
||||||
|
bindings: externalBindings,
|
||||||
|
parameters: parameters
|
||||||
|
): externalBindings {
|
||||||
|
let transformedParemeters = Object.fromEntries(
|
||||||
|
Object.entries(parameters).map(([key, value]) => [
|
||||||
|
"$" + key,
|
||||||
|
jsValueToBinding(value),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
return _.merge(bindings, transformedParemeters);
|
||||||
|
}
|
||||||
|
|
||||||
|
type parameters = { [key: string]: jsValue };
|
||||||
|
|
||||||
|
type jsValue =
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| jsValue[]
|
||||||
|
| { [key: string]: jsValue }
|
||||||
|
| boolean;
|
||||||
|
|
||||||
|
function jsValueToBinding(value: jsValue): rescriptExport {
|
||||||
|
if (typeof value === "boolean") {
|
||||||
|
return { TAG: 1, _0: value as boolean };
|
||||||
|
} else if (typeof value === "string") {
|
||||||
|
return { TAG: 6, _0: value as string };
|
||||||
|
} else if (typeof value === "number") {
|
||||||
|
return { TAG: 4, _0: value as number };
|
||||||
|
} else if (Array.isArray(value)) {
|
||||||
|
return { TAG: 0, _0: value.map(jsValueToBinding) };
|
||||||
|
} else {
|
||||||
|
// Record
|
||||||
|
return { TAG: 5, _0: _.mapValues(value, jsValueToBinding) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTsExport(
|
function createTsExport(
|
||||||
|
|
|
@ -19,6 +19,7 @@ let eval__: string => 'a = %raw(`function (expr) { return {value: Mathjs.evaluat
|
||||||
*/
|
*/
|
||||||
let eval = (expr: string): result<expressionValue, errorValue> => {
|
let eval = (expr: string): result<expressionValue, errorValue> => {
|
||||||
try {
|
try {
|
||||||
|
Js.log(expr)
|
||||||
let answer = eval__(expr)
|
let answer = eval__(expr)
|
||||||
answer["value"]->JavaScript.Gate.jsToEv
|
answer["value"]->JavaScript.Gate.jsToEv
|
||||||
} catch {
|
} catch {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user