Merge branch 'develop' into documentation-refactors-april
* develop: (72 commits) cases to handle with new parser. lambdas in arrays and records Note duplicate parameters Note infinite recursion Note infinite recursion Add array string and function viewers Recurse showTypes Pass showTypes and showControls in playground do not export private modules from Reducer module Allows hiding controls sam's monkeying fixed function f not bound Refactor and rename lambda in partial Make error message more descriptive Refactor and shrink effect code Make a tooltip to restrict users from log scales Add Patrial storybook and update partial bindings async Lint js Format and fix CI bugs Hotfix playground chart Real log scales ...
This commit is contained in:
commit
c2155ef746
|
@ -9,6 +9,7 @@
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-ace": "^10.1.0",
|
"react-ace": "^10.1.0",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
|
"react-use": "^17.3.2",
|
||||||
"react-vega": "^7.5.0",
|
"react-vega": "^7.5.0",
|
||||||
"styled-components": "^5.3.5",
|
"styled-components": "^5.3.5",
|
||||||
"vega": "^5.22.1",
|
"vega": "^5.22.1",
|
||||||
|
@ -30,7 +31,7 @@
|
||||||
"@testing-library/user-event": "^14.1.1",
|
"@testing-library/user-event": "^14.1.1",
|
||||||
"@types/jest": "^27.4.0",
|
"@types/jest": "^27.4.0",
|
||||||
"@types/lodash": "^4.14.182",
|
"@types/lodash": "^4.14.182",
|
||||||
"@types/node": "^17.0.29",
|
"@types/node": "^17.0.31",
|
||||||
"@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/styled-components": "^5.1.24",
|
||||||
|
@ -38,7 +39,7 @@
|
||||||
"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",
|
"style-loader": "^3.3.1",
|
||||||
"ts-loader": "^9.2.9",
|
"ts-loader": "^9.3.0",
|
||||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||||
"typescript": "^4.6.3",
|
"typescript": "^4.6.3",
|
||||||
"web-vitals": "^2.1.4",
|
"web-vitals": "^2.1.4",
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,45 +1,130 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import type { Spec } from "vega";
|
|
||||||
import type { Distribution } from "@quri/squiggle-lang";
|
import type { Distribution } from "@quri/squiggle-lang";
|
||||||
import { distributionErrorToString } from "@quri/squiggle-lang";
|
import { distributionErrorToString } from "@quri/squiggle-lang";
|
||||||
import { createClassFromSpec } from "react-vega";
|
import { Vega, VisualizationSpec } from "react-vega";
|
||||||
import * as chartSpecification from "../vega-specs/spec-distributions.json";
|
import * as chartSpecification from "../vega-specs/spec-distributions.json";
|
||||||
import { ErrorBox } from "./ErrorBox";
|
import { ErrorBox } from "./ErrorBox";
|
||||||
|
import { useSize } from "react-use";
|
||||||
|
import {
|
||||||
|
linearXScale,
|
||||||
|
logXScale,
|
||||||
|
linearYScale,
|
||||||
|
expYScale,
|
||||||
|
} from "./DistributionVegaScales";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
let SquiggleVegaChart = createClassFromSpec({
|
|
||||||
spec: chartSpecification as Spec,
|
|
||||||
});
|
|
||||||
|
|
||||||
type DistributionChartProps = {
|
type DistributionChartProps = {
|
||||||
distribution: Distribution;
|
distribution: Distribution;
|
||||||
width: number;
|
width?: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
/** Whether to show the user graph controls (scale etc) */
|
||||||
|
showControls?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DistributionChart: React.FC<DistributionChartProps> = ({
|
export const DistributionChart: React.FC<DistributionChartProps> = ({
|
||||||
distribution,
|
distribution,
|
||||||
width,
|
|
||||||
height,
|
height,
|
||||||
|
width,
|
||||||
|
showControls = false,
|
||||||
}: DistributionChartProps) => {
|
}: DistributionChartProps) => {
|
||||||
|
let [isLogX, setLogX] = React.useState(false);
|
||||||
|
let [isExpY, setExpY] = React.useState(false);
|
||||||
let shape = distribution.pointSet();
|
let shape = distribution.pointSet();
|
||||||
if (shape.tag === "Ok") {
|
const [sized, _] = useSize((size) => {
|
||||||
let widthProp = width ? width - 20 : undefined;
|
if (shape.tag === "Ok") {
|
||||||
var result = (
|
let massBelow0 =
|
||||||
<SquiggleVegaChart
|
shape.value.continuous.some((x) => x.x <= 0) ||
|
||||||
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
shape.value.discrete.some((x) => x.x <= 0);
|
||||||
width={widthProp}
|
let spec = buildVegaSpec(isLogX, isExpY);
|
||||||
height={height}
|
let widthProp = width ? width - 20 : size.width - 10;
|
||||||
actions={false}
|
|
||||||
/>
|
// Check whether we should disable the checkbox
|
||||||
);
|
var logCheckbox = (
|
||||||
} else {
|
<CheckBox label="Log X scale" value={isLogX} onChange={setLogX} />
|
||||||
var result = (
|
);
|
||||||
<ErrorBox heading="Distribution Error">
|
if (massBelow0) {
|
||||||
{distributionErrorToString(shape.value)}
|
logCheckbox = (
|
||||||
</ErrorBox>
|
<CheckBox
|
||||||
);
|
label="Log X scale"
|
||||||
}
|
value={isLogX}
|
||||||
return result;
|
onChange={setLogX}
|
||||||
|
disabled={true}
|
||||||
|
tooltip={
|
||||||
|
"Your distribution has mass lower than or equal to 0. Log only works on strictly positive values."
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = (
|
||||||
|
<div>
|
||||||
|
<Vega
|
||||||
|
spec={spec}
|
||||||
|
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
||||||
|
width={widthProp}
|
||||||
|
height={height}
|
||||||
|
actions={false}
|
||||||
|
/>
|
||||||
|
{showControls && (
|
||||||
|
<div>
|
||||||
|
{logCheckbox}
|
||||||
|
<CheckBox label="Exp Y scale" value={isExpY} onChange={setExpY} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
var result = (
|
||||||
|
<ErrorBox heading="Distribution Error">
|
||||||
|
{distributionErrorToString(shape.value)}
|
||||||
|
</ErrorBox>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
return sized;
|
||||||
|
};
|
||||||
|
|
||||||
|
function buildVegaSpec(isLogX: boolean, isExpY: boolean): VisualizationSpec {
|
||||||
|
return {
|
||||||
|
...chartSpecification,
|
||||||
|
scales: [
|
||||||
|
isLogX ? logXScale : linearXScale,
|
||||||
|
isExpY ? expYScale : linearYScale,
|
||||||
|
],
|
||||||
|
} as VisualizationSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CheckBoxProps {
|
||||||
|
label: string;
|
||||||
|
onChange: (x: boolean) => void;
|
||||||
|
value: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
tooltip?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Label = styled.label<{ disabled: boolean }>`
|
||||||
|
${(props) => props.disabled && "color: #999;"}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const CheckBox = ({
|
||||||
|
label,
|
||||||
|
onChange,
|
||||||
|
value,
|
||||||
|
disabled = false,
|
||||||
|
tooltip,
|
||||||
|
}: CheckBoxProps) => {
|
||||||
|
return (
|
||||||
|
<span title={tooltip}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
value={value + ""}
|
||||||
|
onChange={() => onChange(!value)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
<Label disabled={disabled}>{label}</Label>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
80
packages/components/src/components/DistributionVegaScales.ts
Normal file
80
packages/components/src/components/DistributionVegaScales.ts
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import type { LogScale, LinearScale, PowScale } from "vega";
|
||||||
|
export let linearXScale: LinearScale = {
|
||||||
|
name: "xscale",
|
||||||
|
type: "linear",
|
||||||
|
range: "width",
|
||||||
|
zero: false,
|
||||||
|
nice: false,
|
||||||
|
domain: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
data: "con",
|
||||||
|
field: "x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "dis",
|
||||||
|
field: "x",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export let linearYScale: LinearScale = {
|
||||||
|
name: "yscale",
|
||||||
|
type: "linear",
|
||||||
|
range: "height",
|
||||||
|
zero: true,
|
||||||
|
domain: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
data: "con",
|
||||||
|
field: "y",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "dis",
|
||||||
|
field: "y",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export let logXScale: LogScale = {
|
||||||
|
name: "xscale",
|
||||||
|
type: "log",
|
||||||
|
range: "width",
|
||||||
|
zero: false,
|
||||||
|
base: 10,
|
||||||
|
nice: false,
|
||||||
|
domain: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
data: "con",
|
||||||
|
field: "x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "dis",
|
||||||
|
field: "x",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export let expYScale: PowScale = {
|
||||||
|
name: "yscale",
|
||||||
|
type: "pow",
|
||||||
|
exponent: 0.1,
|
||||||
|
range: "height",
|
||||||
|
zero: true,
|
||||||
|
nice: false,
|
||||||
|
domain: {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
data: "con",
|
||||||
|
field: "y",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: "dis",
|
||||||
|
field: "y",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
|
@ -33,18 +33,29 @@ const variableBox = {
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const VariableBox: React.FC<{
|
interface VariableBoxProps {
|
||||||
heading: string;
|
heading: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}> = ({ heading = "Error", children }) => {
|
showTypes?: boolean;
|
||||||
return (
|
}
|
||||||
<variableBox.Component>
|
|
||||||
<variableBox.Heading>
|
export const VariableBox: React.FC<VariableBoxProps> = ({
|
||||||
<h3>{heading}</h3>
|
heading = "Error",
|
||||||
</variableBox.Heading>
|
children,
|
||||||
<variableBox.Body>{children}</variableBox.Body>
|
showTypes = false,
|
||||||
</variableBox.Component>
|
}: VariableBoxProps) => {
|
||||||
);
|
if (showTypes) {
|
||||||
|
return (
|
||||||
|
<variableBox.Component>
|
||||||
|
<variableBox.Heading>
|
||||||
|
<h3>{heading}</h3>
|
||||||
|
</variableBox.Heading>
|
||||||
|
<variableBox.Body>{children}</variableBox.Body>
|
||||||
|
</variableBox.Component>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return <>{children}</>;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let RecordKeyHeader = styled.h3``;
|
let RecordKeyHeader = styled.h3``;
|
||||||
|
@ -52,27 +63,36 @@ let RecordKeyHeader = styled.h3``;
|
||||||
export interface SquiggleItemProps {
|
export interface SquiggleItemProps {
|
||||||
/** The input string for squiggle */
|
/** The input string for squiggle */
|
||||||
expression: squiggleExpression;
|
expression: squiggleExpression;
|
||||||
width: number;
|
width?: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
/** Whether to show type information */
|
||||||
|
showTypes?: boolean;
|
||||||
|
/** Whether to show users graph controls (scale etc) */
|
||||||
|
showControls?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
expression,
|
expression,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
showTypes = false,
|
||||||
|
showControls = false,
|
||||||
}: SquiggleItemProps) => {
|
}: SquiggleItemProps) => {
|
||||||
switch (expression.tag) {
|
switch (expression.tag) {
|
||||||
case "number":
|
case "number":
|
||||||
return (
|
return (
|
||||||
<VariableBox heading="Number">
|
<VariableBox heading="Number" showTypes={showTypes}>
|
||||||
<NumberShower precision={3} number={expression.value} />
|
<NumberShower precision={3} number={expression.value} />
|
||||||
</VariableBox>
|
</VariableBox>
|
||||||
);
|
);
|
||||||
case "distribution": {
|
case "distribution": {
|
||||||
let distType = expression.value.type();
|
let distType = expression.value.type();
|
||||||
return (
|
return (
|
||||||
<VariableBox heading={`Distribution (${distType})`}>
|
<VariableBox
|
||||||
{distType === "Symbolic" ? (
|
heading={`Distribution (${distType})`}
|
||||||
|
showTypes={showTypes}
|
||||||
|
>
|
||||||
|
{distType === "Symbolic" && showTypes ? (
|
||||||
<>
|
<>
|
||||||
<div>{expression.value.toString()}</div>
|
<div>{expression.value.toString()}</div>
|
||||||
</>
|
</>
|
||||||
|
@ -83,47 +103,77 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
distribution={expression.value}
|
distribution={expression.value}
|
||||||
height={height}
|
height={height}
|
||||||
width={width}
|
width={width}
|
||||||
|
showControls={showControls}
|
||||||
/>
|
/>
|
||||||
</VariableBox>
|
</VariableBox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case "string":
|
case "string":
|
||||||
return (
|
return (
|
||||||
<VariableBox heading="String">{`"${expression.value}"`}</VariableBox>
|
<VariableBox
|
||||||
|
heading="String"
|
||||||
|
showTypes={showTypes}
|
||||||
|
>{`"${expression.value}"`}</VariableBox>
|
||||||
);
|
);
|
||||||
case "boolean":
|
case "boolean":
|
||||||
return (
|
return (
|
||||||
<VariableBox heading="Boolean">
|
<VariableBox heading="Boolean" showTypes={showTypes}>
|
||||||
{expression.value.toString()}
|
{expression.value.toString()}
|
||||||
</VariableBox>
|
</VariableBox>
|
||||||
);
|
);
|
||||||
case "symbol":
|
case "symbol":
|
||||||
return <VariableBox heading="Symbol">{expression.value}</VariableBox>;
|
return (
|
||||||
|
<VariableBox heading="Symbol" showTypes={showTypes}>
|
||||||
|
{expression.value}
|
||||||
|
</VariableBox>
|
||||||
|
);
|
||||||
case "call":
|
case "call":
|
||||||
return <VariableBox heading="Call">{expression.value}</VariableBox>;
|
return (
|
||||||
|
<VariableBox heading="Call" showTypes={showTypes}>
|
||||||
|
{expression.value}
|
||||||
|
</VariableBox>
|
||||||
|
);
|
||||||
case "array":
|
case "array":
|
||||||
return (
|
return (
|
||||||
<VariableBox heading="Array">
|
<VariableBox heading="Array" showTypes={showTypes}>
|
||||||
{expression.value.map((r) => (
|
{expression.value.map((r) => (
|
||||||
<SquiggleItem expression={r} width={width - 20} height={50} />
|
<SquiggleItem
|
||||||
|
expression={r}
|
||||||
|
width={width !== undefined ? width - 20 : width}
|
||||||
|
height={50}
|
||||||
|
showTypes={showTypes}
|
||||||
|
showControls={showControls}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</VariableBox>
|
</VariableBox>
|
||||||
);
|
);
|
||||||
case "record":
|
case "record":
|
||||||
return (
|
return (
|
||||||
<VariableBox heading="Record">
|
<VariableBox heading="Record" showTypes={showTypes}>
|
||||||
{Object.entries(expression.value).map(([key, r]) => (
|
{Object.entries(expression.value).map(([key, r]) => (
|
||||||
<>
|
<>
|
||||||
<RecordKeyHeader>{key}</RecordKeyHeader>
|
<RecordKeyHeader>{key}</RecordKeyHeader>
|
||||||
<SquiggleItem expression={r} width={width - 20} height={50} />
|
<SquiggleItem
|
||||||
|
expression={r}
|
||||||
|
width={width !== undefined ? width - 20 : width}
|
||||||
|
height={50}
|
||||||
|
showTypes={showTypes}
|
||||||
|
showControls={showControls}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
))}
|
))}
|
||||||
</VariableBox>
|
</VariableBox>
|
||||||
);
|
);
|
||||||
default:
|
case "arraystring":
|
||||||
|
return (
|
||||||
|
<VariableBox heading="Array String" showTypes={showTypes}>
|
||||||
|
{expression.value.map((r) => `"${r}"`)}
|
||||||
|
</VariableBox>
|
||||||
|
);
|
||||||
|
case "lambda":
|
||||||
return (
|
return (
|
||||||
<ErrorBox heading="No Viewer">
|
<ErrorBox heading="No Viewer">
|
||||||
{"We don't currently have a working viewer for record types."}
|
There is no viewer currently available for function types.
|
||||||
</ErrorBox>
|
</ErrorBox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -153,6 +203,10 @@ export interface SquiggleChartProps {
|
||||||
bindings?: bindings;
|
bindings?: bindings;
|
||||||
/** JS imported parameters */
|
/** JS imported parameters */
|
||||||
jsImports?: jsImports;
|
jsImports?: jsImports;
|
||||||
|
/** Whether to show type information about returns, default false */
|
||||||
|
showTypes?: boolean;
|
||||||
|
/** Whether to show graph controls (scale etc)*/
|
||||||
|
showControls?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChartWrapper = styled.div`
|
const ChartWrapper = styled.div`
|
||||||
|
@ -169,7 +223,9 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
||||||
height = 60,
|
height = 60,
|
||||||
bindings = defaultBindings,
|
bindings = defaultBindings,
|
||||||
jsImports = defaultImports,
|
jsImports = defaultImports,
|
||||||
width = NaN,
|
width,
|
||||||
|
showTypes = false,
|
||||||
|
showControls = false,
|
||||||
}: SquiggleChartProps) => {
|
}: SquiggleChartProps) => {
|
||||||
let samplingInputs: samplingParams = {
|
let samplingInputs: samplingParams = {
|
||||||
sampleCount: sampleCount,
|
sampleCount: sampleCount,
|
||||||
|
@ -186,7 +242,13 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
||||||
let expression = expressionResult.value;
|
let expression = expressionResult.value;
|
||||||
onChange(expression);
|
onChange(expression);
|
||||||
internal = (
|
internal = (
|
||||||
<SquiggleItem expression={expression} width={width} height={height} />
|
<SquiggleItem
|
||||||
|
expression={expression}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
showTypes={showTypes}
|
||||||
|
showControls={showControls}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
internal = (
|
internal = (
|
||||||
|
|
|
@ -40,6 +40,10 @@ export interface SquiggleEditorProps {
|
||||||
bindings?: bindings;
|
bindings?: bindings;
|
||||||
/** JS Imports */
|
/** JS Imports */
|
||||||
jsImports?: jsImports;
|
jsImports?: jsImports;
|
||||||
|
/** Whether to show detail about types of the returns, default false */
|
||||||
|
showTypes?: boolean;
|
||||||
|
/** Whether to give users access to graph controls */
|
||||||
|
showControls: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Input = styled.div`
|
const Input = styled.div`
|
||||||
|
@ -50,7 +54,7 @@ const Input = styled.div`
|
||||||
|
|
||||||
export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
||||||
initialSquiggleString = "",
|
initialSquiggleString = "",
|
||||||
width = 500,
|
width,
|
||||||
sampleCount,
|
sampleCount,
|
||||||
outputXYPoints,
|
outputXYPoints,
|
||||||
kernelWidth,
|
kernelWidth,
|
||||||
|
@ -61,6 +65,8 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
||||||
onChange,
|
onChange,
|
||||||
bindings = defaultBindings,
|
bindings = defaultBindings,
|
||||||
jsImports = defaultImports,
|
jsImports = defaultImports,
|
||||||
|
showTypes = false,
|
||||||
|
showControls = false,
|
||||||
}: SquiggleEditorProps) => {
|
}: SquiggleEditorProps) => {
|
||||||
let [expression, setExpression] = React.useState(initialSquiggleString);
|
let [expression, setExpression] = React.useState(initialSquiggleString);
|
||||||
return (
|
return (
|
||||||
|
@ -87,6 +93,8 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
bindings={bindings}
|
bindings={bindings}
|
||||||
jsImports={jsImports}
|
jsImports={jsImports}
|
||||||
|
showTypes={showTypes}
|
||||||
|
showControls={showControls}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -145,6 +153,8 @@ export interface SquigglePartialProps {
|
||||||
bindings?: bindings;
|
bindings?: bindings;
|
||||||
/** Variables imported from js */
|
/** Variables imported from js */
|
||||||
jsImports?: jsImports;
|
jsImports?: jsImports;
|
||||||
|
/** Whether to give users access to graph controls */
|
||||||
|
showControls?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export let SquigglePartial: React.FC<SquigglePartialProps> = ({
|
export let SquigglePartial: React.FC<SquigglePartialProps> = ({
|
||||||
|
@ -160,15 +170,25 @@ export let SquigglePartial: React.FC<SquigglePartialProps> = ({
|
||||||
xyPointLength: outputXYPoints,
|
xyPointLength: outputXYPoints,
|
||||||
};
|
};
|
||||||
let [expression, setExpression] = React.useState(initialSquiggleString);
|
let [expression, setExpression] = React.useState(initialSquiggleString);
|
||||||
let squiggleResult = runPartial(
|
let [error, setError] = React.useState<string | null>(null);
|
||||||
expression,
|
|
||||||
bindings,
|
let runSquiggleAndUpdateBindings = () => {
|
||||||
samplingInputs,
|
let squiggleResult = runPartial(
|
||||||
jsImports
|
expression,
|
||||||
);
|
bindings,
|
||||||
if (squiggleResult.tag == "Ok") {
|
samplingInputs,
|
||||||
if (onChange) onChange(squiggleResult.value);
|
jsImports
|
||||||
}
|
);
|
||||||
|
if (squiggleResult.tag == "Ok") {
|
||||||
|
if (onChange) onChange(squiggleResult.value);
|
||||||
|
setError(null);
|
||||||
|
} else {
|
||||||
|
setError(errorValueToString(squiggleResult.value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
React.useEffect(runSquiggleAndUpdateBindings, [expression]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Input>
|
<Input>
|
||||||
|
@ -180,13 +200,7 @@ export let SquigglePartial: React.FC<SquigglePartialProps> = ({
|
||||||
height={20}
|
height={20}
|
||||||
/>
|
/>
|
||||||
</Input>
|
</Input>
|
||||||
{squiggleResult.tag == "Error" ? (
|
{error !== null ? <ErrorBox heading="Error">{error}</ErrorBox> : <></>}
|
||||||
<ErrorBox heading="Error">
|
|
||||||
{errorValueToString(squiggleResult.value)}
|
|
||||||
</ErrorBox>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,6 +43,8 @@ function FieldFloat(Props: FieldFloatProps) {
|
||||||
interface Props {
|
interface Props {
|
||||||
initialSquiggleString?: string;
|
initialSquiggleString?: string;
|
||||||
height?: number;
|
height?: number;
|
||||||
|
showTypes?: boolean;
|
||||||
|
showControls?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props2 {
|
interface Props2 {
|
||||||
|
@ -55,10 +57,6 @@ const ShowBox = styled.div<Props2>`
|
||||||
height: ${(props) => props.height};
|
height: ${(props) => props.height};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const MyComponent = styled.div`
|
|
||||||
color: ${(props) => props.theme.colors.main};
|
|
||||||
`;
|
|
||||||
|
|
||||||
interface TitleProps {
|
interface TitleProps {
|
||||||
readonly maxHeight: number;
|
readonly maxHeight: number;
|
||||||
}
|
}
|
||||||
|
@ -74,13 +72,15 @@ const Display = styled.div<TitleProps>`
|
||||||
|
|
||||||
const Row = styled.div`
|
const Row = styled.div`
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 50% 50%;
|
||||||
`;
|
`;
|
||||||
const Col = styled.div``;
|
const Col = styled.div``;
|
||||||
|
|
||||||
let SquigglePlayground: FC<Props> = ({
|
let SquigglePlayground: FC<Props> = ({
|
||||||
initialSquiggleString = "",
|
initialSquiggleString = "",
|
||||||
height = 300,
|
height = 300,
|
||||||
|
showTypes = false,
|
||||||
|
showControls = false,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
let [squiggleString, setSquiggleString] = useState(initialSquiggleString);
|
let [squiggleString, setSquiggleString] = useState(initialSquiggleString);
|
||||||
let [sampleCount, setSampleCount] = useState(1000);
|
let [sampleCount, setSampleCount] = useState(1000);
|
||||||
|
@ -112,6 +112,8 @@ let SquigglePlayground: FC<Props> = ({
|
||||||
diagramCount={diagramCount}
|
diagramCount={diagramCount}
|
||||||
pointDistLength={pointDistLength}
|
pointDistLength={pointDistLength}
|
||||||
height={150}
|
height={150}
|
||||||
|
showTypes={showTypes}
|
||||||
|
showControls={showControls}
|
||||||
/>
|
/>
|
||||||
</Display>
|
</Display>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
51
packages/components/src/stories/SquigglePartial.stories.mdx
Normal file
51
packages/components/src/stories/SquigglePartial.stories.mdx
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import { SquigglePartial, SquiggleEditor } from "../components/SquiggleEditor";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Canvas, Meta, Story, Props } from "@storybook/addon-docs";
|
||||||
|
|
||||||
|
<Meta title="Squiggle/SquigglePartial" component={SquigglePartial} />
|
||||||
|
|
||||||
|
export const Template = (props) => <SquigglePartial {...props} />;
|
||||||
|
|
||||||
|
# Squiggle Partial
|
||||||
|
|
||||||
|
A Squiggle Partial is an editor that does not return a graph to the user, but
|
||||||
|
instead returns bindings that can be used by further Squiggle Editors.
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story
|
||||||
|
name="Standalone"
|
||||||
|
args={{
|
||||||
|
initialSquiggleString: "x = normal(5,2)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Template.bind({})}
|
||||||
|
</Story>
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story
|
||||||
|
name="With Editor"
|
||||||
|
args={{
|
||||||
|
initialPartialString: "x = normal(5,2)",
|
||||||
|
initialEditorString: "x",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(props) => {
|
||||||
|
let [bindings, setBindings] = useState({});
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SquigglePartial
|
||||||
|
{...props}
|
||||||
|
initialSquiggleString={props.initialPartialString}
|
||||||
|
onChange={setBindings}
|
||||||
|
/>
|
||||||
|
<SquiggleEditor
|
||||||
|
{...props}
|
||||||
|
initialSquiggleString={props.initialEditorString}
|
||||||
|
bindings={bindings}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Story>
|
||||||
|
</Canvas>
|
|
@ -3,7 +3,6 @@
|
||||||
"description": "A basic area chart example",
|
"description": "A basic area chart example",
|
||||||
"width": 500,
|
"width": 500,
|
||||||
"height": 100,
|
"height": 100,
|
||||||
"autosize": "fit",
|
|
||||||
"padding": 5,
|
"padding": 5,
|
||||||
"data": [
|
"data": [
|
||||||
{
|
{
|
||||||
|
@ -13,72 +12,8 @@
|
||||||
"name": "dis"
|
"name": "dis"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"signals": [
|
"signals": [],
|
||||||
{
|
"scales": [],
|
||||||
"name": "xscale",
|
|
||||||
"description": "The transform of the x scale",
|
|
||||||
"value": false,
|
|
||||||
"bind": {
|
|
||||||
"input": "checkbox",
|
|
||||||
"name": "log x scale"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "yscale",
|
|
||||||
"description": "The transform of the y scale",
|
|
||||||
"value": false,
|
|
||||||
"bind": {
|
|
||||||
"input": "checkbox",
|
|
||||||
"name": "log y scale"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"scales": [
|
|
||||||
{
|
|
||||||
"name": "xscale",
|
|
||||||
"type": "pow",
|
|
||||||
"exponent": {
|
|
||||||
"signal": "xscale ? 0.1 : 1"
|
|
||||||
},
|
|
||||||
"range": "width",
|
|
||||||
"zero": false,
|
|
||||||
"nice": false,
|
|
||||||
"domain": {
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"data": "con",
|
|
||||||
"field": "x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": "dis",
|
|
||||||
"field": "x"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "yscale",
|
|
||||||
"type": "pow",
|
|
||||||
"exponent": {
|
|
||||||
"signal": "yscale ? 0.1 : 1"
|
|
||||||
},
|
|
||||||
"range": "height",
|
|
||||||
"nice": true,
|
|
||||||
"zero": true,
|
|
||||||
"domain": {
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"data": "con",
|
|
||||||
"field": "y"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": "dis",
|
|
||||||
"field": "y"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"axes": [
|
"axes": [
|
||||||
{
|
{
|
||||||
"orient": "bottom",
|
"orient": "bottom",
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
open Jest
|
||||||
|
// open Expect
|
||||||
|
|
||||||
|
open Reducer_Expression_ExpressionBuilder
|
||||||
|
open Reducer_TestMacroHelpers
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
|
||||||
|
let exampleExpression = eNumber(1.)
|
||||||
|
let exampleExpressionY = eSymbol("y")
|
||||||
|
let exampleStatementY = eLetStatement("y", eNumber(1.))
|
||||||
|
let exampleStatementX = eLetStatement("y", eSymbol("x"))
|
||||||
|
let exampleStatementZ = eLetStatement("z", eSymbol("y"))
|
||||||
|
|
||||||
|
// If it is not a macro then it is not expanded
|
||||||
|
testMacro([], exampleExpression, "Ok(1)")
|
||||||
|
|
||||||
|
describe("bindStatement", () => {
|
||||||
|
// A statement is bound by the bindings created by the previous statement
|
||||||
|
testMacro([], eBindStatement(eBindings([]), exampleStatementY), "Ok((:$setBindings {} :y 1))")
|
||||||
|
// Then it answers the bindings for the next statement when reduced
|
||||||
|
testMacroEval([], eBindStatement(eBindings([]), exampleStatementY), "Ok({y: 1})")
|
||||||
|
// Now let's feed a binding to see what happens
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBindStatement(eBindings([("x", EvNumber(2.))]), exampleStatementX),
|
||||||
|
"Ok((:$setBindings {x: 2} :y 2))",
|
||||||
|
)
|
||||||
|
// An expression does not return a binding, thus error
|
||||||
|
testMacro([], eBindStatement(eBindings([]), exampleExpression), "Error(Assignment expected)")
|
||||||
|
// When bindings from previous statement are missing the context is injected. This must be the first statement of a block
|
||||||
|
testMacro(
|
||||||
|
[("z", EvNumber(99.))],
|
||||||
|
eBindStatementDefault(exampleStatementY),
|
||||||
|
"Ok((:$setBindings {z: 99} :y 1))",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("bindExpression", () => {
|
||||||
|
// x is simply bound in the expression
|
||||||
|
testMacro([], eBindExpression(eBindings([("x", EvNumber(2.))]), eSymbol("x")), "Ok(2)")
|
||||||
|
// When an let statement is the end expression then bindings are returned
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatementY),
|
||||||
|
"Ok((:$exportBindings (:$setBindings {x: 2} :y 1)))",
|
||||||
|
)
|
||||||
|
// Now let's reduce that expression
|
||||||
|
testMacroEval(
|
||||||
|
[],
|
||||||
|
eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatementY),
|
||||||
|
"Ok({x: 2,y: 1})",
|
||||||
|
)
|
||||||
|
// When bindings are missing the context is injected. This must be the first and last statement of a block
|
||||||
|
testMacroEval(
|
||||||
|
[("z", EvNumber(99.))],
|
||||||
|
eBindExpressionDefault(exampleStatementY),
|
||||||
|
"Ok({y: 1,z: 99})",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("block", () => {
|
||||||
|
// Block with a single expression
|
||||||
|
testMacro([], eBlock(list{exampleExpression}), "Ok((:$$bindExpression 1))")
|
||||||
|
testMacroEval([], eBlock(list{exampleExpression}), "Ok(1)")
|
||||||
|
// Block with a single statement
|
||||||
|
testMacro([], eBlock(list{exampleStatementY}), "Ok((:$$bindExpression (:$let :y 1)))")
|
||||||
|
testMacroEval([], eBlock(list{exampleStatementY}), "Ok({y: 1})")
|
||||||
|
// Block with a statement and an expression
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBlock(list{exampleStatementY, exampleExpressionY}),
|
||||||
|
"Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) :y))",
|
||||||
|
)
|
||||||
|
testMacroEval([], eBlock(list{exampleStatementY, exampleExpressionY}), "Ok(1)")
|
||||||
|
// Block with a statement and another statement
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBlock(list{exampleStatementY, exampleStatementZ}),
|
||||||
|
"Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) (:$let :z :y)))",
|
||||||
|
)
|
||||||
|
testMacroEval([], eBlock(list{exampleStatementY, exampleStatementZ}), "Ok({y: 1,z: 1})")
|
||||||
|
// Block inside a block
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBlock(list{eBlock(list{exampleExpression})}),
|
||||||
|
"Ok((:$$bindExpression (:$$block 1)))",
|
||||||
|
)
|
||||||
|
testMacroEval([], eBlock(list{eBlock(list{exampleExpression})}), "Ok(1)")
|
||||||
|
// Block assigned to a variable
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBlock(list{eLetStatement("z", eBlock(list{eBlock(list{exampleExpressionY})}))}),
|
||||||
|
"Ok((:$$bindExpression (:$let :z (:$$block (:$$block :y)))))",
|
||||||
|
)
|
||||||
|
testMacroEval(
|
||||||
|
[],
|
||||||
|
eBlock(list{eLetStatement("z", eBlock(list{eBlock(list{exampleExpressionY})}))}),
|
||||||
|
"Ok({z: :y})",
|
||||||
|
)
|
||||||
|
// Empty block
|
||||||
|
testMacro([], eBlock(list{}), "Ok(:undefined block)") //TODO: should be an error
|
||||||
|
// :$$block (:$$block (:$let :y (:add :x 1)) :y)"
|
||||||
|
testMacro(
|
||||||
|
[],
|
||||||
|
eBlock(list{
|
||||||
|
eBlock(list{
|
||||||
|
eLetStatement("y", eFunction("add", list{eSymbol("x"), eNumber(1.)})),
|
||||||
|
eSymbol("y"),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
"Ok((:$$bindExpression (:$$block (:$let :y (:add :x 1)) :y)))",
|
||||||
|
)
|
||||||
|
MyOnly.testMacroEval(
|
||||||
|
[("x", EvNumber(1.))],
|
||||||
|
eBlock(list{
|
||||||
|
eBlock(list{
|
||||||
|
eLetStatement("y", eFunction("add", list{eSymbol("x"), eNumber(1.)})),
|
||||||
|
eSymbol("y"),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
"Ok(2)",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("lambda", () => {
|
||||||
|
// assign a lambda to a variable
|
||||||
|
let lambdaExpression = eFunction("$$lambda", list{eArrayString(["y"]), exampleExpressionY})
|
||||||
|
testMacro([], lambdaExpression, "Ok(lambda(y=>internal))")
|
||||||
|
// call a lambda
|
||||||
|
let callLambdaExpression = list{lambdaExpression, eNumber(1.)}->ExpressionT.EList
|
||||||
|
testMacro([], callLambdaExpression, "Ok(((:$$lambda [y] :y) 1))")
|
||||||
|
testMacroEval([], callLambdaExpression, "Ok(1)")
|
||||||
|
// Parameters shadow the outer scope
|
||||||
|
testMacroEval([("y", EvNumber(666.))], callLambdaExpression, "Ok(1)")
|
||||||
|
// When not shadowed by the parameters, the outer scope variables are available
|
||||||
|
let lambdaExpression = eFunction(
|
||||||
|
"$$lambda",
|
||||||
|
list{eArrayString(["z"]), eFunction("add", list{eSymbol("y"), eSymbol("z")})},
|
||||||
|
)
|
||||||
|
let callLambdaExpression = eList(list{lambdaExpression, eNumber(1.)})
|
||||||
|
testMacroEval([("y", EvNumber(666.))], callLambdaExpression, "Ok(667)")
|
||||||
|
})
|
|
@ -0,0 +1,6 @@
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
|
||||||
|
test("dummy", () => {
|
||||||
|
expect(true)->toBe(true)
|
||||||
|
})
|
|
@ -1,5 +1,5 @@
|
||||||
open ReducerInterface.ExpressionValue
|
open ReducerInterface.ExpressionValue
|
||||||
module MathJs = Reducer.MathJs
|
module MathJs = Reducer_MathJs
|
||||||
module ErrorValue = Reducer.ErrorValue
|
module ErrorValue = Reducer.ErrorValue
|
||||||
|
|
||||||
open Jest
|
open Jest
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module Parse = Reducer.MathJs.Parse
|
module Parse = Reducer_MathJs.Parse
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
|
|
||||||
open Jest
|
open Jest
|
||||||
|
@ -18,8 +18,14 @@ module MySkip = {
|
||||||
Skip.test(desc, () => expectParseToBe(expr, answer))
|
Skip.test(desc, () => expectParseToBe(expr, answer))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module MyOnly = {
|
||||||
|
let testParse = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer))
|
||||||
|
let testDescriptionParse = (desc, expr, answer) =>
|
||||||
|
Only.test(desc, () => expectParseToBe(expr, answer))
|
||||||
|
}
|
||||||
|
|
||||||
describe("MathJs parse", () => {
|
describe("MathJs parse", () => {
|
||||||
describe("literals operators paranthesis", () => {
|
describe("literals operators parenthesis", () => {
|
||||||
testParse("1", "1")
|
testParse("1", "1")
|
||||||
testParse("'hello'", "'hello'")
|
testParse("'hello'", "'hello'")
|
||||||
testParse("true", "true")
|
testParse("true", "true")
|
||||||
|
@ -40,15 +46,15 @@ describe("MathJs parse", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("functions", () => {
|
describe("functions", () => {
|
||||||
MySkip.testParse("identity(x) = x", "???")
|
testParse("identity(x) = x", "identity = (x) => x")
|
||||||
MySkip.testParse("identity(x)", "???")
|
testParse("identity(x)", "identity(x)")
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("arrays", () => {
|
describe("arrays", () => {
|
||||||
testDescriptionParse("empty", "[]", "[]")
|
testDescriptionParse("empty", "[]", "[]")
|
||||||
testDescriptionParse("define", "[0, 1, 2]", "[0, 1, 2]")
|
testDescriptionParse("define", "[0, 1, 2]", "[0, 1, 2]")
|
||||||
testDescriptionParse("define with strings", "['hello', 'world']", "['hello', 'world']")
|
testDescriptionParse("define with strings", "['hello', 'world']", "['hello', 'world']")
|
||||||
MySkip.testParse("range(0, 4)", "range(0, 4)")
|
testParse("range(0, 4)", "range(0, 4)")
|
||||||
testDescriptionParse("index", "([0,1,2])[1]", "([0, 1, 2])[1]")
|
testDescriptionParse("index", "([0,1,2])[1]", "([0, 1, 2])[1]")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -58,11 +64,6 @@ describe("MathJs parse", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("comments", () => {
|
describe("comments", () => {
|
||||||
MySkip.testDescriptionParse("define", "# This is a comment", "???")
|
testDescriptionParse("define", "1 # This is a comment", "1")
|
||||||
})
|
|
||||||
|
|
||||||
describe("if statement", () => {
|
|
||||||
// TODO Tertiary operator instead
|
|
||||||
MySkip.testDescriptionParse("define", "if (true) { 1 } else { 0 }", "???")
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,40 +1,31 @@
|
||||||
module Expression = Reducer.Expression
|
module ExpressionT = Reducer_Expression_T
|
||||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
|
||||||
open Jest
|
open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
|
||||||
|
let unwrapRecord = rValue =>
|
||||||
|
rValue->Belt.Result.flatMap(value =>
|
||||||
|
switch value {
|
||||||
|
| ExpressionValue.EvRecord(aRecord) => Ok(aRecord)
|
||||||
|
| _ => ErrorValue.RETodo("TODO: External bindings must be returned")->Error
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
let expectParseToBe = (expr: string, answer: string) =>
|
let expectParseToBe = (expr: string, answer: string) =>
|
||||||
Reducer.parse(expr)->Expression.toStringResult->expect->toBe(answer)
|
Reducer.parse(expr)->ExpressionT.toStringResult->expect->toBe(answer)
|
||||||
|
|
||||||
let expectParseOuterToBe = (expr: string, answer: string) =>
|
|
||||||
Reducer.parseOuter(expr)->Expression.toStringResult->expect->toBe(answer)
|
|
||||||
|
|
||||||
let expectParsePartialToBe = (expr: string, answer: string) =>
|
|
||||||
Reducer.parsePartial(expr)->Expression.toStringResult->expect->toBe(answer)
|
|
||||||
|
|
||||||
let expectEvalToBe = (expr: string, answer: string) =>
|
let expectEvalToBe = (expr: string, answer: string) =>
|
||||||
Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
|
Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer)
|
||||||
|
|
||||||
let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) =>
|
let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) =>
|
||||||
Reducer.evaluateUsingExternalBindings(expr, bindings)
|
Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~environment=None)
|
||||||
->ExpressionValue.toStringResult
|
->ExpressionValue.toStringResult
|
||||||
->expect
|
->expect
|
||||||
->toBe(answer)
|
->toBe(answer)
|
||||||
|
|
||||||
let expectEvalPartialBindingsToBe = (
|
|
||||||
expr: string,
|
|
||||||
bindings: Reducer.externalBindings,
|
|
||||||
answer: string,
|
|
||||||
) =>
|
|
||||||
Reducer.evaluatePartialUsingExternalBindings(expr, bindings)
|
|
||||||
->ExpressionValue.toStringResultRecord
|
|
||||||
->expect
|
|
||||||
->toBe(answer)
|
|
||||||
|
|
||||||
let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
|
let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
|
||||||
let testParseOuterToBe = (expr, answer) => test(expr, () => expectParseOuterToBe(expr, answer))
|
|
||||||
let testParsePartialToBe = (expr, answer) => test(expr, () => expectParsePartialToBe(expr, answer))
|
|
||||||
let testDescriptionParseToBe = (desc, expr, answer) =>
|
let testDescriptionParseToBe = (desc, expr, answer) =>
|
||||||
test(desc, () => expectParseToBe(expr, answer))
|
test(desc, () => expectParseToBe(expr, answer))
|
||||||
|
|
||||||
|
@ -42,34 +33,16 @@ let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answe
|
||||||
let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer))
|
let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer))
|
||||||
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
||||||
test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
||||||
let testEvalPartialBindingsToBe = (expr, bindingsList, answer) =>
|
|
||||||
test(expr, () => expectEvalPartialBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
|
||||||
|
|
||||||
module MySkip = {
|
module MySkip = {
|
||||||
let testParseToBe = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer))
|
let testParseToBe = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer))
|
||||||
let testParseOuterToBe = (expr, answer) =>
|
|
||||||
Skip.test(expr, () => expectParseOuterToBe(expr, answer))
|
|
||||||
let testParsePartialToBe = (expr, answer) =>
|
|
||||||
Skip.test(expr, () => expectParsePartialToBe(expr, answer))
|
|
||||||
let testEvalToBe = (expr, answer) => Skip.test(expr, () => expectEvalToBe(expr, answer))
|
let testEvalToBe = (expr, answer) => Skip.test(expr, () => expectEvalToBe(expr, answer))
|
||||||
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
||||||
Skip.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
Skip.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
||||||
let testEvalPartialBindingsToBe = (expr, bindingsList, answer) =>
|
|
||||||
Skip.test(expr, () =>
|
|
||||||
expectEvalPartialBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
module MyOnly = {
|
module MyOnly = {
|
||||||
let testParseToBe = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer))
|
let testParseToBe = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer))
|
||||||
let testParseOuterToBe = (expr, answer) =>
|
|
||||||
Only.test(expr, () => expectParseOuterToBe(expr, answer))
|
|
||||||
let testParsePartialToBe = (expr, answer) =>
|
|
||||||
Only.test(expr, () => expectParsePartialToBe(expr, answer))
|
|
||||||
let testEvalToBe = (expr, answer) => Only.test(expr, () => expectEvalToBe(expr, answer))
|
let testEvalToBe = (expr, answer) => Only.test(expr, () => expectEvalToBe(expr, answer))
|
||||||
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
let testEvalBindingsToBe = (expr, bindingsList, answer) =>
|
||||||
Only.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
Only.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer))
|
||||||
let testEvalPartialBindingsToBe = (expr, bindingsList, answer) =>
|
|
||||||
Only.test(expr, () =>
|
|
||||||
expectEvalPartialBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
|
||||||
|
module Bindings = Reducer_Expression_Bindings
|
||||||
|
module Expression = Reducer_Expression
|
||||||
|
module ExpressionValue = ReducerInterface_ExpressionValue
|
||||||
|
module ExpressionWithContext = Reducer_ExpressionWithContext
|
||||||
|
module Macro = Reducer_Expression_Macro
|
||||||
|
module T = Reducer_Expression_T
|
||||||
|
|
||||||
|
let testMacro_ = (
|
||||||
|
tester,
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedCode: string,
|
||||||
|
) => {
|
||||||
|
let bindings = Belt.Map.String.fromArray(bindArray)
|
||||||
|
tester(expr->T.toString, () =>
|
||||||
|
expr
|
||||||
|
->Macro.expandMacroCall(
|
||||||
|
bindings,
|
||||||
|
ExpressionValue.defaultEnvironment,
|
||||||
|
Expression.reduceExpression,
|
||||||
|
)
|
||||||
|
->ExpressionWithContext.toStringResult
|
||||||
|
->expect
|
||||||
|
->toEqual(expectedCode)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let testMacroEval_ = (
|
||||||
|
tester,
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedValue: string,
|
||||||
|
) => {
|
||||||
|
let bindings = Belt.Map.String.fromArray(bindArray)
|
||||||
|
tester(expr->T.toString, () =>
|
||||||
|
expr
|
||||||
|
->Macro.doMacroCall(bindings, ExpressionValue.defaultEnvironment, Expression.reduceExpression)
|
||||||
|
->ExpressionValue.toStringResult
|
||||||
|
->expect
|
||||||
|
->toEqual(expectedValue)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let testMacro = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedExpr: string,
|
||||||
|
) => testMacro_(test, bindArray, expr, expectedExpr)
|
||||||
|
let testMacroEval = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedValue: string,
|
||||||
|
) => testMacroEval_(test, bindArray, expr, expectedValue)
|
||||||
|
|
||||||
|
module MySkip = {
|
||||||
|
let testMacro = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedExpr: string,
|
||||||
|
) => testMacro_(Skip.test, bindArray, expr, expectedExpr)
|
||||||
|
let testMacroEval = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedValue: string,
|
||||||
|
) => testMacroEval_(Skip.test, bindArray, expr, expectedValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
module MyOnly = {
|
||||||
|
let testMacro = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedExpr: string,
|
||||||
|
) => testMacro_(Only.test, bindArray, expr, expectedExpr)
|
||||||
|
let testMacroEval = (
|
||||||
|
bindArray: array<(string, ExpressionValue.expressionValue)>,
|
||||||
|
expr: T.expression,
|
||||||
|
expectedValue: string,
|
||||||
|
) => testMacroEval_(Only.test, bindArray, expr, expectedValue)
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
open Jest
|
||||||
|
open Reducer_TestHelpers
|
||||||
|
|
||||||
|
/*
|
||||||
|
You can wrap around any expression with inspect(expr) to log the value of that expression.
|
||||||
|
This is useful for debugging. inspect(expr) returns the value of expr, but also prints it out.
|
||||||
|
|
||||||
|
There is a second version of inspect that takes a label, which will print out the label and the value.
|
||||||
|
|
||||||
|
inspectPerformace(expr, label) will print out the value of expr, the label, and the time it took to evaluate expr.
|
||||||
|
*/
|
||||||
|
describe("Debugging", () => {
|
||||||
|
testEvalToBe("inspect(1)", "Ok(1)")
|
||||||
|
testEvalToBe("inspect(1, \"one\")", "Ok(1)")
|
||||||
|
testEvalToBe("inspectPerformance(1, \"one\")", "Ok(1)")
|
||||||
|
})
|
|
@ -1,60 +1,63 @@
|
||||||
|
// TODO: Reimplement with usual parse
|
||||||
open Jest
|
open Jest
|
||||||
open Reducer_TestHelpers
|
open Reducer_TestHelpers
|
||||||
|
|
||||||
describe("Parse for Bindings", () => {
|
// describe("Parse for Bindings", () => {
|
||||||
testParseOuterToBe("x", "Ok((:$$bindExpression (:$$bindings) :x))")
|
// testParseOuterToBe("x", "Ok((:$$bindExpression (:$$bindings) :x))")
|
||||||
testParseOuterToBe("x+1", "Ok((:$$bindExpression (:$$bindings) (:add :x 1)))")
|
// testParseOuterToBe("x+1", "Ok((:$$bindExpression (:$$bindings) (:add :x 1)))")
|
||||||
testParseOuterToBe(
|
// testParseOuterToBe(
|
||||||
"y = x+1; y",
|
// "y = x+1; y",
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))",
|
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))",
|
||||||
)
|
// )
|
||||||
})
|
// })
|
||||||
|
|
||||||
describe("Parse Partial", () => {
|
// describe("Parse Partial", () => {
|
||||||
testParsePartialToBe(
|
// testParsePartialToBe(
|
||||||
"x",
|
// "x",
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) :x) (:$exportVariablesExpression)))",
|
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) :x) (:$exportVariablesExpression)))",
|
||||||
)
|
// )
|
||||||
testParsePartialToBe(
|
// testParsePartialToBe(
|
||||||
"y=x",
|
// "y=x",
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y :x)) (:$exportVariablesExpression)))",
|
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y :x)) (:$exportVariablesExpression)))",
|
||||||
)
|
// )
|
||||||
testParsePartialToBe(
|
// testParsePartialToBe(
|
||||||
"y=x+1",
|
// "y=x+1",
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$exportVariablesExpression)))",
|
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$exportVariablesExpression)))",
|
||||||
)
|
// )
|
||||||
testParsePartialToBe(
|
// testParsePartialToBe(
|
||||||
"y = x+1; z = y",
|
// "y = x+1; z = y",
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$let :z :y)) (:$exportVariablesExpression)))",
|
// "Ok((:$$bindExpression (:$$bindStatement (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$let :z :y)) (:$exportVariablesExpression)))",
|
||||||
)
|
// )
|
||||||
})
|
// })
|
||||||
|
|
||||||
describe("Eval with Bindings", () => {
|
describe("Eval with Bindings", () => {
|
||||||
testEvalBindingsToBe("x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(1)")
|
testEvalBindingsToBe("x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(1)")
|
||||||
testEvalBindingsToBe("x+1", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)")
|
testEvalBindingsToBe("x+1", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)")
|
||||||
|
testParseToBe("y = x+1; y", "Ok((:$$block (:$$block (:$let :y (:add :x 1)) :y)))")
|
||||||
testEvalBindingsToBe("y = x+1; y", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)")
|
testEvalBindingsToBe("y = x+1; y", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)")
|
||||||
|
testEvalBindingsToBe("y = x+1", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1,y: 2})")
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Partial code is a partial code fragment that is cut out from a larger code.
|
Partial code is a partial code fragment that is cut out from a larger code.
|
||||||
Therefore it does not end with an expression.
|
Therefore it does not end with an expression.
|
||||||
*/
|
*/
|
||||||
describe("Eval Partial", () => {
|
// describe("Eval Partial", () => {
|
||||||
testEvalPartialBindingsToBe(
|
// testEvalPartialBindingsToBe(
|
||||||
// A partial cannot end with an expression
|
// // A partial cannot end with an expression
|
||||||
"x",
|
// "x",
|
||||||
list{("x", ExpressionValue.EvNumber(1.))},
|
// list{("x", ExpressionValue.EvNumber(1.))},
|
||||||
"Error(Assignment expected)",
|
// "Error(Assignment expected)",
|
||||||
)
|
// )
|
||||||
testEvalPartialBindingsToBe("y=x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1, y: 1})")
|
// testEvalPartialBindingsToBe("y=x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1,y: 1})")
|
||||||
testEvalPartialBindingsToBe(
|
// testEvalPartialBindingsToBe(
|
||||||
"y=x+1",
|
// "y=x+1",
|
||||||
list{("x", ExpressionValue.EvNumber(1.))},
|
// list{("x", ExpressionValue.EvNumber(1.))},
|
||||||
"Ok({x: 1, y: 2})",
|
// "Ok({x: 1,y: 2})",
|
||||||
)
|
// )
|
||||||
testEvalPartialBindingsToBe(
|
// testEvalPartialBindingsToBe(
|
||||||
"y = x+1; z = y",
|
// "y = x+1; z = y",
|
||||||
list{("x", ExpressionValue.EvNumber(1.))},
|
// list{("x", ExpressionValue.EvNumber(1.))},
|
||||||
"Ok({x: 1, y: 2, z: 2})",
|
// "Ok({x: 1,y: 2,z: 2})",
|
||||||
)
|
// )
|
||||||
})
|
// })
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
open Jest
|
||||||
|
open Reducer_TestHelpers
|
||||||
|
|
||||||
|
describe("Parse function assignment", () => {
|
||||||
|
testParseToBe("f(x)=x", "Ok((:$$block (:$let :f (:$$lambda [x] (:$$block :x)))))")
|
||||||
|
testParseToBe("f(x)=2*x", "Ok((:$$block (:$let :f (:$$lambda [x] (:$$block (:multiply 2 :x))))))")
|
||||||
|
//MathJs does not allow blocks in function definitions
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Evaluate function assignment", () => {
|
||||||
|
testEvalToBe("f(x)=x; f(1)", "Ok(1)")
|
||||||
|
})
|
|
@ -0,0 +1,77 @@
|
||||||
|
open Jest
|
||||||
|
open Reducer_TestHelpers
|
||||||
|
|
||||||
|
describe("Arity check", () => {
|
||||||
|
testEvalToBe("f(x,y) = x + y; f(1,2)", "Ok(3)")
|
||||||
|
testEvalToBe(
|
||||||
|
"f(x,y) = x + y; f(1)",
|
||||||
|
"Error(2 arguments expected. Instead 1 argument(s) were passed.)",
|
||||||
|
)
|
||||||
|
testEvalToBe(
|
||||||
|
"f(x,y) = x + y; f(1,2,3)",
|
||||||
|
"Error(2 arguments expected. Instead 3 argument(s) were passed.)",
|
||||||
|
)
|
||||||
|
testEvalToBe(
|
||||||
|
"f(x,y)=x+y; f(1,2,3,4)",
|
||||||
|
"Error(2 arguments expected. Instead 4 argument(s) were passed.)",
|
||||||
|
)
|
||||||
|
testEvalToBe(
|
||||||
|
"f(x,y)=x+y; f(1)",
|
||||||
|
"Error(2 arguments expected. Instead 1 argument(s) were passed.)",
|
||||||
|
)
|
||||||
|
testEvalToBe(
|
||||||
|
"f(x,y)=x(y); f(f)",
|
||||||
|
"Error(2 arguments expected. Instead 1 argument(s) were passed.)",
|
||||||
|
)
|
||||||
|
testEvalToBe("f(x)=x; f(f)", "Ok(lambda(x=>internal code))")
|
||||||
|
testEvalToBe(
|
||||||
|
"f(x,y)=x(y); f(z)",
|
||||||
|
"Error(2 arguments expected. Instead 1 argument(s) were passed.)",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("symbol not defined", () => {
|
||||||
|
testEvalToBe("f(x)=x(y); f(f)", "Error(y is not defined)")
|
||||||
|
testEvalToBe("f(x)=x; f(f)", "Ok(lambda(x=>internal code))")
|
||||||
|
testEvalToBe("f(x)=x(y); f(z)", "Error(z is not defined)")
|
||||||
|
testEvalToBe("f(x)=x(y); f(2)", "Error(2 is not a function)")
|
||||||
|
testEvalToBe("f(x)=x(1); f(2)", "Error(2 is not a function)")
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("call and bindings", () => {
|
||||||
|
testEvalToBe("f(x)=x+1", "Ok({f: lambda(x=>internal code)})")
|
||||||
|
testEvalToBe("f(x)=x+1; f(1)", "Ok(2)")
|
||||||
|
testEvalToBe("f=1;y=2", "Ok({f: 1,y: 2})")
|
||||||
|
testEvalToBe("f(x)=x+1; y=f(1)", "Ok({f: lambda(x=>internal code),y: 2})")
|
||||||
|
testEvalToBe("f(x)=x+1; y=f(1); f(1)", "Ok(2)")
|
||||||
|
testEvalToBe("f(x)=x+1; y=f(1); z=f(1)", "Ok({f: lambda(x=>internal code),y: 2,z: 2})")
|
||||||
|
testEvalToBe(
|
||||||
|
"f(x)=x+1; g(x)=f(x)+1",
|
||||||
|
"Ok({f: lambda(x=>internal code),g: lambda(x=>internal code)})",
|
||||||
|
)
|
||||||
|
testParseToBe(
|
||||||
|
"f=99; g(x)=f; g(2)",
|
||||||
|
"Ok((:$$block (:$$block (:$let :f 99) (:$let :g (:$$lambda [x] (:$$block :f))) (:g 2))))",
|
||||||
|
)
|
||||||
|
testEvalToBe("f=99; g(x)=f; g(2)", "Ok(99)")
|
||||||
|
testEvalToBe("f(x)=x; g(x)=f(x); g(2)", "Ok(2)")
|
||||||
|
testEvalToBe(
|
||||||
|
"f(x)=x+1; g(x)=f(x)+1; y=g(2)",
|
||||||
|
"Ok({f: lambda(x=>internal code),g: lambda(x=>internal code),y: 4})",
|
||||||
|
)
|
||||||
|
testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "Ok(4)")
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("function trics", () => {
|
||||||
|
testParseToBe(
|
||||||
|
"f(x)=f(y)=2; f(2)",
|
||||||
|
"Ok((:$$block (:$$block (:$let :f (:$$lambda [x] (:$$block (:$let :f (:$$lambda [y] (:$$block 2)))))) (:f 2))))",
|
||||||
|
)
|
||||||
|
testEvalToBe("f(x)=f(y)=2; f(2)", "Ok({f: lambda(y=>internal code),x: 2})")
|
||||||
|
testEvalToBe("y=2;g(x)=y+1;g(2)", "Ok(3)")
|
||||||
|
testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok({g: lambda(x=>internal code),y: 2})")
|
||||||
|
MySkip.testEvalToBe("f(x) = x(x); f(f)", "????") // TODO: Infinite loop. Any solution? Catching proper exception or timeout?
|
||||||
|
MySkip.testEvalToBe("f(x, x)=x+x; f(1,2)", "????") // TODO: Duplicate parameters
|
||||||
|
MySkip.testEvalToBe("myadd(x,y)=x+y; z=[add]; z[0](3,2)", "????") //TODO: to fix with new parser
|
||||||
|
MySkip.testEvalToBe("myaddd(x,y)=x+y; z={x: add}; z.x(3,2)", "????") //TODO: to fix with new parser
|
||||||
|
})
|
|
@ -10,46 +10,39 @@ describe("reducer using mathjs parse", () => {
|
||||||
// Those tests toString that we are converting mathjs parse tree to what we need
|
// Those tests toString that we are converting mathjs parse tree to what we need
|
||||||
|
|
||||||
describe("expressions", () => {
|
describe("expressions", () => {
|
||||||
testParseToBe("1", "Ok(1)")
|
testParseToBe("1", "Ok((:$$block 1))")
|
||||||
testParseToBe("(1)", "Ok(1)")
|
testParseToBe("(1)", "Ok((:$$block 1))")
|
||||||
testParseToBe("1+2", "Ok((:add 1 2))")
|
testParseToBe("1+2", "Ok((:$$block (:add 1 2)))")
|
||||||
testParseToBe("1+2", "Ok((:add 1 2))")
|
testParseToBe("1+2*3", "Ok((:$$block (:add 1 (:multiply 2 3))))")
|
||||||
testParseToBe("1+2", "Ok((:add 1 2))")
|
|
||||||
testParseToBe("1+2*3", "Ok((:add 1 (:multiply 2 3)))")
|
|
||||||
})
|
})
|
||||||
describe("arrays", () => {
|
describe("arrays", () => {
|
||||||
//Note. () is a empty list in Lisp
|
//Note. () is a empty list in Lisp
|
||||||
// The only builtin structure in Lisp is list. There are no arrays
|
// The only builtin structure in Lisp is list. There are no arrays
|
||||||
// [1,2,3] becomes (1 2 3)
|
// [1,2,3] becomes (1 2 3)
|
||||||
testDescriptionParseToBe("empty", "[]", "Ok(())")
|
testDescriptionParseToBe("empty", "[]", "Ok((:$$block ()))")
|
||||||
testParseToBe("[1, 2, 3]", "Ok((1 2 3))")
|
testParseToBe("[1, 2, 3]", "Ok((:$$block (1 2 3)))")
|
||||||
testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))")
|
testParseToBe("['hello', 'world']", "Ok((:$$block ('hello' 'world')))")
|
||||||
testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))")
|
testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$$block (:$atIndex (0 1 2) (1))))")
|
||||||
})
|
})
|
||||||
describe("records", () => {
|
describe("records", () => {
|
||||||
testDescriptionParseToBe("define", "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))")
|
testDescriptionParseToBe(
|
||||||
|
"define",
|
||||||
|
"{a: 1, b: 2}",
|
||||||
|
"Ok((:$$block (:$constructRecord (('a' 1) ('b' 2)))))",
|
||||||
|
)
|
||||||
testDescriptionParseToBe(
|
testDescriptionParseToBe(
|
||||||
"use",
|
"use",
|
||||||
"{a: 1, b: 2}.a",
|
"{a: 1, b: 2}.a",
|
||||||
"Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))",
|
"Ok((:$$block (:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a'))))",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("multi-line", () => {
|
describe("multi-line", () => {
|
||||||
testParseToBe("1; 2", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) 1) 2))")
|
testParseToBe("1; 2", "Ok((:$$block (:$$block 1 2)))")
|
||||||
testParseToBe(
|
testParseToBe("1+1; 2+1", "Ok((:$$block (:$$block (:add 1 1) (:add 2 1))))")
|
||||||
"1+1; 2+1",
|
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:add 1 1)) (:add 2 1)))",
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
describe("assignment", () => {
|
describe("assignment", () => {
|
||||||
testParseToBe(
|
testParseToBe("x=1; x", "Ok((:$$block (:$$block (:$let :x 1) :x)))")
|
||||||
"x=1; x",
|
testParseToBe("x=1+1; x+1", "Ok((:$$block (:$$block (:$let :x (:add 1 1)) (:add :x 1))))")
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x 1)) :x))",
|
|
||||||
)
|
|
||||||
testParseToBe(
|
|
||||||
"x=1+1; x+1",
|
|
||||||
"Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x (:add 1 1))) (:add :x 1)))",
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -70,13 +63,13 @@ describe("eval", () => {
|
||||||
})
|
})
|
||||||
describe("arrays", () => {
|
describe("arrays", () => {
|
||||||
test("empty array", () => expectEvalToBe("[]", "Ok([])"))
|
test("empty array", () => expectEvalToBe("[]", "Ok([])"))
|
||||||
testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])")
|
testEvalToBe("[1, 2, 3]", "Ok([1,2,3])")
|
||||||
testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])")
|
testEvalToBe("['hello', 'world']", "Ok(['hello','world'])")
|
||||||
testEvalToBe("([0,1,2])[1]", "Ok(1)")
|
testEvalToBe("([0,1,2])[1]", "Ok(1)")
|
||||||
testDescriptionEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)")
|
testDescriptionEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)")
|
||||||
})
|
})
|
||||||
describe("records", () => {
|
describe("records", () => {
|
||||||
test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1, b: 2})"))
|
test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1,b: 2})"))
|
||||||
test("index", () => expectEvalToBe("{a: 1}.a", "Ok(1)"))
|
test("index", () => expectEvalToBe("{a: 1}.a", "Ok(1)"))
|
||||||
test("index not found", () => expectEvalToBe("{a: 1}.b", "Error(Record property not found: b)"))
|
test("index not found", () => expectEvalToBe("{a: 1}.b", "Error(Record property not found: b)"))
|
||||||
})
|
})
|
||||||
|
@ -91,7 +84,7 @@ describe("eval", () => {
|
||||||
testEvalToBe("x=1; y=x+1; y+1", "Ok(3)")
|
testEvalToBe("x=1; y=x+1; y+1", "Ok(3)")
|
||||||
testEvalToBe("1; x=1", "Error(Assignment expected)")
|
testEvalToBe("1; x=1", "Error(Assignment expected)")
|
||||||
testEvalToBe("1; 1", "Error(Assignment expected)")
|
testEvalToBe("1; 1", "Error(Assignment expected)")
|
||||||
testEvalToBe("x=1; x=1", "Error(Expression expected)")
|
testEvalToBe("x=1; x=1", "Ok({x: 1})")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -119,27 +119,34 @@ describe("eval on distribution functions", () => {
|
||||||
|
|
||||||
describe("parse on distribution functions", () => {
|
describe("parse on distribution functions", () => {
|
||||||
describe("power", () => {
|
describe("power", () => {
|
||||||
testParse("normal(5,2) ^ normal(5,1)", "Ok((:pow (:normal 5 2) (:normal 5 1)))")
|
testParse("normal(5,2) ^ normal(5,1)", "Ok((:$$block (:pow (:normal 5 2) (:normal 5 1))))")
|
||||||
testParse("3 ^ normal(5,1)", "Ok((:pow 3 (:normal 5 1)))")
|
testParse("3 ^ normal(5,1)", "Ok((:$$block (:pow 3 (:normal 5 1))))")
|
||||||
testParse("normal(5,2) ^ 3", "Ok((:pow (:normal 5 2) 3))")
|
testParse("normal(5,2) ^ 3", "Ok((:$$block (:pow (:normal 5 2) 3)))")
|
||||||
})
|
})
|
||||||
describe("subtraction", () => {
|
describe("subtraction", () => {
|
||||||
testParse("10 - normal(5,1)", "Ok((:subtract 10 (:normal 5 1)))")
|
testParse("10 - normal(5,1)", "Ok((:$$block (:subtract 10 (:normal 5 1))))")
|
||||||
testParse("normal(5,1) - 10", "Ok((:subtract (:normal 5 1) 10))")
|
testParse("normal(5,1) - 10", "Ok((:$$block (:subtract (:normal 5 1) 10)))")
|
||||||
})
|
})
|
||||||
describe("pointwise arithmetic expressions", () => {
|
describe("pointwise arithmetic expressions", () => {
|
||||||
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
||||||
testParse(
|
testParse(
|
||||||
~skip=true,
|
~skip=true,
|
||||||
"normal(5,2) .- normal(5,1)",
|
"normal(5,2) .- normal(5,1)",
|
||||||
"Ok((:dotSubtract (:normal 5 2) (:normal 5 1)))",
|
"Ok((:$$block (:dotSubtract (:normal 5 2) (:normal 5 1))))",
|
||||||
|
// TODO: !!! returns "Ok((:$$block (:dotPow (:normal 5 2) (:normal 5 1))))"
|
||||||
)
|
)
|
||||||
testParse("normal(5,2) .* normal(5,1)", "Ok((:dotMultiply (:normal 5 2) (:normal 5 1)))")
|
testParse(
|
||||||
testParse("normal(5,2) ./ normal(5,1)", "Ok((:dotDivide (:normal 5 2) (:normal 5 1)))")
|
"normal(5,2) .* normal(5,1)",
|
||||||
testParse("normal(5,2) .^ normal(5,1)", "Ok((:dotPow (:normal 5 2) (:normal 5 1)))")
|
"Ok((:$$block (:dotMultiply (:normal 5 2) (:normal 5 1))))",
|
||||||
|
)
|
||||||
|
testParse(
|
||||||
|
"normal(5,2) ./ normal(5,1)",
|
||||||
|
"Ok((:$$block (:dotDivide (:normal 5 2) (:normal 5 1))))",
|
||||||
|
)
|
||||||
|
testParse("normal(5,2) .^ normal(5,1)", "Ok((:$$block (:dotPow (:normal 5 2) (:normal 5 1))))")
|
||||||
})
|
})
|
||||||
describe("equality", () => {
|
describe("equality", () => {
|
||||||
testParse("5 == normal(5,2)", "Ok((:equal 5 (:normal 5 2)))")
|
testParse("5 == normal(5,2)", "Ok((:$$block (:equal 5 (:normal 5 2))))")
|
||||||
})
|
})
|
||||||
describe("pointwise adding two normals", () => {
|
describe("pointwise adding two normals", () => {
|
||||||
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))")
|
||||||
|
|
|
@ -3,9 +3,9 @@ open Jest
|
||||||
open Expect
|
open Expect
|
||||||
|
|
||||||
describe("ExpressionValue", () => {
|
describe("ExpressionValue", () => {
|
||||||
test("argsToString", () => expect([EvNumber(1.), EvString("a")]->argsToString)->toBe("1, 'a'"))
|
test("argsToString", () => expect([EvNumber(1.), EvString("a")]->argsToString)->toBe("1,'a'"))
|
||||||
|
|
||||||
test("toStringFunctionCall", () =>
|
test("toStringFunctionCall", () =>
|
||||||
expect(("fn", [EvNumber(1.), EvString("a")])->toStringFunctionCall)->toBe("fn(1, 'a')")
|
expect(("fn", [EvNumber(1.), EvString("a")])->toStringFunctionCall)->toBe("fn(1,'a')")
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
"homepage": "https://squiggle-language.com",
|
"homepage": "https://squiggle-language.com",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rescript build -with-deps && tsc",
|
"build": "yarn build:rescript && yarn build:typescript",
|
||||||
|
"build:rescript": "rescript build -with-deps",
|
||||||
|
"build:typescript": "tsc",
|
||||||
"bundle": "webpack",
|
"bundle": "webpack",
|
||||||
"start": "rescript build -w -with-deps",
|
"start": "rescript build -w -with-deps",
|
||||||
"clean": "rescript clean && rm -r dist",
|
"clean": "rescript clean && rm -r dist",
|
||||||
|
@ -55,7 +57,7 @@
|
||||||
"nyc": "^15.1.0",
|
"nyc": "^15.1.0",
|
||||||
"reanalyze": "^2.19.0",
|
"reanalyze": "^2.19.0",
|
||||||
"ts-jest": "^27.1.4",
|
"ts-jest": "^27.1.4",
|
||||||
"ts-loader": "^9.2.8",
|
"ts-loader": "^9.3.0",
|
||||||
"ts-node": "^10.7.0",
|
"ts-node": "^10.7.0",
|
||||||
"typescript": "^4.6.3",
|
"typescript": "^4.6.3",
|
||||||
"webpack": "^5.72.0",
|
"webpack": "^5.72.0",
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {
|
||||||
genericDist,
|
genericDist,
|
||||||
continuousShape,
|
continuousShape,
|
||||||
discreteShape,
|
discreteShape,
|
||||||
samplingParams,
|
environment,
|
||||||
distributionError,
|
distributionError,
|
||||||
toPointSet,
|
toPointSet,
|
||||||
distributionErrorToString,
|
distributionErrorToString,
|
||||||
|
@ -51,9 +51,9 @@ export type shape = {
|
||||||
|
|
||||||
export class Distribution {
|
export class Distribution {
|
||||||
t: genericDist;
|
t: genericDist;
|
||||||
env: samplingParams;
|
env: environment;
|
||||||
|
|
||||||
constructor(t: genericDist, env: samplingParams) {
|
constructor(t: genericDist, env: environment) {
|
||||||
this.t = t;
|
this.t = t;
|
||||||
this.env = env;
|
this.env = env;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import * as _ from "lodash";
|
import * as _ from "lodash";
|
||||||
import {
|
import {
|
||||||
samplingParams,
|
samplingParams,
|
||||||
evaluateUsingExternalBindings,
|
environment,
|
||||||
|
defaultEnvironment,
|
||||||
evaluatePartialUsingExternalBindings,
|
evaluatePartialUsingExternalBindings,
|
||||||
|
evaluateUsingOptions,
|
||||||
externalBindings,
|
externalBindings,
|
||||||
expressionValue,
|
expressionValue,
|
||||||
errorValue,
|
errorValue,
|
||||||
|
@ -11,6 +13,7 @@ export {
|
||||||
makeSampleSetDist,
|
makeSampleSetDist,
|
||||||
errorValueToString,
|
errorValueToString,
|
||||||
distributionErrorToString,
|
distributionErrorToString,
|
||||||
|
distributionError,
|
||||||
} from "../rescript/TypescriptInterface.gen";
|
} from "../rescript/TypescriptInterface.gen";
|
||||||
export type {
|
export type {
|
||||||
samplingParams,
|
samplingParams,
|
||||||
|
@ -26,9 +29,9 @@ import {
|
||||||
convertRawToTypescript,
|
convertRawToTypescript,
|
||||||
} from "./rescript_interop";
|
} from "./rescript_interop";
|
||||||
import { result, resultMap, tag, tagged } from "./types";
|
import { result, resultMap, tag, tagged } from "./types";
|
||||||
import { Distribution } from "./distribution";
|
import { Distribution, shape } from "./distribution";
|
||||||
|
|
||||||
export { Distribution, squiggleExpression, result, resultMap };
|
export { Distribution, squiggleExpression, result, resultMap, shape };
|
||||||
|
|
||||||
export let defaultSamplingInputs: samplingParams = {
|
export let defaultSamplingInputs: samplingParams = {
|
||||||
sampleCount: 10000,
|
sampleCount: 10000,
|
||||||
|
@ -38,33 +41,34 @@ export let defaultSamplingInputs: samplingParams = {
|
||||||
export function run(
|
export function run(
|
||||||
squiggleString: string,
|
squiggleString: string,
|
||||||
bindings?: externalBindings,
|
bindings?: externalBindings,
|
||||||
samplingInputs?: samplingParams,
|
environment?: environment,
|
||||||
imports?: jsImports
|
imports?: jsImports
|
||||||
): result<squiggleExpression, errorValue> {
|
): result<squiggleExpression, errorValue> {
|
||||||
let b = bindings ? bindings : defaultBindings;
|
let b = bindings ? bindings : defaultBindings;
|
||||||
let i = imports ? imports : defaultImports;
|
let i = imports ? imports : defaultImports;
|
||||||
let si: samplingParams = samplingInputs
|
let e = environment ? environment : defaultEnvironment;
|
||||||
? samplingInputs
|
let res: result<expressionValue, errorValue> = evaluateUsingOptions(
|
||||||
: defaultSamplingInputs;
|
{ externalBindings: mergeImports(b, i), environment: e },
|
||||||
|
squiggleString
|
||||||
let result: result<expressionValue, errorValue> =
|
);
|
||||||
evaluateUsingExternalBindings(squiggleString, mergeImports(b, i));
|
return resultMap(res, (x) => createTsExport(x, e));
|
||||||
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,
|
environment?: environment,
|
||||||
imports?: jsImports
|
imports?: jsImports
|
||||||
): result<externalBindings, errorValue> {
|
): result<externalBindings, errorValue> {
|
||||||
let b = bindings ? bindings : defaultBindings;
|
let b = bindings ? bindings : defaultBindings;
|
||||||
let i = imports ? imports : defaultImports;
|
let i = imports ? imports : defaultImports;
|
||||||
|
let e = environment ? environment : defaultEnvironment;
|
||||||
|
|
||||||
return evaluatePartialUsingExternalBindings(
|
return evaluatePartialUsingExternalBindings(
|
||||||
squiggleString,
|
squiggleString,
|
||||||
mergeImports(b, i)
|
mergeImports(b, i),
|
||||||
|
e
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +92,7 @@ export let defaultBindings: externalBindings = {};
|
||||||
|
|
||||||
function createTsExport(
|
function createTsExport(
|
||||||
x: expressionValue,
|
x: expressionValue,
|
||||||
sampEnv: samplingParams
|
environment: environment
|
||||||
): squiggleExpression {
|
): squiggleExpression {
|
||||||
switch (x.tag) {
|
switch (x.tag) {
|
||||||
case "EvArray":
|
case "EvArray":
|
||||||
|
@ -107,7 +111,10 @@ function createTsExport(
|
||||||
return tag(
|
return tag(
|
||||||
"record",
|
"record",
|
||||||
_.mapValues(arrayItem.value, (recordValue: unknown) =>
|
_.mapValues(arrayItem.value, (recordValue: unknown) =>
|
||||||
convertRawToTypescript(recordValue as rescriptExport, sampEnv)
|
convertRawToTypescript(
|
||||||
|
recordValue as rescriptExport,
|
||||||
|
environment
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
case "EvArray":
|
case "EvArray":
|
||||||
|
@ -115,20 +122,24 @@ function createTsExport(
|
||||||
return tag(
|
return tag(
|
||||||
"array",
|
"array",
|
||||||
y.map((childArrayItem) =>
|
y.map((childArrayItem) =>
|
||||||
convertRawToTypescript(childArrayItem, sampEnv)
|
convertRawToTypescript(childArrayItem, environment)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return createTsExport(arrayItem, sampEnv);
|
return createTsExport(arrayItem, environment);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
case "EvArrayString":
|
||||||
|
return tag("arraystring", x.value);
|
||||||
case "EvBool":
|
case "EvBool":
|
||||||
return tag("boolean", x.value);
|
return tag("boolean", x.value);
|
||||||
case "EvCall":
|
case "EvCall":
|
||||||
return tag("call", x.value);
|
return tag("call", x.value);
|
||||||
|
case "EvLambda":
|
||||||
|
return tag("lambda", x.value);
|
||||||
case "EvDistribution":
|
case "EvDistribution":
|
||||||
return tag("distribution", new Distribution(x.value, sampEnv));
|
return tag("distribution", new Distribution(x.value, environment));
|
||||||
case "EvNumber":
|
case "EvNumber":
|
||||||
return tag("number", x.value);
|
return tag("number", x.value);
|
||||||
case "EvRecord":
|
case "EvRecord":
|
||||||
|
@ -136,7 +147,7 @@ function createTsExport(
|
||||||
let result: tagged<"record", { [key: string]: squiggleExpression }> = tag(
|
let result: tagged<"record", { [key: string]: squiggleExpression }> = tag(
|
||||||
"record",
|
"record",
|
||||||
_.mapValues(x.value, (x: unknown) =>
|
_.mapValues(x.value, (x: unknown) =>
|
||||||
convertRawToTypescript(x as rescriptExport, sampEnv)
|
convertRawToTypescript(x as rescriptExport, environment)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -3,10 +3,11 @@ import {
|
||||||
mixedShape,
|
mixedShape,
|
||||||
sampleSetDist,
|
sampleSetDist,
|
||||||
genericDist,
|
genericDist,
|
||||||
samplingParams,
|
environment,
|
||||||
symbolicDist,
|
symbolicDist,
|
||||||
discreteShape,
|
discreteShape,
|
||||||
continuousShape,
|
continuousShape,
|
||||||
|
lambdaValue,
|
||||||
} from "../rescript/TypescriptInterface.gen";
|
} from "../rescript/TypescriptInterface.gen";
|
||||||
import { Distribution } from "./distribution";
|
import { Distribution } from "./distribution";
|
||||||
import { tagged, tag } from "./types";
|
import { tagged, tag } from "./types";
|
||||||
|
@ -19,31 +20,39 @@ export type rescriptExport =
|
||||||
_0: rescriptExport[];
|
_0: rescriptExport[];
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
TAG: 1; // EvBool
|
TAG: 1; // EvString
|
||||||
|
_0: string[];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
TAG: 2; // EvBool
|
||||||
_0: boolean;
|
_0: boolean;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
TAG: 2; // EvCall
|
TAG: 3; // EvCall
|
||||||
_0: string;
|
_0: string;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
TAG: 3; // EvDistribution
|
TAG: 4; // EvDistribution
|
||||||
_0: rescriptDist;
|
_0: rescriptDist;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
TAG: 4; // EvNumber
|
TAG: 5; // EvLambda
|
||||||
|
_0: lambdaValue;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
TAG: 6; // EvNumber
|
||||||
_0: number;
|
_0: number;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
TAG: 5; // EvRecord
|
TAG: 7; // EvRecord
|
||||||
_0: { [key: string]: rescriptExport };
|
_0: { [key: string]: rescriptExport };
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
TAG: 6; // EvString
|
TAG: 8; // EvString
|
||||||
_0: string;
|
_0: string;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
TAG: 7; // EvSymbol
|
TAG: 9; // EvSymbol
|
||||||
_0: string;
|
_0: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,7 +79,9 @@ export type squiggleExpression =
|
||||||
| tagged<"symbol", string>
|
| tagged<"symbol", string>
|
||||||
| tagged<"string", string>
|
| tagged<"string", string>
|
||||||
| tagged<"call", string>
|
| tagged<"call", string>
|
||||||
|
| tagged<"lambda", lambdaValue>
|
||||||
| tagged<"array", squiggleExpression[]>
|
| tagged<"array", squiggleExpression[]>
|
||||||
|
| tagged<"arraystring", string[]>
|
||||||
| tagged<"boolean", boolean>
|
| tagged<"boolean", boolean>
|
||||||
| tagged<"distribution", Distribution>
|
| tagged<"distribution", Distribution>
|
||||||
| tagged<"number", number>
|
| tagged<"number", number>
|
||||||
|
@ -78,36 +89,40 @@ export type squiggleExpression =
|
||||||
|
|
||||||
export function convertRawToTypescript(
|
export function convertRawToTypescript(
|
||||||
result: rescriptExport,
|
result: rescriptExport,
|
||||||
sampEnv: samplingParams
|
environment: environment
|
||||||
): squiggleExpression {
|
): squiggleExpression {
|
||||||
switch (result.TAG) {
|
switch (result.TAG) {
|
||||||
case 0: // EvArray
|
case 0: // EvArray
|
||||||
return tag(
|
return tag(
|
||||||
"array",
|
"array",
|
||||||
result._0.map((x) => convertRawToTypescript(x, sampEnv))
|
result._0.map((x) => convertRawToTypescript(x, environment))
|
||||||
);
|
);
|
||||||
case 1: // EvBool
|
case 1: // EvArrayString
|
||||||
|
return tag("arraystring", result._0);
|
||||||
|
case 2: // EvBool
|
||||||
return tag("boolean", result._0);
|
return tag("boolean", result._0);
|
||||||
case 2: // EvCall
|
case 3: // EvCall
|
||||||
return tag("call", result._0);
|
return tag("call", result._0);
|
||||||
case 3: // EvDistribution
|
case 4: // EvDistribution
|
||||||
return tag(
|
return tag(
|
||||||
"distribution",
|
"distribution",
|
||||||
new Distribution(
|
new Distribution(
|
||||||
convertRawDistributionToGenericDist(result._0),
|
convertRawDistributionToGenericDist(result._0),
|
||||||
sampEnv
|
environment
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
case 4: // EvNumber
|
case 5: // EvDistribution
|
||||||
|
return tag("lambda", result._0);
|
||||||
|
case 6: // EvNumber
|
||||||
return tag("number", result._0);
|
return tag("number", result._0);
|
||||||
case 5: // EvRecord
|
case 7: // EvRecord
|
||||||
return tag(
|
return tag(
|
||||||
"record",
|
"record",
|
||||||
_.mapValues(result._0, (x) => convertRawToTypescript(x, sampEnv))
|
_.mapValues(result._0, (x) => convertRawToTypescript(x, environment))
|
||||||
);
|
);
|
||||||
case 6: // EvString
|
case 8: // EvString
|
||||||
return tag("string", result._0);
|
return tag("string", result._0);
|
||||||
case 7: // EvSymbol
|
case 9: // EvSymbol
|
||||||
return tag("symbol", result._0);
|
return tag("symbol", result._0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,15 +156,15 @@ export type jsValue =
|
||||||
|
|
||||||
export function jsValueToBinding(value: jsValue): rescriptExport {
|
export function jsValueToBinding(value: jsValue): rescriptExport {
|
||||||
if (typeof value === "boolean") {
|
if (typeof value === "boolean") {
|
||||||
return { TAG: 1, _0: value as boolean };
|
return { TAG: 2, _0: value as boolean };
|
||||||
} else if (typeof value === "string") {
|
} else if (typeof value === "string") {
|
||||||
return { TAG: 6, _0: value as string };
|
return { TAG: 8, _0: value as string };
|
||||||
} else if (typeof value === "number") {
|
} else if (typeof value === "number") {
|
||||||
return { TAG: 4, _0: value as number };
|
return { TAG: 6, _0: value as number };
|
||||||
} else if (Array.isArray(value)) {
|
} else if (Array.isArray(value)) {
|
||||||
return { TAG: 0, _0: value.map(jsValueToBinding) };
|
return { TAG: 0, _0: value.map(jsValueToBinding) };
|
||||||
} else {
|
} else {
|
||||||
// Record
|
// Record
|
||||||
return { TAG: 5, _0: _.mapValues(value, jsValueToBinding) };
|
return { TAG: 7, _0: _.mapValues(value, jsValueToBinding) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,11 @@ type env = {
|
||||||
xyPointLength: int,
|
xyPointLength: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let defaultEnv = {
|
||||||
|
sampleCount: 10000,
|
||||||
|
xyPointLength: 10000,
|
||||||
|
}
|
||||||
|
|
||||||
type outputType =
|
type outputType =
|
||||||
| Dist(genericDist)
|
| Dist(genericDist)
|
||||||
| Float(float)
|
| Float(float)
|
||||||
|
|
|
@ -4,6 +4,9 @@ type env = {
|
||||||
xyPointLength: int,
|
xyPointLength: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let defaultEnv: env
|
||||||
|
|
||||||
open DistributionTypes
|
open DistributionTypes
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
|
|
|
@ -114,6 +114,7 @@ module DistributionOperation = {
|
||||||
| ToFloat(#Mean) => `mean`
|
| ToFloat(#Mean) => `mean`
|
||||||
| ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})`
|
| ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})`
|
||||||
| ToFloat(#Sample) => `sample`
|
| ToFloat(#Sample) => `sample`
|
||||||
|
| ToFloat(#IntegralSum) => `integralSum`
|
||||||
| ToDist(Normalize) => `normalize`
|
| ToDist(Normalize) => `normalize`
|
||||||
| ToDist(ToPointSet) => `toPointSet`
|
| ToDist(ToPointSet) => `toPointSet`
|
||||||
| ToDist(ToSampleSet(r)) => `toSampleSet(${E.I.toString(r)})`
|
| ToDist(ToSampleSet(r)) => `toSampleSet(${E.I.toString(r)})`
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
module Dispatch = Reducer_Dispatch
|
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
module Expression = Reducer_Expression
|
module Expression = Reducer_Expression
|
||||||
module Extra = Reducer_Extra
|
|
||||||
module Js = Reducer_Js
|
|
||||||
module MathJs = Reducer_MathJs
|
|
||||||
|
|
||||||
type expressionValue = Reducer_Expression.expressionValue
|
type environment = ReducerInterface_ExpressionValue.environment
|
||||||
type externalBindings = Expression.externalBindings
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
let evaluate = Expression.eval
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
let evaluateUsingExternalBindings = Expression.evalUsingExternalBindings
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
let evaluatePartialUsingExternalBindings = Expression.evalPartialUsingExternalBindings
|
let evaluate = Expression.evaluate
|
||||||
|
let evaluateUsingOptions = Expression.evaluateUsingOptions
|
||||||
|
let evaluatePartialUsingExternalBindings = Expression.evaluatePartialUsingExternalBindings
|
||||||
let parse = Expression.parse
|
let parse = Expression.parse
|
||||||
let parseOuter = Expression.parseOuter
|
|
||||||
let parsePartial = Expression.parsePartial
|
|
||||||
|
|
|
@ -1,26 +1,28 @@
|
||||||
module Dispatch = Reducer_Dispatch
|
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
module Expression = Reducer_Expression
|
module Expression = Reducer_Expression
|
||||||
module Extra = Reducer_Extra
|
|
||||||
module Js = Reducer_Js
|
|
||||||
module MathJs = Reducer_MathJs
|
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type environment = ReducerInterface_ExpressionValue.environment
|
||||||
|
@genType
|
||||||
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
@genType
|
@genType
|
||||||
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
@genType
|
@genType
|
||||||
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let evaluate: string => result<expressionValue, Reducer_ErrorValue.errorValue>
|
let evaluateUsingOptions: (
|
||||||
@genType
|
~environment: option<QuriSquiggleLang.ReducerInterface_ExpressionValue.environment>,
|
||||||
let evaluateUsingExternalBindings: (
|
~externalBindings: option<QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings>,
|
||||||
string,
|
string,
|
||||||
externalBindings,
|
) => result<expressionValue, errorValue>
|
||||||
) => result<expressionValue, Reducer_ErrorValue.errorValue>
|
|
||||||
@genType
|
@genType
|
||||||
let evaluatePartialUsingExternalBindings: (
|
let evaluatePartialUsingExternalBindings: (
|
||||||
string,
|
string,
|
||||||
externalBindings,
|
QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings,
|
||||||
) => result<externalBindings, Reducer_ErrorValue.errorValue>
|
QuriSquiggleLang.ReducerInterface_ExpressionValue.environment,
|
||||||
let parse: string => result<Expression.expression, ErrorValue.errorValue>
|
) => result<externalBindings, errorValue>
|
||||||
let parseOuter: string => result<Expression.expression, ErrorValue.errorValue>
|
@genType
|
||||||
let parsePartial: string => result<Expression.expression, ErrorValue.errorValue>
|
let evaluate: string => result<expressionValue, errorValue>
|
||||||
|
|
||||||
|
let parse: string => result<Expression.expression, errorValue>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
module ExternalLibrary = ReducerInterface.ExternalLibrary
|
module ExternalLibrary = ReducerInterface.ExternalLibrary
|
||||||
module MathJs = Reducer_MathJs
|
module MathJs = Reducer_MathJs
|
||||||
|
module Bindings = Reducer_Expression_Bindings
|
||||||
open ReducerInterface.ExpressionValue
|
open ReducerInterface.ExpressionValue
|
||||||
open Reducer_ErrorValue
|
open Reducer_ErrorValue
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ open Reducer_ErrorValue
|
||||||
|
|
||||||
exception TestRescriptException
|
exception TestRescriptException
|
||||||
|
|
||||||
let callInternal = (call: functionCall): result<'b, errorValue> => {
|
let callInternal = (call: functionCall, _environment): result<'b, errorValue> => {
|
||||||
let callMathJs = (call: functionCall): result<'b, errorValue> =>
|
let callMathJs = (call: functionCall): result<'b, errorValue> =>
|
||||||
switch call {
|
switch call {
|
||||||
| ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests
|
| ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests
|
||||||
|
@ -20,12 +21,12 @@ let callInternal = (call: functionCall): result<'b, errorValue> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
let constructRecord = arrayOfPairs => {
|
let constructRecord = arrayOfPairs => {
|
||||||
Belt.Array.map(arrayOfPairs, pairValue => {
|
Belt.Array.map(arrayOfPairs, pairValue =>
|
||||||
switch pairValue {
|
switch pairValue {
|
||||||
| EvArray([EvString(key), valueValue]) => (key, valueValue)
|
| EvArray([EvString(key), valueValue]) => (key, valueValue)
|
||||||
| _ => ("wrong key type", pairValue->toStringWithType->EvString)
|
| _ => ("wrong key type", pairValue->toStringWithType->EvString)
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
->Js.Dict.fromArray
|
->Js.Dict.fromArray
|
||||||
->EvRecord
|
->EvRecord
|
||||||
->Ok
|
->Ok
|
||||||
|
@ -43,16 +44,58 @@ let callInternal = (call: functionCall): result<'b, errorValue> => {
|
||||||
| None => RERecordPropertyNotFound("Record property not found", sIndex)->Error
|
| None => RERecordPropertyNotFound("Record property not found", sIndex)->Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let inspect = (value: expressionValue) => {
|
||||||
|
Js.log(value->toString)
|
||||||
|
value->Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
let inspectLabel = (value: expressionValue, label: string) => {
|
||||||
|
Js.log(`${label}: ${value->toString}`)
|
||||||
|
value->Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: This function is cancelled. The related issue is
|
||||||
|
https://github.com/webpack/webpack/issues/13435
|
||||||
|
*/
|
||||||
|
let inspectPerformance = (value: expressionValue, label: string) => {
|
||||||
|
// let _ = %raw("{performance} = require('perf_hooks')")
|
||||||
|
// let start = %raw(`performance.now()`)
|
||||||
|
// let finish = %raw(`performance.now()`)
|
||||||
|
// let performance = finish - start
|
||||||
|
// Js.log(`${label}: ${value->toString} performance: ${Js.String.make(performance)}ms`)
|
||||||
|
// TODO find a way of failing the hook gracefully, also needs a block parameter
|
||||||
|
Js.log(`${label}: ${value->toString}`)
|
||||||
|
value->Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
let doSetBindings = (
|
||||||
|
externalBindings: externalBindings,
|
||||||
|
symbol: string,
|
||||||
|
value: expressionValue,
|
||||||
|
) => {
|
||||||
|
Bindings.fromExternalBindings(externalBindings)
|
||||||
|
->Belt.Map.String.set(symbol, value)
|
||||||
|
->Bindings.toExternalBindings
|
||||||
|
->EvRecord
|
||||||
|
->Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
let doExportBindings = (externalBindings: externalBindings) => EvRecord(externalBindings)->Ok
|
||||||
|
|
||||||
switch call {
|
switch call {
|
||||||
// | ("$constructRecord", pairArray)
|
|
||||||
// | ("$atIndex", [EvArray(anArray), EvNumber(fIndex)]) => arrayAtIndex(anArray, fIndex)
|
|
||||||
// | ("$atIndex", [EvRecord(aRecord), EvString(sIndex)]) => recordAtIndex(aRecord, sIndex)
|
|
||||||
| ("$constructRecord", [EvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs)
|
|
||||||
| ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) =>
|
| ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) =>
|
||||||
arrayAtIndex(aValueArray, fIndex)
|
arrayAtIndex(aValueArray, fIndex)
|
||||||
| ("$atIndex", [EvRecord(dict), EvArray([EvString(sIndex)])]) => recordAtIndex(dict, sIndex)
|
| ("$atIndex", [EvRecord(dict), EvArray([EvString(sIndex)])]) => recordAtIndex(dict, sIndex)
|
||||||
| ("$atIndex", [obj, index]) =>
|
| ("$atIndex", [obj, index]) =>
|
||||||
(toStringWithType(obj) ++ "??~~~~" ++ toStringWithType(index))->EvString->Ok
|
(toStringWithType(obj) ++ "??~~~~" ++ toStringWithType(index))->EvString->Ok
|
||||||
|
| ("$constructRecord", [EvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs)
|
||||||
|
| ("inspect", [value, EvString(label)]) => inspectLabel(value, label)
|
||||||
|
| ("inspect", [value]) => inspect(value)
|
||||||
|
| ("inspectPerformance", [value, EvString(label)]) => inspectPerformance(value, label)
|
||||||
|
| ("$setBindings", [EvRecord(externalBindings), EvSymbol(symbol), value]) =>
|
||||||
|
doSetBindings(externalBindings, symbol, value)
|
||||||
|
| ("$exportBindings", [EvRecord(externalBindings)]) => doExportBindings(externalBindings)
|
||||||
| call => callMathJs(call)
|
| call => callMathJs(call)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,12 +103,12 @@ let callInternal = (call: functionCall): result<'b, errorValue> => {
|
||||||
/*
|
/*
|
||||||
Reducer uses Result monad while reducing expressions
|
Reducer uses Result monad while reducing expressions
|
||||||
*/
|
*/
|
||||||
let dispatch = (call: functionCall): result<expressionValue, errorValue> =>
|
let dispatch = (call: functionCall, environment): result<expressionValue, errorValue> =>
|
||||||
try {
|
try {
|
||||||
let (fn, args) = call
|
let (fn, args) = call
|
||||||
// There is a bug that prevents string match in patterns
|
// There is a bug that prevents string match in patterns
|
||||||
// So we have to recreate a copy of the string
|
// So we have to recreate a copy of the string
|
||||||
ExternalLibrary.dispatch((Js.String.make(fn), args), callInternal)
|
ExternalLibrary.dispatch((Js.String.make(fn), args), environment, callInternal)
|
||||||
} catch {
|
} catch {
|
||||||
| Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error
|
| Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error
|
||||||
| _ => RETodo("unhandled rescript exception")->Error
|
| _ => RETodo("unhandled rescript exception")->Error
|
||||||
|
|
|
@ -3,120 +3,170 @@
|
||||||
they take expressions as parameters and return a new expression.
|
they take expressions as parameters and return a new expression.
|
||||||
Macros are used to define language building blocks. They are like Lisp macros.
|
Macros are used to define language building blocks. They are like Lisp macros.
|
||||||
*/
|
*/
|
||||||
|
module Bindings = Reducer_Expression_Bindings
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
module ExpressionWithContext = Reducer_ExpressionWithContext
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
|
open Reducer_Expression_ExpressionBuilder
|
||||||
|
|
||||||
open Reducer_ErrorValue
|
type environment = ExpressionValue.environment
|
||||||
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
type expression = ExpressionT.expression
|
type expression = ExpressionT.expression
|
||||||
|
type expressionValue = ExpressionValue.expressionValue
|
||||||
type reducerFn = (
|
type expressionWithContext = ExpressionWithContext.expressionWithContext
|
||||||
expression,
|
|
||||||
ExpressionT.bindings,
|
|
||||||
) => result<ExpressionValue.expressionValue, errorValue>
|
|
||||||
|
|
||||||
let dispatchMacroCall = (
|
let dispatchMacroCall = (
|
||||||
list: list<expression>,
|
macroExpression: expression,
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
reduceExpression: reducerFn,
|
environment,
|
||||||
): result<expression, 'e> => {
|
reduceExpression: ExpressionT.reducerFn,
|
||||||
let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings): result<
|
): result<expressionWithContext, errorValue> => {
|
||||||
expression,
|
let doBindStatement = (bindingExpr: expression, statement: expression, environment) =>
|
||||||
errorValue,
|
|
||||||
> =>
|
|
||||||
switch expression {
|
|
||||||
| ExpressionT.EValue(EvSymbol(aSymbol)) =>
|
|
||||||
switch bindings->Belt.Map.String.get(aSymbol) {
|
|
||||||
| Some(boundExpression) => boundExpression->Ok
|
|
||||||
| None => RESymbolNotFound(aSymbol)->Error
|
|
||||||
}
|
|
||||||
| ExpressionT.EValue(_) => expression->Ok
|
|
||||||
| ExpressionT.EBindings(_) => expression->Ok
|
|
||||||
| ExpressionT.EList(list) => {
|
|
||||||
let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) =>
|
|
||||||
racc->Result.flatMap(acc => {
|
|
||||||
each
|
|
||||||
->replaceSymbols(bindings)
|
|
||||||
->Result.flatMap(newNode => {
|
|
||||||
acc->Belt.List.add(newNode)->Ok
|
|
||||||
})
|
|
||||||
})
|
|
||||||
)
|
|
||||||
racc->Result.map(acc => acc->ExpressionT.EList)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => {
|
|
||||||
switch statement {
|
switch statement {
|
||||||
| ExpressionT.EList(list{
|
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => {
|
||||||
ExpressionT.EValue(EvCall("$let")),
|
let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment)
|
||||||
ExpressionT.EValue(EvSymbol(aSymbol)),
|
|
||||||
expressionToReduce,
|
|
||||||
}) => {
|
|
||||||
let rNewExpressionToReduce = replaceSymbols(expressionToReduce, bindings)
|
|
||||||
|
|
||||||
let rNewValue =
|
rExternalBindingsValue->Result.flatMap(externalBindingsValue => {
|
||||||
rNewExpressionToReduce->Result.flatMap(newExpressionToReduce =>
|
let newBindings = Bindings.fromValue(externalBindingsValue)
|
||||||
reduceExpression(newExpressionToReduce, bindings)
|
|
||||||
|
// Js.log(
|
||||||
|
// `bindStatement ${Bindings.toString(newBindings)}<==${ExpressionT.toString(
|
||||||
|
// bindingExpr,
|
||||||
|
// )} statement: $let ${ExpressionT.toString(symbolExpr)}=${ExpressionT.toString(
|
||||||
|
// statement,
|
||||||
|
// )}`,
|
||||||
|
// )
|
||||||
|
|
||||||
|
let rNewStatement = Bindings.replaceSymbols(newBindings, statement)
|
||||||
|
rNewStatement->Result.map(newStatement =>
|
||||||
|
ExpressionWithContext.withContext(
|
||||||
|
eFunction(
|
||||||
|
"$setBindings",
|
||||||
|
list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement},
|
||||||
|
),
|
||||||
|
newBindings,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
})
|
||||||
let rNewExpression = rNewValue->Result.map(newValue => ExpressionT.EValue(newValue))
|
|
||||||
rNewExpression->Result.map(newExpression =>
|
|
||||||
Belt.Map.String.set(bindings, aSymbol, newExpression)->ExpressionT.EBindings
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
| _ => REAssignmentExpected->Error
|
| _ => REAssignmentExpected->Error
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let doExportVariableExpression = (bindings: ExpressionT.bindings) => {
|
let doBindExpression = (bindingExpr: expression, statement: expression, environment): result<
|
||||||
let emptyDictionary: Js.Dict.t<ExpressionValue.expressionValue> = Js.Dict.empty()
|
expressionWithContext,
|
||||||
let reducedBindings = bindings->Belt.Map.String.keep((_key, value) =>
|
errorValue,
|
||||||
switch value {
|
> =>
|
||||||
| ExpressionT.EValue(_) => true
|
switch statement {
|
||||||
| _ => false
|
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => {
|
||||||
}
|
let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment)
|
||||||
)
|
|
||||||
let externalBindings = reducedBindings->Belt.Map.String.reduce(emptyDictionary, (
|
|
||||||
acc,
|
|
||||||
key,
|
|
||||||
expressionValue,
|
|
||||||
) => {
|
|
||||||
let value = switch expressionValue {
|
|
||||||
| EValue(aValue) => aValue
|
|
||||||
| _ => EvSymbol("internal")
|
|
||||||
}
|
|
||||||
Js.Dict.set(acc, key, value)
|
|
||||||
acc
|
|
||||||
})
|
|
||||||
externalBindings->ExpressionValue.EvRecord->ExpressionT.EValue->Ok
|
|
||||||
}
|
|
||||||
|
|
||||||
let doBindExpression = (expression: expression, bindings: ExpressionT.bindings) =>
|
rExternalBindingsValue->Result.flatMap(externalBindingsValue => {
|
||||||
switch expression {
|
let newBindings = Bindings.fromValue(externalBindingsValue)
|
||||||
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), ..._}) =>
|
let rNewStatement = Bindings.replaceSymbols(newBindings, statement)
|
||||||
REExpressionExpected->Error
|
rNewStatement->Result.map(newStatement =>
|
||||||
| ExpressionT.EList(list{ExpressionT.EValue(EvCall("$exportVariablesExpression"))}) =>
|
ExpressionWithContext.withContext(
|
||||||
doExportVariableExpression(bindings)
|
eFunction(
|
||||||
| _ => replaceSymbols(expression, bindings)
|
"$exportBindings",
|
||||||
|
list{
|
||||||
|
eFunction(
|
||||||
|
"$setBindings",
|
||||||
|
list{
|
||||||
|
newBindings->Bindings.toExternalBindings->eRecord,
|
||||||
|
symbolExpr,
|
||||||
|
newStatement,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
newBindings,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
| _ => {
|
||||||
|
let rExternalBindingsValue: result<expressionValue, errorValue> = reduceExpression(
|
||||||
|
bindingExpr,
|
||||||
|
bindings,
|
||||||
|
environment,
|
||||||
|
)
|
||||||
|
|
||||||
|
rExternalBindingsValue->Result.flatMap(externalBindingsValue => {
|
||||||
|
let newBindings = Bindings.fromValue(externalBindingsValue)
|
||||||
|
let rNewStatement = Bindings.replaceSymbols(newBindings, statement)
|
||||||
|
rNewStatement->Result.map(newStatement =>
|
||||||
|
ExpressionWithContext.withContext(newStatement, newBindings)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch list {
|
let doBlock = (exprs: list<expression>, _bindings: ExpressionT.bindings, _environment): result<
|
||||||
| list{ExpressionT.EValue(EvCall("$$bindings"))} => bindings->ExpressionT.EBindings->Ok
|
expressionWithContext,
|
||||||
|
errorValue,
|
||||||
|
> => {
|
||||||
|
let exprsArray = Belt.List.toArray(exprs)
|
||||||
|
let maxIndex = Js.Array2.length(exprsArray) - 1
|
||||||
|
let newStatement = exprsArray->Js.Array2.reducei((acc, statement, index) =>
|
||||||
|
if index == 0 {
|
||||||
|
if index == maxIndex {
|
||||||
|
eBindExpressionDefault(statement)
|
||||||
|
} else {
|
||||||
|
eBindStatementDefault(statement)
|
||||||
|
}
|
||||||
|
} else if index == maxIndex {
|
||||||
|
eBindExpression(acc, statement)
|
||||||
|
} else {
|
||||||
|
eBindStatement(acc, statement)
|
||||||
|
}
|
||||||
|
, eSymbol("undefined block"))
|
||||||
|
ExpressionWithContext.noContext(newStatement)->Ok
|
||||||
|
}
|
||||||
|
|
||||||
| list{
|
let doLambdaDefinition = (
|
||||||
ExpressionT.EValue(EvCall("$$bindStatement")),
|
bindings: ExpressionT.bindings,
|
||||||
ExpressionT.EBindings(bindings),
|
parameters: array<string>,
|
||||||
statement,
|
lambdaDefinition: ExpressionT.expression,
|
||||||
} =>
|
) =>
|
||||||
doBindStatement(statement, bindings)
|
ExpressionWithContext.noContext(
|
||||||
| list{
|
eLambda(parameters, bindings->Bindings.toExternalBindings, lambdaDefinition),
|
||||||
ExpressionT.EValue(EvCall("$$bindExpression")),
|
)->Ok
|
||||||
ExpressionT.EBindings(bindings),
|
|
||||||
expression,
|
let expandExpressionList = (aList, bindings: ExpressionT.bindings, environment): result<
|
||||||
} =>
|
expressionWithContext,
|
||||||
doBindExpression(expression, bindings)
|
errorValue,
|
||||||
| _ => list->ExpressionT.EList->Ok
|
> =>
|
||||||
|
switch aList {
|
||||||
|
| list{
|
||||||
|
ExpressionT.EValue(EvCall("$$bindStatement")),
|
||||||
|
bindingExpr: ExpressionT.expression,
|
||||||
|
statement,
|
||||||
|
} =>
|
||||||
|
doBindStatement(bindingExpr, statement, environment)
|
||||||
|
| list{ExpressionT.EValue(EvCall("$$bindStatement")), statement} =>
|
||||||
|
// bindings of the context are used when there is no binding expression
|
||||||
|
doBindStatement(eRecord(Bindings.toExternalBindings(bindings)), statement, environment)
|
||||||
|
| list{
|
||||||
|
ExpressionT.EValue(EvCall("$$bindExpression")),
|
||||||
|
bindingExpr: ExpressionT.expression,
|
||||||
|
expression,
|
||||||
|
} =>
|
||||||
|
doBindExpression(bindingExpr, expression, environment)
|
||||||
|
| list{ExpressionT.EValue(EvCall("$$bindExpression")), expression} =>
|
||||||
|
// bindings of the context are used when there is no binding expression
|
||||||
|
doBindExpression(eRecord(Bindings.toExternalBindings(bindings)), expression, environment)
|
||||||
|
| list{ExpressionT.EValue(EvCall("$$block")), ...exprs} => doBlock(exprs, bindings, environment)
|
||||||
|
| list{
|
||||||
|
ExpressionT.EValue(EvCall("$$lambda")),
|
||||||
|
ExpressionT.EValue(EvArrayString(parameters)),
|
||||||
|
lambdaDefinition,
|
||||||
|
} =>
|
||||||
|
doLambdaDefinition(bindings, parameters, lambdaDefinition)
|
||||||
|
| _ => ExpressionWithContext.noContext(ExpressionT.EList(aList))->Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
switch macroExpression {
|
||||||
|
| EList(aList) => expandExpressionList(aList, bindings, environment)
|
||||||
|
| _ => ExpressionWithContext.noContext(macroExpression)->Ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
@genType
|
@genType
|
||||||
type errorValue =
|
type errorValue =
|
||||||
|
| REArityError(option<string>, int, int) //TODO: Binding a lambda to a variable should record the variable name in lambda for error reporting
|
||||||
| REArrayIndexNotFound(string, int)
|
| REArrayIndexNotFound(string, int)
|
||||||
| REAssignmentExpected
|
| REAssignmentExpected
|
||||||
|
| REDistributionError(DistributionTypes.error)
|
||||||
| REExpressionExpected
|
| REExpressionExpected
|
||||||
| REFunctionExpected(string)
|
| REFunctionExpected(string)
|
||||||
| REJavaScriptExn(option<string>, option<string>) // Javascript Exception
|
| REJavaScriptExn(option<string>, option<string>) // Javascript Exception
|
||||||
| REMacroNotFound(string)
|
| REMacroNotFound(string)
|
||||||
|
| RENotAFunction(string)
|
||||||
| RERecordPropertyNotFound(string, string)
|
| RERecordPropertyNotFound(string, string)
|
||||||
| RESymbolNotFound(string)
|
| RESymbolNotFound(string)
|
||||||
| RESyntaxError(string)
|
| RESyntaxError(string)
|
||||||
| REDistributionError(DistributionTypes.error)
|
|
||||||
| RETodo(string) // To do
|
| RETodo(string) // To do
|
||||||
|
|
||||||
type t = errorValue
|
type t = errorValue
|
||||||
|
@ -17,6 +19,10 @@ type t = errorValue
|
||||||
@genType
|
@genType
|
||||||
let errorToString = err =>
|
let errorToString = err =>
|
||||||
switch err {
|
switch err {
|
||||||
|
| REArityError(_oFnName, arity, usedArity) =>
|
||||||
|
`${Js.String.make(arity)} arguments expected. Instead ${Js.String.make(
|
||||||
|
usedArity,
|
||||||
|
)} argument(s) were passed.`
|
||||||
| REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}`
|
| REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}`
|
||||||
| REAssignmentExpected => "Assignment expected"
|
| REAssignmentExpected => "Assignment expected"
|
||||||
| REExpressionExpected => "Expression expected"
|
| REExpressionExpected => "Expression expected"
|
||||||
|
@ -35,6 +41,7 @@ let errorToString = err =>
|
||||||
answer
|
answer
|
||||||
}
|
}
|
||||||
| REMacroNotFound(macro) => `Macro not found: ${macro}`
|
| REMacroNotFound(macro) => `Macro not found: ${macro}`
|
||||||
|
| RENotAFunction(valueString) => `${valueString} is not a function`
|
||||||
| RERecordPropertyNotFound(msg, index) => `${msg}: ${index}`
|
| RERecordPropertyNotFound(msg, index) => `${msg}: ${index}`
|
||||||
| RESymbolNotFound(symbolName) => `${symbolName} is not defined`
|
| RESymbolNotFound(symbolName) => `${symbolName} is not defined`
|
||||||
| RESyntaxError(desc) => `Syntax Error: ${desc}`
|
| RESyntaxError(desc) => `Syntax Error: ${desc}`
|
||||||
|
|
|
@ -1,35 +1,22 @@
|
||||||
|
module Bindings = Reducer_Expression_Bindings
|
||||||
module BuiltIn = Reducer_Dispatch_BuiltIn
|
module BuiltIn = Reducer_Dispatch_BuiltIn
|
||||||
|
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
module Extra = Reducer_Extra
|
module Extra = Reducer_Extra
|
||||||
|
module Lambda = Reducer_Expression_Lambda
|
||||||
|
module Macro = Reducer_Expression_Macro
|
||||||
module MathJs = Reducer_MathJs
|
module MathJs = Reducer_MathJs
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
module T = Reducer_Expression_T
|
module T = Reducer_Expression_T
|
||||||
open Reducer_ErrorValue
|
|
||||||
|
|
||||||
|
type environment = ReducerInterface_ExpressionValue.environment
|
||||||
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
type expression = T.expression
|
type expression = T.expression
|
||||||
type expressionValue = ExpressionValue.expressionValue
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
|
type internalCode = ReducerInterface_ExpressionValue.internalCode
|
||||||
type t = expression
|
type t = expression
|
||||||
|
|
||||||
/*
|
|
||||||
Shows the expression as text of expression
|
|
||||||
*/
|
|
||||||
let rec toString = expression =>
|
|
||||||
switch expression {
|
|
||||||
| T.EBindings(_) => "$$bound"
|
|
||||||
| T.EList(aList) =>
|
|
||||||
`(${Belt.List.map(aList, aValue => toString(aValue))
|
|
||||||
->Extra.List.interperse(" ")
|
|
||||||
->Belt.List.toArray
|
|
||||||
->Js.String.concatMany("")})`
|
|
||||||
| EValue(aValue) => ExpressionValue.toString(aValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
let toStringResult = codeResult =>
|
|
||||||
switch codeResult {
|
|
||||||
| Ok(a) => `Ok(${toString(a)})`
|
|
||||||
| Error(m) => `Error(${Js.String.make(m)})`
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Converts a MathJs code to expression
|
Converts a MathJs code to expression
|
||||||
*/
|
*/
|
||||||
|
@ -39,148 +26,115 @@ let parse_ = (expr: string, parser, converter): result<t, errorValue> =>
|
||||||
let parse = (mathJsCode: string): result<t, errorValue> =>
|
let parse = (mathJsCode: string): result<t, errorValue> =>
|
||||||
mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode)
|
mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode)
|
||||||
|
|
||||||
let parsePartial = (mathJsCode: string): result<t, errorValue> =>
|
|
||||||
mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromPartialNode)
|
|
||||||
|
|
||||||
let parseOuter = (mathJsCode: string): result<t, errorValue> =>
|
|
||||||
mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromOuterNode)
|
|
||||||
|
|
||||||
let defaultBindings: T.bindings = Belt.Map.String.empty
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Recursively evaluate/reduce the expression (Lisp AST)
|
Recursively evaluate/reduce the expression (Lisp AST)
|
||||||
*/
|
*/
|
||||||
let rec reduceExpression = (expression: t, bindings: T.bindings): result<expressionValue, 'e> => {
|
let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result<
|
||||||
/*
|
expressionValue,
|
||||||
Macros are like functions but instead of taking values as parameters,
|
'e,
|
||||||
they take expressions as parameters and return a new expression.
|
> => {
|
||||||
Macros are used to define language building blocks. They are like Lisp macros.
|
// Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`)
|
||||||
*/
|
switch expression {
|
||||||
let doMacroCall = (list: list<t>, bindings: T.bindings): result<t, 'e> =>
|
| T.EValue(value) => value->Ok
|
||||||
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(list, bindings, reduceExpression)
|
| T.EList(list) =>
|
||||||
|
switch list {
|
||||||
|
| list{EValue(EvCall(fName)), ..._args} =>
|
||||||
|
switch Macro.isMacroName(fName) {
|
||||||
|
// A macro expands then reduces itself
|
||||||
|
| true => Macro.doMacroCall(expression, bindings, environment, reduceExpression)
|
||||||
|
| false => reduceExpressionList(list, bindings, environment)
|
||||||
|
}
|
||||||
|
| _ => reduceExpressionList(list, bindings, environment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
and reduceExpressionList = (
|
||||||
|
expressions: list<t>,
|
||||||
|
bindings: T.bindings,
|
||||||
|
environment: environment,
|
||||||
|
): result<expressionValue, 'e> => {
|
||||||
|
let racc: result<list<expressionValue>, 'e> = expressions->Belt.List.reduceReverse(Ok(list{}), (
|
||||||
|
racc,
|
||||||
|
each: expression,
|
||||||
|
) =>
|
||||||
|
racc->Result.flatMap(acc => {
|
||||||
|
each
|
||||||
|
->reduceExpression(bindings, environment)
|
||||||
|
->Result.map(newNode => {
|
||||||
|
acc->Belt.List.add(newNode)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
racc->Result.flatMap(acc => acc->reduceValueList(environment))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
After reducing each level of expression(Lisp AST), we have a value list to evaluate
|
After reducing each level of expression(Lisp AST), we have a value list to evaluate
|
||||||
*/
|
*/
|
||||||
let reduceValueList = (valueList: list<expressionValue>): result<expressionValue, 'e> =>
|
and reduceValueList = (valueList: list<expressionValue>, environment): result<
|
||||||
switch valueList {
|
expressionValue,
|
||||||
| list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch
|
'e,
|
||||||
| _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok
|
> =>
|
||||||
}
|
switch valueList {
|
||||||
|
| list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment)
|
||||||
|
|
||||||
let rec seekMacros = (expression: t, bindings: T.bindings): result<t, 'e> =>
|
| list{EvLambda(lamdaCall), ...args} =>
|
||||||
switch expression {
|
Lambda.doLambdaCall(lamdaCall, args, environment, reduceExpression)
|
||||||
| T.EValue(_value) => expression->Ok
|
| _ =>
|
||||||
| T.EBindings(_value) => expression->Ok
|
valueList
|
||||||
| T.EList(list) => {
|
->Lambda.checkIfReduced
|
||||||
let racc: result<list<t>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), (
|
->Result.flatMap(reducedValueList =>
|
||||||
racc,
|
reducedValueList->Belt.List.toArray->ExpressionValue.EvArray->Ok
|
||||||
each: expression,
|
)
|
||||||
) =>
|
}
|
||||||
racc->Result.flatMap(acc => {
|
|
||||||
each
|
|
||||||
->seekMacros(bindings)
|
|
||||||
->Result.flatMap(newNode => {
|
|
||||||
acc->Belt.List.add(newNode)->Ok
|
|
||||||
})
|
|
||||||
})
|
|
||||||
)
|
|
||||||
racc->Result.flatMap(acc => acc->doMacroCall(bindings))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let rec reduceExpandedExpression = (expression: t): result<expressionValue, 'e> =>
|
let evalUsingBindingsExpression_ = (aExpression, bindings, environment): result<
|
||||||
switch expression {
|
expressionValue,
|
||||||
| T.EValue(value) => value->Ok
|
'e,
|
||||||
| T.EList(list) => {
|
> => reduceExpression(aExpression, bindings, environment)
|
||||||
let racc: result<list<expressionValue>, 'e> = list->Belt.List.reduceReverse(Ok(list{}), (
|
|
||||||
racc,
|
|
||||||
each: expression,
|
|
||||||
) =>
|
|
||||||
racc->Result.flatMap(acc => {
|
|
||||||
each
|
|
||||||
->reduceExpandedExpression
|
|
||||||
->Result.flatMap(newNode => {
|
|
||||||
acc->Belt.List.add(newNode)->Ok
|
|
||||||
})
|
|
||||||
})
|
|
||||||
)
|
|
||||||
racc->Result.flatMap(acc => acc->reduceValueList)
|
|
||||||
}
|
|
||||||
| EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error
|
|
||||||
}
|
|
||||||
|
|
||||||
let rExpandedExpression: result<t, 'e> = expression->seekMacros(bindings)
|
let evaluateUsingOptions = (
|
||||||
rExpandedExpression->Result.flatMap(expandedExpression =>
|
~environment: option<ReducerInterface_ExpressionValue.environment>,
|
||||||
expandedExpression->reduceExpandedExpression
|
~externalBindings: option<ReducerInterface_ExpressionValue.externalBindings>,
|
||||||
)
|
code: string,
|
||||||
}
|
): result<expressionValue, errorValue> => {
|
||||||
|
let anEnvironment = switch environment {
|
||||||
|
| Some(env) => env
|
||||||
|
| None => ReducerInterface_ExpressionValue.defaultEnvironment
|
||||||
|
}
|
||||||
|
|
||||||
let evalUsingExternalBindingsExpression_ = (aExpression, bindings): result<expressionValue, 'e> =>
|
let anExternalBindings = switch externalBindings {
|
||||||
reduceExpression(aExpression, bindings)
|
| Some(bindings) => bindings
|
||||||
|
| None => ReducerInterface_ExpressionValue.defaultExternalBindings
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
let bindings = anExternalBindings->Bindings.fromExternalBindings
|
||||||
Evaluates MathJs code via Reducer using bindings and answers the result.
|
|
||||||
When bindings are used, the code is a partial code as if it is cut from a larger code.
|
|
||||||
Therefore all statements are assignments.
|
|
||||||
*/
|
|
||||||
let evalPartialUsingExternalBindings_ = (codeText: string, bindings: T.bindings) => {
|
|
||||||
parsePartial(codeText)->Result.flatMap(expression =>
|
|
||||||
expression->evalUsingExternalBindingsExpression_(bindings)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
parse(code)->Result.flatMap(expr => evalUsingBindingsExpression_(expr, bindings, anEnvironment))
|
||||||
Evaluates MathJs code via Reducer using bindings and answers the result.
|
|
||||||
When bindings are used, the code is a partial code as if it is cut from a larger code.
|
|
||||||
Therefore all statments are assignments.
|
|
||||||
*/
|
|
||||||
let evalOuterWBindings_ = (codeText: string, bindings: T.bindings) => {
|
|
||||||
parseOuter(codeText)->Result.flatMap(expression =>
|
|
||||||
expression->evalUsingExternalBindingsExpression_(bindings)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Evaluates MathJs code and bindings via Reducer and answers the result
|
Evaluates MathJs code and bindings via Reducer and answers the result
|
||||||
*/
|
*/
|
||||||
let eval = (codeText: string) => {
|
let evaluate = (code: string): result<expressionValue, errorValue> => {
|
||||||
parse(codeText)->Result.flatMap(expression =>
|
evaluateUsingOptions(~environment=None, ~externalBindings=None, code)
|
||||||
expression->evalUsingExternalBindingsExpression_(defaultBindings)
|
}
|
||||||
)
|
let eval = evaluate
|
||||||
}
|
let evaluatePartialUsingExternalBindings = (
|
||||||
|
code: string,
|
||||||
type externalBindings = ReducerInterface.ExpressionValue.externalBindings //Js.Dict.t<expressionValue>
|
externalBindings: ReducerInterface_ExpressionValue.externalBindings,
|
||||||
|
environment: ReducerInterface_ExpressionValue.environment,
|
||||||
let externalBindingsToBindings = (externalBindings: externalBindings): T.bindings => {
|
): result<externalBindings, errorValue> => {
|
||||||
let keys = Js.Dict.keys(externalBindings)
|
let rAnswer = evaluateUsingOptions(
|
||||||
keys->Belt.Array.reduce(defaultBindings, (acc, key) => {
|
~environment=Some(environment),
|
||||||
let value = Js.Dict.unsafeGet(externalBindings, key)
|
~externalBindings=Some(externalBindings),
|
||||||
acc->Belt.Map.String.set(key, T.EValue(value))
|
code,
|
||||||
})
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
Evaluates code with external bindings. External bindings are a record of expression values.
|
|
||||||
*/
|
|
||||||
let evalUsingExternalBindings = (code: string, externalBindings: externalBindings) => {
|
|
||||||
let bindings = externalBindings->externalBindingsToBindings
|
|
||||||
evalOuterWBindings_(code, bindings)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Evaluates code with external bindings. External bindings are a record of expression values.
|
|
||||||
The code is a partial code as if it is cut from a larger code. Therefore all statments are assignments.
|
|
||||||
*/
|
|
||||||
let evalPartialUsingExternalBindings = (code: string, externalBindings: externalBindings): result<
|
|
||||||
externalBindings,
|
|
||||||
'e,
|
|
||||||
> => {
|
|
||||||
let bindings = externalBindings->externalBindingsToBindings
|
|
||||||
let answer = evalPartialUsingExternalBindings_(code, bindings)
|
|
||||||
answer->Result.flatMap(answer =>
|
|
||||||
switch answer {
|
|
||||||
| EvRecord(aRecord) => Ok(aRecord)
|
|
||||||
| _ => RETodo("TODO: External bindings must be returned")->Error
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
switch rAnswer {
|
||||||
|
| Ok(EvRecord(externalBindings)) => Ok(externalBindings)
|
||||||
|
| Ok(_) =>
|
||||||
|
Error(Reducer_ErrorValue.RESyntaxError(`Partials must end with an assignment or record`))
|
||||||
|
| Error(err) => err->Error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
module Bindings = Reducer_Expression_Bindings
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
module Result = Belt.Result
|
||||||
|
|
||||||
|
type bindings = ExpressionT.bindings
|
||||||
|
type context = bindings
|
||||||
|
type environment = ExpressionValue.environment
|
||||||
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
|
type expression = ExpressionT.expression
|
||||||
|
type expressionValue = ExpressionValue.expressionValue
|
||||||
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
|
type reducerFn = ExpressionT.reducerFn
|
||||||
|
|
||||||
|
type expressionWithContext =
|
||||||
|
| ExpressionWithContext(expression, context)
|
||||||
|
| ExpressionNoContext(expression)
|
||||||
|
|
||||||
|
let callReducer = (
|
||||||
|
expressionWithContext: expressionWithContext,
|
||||||
|
bindings: bindings,
|
||||||
|
environment: environment,
|
||||||
|
reducer: reducerFn,
|
||||||
|
): result<expressionValue, errorValue> =>
|
||||||
|
switch expressionWithContext {
|
||||||
|
| ExpressionNoContext(expr) => reducer(expr, bindings, environment)
|
||||||
|
| ExpressionWithContext(expr, context) => reducer(expr, context, environment)
|
||||||
|
}
|
||||||
|
|
||||||
|
let withContext = (expression, context) => ExpressionWithContext(expression, context)
|
||||||
|
let noContext = expression => ExpressionNoContext(expression)
|
||||||
|
|
||||||
|
let toString = expressionWithContext =>
|
||||||
|
switch expressionWithContext {
|
||||||
|
| ExpressionNoContext(expr) => ExpressionT.toString(expr)
|
||||||
|
| ExpressionWithContext(expr, context) =>
|
||||||
|
`${ExpressionT.toString(expr)} context: ${Bindings.toString(context)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
let toStringResult = rExpressionWithContext =>
|
||||||
|
switch rExpressionWithContext {
|
||||||
|
| Ok(expressionWithContext) => `Ok(${toString(expressionWithContext)})`
|
||||||
|
| Error(errorValue) => ErrorValue.errorToString(errorValue)
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
module Result = Belt.Result
|
||||||
|
|
||||||
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
|
type expression = ExpressionT.expression
|
||||||
|
type expressionValue = ExpressionValue.expressionValue
|
||||||
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
|
|
||||||
|
let defaultBindings: ExpressionT.bindings = Belt.Map.String.empty
|
||||||
|
|
||||||
|
let fromExternalBindings = (externalBindings: externalBindings): ExpressionT.bindings => {
|
||||||
|
let keys = Js.Dict.keys(externalBindings)
|
||||||
|
keys->Belt.Array.reduce(defaultBindings, (acc, key) => {
|
||||||
|
let value = Js.Dict.unsafeGet(externalBindings, key)
|
||||||
|
acc->Belt.Map.String.set(key, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let toExternalBindings = (bindings: ExpressionT.bindings): externalBindings => {
|
||||||
|
let keys = Belt.Map.String.keysToArray(bindings)
|
||||||
|
keys->Belt.Array.reduce(Js.Dict.empty(), (acc, key) => {
|
||||||
|
let value = bindings->Belt.Map.String.getExn(key)
|
||||||
|
Js.Dict.set(acc, key, value)
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let fromValue = (aValue: expressionValue) =>
|
||||||
|
switch aValue {
|
||||||
|
| EvRecord(externalBindings) => fromExternalBindings(externalBindings)
|
||||||
|
| _ => defaultBindings
|
||||||
|
}
|
||||||
|
|
||||||
|
let externalFromArray = anArray => Js.Dict.fromArray(anArray)
|
||||||
|
|
||||||
|
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")
|
||||||
|
|
||||||
|
let rec replaceSymbols = (bindings: ExpressionT.bindings, expression: expression): result<
|
||||||
|
expression,
|
||||||
|
errorValue,
|
||||||
|
> =>
|
||||||
|
switch expression {
|
||||||
|
| ExpressionT.EValue(value) =>
|
||||||
|
replaceSymbolOnValue(bindings, value)->Result.map(evValue => evValue->ExpressionT.EValue)
|
||||||
|
| ExpressionT.EList(list) =>
|
||||||
|
switch list {
|
||||||
|
| list{EValue(EvCall(fName)), ..._args} =>
|
||||||
|
switch isMacroName(fName) {
|
||||||
|
// A macro reduces itself so we dont dive in it
|
||||||
|
| true => expression->Ok
|
||||||
|
| false => replaceSymbolsOnExpressionList(bindings, list)
|
||||||
|
}
|
||||||
|
| _ => replaceSymbolsOnExpressionList(bindings, list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
and replaceSymbolsOnExpressionList = (bindings, list) => {
|
||||||
|
let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) =>
|
||||||
|
racc->Result.flatMap(acc => {
|
||||||
|
replaceSymbols(bindings, each)->Result.flatMap(newNode => {
|
||||||
|
acc->Belt.List.add(newNode)->Ok
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
racc->Result.map(acc => acc->ExpressionT.EList)
|
||||||
|
}
|
||||||
|
and replaceSymbolOnValue = (bindings, evValue: expressionValue) =>
|
||||||
|
switch evValue {
|
||||||
|
| EvSymbol(symbol) => Belt.Map.String.getWithDefault(bindings, symbol, evValue)->Ok
|
||||||
|
| EvCall(symbol) => Belt.Map.String.getWithDefault(bindings, symbol, evValue)->checkIfCallable
|
||||||
|
| _ => evValue->Ok
|
||||||
|
}
|
||||||
|
and checkIfCallable = (evValue: expressionValue) =>
|
||||||
|
switch evValue {
|
||||||
|
| EvCall(_) | EvLambda(_) => evValue->Ok
|
||||||
|
| _ => ErrorValue.RENotAFunction(ExpressionValue.toString(evValue))->Error
|
||||||
|
}
|
||||||
|
|
||||||
|
let toString = (bindings: ExpressionT.bindings) =>
|
||||||
|
bindings->toExternalBindings->ExpressionValue.EvRecord->ExpressionValue.toString
|
||||||
|
|
||||||
|
let externalBindingsToString = (externalBindings: externalBindings) =>
|
||||||
|
externalBindings->ExpressionValue.EvRecord->ExpressionValue.toString
|
|
@ -0,0 +1,66 @@
|
||||||
|
module BBindings = Reducer_Expression_Bindings
|
||||||
|
module BErrorValue = Reducer_ErrorValue
|
||||||
|
module BExpressionT = Reducer_Expression_T
|
||||||
|
module BExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
|
||||||
|
type errorValue = BErrorValue.errorValue
|
||||||
|
type expression = BExpressionT.expression
|
||||||
|
type internalCode = ReducerInterface_ExpressionValue.internalCode
|
||||||
|
|
||||||
|
external castExpressionToInternalCode: expression => internalCode = "%identity"
|
||||||
|
|
||||||
|
let eArray = anArray => anArray->BExpressionValue.EvArray->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eArrayString = anArray => anArray->BExpressionValue.EvArrayString->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eBindings = (anArray: array<(string, BExpressionValue.expressionValue)>) =>
|
||||||
|
anArray->Js.Dict.fromArray->EvRecord->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eBool = aBool => aBool->BExpressionValue.EvBool->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eCall = (name: string): expression => name->BExpressionValue.EvCall->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eFunction = (fName: string, lispArgs: list<expression>): expression => {
|
||||||
|
let fn = fName->eCall
|
||||||
|
list{fn, ...lispArgs}->BExpressionT.EList
|
||||||
|
}
|
||||||
|
|
||||||
|
let eLambda = (
|
||||||
|
parameters: array<string>,
|
||||||
|
context: BExpressionValue.externalBindings,
|
||||||
|
expr: expression,
|
||||||
|
) => {
|
||||||
|
// Js.log(`eLambda context ${BBindings.externalBindingsToString(context)}`)
|
||||||
|
BExpressionValue.EvLambda({
|
||||||
|
parameters: parameters,
|
||||||
|
context: context,
|
||||||
|
body: expr->castExpressionToInternalCode,
|
||||||
|
})->BExpressionT.EValue
|
||||||
|
}
|
||||||
|
|
||||||
|
let eNumber = aNumber => aNumber->BExpressionValue.EvNumber->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eRecord = aRecord => aRecord->BExpressionValue.EvRecord->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eString = aString => aString->BExpressionValue.EvString->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eSymbol = (name: string): expression => name->BExpressionValue.EvSymbol->BExpressionT.EValue
|
||||||
|
|
||||||
|
let eList = (list: list<expression>): expression => list->BExpressionT.EList
|
||||||
|
|
||||||
|
let eBlock = (exprs: list<expression>): expression => eFunction("$$block", exprs)
|
||||||
|
|
||||||
|
let eLetStatement = (symbol: string, valueExpression: expression): expression =>
|
||||||
|
eFunction("$let", list{eSymbol(symbol), valueExpression})
|
||||||
|
|
||||||
|
let eBindStatement = (bindingExpr: expression, letStatement: expression): expression =>
|
||||||
|
eFunction("$$bindStatement", list{bindingExpr, letStatement})
|
||||||
|
|
||||||
|
let eBindStatementDefault = (letStatement: expression): expression =>
|
||||||
|
eFunction("$$bindStatement", list{letStatement})
|
||||||
|
|
||||||
|
let eBindExpression = (bindingExpr: expression, expression: expression): expression =>
|
||||||
|
eFunction("$$bindExpression", list{bindingExpr, expression})
|
||||||
|
|
||||||
|
let eBindExpressionDefault = (expression: expression): expression =>
|
||||||
|
eFunction("$$bindExpression", list{expression})
|
|
@ -0,0 +1,60 @@
|
||||||
|
module Bindings = Reducer_Expression_Bindings
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
module Result = Belt.Result
|
||||||
|
|
||||||
|
type environment = ReducerInterface_ExpressionValue.environment
|
||||||
|
type expression = ExpressionT.expression
|
||||||
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
|
type externalBindings = ReducerInterface_ExpressionValue.externalBindings
|
||||||
|
type internalCode = ReducerInterface_ExpressionValue.internalCode
|
||||||
|
|
||||||
|
external castInternalCodeToExpression: internalCode => expression = "%identity"
|
||||||
|
|
||||||
|
let checkArity = (lambdaValue: ExpressionValue.lambdaValue, args: list<expressionValue>) => {
|
||||||
|
let argsLength = Belt.List.length(args)
|
||||||
|
let parametersLength = Js.Array2.length(lambdaValue.parameters)
|
||||||
|
if argsLength !== parametersLength {
|
||||||
|
ErrorValue.REArityError(None, parametersLength, argsLength)->Error
|
||||||
|
} else {
|
||||||
|
args->Ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let checkIfReduced = (args: list<expressionValue>) =>
|
||||||
|
args->Belt.List.reduceReverse(Ok(list{}), (rAcc, arg) =>
|
||||||
|
rAcc->Result.flatMap(acc =>
|
||||||
|
switch arg {
|
||||||
|
| EvSymbol(symbol) => ErrorValue.RESymbolNotFound(symbol)->Error
|
||||||
|
| _ => list{arg, ...acc}->Ok
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
let applyParametersToLambda = (
|
||||||
|
lambdaValue: ExpressionValue.lambdaValue,
|
||||||
|
args,
|
||||||
|
environment,
|
||||||
|
reducer: ExpressionT.reducerFn,
|
||||||
|
): result<expressionValue, 'e> => {
|
||||||
|
checkArity(lambdaValue, args)->Result.flatMap(args =>
|
||||||
|
checkIfReduced(args)->Result.flatMap(args => {
|
||||||
|
let expr = castInternalCodeToExpression(lambdaValue.body)
|
||||||
|
let parameterList = lambdaValue.parameters->Belt.List.fromArray
|
||||||
|
let zippedParameterList = parameterList->Belt.List.zip(args)
|
||||||
|
let bindings = Belt.List.reduce(
|
||||||
|
zippedParameterList,
|
||||||
|
lambdaValue.context->Bindings.fromExternalBindings,
|
||||||
|
(acc, (variable, variableValue)) => acc->Belt.Map.String.set(variable, variableValue),
|
||||||
|
)
|
||||||
|
let newExpression = ExpressionBuilder.eBlock(list{expr})
|
||||||
|
reducer(newExpression, bindings, environment)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let doLambdaCall = (lambdaValue: ExpressionValue.lambdaValue, args, environment, reducer) => {
|
||||||
|
applyParametersToLambda(lambdaValue, args, environment, reducer)
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
module ExpressionWithContext = Reducer_ExpressionWithContext
|
||||||
|
module Result = Belt.Result
|
||||||
|
|
||||||
|
type environment = ExpressionValue.environment
|
||||||
|
type expression = ExpressionT.expression
|
||||||
|
type expressionValue = ExpressionValue.expressionValue
|
||||||
|
type expressionWithContext = ExpressionWithContext.expressionWithContext
|
||||||
|
|
||||||
|
let expandMacroCall = (
|
||||||
|
macroExpression: expression,
|
||||||
|
bindings: ExpressionT.bindings,
|
||||||
|
environment: environment,
|
||||||
|
reduceExpression: ExpressionT.reducerFn,
|
||||||
|
): result<expressionWithContext, 'e> =>
|
||||||
|
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(
|
||||||
|
macroExpression,
|
||||||
|
bindings,
|
||||||
|
environment,
|
||||||
|
reduceExpression,
|
||||||
|
)
|
||||||
|
|
||||||
|
let doMacroCall = (
|
||||||
|
macroExpression: expression,
|
||||||
|
bindings: ExpressionT.bindings,
|
||||||
|
environment: environment,
|
||||||
|
reduceExpression: ExpressionT.reducerFn,
|
||||||
|
): result<expressionValue, 'e> =>
|
||||||
|
expandMacroCall(
|
||||||
|
macroExpression,
|
||||||
|
bindings,
|
||||||
|
environment,
|
||||||
|
reduceExpression,
|
||||||
|
)->Result.flatMap(expressionWithContext =>
|
||||||
|
ExpressionWithContext.callReducer(
|
||||||
|
expressionWithContext,
|
||||||
|
bindings,
|
||||||
|
environment,
|
||||||
|
reduceExpression,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")
|
|
@ -1,5 +1,3 @@
|
||||||
open ReducerInterface.ExpressionValue
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An expression is a Lisp AST. An expression is either a primitive value or a list of expressions.
|
An expression is a Lisp AST. An expression is either a primitive value or a list of expressions.
|
||||||
In the case of a list of expressions (e1, e2, e3, ...eN), the semantic is
|
In the case of a list of expressions (e1, e2, e3, ...eN), the semantic is
|
||||||
|
@ -8,8 +6,51 @@ open ReducerInterface.ExpressionValue
|
||||||
A Lisp AST contains only expressions/primitive values to apply to their left.
|
A Lisp AST contains only expressions/primitive values to apply to their left.
|
||||||
The act of defining the semantics of a functional language is to write it in terms of Lisp AST.
|
The act of defining the semantics of a functional language is to write it in terms of Lisp AST.
|
||||||
*/
|
*/
|
||||||
|
module Extra = Reducer_Extra
|
||||||
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
|
|
||||||
|
type expressionValue = ExpressionValue.expressionValue
|
||||||
|
type environment = ExpressionValue.environment
|
||||||
|
|
||||||
type rec expression =
|
type rec expression =
|
||||||
| EList(list<expression>) // A list to map-reduce
|
| EList(list<expression>) // A list to map-reduce
|
||||||
| EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible
|
| EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible
|
||||||
| EBindings(bindings) // let/def kind of statements return bindings
|
and bindings = Belt.Map.String.t<expressionValue>
|
||||||
and bindings = Belt.Map.String.t<expression>
|
|
||||||
|
type reducerFn = (
|
||||||
|
expression,
|
||||||
|
bindings,
|
||||||
|
environment,
|
||||||
|
) => result<expressionValue, Reducer_ErrorValue.errorValue>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Converts the expression to String
|
||||||
|
*/
|
||||||
|
let rec toString = expression =>
|
||||||
|
switch expression {
|
||||||
|
| EList(aList) =>
|
||||||
|
`(${Belt.List.map(aList, aValue => toString(aValue))
|
||||||
|
->Extra.List.interperse(" ")
|
||||||
|
->Belt.List.toArray
|
||||||
|
->Js.String.concatMany("")})`
|
||||||
|
| EValue(aValue) => ExpressionValue.toString(aValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
let toStringResult = codeResult =>
|
||||||
|
switch codeResult {
|
||||||
|
| Ok(a) => `Ok(${toString(a)})`
|
||||||
|
| Error(m) => `Error(${Reducer_ErrorValue.errorToString(m)})`
|
||||||
|
}
|
||||||
|
|
||||||
|
let inspect = (expr: expression): expression => {
|
||||||
|
Js.log(toString(expr))
|
||||||
|
expr
|
||||||
|
}
|
||||||
|
|
||||||
|
let inspectResult = (r: result<expression, Reducer_ErrorValue.errorValue>): result<
|
||||||
|
expression,
|
||||||
|
Reducer_ErrorValue.errorValue,
|
||||||
|
> => {
|
||||||
|
Js.log(toStringResult(r))
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
|
@ -8,11 +8,10 @@ external castString: unit => string = "%identity"
|
||||||
/*
|
/*
|
||||||
As JavaScript returns us any type, we need to type check and cast type propertype before using it
|
As JavaScript returns us any type, we need to type check and cast type propertype before using it
|
||||||
*/
|
*/
|
||||||
let jsToEv = (jsValue): result<expressionValue, errorValue> => {
|
let jsToEv = (jsValue): result<expressionValue, errorValue> =>
|
||||||
switch Js.typeof(jsValue) {
|
switch Js.typeof(jsValue) {
|
||||||
| "boolean" => jsValue->castBool->EvBool->Ok
|
| "boolean" => jsValue->castBool->EvBool->Ok
|
||||||
| "number" => jsValue->castNumber->EvNumber->Ok
|
| "number" => jsValue->castNumber->EvNumber->Ok
|
||||||
| "string" => jsValue->castString->EvString->Ok
|
| "string" => jsValue->castString->EvString->Ok
|
||||||
| other => RETodo(`Unhandled MathJs literal type: ${Js.String.make(other)}`)->Error
|
| other => RETodo(`Unhandled MathJs literal type: ${Js.String.make(other)}`)->Error
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -11,11 +11,10 @@ type block = {"node": node}
|
||||||
type blockNode = {...node, "blocks": array<block>}
|
type blockNode = {...node, "blocks": array<block>}
|
||||||
//conditionalNode
|
//conditionalNode
|
||||||
type constantNode = {...node, "value": unit}
|
type constantNode = {...node, "value": unit}
|
||||||
//functionAssignmentNode
|
type functionAssignmentNode = {...node, "name": string, "params": array<string>, "expr": node}
|
||||||
type indexNode = {...node, "dimensions": array<node>}
|
type indexNode = {...node, "dimensions": array<node>}
|
||||||
type objectNode = {...node, "properties": Js.Dict.t<node>}
|
type objectNode = {...node, "properties": Js.Dict.t<node>}
|
||||||
type accessorNode = {...node, "object": node, "index": indexNode, "name": string}
|
type accessorNode = {...node, "object": node, "index": indexNode, "name": string}
|
||||||
|
|
||||||
type parenthesisNode = {...node, "content": node}
|
type parenthesisNode = {...node, "content": node}
|
||||||
//rangeNode
|
//rangeNode
|
||||||
//relationalNode
|
//relationalNode
|
||||||
|
@ -33,6 +32,7 @@ external castAssignmentNodeWAccessor: node => assignmentNodeWAccessor = "%identi
|
||||||
external castAssignmentNodeWIndex: node => assignmentNodeWIndex = "%identity"
|
external castAssignmentNodeWIndex: node => assignmentNodeWIndex = "%identity"
|
||||||
external castBlockNode: node => blockNode = "%identity"
|
external castBlockNode: node => blockNode = "%identity"
|
||||||
external castConstantNode: node => constantNode = "%identity"
|
external castConstantNode: node => constantNode = "%identity"
|
||||||
|
external castFunctionAssignmentNode: node => functionAssignmentNode = "%identity"
|
||||||
external castFunctionNode: node => functionNode = "%identity"
|
external castFunctionNode: node => functionNode = "%identity"
|
||||||
external castIndexNode: node => indexNode = "%identity"
|
external castIndexNode: node => indexNode = "%identity"
|
||||||
external castObjectNode: node => objectNode = "%identity"
|
external castObjectNode: node => objectNode = "%identity"
|
||||||
|
@ -59,6 +59,7 @@ type mathJsNode =
|
||||||
| MjAssignmentNode(assignmentNode)
|
| MjAssignmentNode(assignmentNode)
|
||||||
| MjBlockNode(blockNode)
|
| MjBlockNode(blockNode)
|
||||||
| MjConstantNode(constantNode)
|
| MjConstantNode(constantNode)
|
||||||
|
| MjFunctionAssignmentNode(functionAssignmentNode)
|
||||||
| MjFunctionNode(functionNode)
|
| MjFunctionNode(functionNode)
|
||||||
| MjIndexNode(indexNode)
|
| MjIndexNode(indexNode)
|
||||||
| MjObjectNode(objectNode)
|
| MjObjectNode(objectNode)
|
||||||
|
@ -82,6 +83,7 @@ let castNodeType = (node: node) => {
|
||||||
| "AssignmentNode" => node->decideAssignmentNode
|
| "AssignmentNode" => node->decideAssignmentNode
|
||||||
| "BlockNode" => node->castBlockNode->MjBlockNode->Ok
|
| "BlockNode" => node->castBlockNode->MjBlockNode->Ok
|
||||||
| "ConstantNode" => node->castConstantNode->MjConstantNode->Ok
|
| "ConstantNode" => node->castConstantNode->MjConstantNode->Ok
|
||||||
|
| "FunctionAssignmentNode" => node->castFunctionAssignmentNode->MjFunctionAssignmentNode->Ok
|
||||||
| "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok
|
| "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok
|
||||||
| "IndexNode" => node->castIndexNode->MjIndexNode->Ok
|
| "IndexNode" => node->castIndexNode->MjIndexNode->Ok
|
||||||
| "ObjectNode" => node->castObjectNode->MjObjectNode->Ok
|
| "ObjectNode" => node->castObjectNode->MjObjectNode->Ok
|
||||||
|
@ -118,6 +120,10 @@ let rec toString = (mathJsNode: mathJsNode): string => {
|
||||||
->Extra.Array.interperse(", ")
|
->Extra.Array.interperse(", ")
|
||||||
->Js.String.concatMany("")
|
->Js.String.concatMany("")
|
||||||
|
|
||||||
|
let toStringFunctionAssignmentNode = (faNode: functionAssignmentNode): string => {
|
||||||
|
let paramNames = Js.Array2.toString(faNode["params"])
|
||||||
|
`${faNode["name"]} = (${paramNames}) => ${toStringMathJsNode(faNode["expr"])}`
|
||||||
|
}
|
||||||
let toStringFunctionNode = (fnode: functionNode): string =>
|
let toStringFunctionNode = (fnode: functionNode): string =>
|
||||||
`${fnode->nameOfFunctionNode}(${fnode["args"]->toStringNodeArray})`
|
`${fnode->nameOfFunctionNode}(${fnode["args"]->toStringNodeArray})`
|
||||||
|
|
||||||
|
@ -152,6 +158,7 @@ let rec toString = (mathJsNode: mathJsNode): string => {
|
||||||
`${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}`
|
`${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}`
|
||||||
| MjBlockNode(bNode) => `{${bNode["blocks"]->toStringBlocks}}`
|
| MjBlockNode(bNode) => `{${bNode["blocks"]->toStringBlocks}}`
|
||||||
| MjConstantNode(cNode) => cNode["value"]->toStringValue
|
| MjConstantNode(cNode) => cNode["value"]->toStringValue
|
||||||
|
| MjFunctionAssignmentNode(faNode) => faNode->toStringFunctionAssignmentNode
|
||||||
| MjFunctionNode(fNode) => fNode->toStringFunctionNode
|
| MjFunctionNode(fNode) => fNode->toStringFunctionNode
|
||||||
| MjIndexNode(iNode) => iNode->toStringIndexNode
|
| MjIndexNode(iNode) => iNode->toStringIndexNode
|
||||||
| MjObjectNode(oNode) => oNode->toStringObjectNode
|
| MjObjectNode(oNode) => oNode->toStringObjectNode
|
||||||
|
|
|
@ -1,45 +1,35 @@
|
||||||
|
/* * WARNING. DO NOT EDIT, BEAUTIFY, COMMENT ON OR REFACTOR THIS CODE.
|
||||||
|
We will stop using MathJs parser and
|
||||||
|
this whole file will go to trash
|
||||||
|
**/
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
module ExpressionValue = ReducerInterface.ExpressionValue
|
module ExpressionBuilder = Reducer_Expression_ExpressionBuilder
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module ExpressionValue = ReducerInterface.ExpressionValue
|
||||||
module JavaScript = Reducer_Js
|
module JavaScript = Reducer_Js
|
||||||
module Parse = Reducer_MathJs_Parse
|
module Parse = Reducer_MathJs_Parse
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
|
|
||||||
|
type errorValue = ErrorValue.errorValue
|
||||||
type expression = ExpressionT.expression
|
type expression = ExpressionT.expression
|
||||||
type expressionValue = ExpressionValue.expressionValue
|
type expressionValue = ExpressionValue.expressionValue
|
||||||
type errorValue = ErrorValue.errorValue
|
|
||||||
|
|
||||||
let passToFunction = (fName: string, rLispArgs): result<expression, errorValue> => {
|
let blockToNode = block => block["node"]
|
||||||
let toEvCallValue = (name: string): expression => name->ExpressionValue.EvCall->ExpressionT.EValue
|
|
||||||
|
|
||||||
let fn = fName->toEvCallValue
|
let rec fromInnerNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||||
rLispArgs->Result.flatMap(lispArgs => list{fn, ...lispArgs}->ExpressionT.EList->Ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
type blockTag =
|
|
||||||
| ImportVariablesStatement
|
|
||||||
| ExportVariablesExpression
|
|
||||||
type tagOrNode =
|
|
||||||
| BlockTag(blockTag)
|
|
||||||
| BlockNode(Parse.node)
|
|
||||||
|
|
||||||
let toTagOrNode = block => BlockNode(block["node"])
|
|
||||||
|
|
||||||
let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
|
||||||
Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => {
|
Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => {
|
||||||
let fromNodeList = (nodeList: list<Parse.node>): result<list<expression>, 'e> =>
|
let fromNodeList = (nodeList: list<Parse.node>): result<list<expression>, 'e> =>
|
||||||
Belt.List.reduceReverse(nodeList, Ok(list{}), (racc, currNode) =>
|
Belt.List.reduceReverse(nodeList, Ok(list{}), (racc, currNode) =>
|
||||||
racc->Result.flatMap(acc =>
|
racc->Result.flatMap(acc =>
|
||||||
fromNode(currNode)->Result.map(currCode => list{currCode, ...acc})
|
fromInnerNode(currNode)->Result.map(currCode => list{currCode, ...acc})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
let toEvSymbolValue = (name: string): expression =>
|
|
||||||
name->ExpressionValue.EvSymbol->ExpressionT.EValue
|
|
||||||
|
|
||||||
let caseFunctionNode = fNode => {
|
let caseFunctionNode = fNode => {
|
||||||
let lispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList
|
let rLispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList
|
||||||
passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs)
|
rLispArgs->Result.map(lispArgs =>
|
||||||
|
ExpressionBuilder.eFunction(fNode->Parse.nameOfFunctionNode, lispArgs)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let caseObjectNode = oNode => {
|
let caseObjectNode = oNode => {
|
||||||
|
@ -49,19 +39,16 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||||
(key: string, value: Parse.node),
|
(key: string, value: Parse.node),
|
||||||
) =>
|
) =>
|
||||||
racc->Result.flatMap(acc =>
|
racc->Result.flatMap(acc =>
|
||||||
fromNode(value)->Result.map(valueExpression => {
|
fromInnerNode(value)->Result.map(valueExpression => {
|
||||||
let entryCode =
|
let entryCode =
|
||||||
list{
|
list{ExpressionBuilder.eString(key), valueExpression}->ExpressionT.EList
|
||||||
key->ExpressionValue.EvString->ExpressionT.EValue,
|
|
||||||
valueExpression,
|
|
||||||
}->ExpressionT.EList
|
|
||||||
list{entryCode, ...acc}
|
list{entryCode, ...acc}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
rargs->Result.flatMap(args =>
|
rargs->Result.flatMap(args =>
|
||||||
passToFunction("$constructRecord", list{ExpressionT.EList(args)}->Ok)
|
ExpressionBuilder.eFunction("$constructRecord", list{ExpressionT.EList(args)})->Ok
|
||||||
) // $consturctRecord gets a single argument: List of key-value paiers
|
) // $constructRecord gets a single argument: List of key-value paiers
|
||||||
}
|
}
|
||||||
|
|
||||||
oNode["properties"]->Js.Dict.entries->Belt.List.fromArray->fromObjectEntries
|
oNode["properties"]->Js.Dict.entries->Belt.List.fromArray->fromObjectEntries
|
||||||
|
@ -73,7 +60,7 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||||
Ok(list{}),
|
Ok(list{}),
|
||||||
(racc, currentPropertyMathJsNode) =>
|
(racc, currentPropertyMathJsNode) =>
|
||||||
racc->Result.flatMap(acc =>
|
racc->Result.flatMap(acc =>
|
||||||
fromNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{
|
fromInnerNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{
|
||||||
propertyCode,
|
propertyCode,
|
||||||
...acc,
|
...acc,
|
||||||
})
|
})
|
||||||
|
@ -84,18 +71,41 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||||
|
|
||||||
let caseAccessorNode = (objectNode, indexNode) => {
|
let caseAccessorNode = (objectNode, indexNode) => {
|
||||||
caseIndexNode(indexNode)->Result.flatMap(indexCode => {
|
caseIndexNode(indexNode)->Result.flatMap(indexCode => {
|
||||||
fromNode(objectNode)->Result.flatMap(objectCode =>
|
fromInnerNode(objectNode)->Result.flatMap(objectCode =>
|
||||||
passToFunction("$atIndex", list{objectCode, indexCode}->Ok)
|
ExpressionBuilder.eFunction("$atIndex", list{objectCode, indexCode})->Ok
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let caseBlock = (nodesArray: array<Parse.node>): result<expression, errorValue> => {
|
||||||
|
let rStatements: result<list<expression>, 'a> =
|
||||||
|
nodesArray
|
||||||
|
->Belt.List.fromArray
|
||||||
|
->Belt.List.reduceReverse(Ok(list{}), (racc, currNode) =>
|
||||||
|
racc->Result.flatMap(acc =>
|
||||||
|
fromInnerNode(currNode)->Result.map(currCode => list{currCode, ...acc})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
rStatements->Result.map(statements => ExpressionBuilder.eBlock(statements))
|
||||||
|
}
|
||||||
|
|
||||||
let caseAssignmentNode = aNode => {
|
let caseAssignmentNode = aNode => {
|
||||||
let symbol = aNode["object"]["name"]->toEvSymbolValue
|
let symbolName = aNode["object"]["name"]
|
||||||
let rValueExpression = fromNode(aNode["value"])
|
let rValueExpression = fromInnerNode(aNode["value"])
|
||||||
|
rValueExpression->Result.map(valueExpression =>
|
||||||
|
ExpressionBuilder.eLetStatement(symbolName, valueExpression)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let caseFunctionAssignmentNode = faNode => {
|
||||||
|
let symbol = faNode["name"]->ExpressionBuilder.eSymbol
|
||||||
|
let rValueExpression = fromInnerNode(faNode["expr"])
|
||||||
|
|
||||||
rValueExpression->Result.flatMap(valueExpression => {
|
rValueExpression->Result.flatMap(valueExpression => {
|
||||||
let lispArgs = list{symbol, valueExpression}->Ok
|
let lispParams = ExpressionBuilder.eArrayString(faNode["params"])
|
||||||
passToFunction("$let", lispArgs)
|
let valueBlock = ExpressionBuilder.eBlock(list{valueExpression})
|
||||||
|
let lambda = ExpressionBuilder.eFunction("$$lambda", list{lispParams, valueBlock})
|
||||||
|
ExpressionBuilder.eFunction("$let", list{symbol, lambda})->Ok
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,88 +118,22 @@ let rec fromNode = (mathJsNode: Parse.node): result<expression, errorValue> =>
|
||||||
| MjArrayNode(aNode) => caseArrayNode(aNode)
|
| MjArrayNode(aNode) => caseArrayNode(aNode)
|
||||||
| MjAssignmentNode(aNode) => caseAssignmentNode(aNode)
|
| MjAssignmentNode(aNode) => caseAssignmentNode(aNode)
|
||||||
| MjSymbolNode(sNode) => {
|
| MjSymbolNode(sNode) => {
|
||||||
let expr: expression = toEvSymbolValue(sNode["name"])
|
let expr: expression = ExpressionBuilder.eSymbol(sNode["name"])
|
||||||
let rExpr: result<expression, errorValue> = expr->Ok
|
let rExpr: result<expression, errorValue> = expr->Ok
|
||||||
rExpr
|
rExpr
|
||||||
}
|
}
|
||||||
| MjBlockNode(bNode) => bNode["blocks"]->Belt.Array.map(toTagOrNode)->caseTagOrNodes
|
| MjBlockNode(bNode) => bNode["blocks"]->Js.Array2.map(blockToNode)->caseBlock
|
||||||
| MjConstantNode(cNode) =>
|
| MjConstantNode(cNode) =>
|
||||||
cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok)
|
cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok)
|
||||||
|
| MjFunctionAssignmentNode(faNode) => caseFunctionAssignmentNode(faNode)
|
||||||
| MjFunctionNode(fNode) => fNode->caseFunctionNode
|
| MjFunctionNode(fNode) => fNode->caseFunctionNode
|
||||||
| MjIndexNode(iNode) => caseIndexNode(iNode)
|
| MjIndexNode(iNode) => caseIndexNode(iNode)
|
||||||
| MjObjectNode(oNode) => caseObjectNode(oNode)
|
| MjObjectNode(oNode) => caseObjectNode(oNode)
|
||||||
| MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->caseFunctionNode
|
| MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->caseFunctionNode
|
||||||
| MjParenthesisNode(pNode) => pNode["content"]->fromNode
|
| MjParenthesisNode(pNode) => pNode["content"]->fromInnerNode
|
||||||
}
|
}
|
||||||
rFinalExpression
|
rFinalExpression
|
||||||
})
|
})
|
||||||
and caseTagOrNodes = (tagOrNodes): result<expression, errorValue> => {
|
|
||||||
let initialBindings = passToFunction("$$bindings", list{}->Ok)
|
|
||||||
let lastIndex = Belt.Array.length(tagOrNodes) - 1
|
|
||||||
tagOrNodes->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, tagOrNode, i) => {
|
|
||||||
rPreviousBindings->Result.flatMap(previousBindings => {
|
|
||||||
let rStatement: result<expression, errorValue> = switch tagOrNode {
|
|
||||||
| BlockNode(node) => fromNode(node)
|
|
||||||
| BlockTag(tag) =>
|
|
||||||
switch tag {
|
|
||||||
| ImportVariablesStatement => passToFunction("$importVariablesStatement", list{}->Ok)
|
|
||||||
| ExportVariablesExpression => passToFunction("$exportVariablesExpression", list{}->Ok)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let bindName = if i == lastIndex {
|
let fromNode = (node: Parse.node): result<expression, errorValue> =>
|
||||||
"$$bindExpression"
|
fromInnerNode(node)->Result.map(expr => ExpressionBuilder.eBlock(list{expr}))
|
||||||
} else {
|
|
||||||
"$$bindStatement"
|
|
||||||
}
|
|
||||||
|
|
||||||
rStatement->Result.flatMap((statement: expression) => {
|
|
||||||
let lispArgs = list{previousBindings, statement}->Ok
|
|
||||||
passToFunction(bindName, lispArgs)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let fromPartialNode = (mathJsNode: Parse.node): result<expression, errorValue> => {
|
|
||||||
Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => {
|
|
||||||
let casePartialBlockNode = (bNode: Parse.blockNode) => {
|
|
||||||
let blocksOrTags = bNode["blocks"]->Belt.Array.map(toTagOrNode)
|
|
||||||
let completed = Js.Array2.concat(blocksOrTags, [BlockTag(ExportVariablesExpression)])
|
|
||||||
completed->caseTagOrNodes
|
|
||||||
}
|
|
||||||
|
|
||||||
let casePartialExpression = (node: Parse.node) => {
|
|
||||||
let completed = [BlockNode(node), BlockTag(ExportVariablesExpression)]
|
|
||||||
|
|
||||||
completed->caseTagOrNodes
|
|
||||||
}
|
|
||||||
|
|
||||||
let rFinalExpression: result<expression, errorValue> = switch typedMathJsNode {
|
|
||||||
| MjBlockNode(bNode) => casePartialBlockNode(bNode)
|
|
||||||
| _ => casePartialExpression(mathJsNode)
|
|
||||||
}
|
|
||||||
rFinalExpression
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let fromOuterNode = (mathJsNode: Parse.node): result<expression, errorValue> => {
|
|
||||||
Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => {
|
|
||||||
let casePartialBlockNode = (bNode: Parse.blockNode) => {
|
|
||||||
let blocksOrTags = bNode["blocks"]->Belt.Array.map(toTagOrNode)
|
|
||||||
let completed = blocksOrTags
|
|
||||||
completed->caseTagOrNodes
|
|
||||||
}
|
|
||||||
|
|
||||||
let casePartialExpression = (node: Parse.node) => {
|
|
||||||
let completed = [BlockNode(node)]
|
|
||||||
completed->caseTagOrNodes
|
|
||||||
}
|
|
||||||
|
|
||||||
let rFinalExpression: result<expression, errorValue> = switch typedMathJsNode {
|
|
||||||
| MjBlockNode(bNode) => casePartialBlockNode(bNode)
|
|
||||||
| _ => casePartialExpression(mathJsNode)
|
|
||||||
}
|
|
||||||
rFinalExpression
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,37 +5,50 @@
|
||||||
module Extra_Array = Reducer_Extra_Array
|
module Extra_Array = Reducer_Extra_Array
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
|
||||||
|
@genType.opaque
|
||||||
|
type internalCode = Object
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type rec expressionValue =
|
type rec expressionValue =
|
||||||
| EvArray(array<expressionValue>)
|
| EvArray(array<expressionValue>)
|
||||||
|
| EvArrayString(array<string>)
|
||||||
| EvBool(bool)
|
| EvBool(bool)
|
||||||
| EvCall(string) // External function call
|
| EvCall(string) // External function call
|
||||||
| EvDistribution(DistributionTypes.genericDist)
|
| EvDistribution(DistributionTypes.genericDist)
|
||||||
|
| EvLambda(lambdaValue)
|
||||||
| EvNumber(float)
|
| EvNumber(float)
|
||||||
| EvRecord(Js.Dict.t<expressionValue>)
|
| EvRecord(record)
|
||||||
| EvString(string)
|
| EvString(string)
|
||||||
| EvSymbol(string)
|
| EvSymbol(string)
|
||||||
|
and record = Js.Dict.t<expressionValue>
|
||||||
|
and externalBindings = record
|
||||||
|
and lambdaValue = {
|
||||||
|
parameters: array<string>,
|
||||||
|
context: externalBindings,
|
||||||
|
body: internalCode,
|
||||||
|
}
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type externalBindings = Js.Dict.t<expressionValue>
|
let defaultExternalBindings: externalBindings = Js.Dict.empty()
|
||||||
|
|
||||||
type functionCall = (string, array<expressionValue>)
|
type functionCall = (string, array<expressionValue>)
|
||||||
|
|
||||||
let rec toString = aValue =>
|
let rec toString = aValue =>
|
||||||
switch aValue {
|
switch aValue {
|
||||||
|
| EvArray(anArray) => {
|
||||||
|
let args = anArray->Js.Array2.map(each => toString(each))->Js.Array2.toString
|
||||||
|
`[${args}]`
|
||||||
|
}
|
||||||
|
| EvArrayString(anArray) => {
|
||||||
|
let args = anArray->Js.Array2.toString
|
||||||
|
`[${args}]`
|
||||||
|
}
|
||||||
| EvBool(aBool) => Js.String.make(aBool)
|
| EvBool(aBool) => Js.String.make(aBool)
|
||||||
| EvCall(fName) => `:${fName}`
|
| EvCall(fName) => `:${fName}`
|
||||||
|
| EvLambda(lambdaValue) => `lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)`
|
||||||
| EvNumber(aNumber) => Js.String.make(aNumber)
|
| EvNumber(aNumber) => Js.String.make(aNumber)
|
||||||
| EvString(aString) => `'${aString}'`
|
| EvString(aString) => `'${aString}'`
|
||||||
| EvSymbol(aString) => `:${aString}`
|
| EvSymbol(aString) => `:${aString}`
|
||||||
| EvArray(anArray) => {
|
|
||||||
let args =
|
|
||||||
anArray
|
|
||||||
->Belt.Array.map(each => toString(each))
|
|
||||||
->Extra_Array.interperse(", ")
|
|
||||||
->Js.String.concatMany("")
|
|
||||||
`[${args}]`
|
|
||||||
}
|
|
||||||
| EvRecord(aRecord) => aRecord->toStringRecord
|
| EvRecord(aRecord) => aRecord->toStringRecord
|
||||||
| EvDistribution(dist) => GenericDist.toString(dist)
|
| EvDistribution(dist) => GenericDist.toString(dist)
|
||||||
}
|
}
|
||||||
|
@ -43,26 +56,27 @@ and toStringRecord = aRecord => {
|
||||||
let pairs =
|
let pairs =
|
||||||
aRecord
|
aRecord
|
||||||
->Js.Dict.entries
|
->Js.Dict.entries
|
||||||
->Belt.Array.map(((eachKey, eachValue)) => `${eachKey}: ${toString(eachValue)}`)
|
->Js.Array2.map(((eachKey, eachValue)) => `${eachKey}: ${toString(eachValue)}`)
|
||||||
->Extra_Array.interperse(", ")
|
->Js.Array2.toString
|
||||||
->Js.String.concatMany("")
|
|
||||||
`{${pairs}}`
|
`{${pairs}}`
|
||||||
}
|
}
|
||||||
|
|
||||||
let toStringWithType = aValue =>
|
let toStringWithType = aValue =>
|
||||||
switch aValue {
|
switch aValue {
|
||||||
|
| EvArray(_) => `Array::${toString(aValue)}`
|
||||||
|
| EvArrayString(_) => `ArrayString::${toString(aValue)}`
|
||||||
| EvBool(_) => `Bool::${toString(aValue)}`
|
| EvBool(_) => `Bool::${toString(aValue)}`
|
||||||
| EvCall(_) => `Call::${toString(aValue)}`
|
| EvCall(_) => `Call::${toString(aValue)}`
|
||||||
|
| EvDistribution(_) => `Distribution::${toString(aValue)}`
|
||||||
|
| EvLambda(_) => `Lambda::${toString(aValue)}`
|
||||||
| EvNumber(_) => `Number::${toString(aValue)}`
|
| EvNumber(_) => `Number::${toString(aValue)}`
|
||||||
|
| EvRecord(_) => `Record::${toString(aValue)}`
|
||||||
| EvString(_) => `String::${toString(aValue)}`
|
| EvString(_) => `String::${toString(aValue)}`
|
||||||
| EvSymbol(_) => `Symbol::${toString(aValue)}`
|
| EvSymbol(_) => `Symbol::${toString(aValue)}`
|
||||||
| EvArray(_) => `Array::${toString(aValue)}`
|
|
||||||
| EvRecord(_) => `Record::${toString(aValue)}`
|
|
||||||
| EvDistribution(_) => `Distribution::${toString(aValue)}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let argsToString = (args: array<expressionValue>): string => {
|
let argsToString = (args: array<expressionValue>): string => {
|
||||||
args->Belt.Array.map(arg => arg->toString)->Extra_Array.interperse(", ")->Js.String.concatMany("")
|
args->Js.Array2.map(arg => arg->toString)->Js.Array2.toString
|
||||||
}
|
}
|
||||||
|
|
||||||
let toStringFunctionCall = ((fn, args)): string => `${fn}(${argsToString(args)})`
|
let toStringFunctionCall = ((fn, args)): string => `${fn}(${argsToString(args)})`
|
||||||
|
@ -78,3 +92,9 @@ let toStringResultRecord = x =>
|
||||||
| Ok(a) => `Ok(${toStringRecord(a)})`
|
| Ok(a) => `Ok(${toStringRecord(a)})`
|
||||||
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
| Error(m) => `Error(${ErrorValue.errorToString(m)})`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type environment = DistributionOperation.env
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let defaultEnvironment: environment = DistributionOperation.defaultEnv
|
||||||
|
|
|
@ -14,8 +14,13 @@ type expressionValue = ExpressionValue.expressionValue
|
||||||
Map external calls of Reducer
|
Map external calls of Reducer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let dispatch = (call: ExpressionValue.functionCall, chain): result<expressionValue, 'e> =>
|
let dispatch = (call: ExpressionValue.functionCall, environment, chain): result<
|
||||||
ReducerInterface_GenericDistribution.dispatch(call) |> E.O.default(chain(call))
|
expressionValue,
|
||||||
|
'e,
|
||||||
|
> =>
|
||||||
|
ReducerInterface_GenericDistribution.dispatch(call, environment) |> E.O.default(
|
||||||
|
chain(call, environment),
|
||||||
|
)
|
||||||
/*
|
/*
|
||||||
If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally.
|
If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally.
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
module ExpressionValue = ReducerInterface_ExpressionValue
|
module ExpressionValue = ReducerInterface_ExpressionValue
|
||||||
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
|
|
||||||
let runGenericOperation = DistributionOperation.run(
|
let defaultEnv: DistributionOperation.env = {
|
||||||
~env={
|
sampleCount: MagicNumbers.Environment.defaultSampleCount,
|
||||||
sampleCount: MagicNumbers.Environment.defaultSampleCount,
|
xyPointLength: MagicNumbers.Environment.defaultXYPointLength,
|
||||||
xyPointLength: MagicNumbers.Environment.defaultXYPointLength,
|
}
|
||||||
},
|
|
||||||
)
|
let runGenericOperation = DistributionOperation.run(~env=defaultEnv)
|
||||||
|
|
||||||
module Helpers = {
|
module Helpers = {
|
||||||
let arithmeticMap = r =>
|
let arithmeticMap = r =>
|
||||||
|
@ -28,14 +28,13 @@ module Helpers = {
|
||||||
let catchAndConvertTwoArgsToDists = (args: array<expressionValue>): option<(
|
let catchAndConvertTwoArgsToDists = (args: array<expressionValue>): option<(
|
||||||
DistributionTypes.genericDist,
|
DistributionTypes.genericDist,
|
||||||
DistributionTypes.genericDist,
|
DistributionTypes.genericDist,
|
||||||
)> => {
|
)> =>
|
||||||
switch args {
|
switch args {
|
||||||
| [EvDistribution(a), EvDistribution(b)] => Some((a, b))
|
| [EvDistribution(a), EvDistribution(b)] => Some((a, b))
|
||||||
| [EvNumber(a), EvDistribution(b)] => Some((GenericDist.fromFloat(a), b))
|
| [EvNumber(a), EvDistribution(b)] => Some((GenericDist.fromFloat(a), b))
|
||||||
| [EvDistribution(a), EvNumber(b)] => Some((a, GenericDist.fromFloat(b)))
|
| [EvDistribution(a), EvNumber(b)] => Some((a, GenericDist.fromFloat(b)))
|
||||||
| _ => None
|
| _ => None
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let toFloatFn = (
|
let toFloatFn = (
|
||||||
fnCall: DistributionTypes.DistributionOperation.toFloat,
|
fnCall: DistributionTypes.DistributionOperation.toFloat,
|
||||||
|
@ -119,7 +118,7 @@ module Helpers = {
|
||||||
mixtureWithGivenWeights(distributions, weights)
|
mixtureWithGivenWeights(distributions, weights)
|
||||||
}
|
}
|
||||||
|
|
||||||
let mixture = (args: array<expressionValue>): DistributionOperation.outputType => {
|
let mixture = (args: array<expressionValue>): DistributionOperation.outputType =>
|
||||||
switch E.A.last(args) {
|
switch E.A.last(args) {
|
||||||
| Some(EvArray(b)) => {
|
| Some(EvArray(b)) => {
|
||||||
let weights = parseNumberArray(b)
|
let weights = parseNumberArray(b)
|
||||||
|
@ -139,7 +138,6 @@ module Helpers = {
|
||||||
}
|
}
|
||||||
| _ => GenDistError(ArgumentError("Last argument of mx must be array or distribution"))
|
| _ => GenDistError(ArgumentError("Last argument of mx must be array or distribution"))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module SymbolicConstructors = {
|
module SymbolicConstructors = {
|
||||||
|
@ -175,7 +173,7 @@ module SymbolicConstructors = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option<
|
let dispatchToGenericOutput = (call: ExpressionValue.functionCall, _environment): option<
|
||||||
DistributionOperation.outputType,
|
DistributionOperation.outputType,
|
||||||
> => {
|
> => {
|
||||||
let (fnName, args) = call
|
let (fnName, args) = call
|
||||||
|
@ -296,6 +294,6 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result<
|
||||||
| GenDistError(err) => Error(REDistributionError(err))
|
| GenDistError(err) => Error(REDistributionError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
let dispatch = call => {
|
let dispatch = (call, environment) => {
|
||||||
dispatchToGenericOutput(call)->E.O2.fmap(genericOutputToReducerValue)
|
dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
let dispatch: ReducerInterface_ExpressionValue.functionCall => option<
|
let defaultEnv: DistributionOperation.env
|
||||||
result<ReducerInterface_ExpressionValue.expressionValue, Reducer_ErrorValue.errorValue>,
|
let dispatch: (
|
||||||
>
|
ReducerInterface_ExpressionValue.functionCall,
|
||||||
|
ReducerInterface_ExpressionValue.environment,
|
||||||
|
) => option<result<ReducerInterface_ExpressionValue.expressionValue, Reducer_ErrorValue.errorValue>>
|
||||||
|
|
|
@ -38,7 +38,7 @@ let makeSampleSetDist = SampleSetDist.make
|
||||||
let evaluate = Reducer.evaluate
|
let evaluate = Reducer.evaluate
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let evaluateUsingExternalBindings = Reducer.evaluateUsingExternalBindings
|
let evaluateUsingOptions = Reducer.evaluateUsingOptions
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let evaluatePartialUsingExternalBindings = Reducer.evaluatePartialUsingExternalBindings
|
let evaluatePartialUsingExternalBindings = Reducer.evaluatePartialUsingExternalBindings
|
||||||
|
@ -49,6 +49,9 @@ type externalBindings = Reducer.externalBindings
|
||||||
@genType
|
@genType
|
||||||
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type recordEV = ReducerInterface_ExpressionValue.record
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
type errorValue = Reducer_ErrorValue.errorValue
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
|
|
||||||
|
@ -69,3 +72,15 @@ let errorValueToString = Reducer_ErrorValue.errorToString
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let distributionErrorToString = DistributionTypes.Error.toString
|
let distributionErrorToString = DistributionTypes.Error.toString
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type lambdaValue = ReducerInterface_ExpressionValue.lambdaValue
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let defaultSamplingEnv = ReducerInterface_GenericDistribution.defaultEnv
|
||||||
|
|
||||||
|
@genType
|
||||||
|
type environment = ReducerInterface_ExpressionValue.environment
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let defaultEnvironment = ReducerInterface_ExpressionValue.defaultEnvironment
|
||||||
|
|
158
yarn.lock
158
yarn.lock
|
@ -4025,6 +4025,11 @@
|
||||||
jest-matcher-utils "^27.0.0"
|
jest-matcher-utils "^27.0.0"
|
||||||
pretty-format "^27.0.0"
|
pretty-format "^27.0.0"
|
||||||
|
|
||||||
|
"@types/js-cookie@^2.2.6":
|
||||||
|
version "2.2.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3"
|
||||||
|
integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==
|
||||||
|
|
||||||
"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
|
"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
|
||||||
version "7.0.11"
|
version "7.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
|
||||||
|
@ -4070,10 +4075,10 @@
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
form-data "^3.0.0"
|
form-data "^3.0.0"
|
||||||
|
|
||||||
"@types/node@*", "@types/node@^17.0.29", "@types/node@^17.0.5":
|
"@types/node@*", "@types/node@^17.0.31", "@types/node@^17.0.5":
|
||||||
version "17.0.30"
|
version "17.0.31"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.30.tgz#2c6e8512acac70815e8176aa30c38025067880ef"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.31.tgz#a5bb84ecfa27eec5e1c802c6bbf8139bdb163a5d"
|
||||||
integrity sha512-oNBIZjIqyHYP8VCNAV9uEytXVeXG2oR0w9lgAXro20eugRQfY002qr3CUl6BAe+Yf/z3CRjPdz27Pu6WWtuSRw==
|
integrity sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q==
|
||||||
|
|
||||||
"@types/node@^14.0.10":
|
"@types/node@^14.0.10":
|
||||||
version "14.18.16"
|
version "14.18.16"
|
||||||
|
@ -4721,6 +4726,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe"
|
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe"
|
||||||
integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==
|
integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==
|
||||||
|
|
||||||
|
"@xobotyi/scrollbar-width@^1.9.5":
|
||||||
|
version "1.9.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d"
|
||||||
|
integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==
|
||||||
|
|
||||||
"@xtuc/ieee754@^1.2.0":
|
"@xtuc/ieee754@^1.2.0":
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
|
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
|
||||||
|
@ -6991,6 +7001,14 @@ css-has-pseudo@^3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss-selector-parser "^6.0.9"
|
postcss-selector-parser "^6.0.9"
|
||||||
|
|
||||||
|
css-in-js-utils@^2.0.0:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-2.0.1.tgz#3b472b398787291b47cfe3e44fecfdd9e914ba99"
|
||||||
|
integrity sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA==
|
||||||
|
dependencies:
|
||||||
|
hyphenate-style-name "^1.0.2"
|
||||||
|
isobject "^3.0.1"
|
||||||
|
|
||||||
css-loader@^3.6.0:
|
css-loader@^3.6.0:
|
||||||
version "3.6.0"
|
version "3.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645"
|
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645"
|
||||||
|
@ -7247,7 +7265,7 @@ csstype@^2.5.7:
|
||||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.20.tgz#9229c65ea0b260cf4d3d997cb06288e36a8d6dda"
|
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.20.tgz#9229c65ea0b260cf4d3d997cb06288e36a8d6dda"
|
||||||
integrity sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==
|
integrity sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==
|
||||||
|
|
||||||
csstype@^3.0.2:
|
csstype@^3.0.2, csstype@^3.0.6:
|
||||||
version "3.0.11"
|
version "3.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33"
|
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33"
|
||||||
integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==
|
integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==
|
||||||
|
@ -8662,6 +8680,11 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
|
||||||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||||
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
||||||
|
|
||||||
|
fast-shallow-equal@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b"
|
||||||
|
integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==
|
||||||
|
|
||||||
fast-url-parser@1.1.3, fast-url-parser@^1.1.3:
|
fast-url-parser@1.1.3, fast-url-parser@^1.1.3:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d"
|
resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d"
|
||||||
|
@ -8674,6 +8697,11 @@ fastest-levenshtein@^1.0.12:
|
||||||
resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
|
resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
|
||||||
integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==
|
integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==
|
||||||
|
|
||||||
|
fastest-stable-stringify@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz#3757a6774f6ec8de40c4e86ec28ea02417214c76"
|
||||||
|
integrity sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==
|
||||||
|
|
||||||
fastq@^1.6.0:
|
fastq@^1.6.0:
|
||||||
version "1.13.0"
|
version "1.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
|
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
|
||||||
|
@ -9881,6 +9909,11 @@ human-signals@^2.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
|
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
|
||||||
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
|
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
|
||||||
|
|
||||||
|
hyphenate-style-name@^1.0.2:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d"
|
||||||
|
integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==
|
||||||
|
|
||||||
iconv-lite@0.4.24:
|
iconv-lite@0.4.24:
|
||||||
version "0.4.24"
|
version "0.4.24"
|
||||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||||
|
@ -10037,6 +10070,13 @@ inline-style-parser@0.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
|
resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
|
||||||
integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==
|
integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==
|
||||||
|
|
||||||
|
inline-style-prefixer@^6.0.0:
|
||||||
|
version "6.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-6.0.1.tgz#c5c0e43ba8831707afc5f5bbfd97edf45c1fa7ae"
|
||||||
|
integrity sha512-AsqazZ8KcRzJ9YPN1wMH2aNM7lkWQ8tSPrW5uDk1ziYwiAPWSZnUsC7lfZq+BDqLqz0B4Pho5wscWcJzVvRzDQ==
|
||||||
|
dependencies:
|
||||||
|
css-in-js-utils "^2.0.0"
|
||||||
|
|
||||||
internal-slot@^1.0.3:
|
internal-slot@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
|
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
|
||||||
|
@ -11163,6 +11203,11 @@ joi@^17.6.0:
|
||||||
"@sideway/formula" "^3.0.0"
|
"@sideway/formula" "^3.0.0"
|
||||||
"@sideway/pinpoint" "^2.0.0"
|
"@sideway/pinpoint" "^2.0.0"
|
||||||
|
|
||||||
|
js-cookie@^2.2.1:
|
||||||
|
version "2.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
|
||||||
|
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
|
||||||
|
|
||||||
js-string-escape@^1.0.1:
|
js-string-escape@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef"
|
resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef"
|
||||||
|
@ -12183,6 +12228,20 @@ nan@^2.12.1:
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee"
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee"
|
||||||
integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==
|
integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==
|
||||||
|
|
||||||
|
nano-css@^5.3.1:
|
||||||
|
version "5.3.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.3.4.tgz#40af6a83a76f84204f346e8ccaa9169cdae9167b"
|
||||||
|
integrity sha512-wfcviJB6NOxDIDfr7RFn/GlaN7I/Bhe4d39ZRCJ3xvZX60LVe2qZ+rDqM49nm4YT81gAjzS+ZklhKP/Gnfnubg==
|
||||||
|
dependencies:
|
||||||
|
css-tree "^1.1.2"
|
||||||
|
csstype "^3.0.6"
|
||||||
|
fastest-stable-stringify "^2.0.2"
|
||||||
|
inline-style-prefixer "^6.0.0"
|
||||||
|
rtl-css-js "^1.14.0"
|
||||||
|
sourcemap-codec "^1.4.8"
|
||||||
|
stacktrace-js "^2.0.2"
|
||||||
|
stylis "^4.0.6"
|
||||||
|
|
||||||
nanoid@^3.1.23, nanoid@^3.3.1:
|
nanoid@^3.1.23, nanoid@^3.3.1:
|
||||||
version "3.3.3"
|
version "3.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
|
||||||
|
@ -14778,6 +14837,31 @@ react-textarea-autosize@^8.3.0, react-textarea-autosize@^8.3.2:
|
||||||
use-composed-ref "^1.0.0"
|
use-composed-ref "^1.0.0"
|
||||||
use-latest "^1.0.0"
|
use-latest "^1.0.0"
|
||||||
|
|
||||||
|
react-universal-interface@^0.6.2:
|
||||||
|
version "0.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b"
|
||||||
|
integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==
|
||||||
|
|
||||||
|
react-use@^17.3.2:
|
||||||
|
version "17.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.3.2.tgz#448abf515f47c41c32455024db28167cb6e53be8"
|
||||||
|
integrity sha512-bj7OD0/1wL03KyWmzFXAFe425zziuTf7q8olwCYBfOeFHY1qfO1FAMjROQLsLZYwG4Rx63xAfb7XAbBrJsZmEw==
|
||||||
|
dependencies:
|
||||||
|
"@types/js-cookie" "^2.2.6"
|
||||||
|
"@xobotyi/scrollbar-width" "^1.9.5"
|
||||||
|
copy-to-clipboard "^3.3.1"
|
||||||
|
fast-deep-equal "^3.1.3"
|
||||||
|
fast-shallow-equal "^1.0.0"
|
||||||
|
js-cookie "^2.2.1"
|
||||||
|
nano-css "^5.3.1"
|
||||||
|
react-universal-interface "^0.6.2"
|
||||||
|
resize-observer-polyfill "^1.5.1"
|
||||||
|
screenfull "^5.1.0"
|
||||||
|
set-harmonic-interval "^1.0.1"
|
||||||
|
throttle-debounce "^3.0.1"
|
||||||
|
ts-easing "^0.2.0"
|
||||||
|
tslib "^2.1.0"
|
||||||
|
|
||||||
react-vega@^7.5.0:
|
react-vega@^7.5.0:
|
||||||
version "7.5.0"
|
version "7.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-vega/-/react-vega-7.5.0.tgz#b9726d4fd7f35299d417d340935e093bf4bed558"
|
resolved "https://registry.yarnpkg.com/react-vega/-/react-vega-7.5.0.tgz#b9726d4fd7f35299d417d340935e093bf4bed558"
|
||||||
|
@ -15335,6 +15419,13 @@ rsvp@^4.8.4:
|
||||||
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
|
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
|
||||||
integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==
|
integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==
|
||||||
|
|
||||||
|
rtl-css-js@^1.14.0:
|
||||||
|
version "1.15.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/rtl-css-js/-/rtl-css-js-1.15.0.tgz#680ed816e570a9ebccba9e1cd0f202c6a8bb2dc0"
|
||||||
|
integrity sha512-99Cu4wNNIhrI10xxUaABHsdDqzalrSRTie4GeCmbGVuehm4oj+fIy8fTzB+16pmKe8Bv9rl+hxIBez6KxExTew==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.1.2"
|
||||||
|
|
||||||
rtl-detect@^1.0.4:
|
rtl-detect@^1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.0.4.tgz#40ae0ea7302a150b96bc75af7d749607392ecac6"
|
resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.0.4.tgz#40ae0ea7302a150b96bc75af7d749607392ecac6"
|
||||||
|
@ -15496,6 +15587,11 @@ schema-utils@^4.0.0:
|
||||||
ajv-formats "^2.1.1"
|
ajv-formats "^2.1.1"
|
||||||
ajv-keywords "^5.0.0"
|
ajv-keywords "^5.0.0"
|
||||||
|
|
||||||
|
screenfull@^5.1.0:
|
||||||
|
version "5.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba"
|
||||||
|
integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==
|
||||||
|
|
||||||
scroll-into-view-if-needed@^2.2.25:
|
scroll-into-view-if-needed@^2.2.25:
|
||||||
version "2.2.29"
|
version "2.2.29"
|
||||||
resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz#551791a84b7e2287706511f8c68161e4990ab885"
|
resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz#551791a84b7e2287706511f8c68161e4990ab885"
|
||||||
|
@ -15669,6 +15765,11 @@ set-blocking@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||||
|
|
||||||
|
set-harmonic-interval@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz#e1773705539cdfb80ce1c3d99e7f298bb3995249"
|
||||||
|
integrity sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==
|
||||||
|
|
||||||
set-value@^2.0.0, set-value@^2.0.1:
|
set-value@^2.0.0, set-value@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
|
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
|
||||||
|
@ -15900,6 +16001,11 @@ source-map-url@^0.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
|
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
|
||||||
integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
|
integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
|
||||||
|
|
||||||
|
source-map@0.5.6:
|
||||||
|
version "0.5.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
|
||||||
|
integrity sha1-dc449SvwczxafwwRjYEzSiu19BI=
|
||||||
|
|
||||||
source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
|
source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
|
||||||
version "0.6.1"
|
version "0.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||||
|
@ -16024,6 +16130,13 @@ stable@^0.1.8:
|
||||||
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
|
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
|
||||||
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
|
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
|
||||||
|
|
||||||
|
stack-generator@^2.0.5:
|
||||||
|
version "2.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/stack-generator/-/stack-generator-2.0.5.tgz#fb00e5b4ee97de603e0773ea78ce944d81596c36"
|
||||||
|
integrity sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q==
|
||||||
|
dependencies:
|
||||||
|
stackframe "^1.1.1"
|
||||||
|
|
||||||
stack-utils@^2.0.3:
|
stack-utils@^2.0.3:
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5"
|
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5"
|
||||||
|
@ -16036,6 +16149,23 @@ stackframe@^1.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.1.tgz#1033a3473ee67f08e2f2fc8eba6aef4f845124e1"
|
resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.1.tgz#1033a3473ee67f08e2f2fc8eba6aef4f845124e1"
|
||||||
integrity sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==
|
integrity sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==
|
||||||
|
|
||||||
|
stacktrace-gps@^3.0.4:
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz#7688dc2fc09ffb3a13165ebe0dbcaf41bcf0c69a"
|
||||||
|
integrity sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg==
|
||||||
|
dependencies:
|
||||||
|
source-map "0.5.6"
|
||||||
|
stackframe "^1.1.1"
|
||||||
|
|
||||||
|
stacktrace-js@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.2.tgz#4ca93ea9f494752d55709a081d400fdaebee897b"
|
||||||
|
integrity sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==
|
||||||
|
dependencies:
|
||||||
|
error-stack-parser "^2.0.6"
|
||||||
|
stack-generator "^2.0.5"
|
||||||
|
stacktrace-gps "^3.0.4"
|
||||||
|
|
||||||
state-toggle@^1.0.0:
|
state-toggle@^1.0.0:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe"
|
resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe"
|
||||||
|
@ -16348,6 +16478,11 @@ stylehacks@^5.1.0:
|
||||||
browserslist "^4.16.6"
|
browserslist "^4.16.6"
|
||||||
postcss-selector-parser "^6.0.4"
|
postcss-selector-parser "^6.0.4"
|
||||||
|
|
||||||
|
stylis@^4.0.6:
|
||||||
|
version "4.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.1.tgz#e46c6a9bbf7c58db1e65bb730be157311ae1fe12"
|
||||||
|
integrity sha512-lVrM/bNdhVX2OgBFNa2YJ9Lxj7kPzylieHd3TNjuGE0Re9JB7joL5VUKOVH1kdNNJTgGPpT8hmwIAPLaSyEVFQ==
|
||||||
|
|
||||||
supports-color@^2.0.0:
|
supports-color@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
||||||
|
@ -16792,6 +16927,11 @@ ts-dedent@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5"
|
resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5"
|
||||||
integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==
|
integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==
|
||||||
|
|
||||||
|
ts-easing@^0.2.0:
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec"
|
||||||
|
integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==
|
||||||
|
|
||||||
ts-jest@^27.1.4:
|
ts-jest@^27.1.4:
|
||||||
version "27.1.4"
|
version "27.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.4.tgz#84d42cf0f4e7157a52e7c64b1492c46330943e00"
|
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.4.tgz#84d42cf0f4e7157a52e7c64b1492c46330943e00"
|
||||||
|
@ -16806,10 +16946,10 @@ ts-jest@^27.1.4:
|
||||||
semver "7.x"
|
semver "7.x"
|
||||||
yargs-parser "20.x"
|
yargs-parser "20.x"
|
||||||
|
|
||||||
ts-loader@^9.2.8, ts-loader@^9.2.9:
|
ts-loader@^9.3.0:
|
||||||
version "9.2.9"
|
version "9.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.2.9.tgz#0653e07fa1b4f225d0ca57a84fddbfd43d930f9e"
|
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.3.0.tgz#980f4dbfb60e517179e15e10ed98e454b132159f"
|
||||||
integrity sha512-b0+vUY2/enb0qYtDQuNlDnJ9900NTiPiJcDJ6sY7ax1CCCwXfYIqPOMm/BwW7jsF1km+Oz8W9s31HLuD+FLIMg==
|
integrity sha512-2kLLAdAD+FCKijvGKi9sS0OzoqxLCF3CxHpok7rVgCZ5UldRzH0TkbwG9XECKjBzHsAewntC5oDaI/FwKzEUog==
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk "^4.1.0"
|
chalk "^4.1.0"
|
||||||
enhanced-resolve "^5.0.0"
|
enhanced-resolve "^5.0.0"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user