TS & components (WIP)
This commit is contained in:
parent
68ddf35387
commit
32cefb40da
|
@ -2,10 +2,10 @@ import * as React from "react";
|
|||
import {
|
||||
Distribution,
|
||||
result,
|
||||
distributionError,
|
||||
distributionErrorToString,
|
||||
squiggleExpression,
|
||||
DistributionError,
|
||||
SquiggleValue,
|
||||
resultMap,
|
||||
SquiggleRecord,
|
||||
} from "@quri/squiggle-lang";
|
||||
import { Vega } from "react-vega";
|
||||
import { ErrorAlert } from "./Alert";
|
||||
|
@ -36,9 +36,7 @@ export function defaultPlot(distribution: Distribution): Plot {
|
|||
return { distributions: [{ name: "default", distribution }] };
|
||||
}
|
||||
|
||||
export function makePlot(record: {
|
||||
[key: string]: squiggleExpression;
|
||||
}): Plot | void {
|
||||
export function makePlot(record: SquiggleRecord): Plot | void {
|
||||
const plotResult = parsePlot(record);
|
||||
if (plotResult.tag === "Ok") {
|
||||
return plotResult.value;
|
||||
|
@ -50,18 +48,17 @@ export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
|
|||
const [sized] = useSize((size) => {
|
||||
let shapes = flattenResult(
|
||||
plot.distributions.map((x) =>
|
||||
resultMap(x.distribution.pointSet(), (shape) => ({
|
||||
resultMap(x.distribution.pointSet(), (pointSet) => ({
|
||||
...pointSet.asShape(),
|
||||
name: x.name,
|
||||
// color: x.color, // not supported yet
|
||||
continuous: shape.continuous,
|
||||
discrete: shape.discrete,
|
||||
}))
|
||||
)
|
||||
);
|
||||
if (shapes.tag === "Error") {
|
||||
return (
|
||||
<ErrorAlert heading="Distribution Error">
|
||||
{distributionErrorToString(shapes.value)}
|
||||
{shapes.value.toString()}
|
||||
</ErrorAlert>
|
||||
);
|
||||
}
|
||||
|
@ -134,18 +131,18 @@ const SummaryTable: React.FC<SummaryTableProps> = ({ distribution }) => {
|
|||
const p90 = distribution.inv(0.9);
|
||||
const p95 = distribution.inv(0.95);
|
||||
|
||||
const hasResult = (x: result<number, distributionError>): boolean =>
|
||||
const hasResult = (x: result<number, DistributionError>): boolean =>
|
||||
x.tag === "Ok";
|
||||
|
||||
const unwrapResult = (
|
||||
x: result<number, distributionError>
|
||||
x: result<number, DistributionError>
|
||||
): React.ReactNode => {
|
||||
if (x.tag === "Ok") {
|
||||
return <NumberShower number={x.value} />;
|
||||
} else {
|
||||
return (
|
||||
<ErrorAlert heading="Distribution Error">
|
||||
{distributionErrorToString(x.value)}
|
||||
{x.value.toString()}
|
||||
</ErrorAlert>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
import * as React from "react";
|
||||
import {
|
||||
lambdaValue,
|
||||
environment,
|
||||
runForeign,
|
||||
errorValueToString,
|
||||
} from "@quri/squiggle-lang";
|
||||
import { LambdaValue, environment, runForeign } from "@quri/squiggle-lang";
|
||||
import { FunctionChart1Dist } from "./FunctionChart1Dist";
|
||||
import { FunctionChart1Number } from "./FunctionChart1Number";
|
||||
import { DistributionPlottingSettings } from "./DistributionChart";
|
||||
|
@ -17,7 +12,7 @@ export type FunctionChartSettings = {
|
|||
};
|
||||
|
||||
interface FunctionChartProps {
|
||||
fn: lambdaValue;
|
||||
fn: LambdaValue;
|
||||
chartSettings: FunctionChartSettings;
|
||||
distributionPlotSettings: DistributionPlottingSettings;
|
||||
environment: environment;
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import * as React from "react";
|
||||
import {
|
||||
squiggleExpression,
|
||||
bindings,
|
||||
SquiggleValue,
|
||||
environment,
|
||||
jsImports,
|
||||
defaultImports,
|
||||
defaultBindings,
|
||||
defaultEnvironment,
|
||||
} from "@quri/squiggle-lang";
|
||||
import { useSquiggle } from "../lib/hooks";
|
||||
|
@ -27,14 +23,12 @@ export interface SquiggleChartProps {
|
|||
/** If the result is a function, the amount of stops sampled */
|
||||
diagramCount?: number;
|
||||
/** When the squiggle code gets reevaluated */
|
||||
onChange?(expr: squiggleExpression | undefined): void;
|
||||
onChange?(expr: SquiggleValue | undefined): void;
|
||||
/** CSS width of the element */
|
||||
width?: number;
|
||||
height?: number;
|
||||
/** Bindings of previous variables declared */
|
||||
bindings?: bindings;
|
||||
/** JS imported parameters */
|
||||
jsImports?: jsImports;
|
||||
// jsImports?: jsImports;
|
||||
/** Whether to show a summary of the distribution */
|
||||
showSummary?: boolean;
|
||||
/** Set the x scale to be logarithmic by deault */
|
||||
|
@ -65,8 +59,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
|
|||
environment,
|
||||
onChange = defaultOnChange, // defaultOnChange must be constant, don't move its definition here
|
||||
height = 200,
|
||||
bindings = defaultBindings,
|
||||
jsImports = defaultImports,
|
||||
// jsImports = defaultImports,
|
||||
showSummary = false,
|
||||
width,
|
||||
logX = false,
|
||||
|
@ -84,9 +77,8 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
|
|||
}) => {
|
||||
const result = useSquiggle({
|
||||
code,
|
||||
bindings,
|
||||
environment,
|
||||
jsImports,
|
||||
// jsImports,
|
||||
onChange,
|
||||
executionId,
|
||||
});
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import React from "react";
|
||||
import { CodeEditor } from "./CodeEditor";
|
||||
import { environment, bindings, jsImports } from "@quri/squiggle-lang";
|
||||
import { defaultImports, defaultBindings } from "@quri/squiggle-lang";
|
||||
import { SquiggleContainer } from "./SquiggleContainer";
|
||||
import { SquiggleChart, SquiggleChartProps } from "./SquiggleChart";
|
||||
import { useSquigglePartial, useMaybeControlledValue } from "../lib/hooks";
|
||||
import { SquiggleErrorAlert } from "./SquiggleErrorAlert";
|
||||
import { useMaybeControlledValue } from "../lib/hooks";
|
||||
|
||||
const WrappedCodeEditor: React.FC<{
|
||||
code: string;
|
||||
|
@ -42,51 +39,3 @@ export const SquiggleEditor: React.FC<SquiggleEditorProps> = (props) => {
|
|||
</SquiggleContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export interface SquigglePartialProps {
|
||||
/** The text inside the input (controlled) */
|
||||
code?: string;
|
||||
/** The default text inside the input (unControlled) */
|
||||
defaultCode?: string;
|
||||
/** when the environment changes. Used again for notebook magic*/
|
||||
onChange?(expr: bindings | undefined): void;
|
||||
/** When the code changes */
|
||||
onCodeChange?(code: string): void;
|
||||
/** Previously declared variables */
|
||||
bindings?: bindings;
|
||||
/** If the output requires monte carlo sampling, the amount of samples */
|
||||
environment?: environment;
|
||||
/** Variables imported from js */
|
||||
jsImports?: jsImports;
|
||||
}
|
||||
|
||||
export const SquigglePartial: React.FC<SquigglePartialProps> = ({
|
||||
code: controlledCode,
|
||||
defaultCode = "",
|
||||
onChange,
|
||||
onCodeChange,
|
||||
bindings = defaultBindings,
|
||||
environment,
|
||||
jsImports = defaultImports,
|
||||
}: SquigglePartialProps) => {
|
||||
const [code, setCode] = useMaybeControlledValue<string>({
|
||||
value: controlledCode,
|
||||
defaultValue: defaultCode,
|
||||
onChange: onCodeChange,
|
||||
});
|
||||
|
||||
const result = useSquigglePartial({
|
||||
code,
|
||||
bindings,
|
||||
environment,
|
||||
jsImports,
|
||||
onChange,
|
||||
});
|
||||
|
||||
return (
|
||||
<SquiggleContainer>
|
||||
<WrappedCodeEditor code={code} setCode={setCode} />
|
||||
{result.tag !== "Ok" ? <SquiggleErrorAlert error={result.value} /> : null}
|
||||
</SquiggleContainer>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { errorValue, errorValueToString } from "@quri/squiggle-lang";
|
||||
import { ErrorValue } from "@quri/squiggle-lang";
|
||||
import React from "react";
|
||||
import { ErrorAlert } from "./Alert";
|
||||
|
||||
type Props = {
|
||||
error: errorValue;
|
||||
error: ErrorValue;
|
||||
};
|
||||
|
||||
export const SquiggleErrorAlert: React.FC<Props> = ({ error }) => {
|
||||
return <ErrorAlert heading="Error">{errorValueToString(error)}</ErrorAlert>;
|
||||
return <ErrorAlert heading="Error">{error.toString()}</ErrorAlert>;
|
||||
};
|
||||
|
|
|
@ -24,7 +24,7 @@ import {
|
|||
} from "@heroicons/react/solid";
|
||||
import clsx from "clsx";
|
||||
|
||||
import { defaultBindings, environment } from "@quri/squiggle-lang";
|
||||
import { environment } from "@quri/squiggle-lang";
|
||||
|
||||
import { SquiggleChart, SquiggleChartProps } from "./SquiggleChart";
|
||||
import { CodeEditor } from "./CodeEditor";
|
||||
|
@ -309,8 +309,7 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
|
|||
executionId={executionId}
|
||||
environment={env}
|
||||
{...vars}
|
||||
bindings={defaultBindings}
|
||||
jsImports={imports}
|
||||
// jsImports={imports}
|
||||
enableLocalSettings={true}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import React from "react";
|
||||
import { squiggleExpression, declaration } from "@quri/squiggle-lang";
|
||||
import {
|
||||
DistributionTag,
|
||||
SquiggleValue,
|
||||
SquiggleValueTag,
|
||||
} from "@quri/squiggle-lang";
|
||||
import { NumberShower } from "../NumberShower";
|
||||
import { DistributionChart, defaultPlot, makePlot } from "../DistributionChart";
|
||||
import { FunctionChart, FunctionChartSettings } from "../FunctionChart";
|
||||
|
@ -9,6 +13,8 @@ import { ItemSettingsMenu } from "./ItemSettingsMenu";
|
|||
import { hasMassBelowZero } from "../../lib/distributionUtils";
|
||||
import { MergedItemSettings } from "./utils";
|
||||
|
||||
/*
|
||||
// DISABLED FOR 0.4 branch, for now
|
||||
function getRange<a>(x: declaration<a>) {
|
||||
const first = x.args[0];
|
||||
switch (first.tag) {
|
||||
|
@ -31,6 +37,7 @@ function getChartSettings<a>(x: declaration<a>): FunctionChartSettings {
|
|||
count: 20,
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
const VariableList: React.FC<{
|
||||
path: string[];
|
||||
|
@ -48,7 +55,7 @@ const VariableList: React.FC<{
|
|||
|
||||
export interface Props {
|
||||
/** The output of squiggle's run */
|
||||
expression: squiggleExpression;
|
||||
expression: SquiggleValue;
|
||||
/** Path to the current item, e.g. `['foo', 'bar', '3']` for `foo.bar[3]`; can be empty on the top-level item. */
|
||||
path: string[];
|
||||
width?: number;
|
||||
|
@ -67,7 +74,7 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
);
|
||||
}
|
||||
switch (expression.tag) {
|
||||
case "number":
|
||||
case SquiggleValueTag.SvtNumber:
|
||||
return (
|
||||
<VariableBox path={path} heading="Number">
|
||||
{() => (
|
||||
|
@ -77,13 +84,15 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
)}
|
||||
</VariableBox>
|
||||
);
|
||||
case "distribution": {
|
||||
const distType = expression.value.type();
|
||||
case SquiggleValueTag.SvtDistribution: {
|
||||
const distType = expression.value.tag;
|
||||
return (
|
||||
<VariableBox
|
||||
path={path}
|
||||
heading={`Distribution (${distType})\n${
|
||||
distType === "Symbolic" ? expression.value.toString() : ""
|
||||
distType === DistributionTag.DtSymbolic
|
||||
? expression.value.toString()
|
||||
: ""
|
||||
}`}
|
||||
renderSettingsMenu={({ onChange }) => {
|
||||
const shape = expression.value.pointSet();
|
||||
|
@ -112,7 +121,7 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
</VariableBox>
|
||||
);
|
||||
}
|
||||
case "string":
|
||||
case SquiggleValueTag.SvtString:
|
||||
return (
|
||||
<VariableBox path={path} heading="String">
|
||||
{() => (
|
||||
|
@ -126,13 +135,13 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
)}
|
||||
</VariableBox>
|
||||
);
|
||||
case "boolean":
|
||||
case SquiggleValueTag.SvtBool:
|
||||
return (
|
||||
<VariableBox path={path} heading="Boolean">
|
||||
{() => expression.value.toString()}
|
||||
</VariableBox>
|
||||
);
|
||||
case "symbol":
|
||||
case SquiggleValueTag.SvtSymbol:
|
||||
return (
|
||||
<VariableBox path={path} heading="Symbol">
|
||||
{() => (
|
||||
|
@ -143,38 +152,38 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
)}
|
||||
</VariableBox>
|
||||
);
|
||||
case "call":
|
||||
case SquiggleValueTag.SvtCall:
|
||||
return (
|
||||
<VariableBox path={path} heading="Call">
|
||||
{() => expression.value}
|
||||
</VariableBox>
|
||||
);
|
||||
case "arraystring":
|
||||
case SquiggleValueTag.SvtArrayString:
|
||||
return (
|
||||
<VariableBox path={path} heading="Array String">
|
||||
{() => expression.value.map((r) => `"${r}"`).join(", ")}
|
||||
</VariableBox>
|
||||
);
|
||||
case "date":
|
||||
case SquiggleValueTag.SvtDate:
|
||||
return (
|
||||
<VariableBox path={path} heading="Date">
|
||||
{() => expression.value.toDateString()}
|
||||
</VariableBox>
|
||||
);
|
||||
case "void":
|
||||
case SquiggleValueTag.SvtVoid:
|
||||
return (
|
||||
<VariableBox path={path} heading="Void">
|
||||
{() => "Void"}
|
||||
</VariableBox>
|
||||
);
|
||||
case "timeDuration": {
|
||||
case SquiggleValueTag.SvtTimeDuration: {
|
||||
return (
|
||||
<VariableBox path={path} heading="Time Duration">
|
||||
{() => <NumberShower precision={3} number={expression.value} />}
|
||||
</VariableBox>
|
||||
);
|
||||
}
|
||||
case "lambda":
|
||||
case SquiggleValueTag.SvtLambda:
|
||||
return (
|
||||
<VariableBox
|
||||
path={path}
|
||||
|
@ -208,7 +217,7 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
)}
|
||||
</VariableBox>
|
||||
);
|
||||
case "lambdaDeclaration": {
|
||||
case SquiggleValueTag.SvtDeclaration: {
|
||||
return (
|
||||
<VariableBox
|
||||
path={path}
|
||||
|
@ -224,21 +233,22 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
}}
|
||||
>
|
||||
{(settings) => (
|
||||
<FunctionChart
|
||||
fn={expression.value.fn}
|
||||
chartSettings={getChartSettings(expression.value)}
|
||||
distributionPlotSettings={settings.distributionPlotSettings}
|
||||
height={settings.height}
|
||||
environment={{
|
||||
sampleCount: settings.environment.sampleCount / 10,
|
||||
xyPointLength: settings.environment.xyPointLength / 10,
|
||||
}}
|
||||
/>
|
||||
<div>NOT IMPLEMENTED IN 0.4 YET</div>
|
||||
// <FunctionChart
|
||||
// fn={expression.value.fn}
|
||||
// chartSettings={getChartSettings(expression.value)}
|
||||
// distributionPlotSettings={settings.distributionPlotSettings}
|
||||
// height={settings.height}
|
||||
// environment={{
|
||||
// sampleCount: settings.environment.sampleCount / 10,
|
||||
// xyPointLength: settings.environment.xyPointLength / 10,
|
||||
// }}
|
||||
// />
|
||||
)}
|
||||
</VariableBox>
|
||||
);
|
||||
}
|
||||
case "module": {
|
||||
case SquiggleValueTag.SvtModule: {
|
||||
return (
|
||||
<VariableList path={path} heading="Module">
|
||||
{(_) =>
|
||||
|
@ -256,7 +266,7 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
</VariableList>
|
||||
);
|
||||
}
|
||||
case "record":
|
||||
case SquiggleValueTag.SvtRecord:
|
||||
const plot = makePlot(expression.value);
|
||||
if (plot) {
|
||||
return (
|
||||
|
@ -308,11 +318,13 @@ export const ExpressionViewer: React.FC<Props> = ({
|
|||
</VariableList>
|
||||
);
|
||||
}
|
||||
case "array":
|
||||
case SquiggleValueTag.SvtArray:
|
||||
return (
|
||||
<VariableList path={path} heading="Array">
|
||||
{(_) =>
|
||||
expression.value.map((r, i) => (
|
||||
expression.value
|
||||
.getValues()
|
||||
.map((r, i) => (
|
||||
<ExpressionViewer
|
||||
key={i}
|
||||
path={[...path, String(i)]}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
export { SquiggleChart } from "./components/SquiggleChart";
|
||||
export { SquiggleEditor, SquigglePartial } from "./components/SquiggleEditor";
|
||||
export { SquiggleEditor } from "./components/SquiggleEditor";
|
||||
export { SquigglePlayground } from "./components/SquigglePlayground";
|
||||
export { SquiggleContainer } from "./components/SquiggleContainer";
|
||||
export { SquiggleEditorWithImportedBindings } from "./components/SquiggleEditorWithImportedBindings";
|
||||
|
||||
export { mergeBindings } from "@quri/squiggle-lang";
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export { useMaybeControlledValue } from "./useMaybeControlledValue";
|
||||
export { useSquiggle, useSquigglePartial } from "./useSquiggle";
|
||||
export { useSquiggle } from "./useSquiggle";
|
||||
export { useRunnerState } from "./useRunnerState";
|
||||
|
|
|
@ -1,34 +1,25 @@
|
|||
import {
|
||||
bindings,
|
||||
environment,
|
||||
jsImports,
|
||||
run,
|
||||
runPartial,
|
||||
} from "@quri/squiggle-lang";
|
||||
import { environment, run, SquiggleValue } from "@quri/squiggle-lang";
|
||||
import { useEffect, useMemo } from "react";
|
||||
|
||||
type SquiggleArgs<T extends ReturnType<typeof run | typeof runPartial>> = {
|
||||
type SquiggleArgs = {
|
||||
code: string;
|
||||
executionId?: number;
|
||||
bindings?: bindings;
|
||||
jsImports?: jsImports;
|
||||
// jsImports?: jsImports;
|
||||
environment?: environment;
|
||||
onChange?: (expr: Extract<T, { tag: "Ok" }>["value"] | undefined) => void;
|
||||
onChange?: (expr: SquiggleValue | undefined) => void;
|
||||
};
|
||||
|
||||
const useSquiggleAny = <T extends ReturnType<typeof run | typeof runPartial>>(
|
||||
args: SquiggleArgs<T>,
|
||||
f: (...args: Parameters<typeof run>) => T
|
||||
) => {
|
||||
const result: T = useMemo<T>(
|
||||
() => f(args.code, args.bindings, args.environment, args.jsImports),
|
||||
export const useSquiggle = (args: SquiggleArgs) => {
|
||||
const result = useMemo(
|
||||
() => {
|
||||
const { result } = run(args.code, { environment: args.environment });
|
||||
return result;
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[
|
||||
f,
|
||||
args.code,
|
||||
args.bindings,
|
||||
args.environment,
|
||||
args.jsImports,
|
||||
// args.environment,
|
||||
// args.jsImports,
|
||||
args.executionId,
|
||||
]
|
||||
);
|
||||
|
@ -41,13 +32,3 @@ const useSquiggleAny = <T extends ReturnType<typeof run | typeof runPartial>>(
|
|||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const useSquigglePartial = (
|
||||
args: SquiggleArgs<ReturnType<typeof runPartial>>
|
||||
) => {
|
||||
return useSquiggleAny(args, runPartial);
|
||||
};
|
||||
|
||||
export const useSquiggle = (args: SquiggleArgs<ReturnType<typeof run>>) => {
|
||||
return useSquiggleAny(args, run);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as yup from "yup";
|
||||
import { Distribution, result, squiggleExpression } from "@quri/squiggle-lang";
|
||||
import { Distribution, result, SquiggleRecord } from "@quri/squiggle-lang";
|
||||
|
||||
export type LabeledDistribution = {
|
||||
name: string;
|
||||
|
@ -53,9 +53,7 @@ const schema = yup
|
|||
}),
|
||||
});
|
||||
|
||||
export function parsePlot(record: {
|
||||
[key: string]: squiggleExpression;
|
||||
}): result<Plot, string> {
|
||||
export function parsePlot(record: SquiggleRecord): result<Plot, string> {
|
||||
try {
|
||||
const plotRecord = schema.validateSync(record);
|
||||
return ok({
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import {
|
||||
Distribution,
|
||||
resultMap,
|
||||
defaultBindings,
|
||||
mergeBindings,
|
||||
} from "../../src/js/index";
|
||||
import { testRun, testRunPartial } from "./TestHelpers";
|
||||
import { Project, SquiggleValue } from "../../src/js";
|
||||
import { NumberValue } from "../../src/js/SquiggleValue";
|
||||
import { failDefault, testRun } from "./TestHelpers";
|
||||
|
||||
function Ok<b>(x: b) {
|
||||
return { tag: "Ok", value: x };
|
||||
|
@ -12,150 +8,175 @@ function Ok<b>(x: b) {
|
|||
|
||||
describe("Simple calculations and results", () => {
|
||||
test("mean(normal(5,2))", () => {
|
||||
expect(testRun("mean(normal(5,2))")).toEqual({
|
||||
tag: "number",
|
||||
value: 5,
|
||||
});
|
||||
const result = testRun("mean(normal(5,2))"); // FIXME
|
||||
expect(result.tag).toEqual("Number");
|
||||
switch (result.tag) {
|
||||
case "Number":
|
||||
expect(result.value()).toEqual(5);
|
||||
break;
|
||||
default:
|
||||
fail();
|
||||
}
|
||||
// tag: "number",
|
||||
// value: 5,
|
||||
// });
|
||||
});
|
||||
test("10+10", () => {
|
||||
let foo = testRun("10 + 10");
|
||||
expect(foo).toEqual({ tag: "number", value: 20 });
|
||||
});
|
||||
});
|
||||
describe("Log function", () => {
|
||||
test("log(1) = 0", () => {
|
||||
let foo = testRun("log(1)");
|
||||
expect(foo).toEqual({ tag: "number", value: 0 });
|
||||
let result = testRun("10 + 10") as NumberValue;
|
||||
expect(result.tag).toEqual("Number");
|
||||
switch (result.tag) {
|
||||
case "Number":
|
||||
expect(result.value()).toEqual(20);
|
||||
break;
|
||||
default:
|
||||
fail();
|
||||
}
|
||||
});
|
||||
});
|
||||
// describe("Log function", () => {
|
||||
// test("log(1) = 0", () => {
|
||||
// let foo = testRun("log(1)");
|
||||
// expect(foo).toEqual({ tag: "number", value: 0 });
|
||||
// });
|
||||
// });
|
||||
|
||||
describe("Array", () => {
|
||||
test("nested Array", () => {
|
||||
expect(testRun("[[1]]")).toEqual({
|
||||
tag: "array",
|
||||
value: [
|
||||
{
|
||||
tag: "array",
|
||||
value: [
|
||||
{
|
||||
tag: "number",
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
// describe("Array", () => {
|
||||
// test("nested Array", () => {
|
||||
// expect(testRun("[[1]]")).toEqual({
|
||||
// tag: "array",
|
||||
// value: [
|
||||
// {
|
||||
// tag: "array",
|
||||
// value: [
|
||||
// {
|
||||
// tag: "number",
|
||||
// value: 1,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
describe("Record", () => {
|
||||
test("Return record", () => {
|
||||
expect(testRun("{a: 1}")).toEqual({
|
||||
tag: "record",
|
||||
value: {
|
||||
a: {
|
||||
tag: "number",
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
// describe("Record", () => {
|
||||
// test("Return record", () => {
|
||||
// expect(testRun("{a: 1}")).toEqual({
|
||||
// tag: "record",
|
||||
// value: {
|
||||
// a: {
|
||||
// tag: "number",
|
||||
// value: 1,
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
describe("Partials", () => {
|
||||
test("Can pass variables between partials and cells", () => {
|
||||
let bindings = testRunPartial(`x = 5`);
|
||||
let bindings2 = testRunPartial(`y = x + 2`, bindings);
|
||||
expect(testRun(`y + 3`, bindings2)).toEqual({
|
||||
tag: "number",
|
||||
value: 10,
|
||||
});
|
||||
});
|
||||
test("Can merge bindings from three partials", () => {
|
||||
let bindings1 = testRunPartial(`x = 1`);
|
||||
let bindings2 = testRunPartial(`y = 2`);
|
||||
let bindings3 = testRunPartial(`z = 3`);
|
||||
expect(
|
||||
testRun(`x + y + z`, mergeBindings([bindings1, bindings2, bindings3]))
|
||||
).toEqual({
|
||||
tag: "number",
|
||||
value: 6,
|
||||
});
|
||||
});
|
||||
});
|
||||
// describe("Partials", () => {
|
||||
// test("Can pass variables between partials and cells", () => {
|
||||
// const project = Project.create();
|
||||
// project.setSource("p1", "x = 5");
|
||||
// project.setSource("p2", "y = x + 2");
|
||||
// project.setSource("main", "y + 3");
|
||||
// project.run("main");
|
||||
// const result = project.getResult("main");
|
||||
// expect(result.tag).toEqual("Ok");
|
||||
// expect(result.value).toBeInstanceOf(SquiggleValue);
|
||||
// expect(result.value).toHaveProperty("tag", "number");
|
||||
// failDefault(); // FIXME
|
||||
// // let bindings = testRunPartial(`x = 5`);
|
||||
// // let bindings2 = testRunPartial(`y = x + 2`, bindings);
|
||||
// // expect(testRun(`y + 3`, bindings2)).toEqual({
|
||||
// // tag: "number",
|
||||
// // value: 10,
|
||||
// // });
|
||||
// });
|
||||
// test("Can merge bindings from three partials", () => {
|
||||
// let bindings1 = testRunPartial(`x = 1`);
|
||||
// let bindings2 = testRunPartial(`y = 2`);
|
||||
// let bindings3 = testRunPartial(`z = 3`);
|
||||
// expect(
|
||||
// testRun(`x + y + z`, mergeBindings([bindings1, bindings2, bindings3]))
|
||||
// ).toEqual({
|
||||
// tag: "number",
|
||||
// value: 6,
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
describe("JS Imports", () => {
|
||||
test("Can pass parameters into partials and cells", () => {
|
||||
let bindings = testRunPartial(`y = $x + 2`, defaultBindings, { x: 1 });
|
||||
let bindings2 = testRunPartial(`z = y + $a`, bindings, { a: 3 });
|
||||
expect(testRun(`z`, bindings2)).toEqual({
|
||||
tag: "number",
|
||||
value: 6,
|
||||
});
|
||||
});
|
||||
test("Complicated deep parameters", () => {
|
||||
expect(
|
||||
testRun(`$x.y[0][0].w + $x.z + $u.v`, defaultBindings, {
|
||||
x: { y: [[{ w: 1 }]], z: 2 },
|
||||
u: { v: 3 },
|
||||
})
|
||||
).toEqual({
|
||||
tag: "number",
|
||||
value: 6,
|
||||
});
|
||||
});
|
||||
});
|
||||
// describe("JS Imports", () => {
|
||||
// test("Can pass parameters into partials and cells", () => {
|
||||
// let bindings = testRunPartial(`y = $x + 2`, defaultBindings, { x: 1 });
|
||||
// let bindings2 = testRunPartial(`z = y + $a`, bindings, { a: 3 });
|
||||
// expect(testRun(`z`, bindings2)).toEqual({
|
||||
// tag: "number",
|
||||
// value: 6,
|
||||
// });
|
||||
// });
|
||||
// test("Complicated deep parameters", () => {
|
||||
// expect(
|
||||
// testRun(`$x.y[0][0].w + $x.z + $u.v`, defaultBindings, {
|
||||
// x: { y: [[{ w: 1 }]], z: 2 },
|
||||
// u: { v: 3 },
|
||||
// })
|
||||
// ).toEqual({
|
||||
// tag: "number",
|
||||
// value: 6,
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
describe("Distribution", () => {
|
||||
//It's important that sampleCount is less than 9. If it's more, than that will create randomness
|
||||
//Also, note, the value should be created using makeSampleSetDist() later on.
|
||||
let env = { sampleCount: 8, xyPointLength: 100 };
|
||||
let dist1Samples = [3, 4, 5, 6, 6, 7, 10, 15, 30];
|
||||
let dist1SampleCount = dist1Samples.length;
|
||||
let dist = new Distribution(
|
||||
{ tag: "SampleSet", value: [3, 4, 5, 6, 6, 7, 10, 15, 30] },
|
||||
env
|
||||
);
|
||||
let dist2 = new Distribution(
|
||||
{ tag: "SampleSet", value: [20, 22, 24, 29, 30, 35, 38, 44, 52] },
|
||||
env
|
||||
);
|
||||
// describe("Distribution", () => {
|
||||
// //It's important that sampleCount is less than 9. If it's more, than that will create randomness
|
||||
// //Also, note, the value should be created using makeSampleSetDist() later on.
|
||||
// let env = { sampleCount: 8, xyPointLength: 100 };
|
||||
// let dist1Samples = [3, 4, 5, 6, 6, 7, 10, 15, 30];
|
||||
// let dist1SampleCount = dist1Samples.length;
|
||||
// let dist = new Distribution(
|
||||
// { tag: "SampleSet", value: [3, 4, 5, 6, 6, 7, 10, 15, 30] },
|
||||
// env
|
||||
// );
|
||||
// let dist2 = new Distribution(
|
||||
// { tag: "SampleSet", value: [20, 22, 24, 29, 30, 35, 38, 44, 52] },
|
||||
// env
|
||||
// );
|
||||
|
||||
test("mean", () => {
|
||||
expect(dist.mean().value).toBeCloseTo(9.5555555);
|
||||
});
|
||||
test("pdf", () => {
|
||||
expect(dist.pdf(5.0).value).toBeCloseTo(0.10499097598222966, 1);
|
||||
});
|
||||
test("cdf", () => {
|
||||
expect(dist.cdf(5.0).value).toBeCloseTo(
|
||||
dist1Samples.filter((x) => x <= 5).length / dist1SampleCount,
|
||||
1
|
||||
);
|
||||
});
|
||||
test("inv", () => {
|
||||
expect(dist.inv(0.5).value).toBeCloseTo(6);
|
||||
});
|
||||
test("toPointSet", () => {
|
||||
expect(
|
||||
resultMap(dist.toPointSet(), (r: Distribution) => r.toString())
|
||||
).toEqual(Ok("Point Set Distribution"));
|
||||
});
|
||||
test("toSparkline", () => {
|
||||
expect(dist.toSparkline(20).value).toEqual("▁▁▃▇█▇▄▂▂▂▁▁▁▁▁▂▂▁▁▁");
|
||||
});
|
||||
test("algebraicAdd", () => {
|
||||
expect(
|
||||
resultMap(dist.algebraicAdd(dist2), (r: Distribution) =>
|
||||
r.toSparkline(20)
|
||||
).value
|
||||
).toEqual(Ok("▁▁▂▄▆████▇▆▄▄▃▃▃▂▁▁▁"));
|
||||
});
|
||||
test("pointwiseAdd", () => {
|
||||
expect(
|
||||
resultMap(dist.pointwiseAdd(dist2), (r: Distribution) =>
|
||||
r.toSparkline(20)
|
||||
).value
|
||||
).toEqual(Ok("▁▂██▃▃▃▃▄▅▄▃▃▂▂▂▁▁▁▁"));
|
||||
});
|
||||
});
|
||||
// test("mean", () => {
|
||||
// expect(dist.mean().value).toBeCloseTo(9.5555555);
|
||||
// });
|
||||
// test("pdf", () => {
|
||||
// expect(dist.pdf(5.0).value).toBeCloseTo(0.10499097598222966, 1);
|
||||
// });
|
||||
// test("cdf", () => {
|
||||
// expect(dist.cdf(5.0).value).toBeCloseTo(
|
||||
// dist1Samples.filter((x) => x <= 5).length / dist1SampleCount,
|
||||
// 1
|
||||
// );
|
||||
// });
|
||||
// test("inv", () => {
|
||||
// expect(dist.inv(0.5).value).toBeCloseTo(6);
|
||||
// });
|
||||
// test("toPointSet", () => {
|
||||
// expect(
|
||||
// resultMap(dist.toPointSet(), (r: Distribution) => r.toString())
|
||||
// ).toEqual(Ok("Point Set Distribution"));
|
||||
// });
|
||||
// test("toSparkline", () => {
|
||||
// expect(dist.toSparkline(20).value).toEqual("▁▁▃▇█▇▄▂▂▂▁▁▁▁▁▂▂▁▁▁");
|
||||
// });
|
||||
// test("algebraicAdd", () => {
|
||||
// expect(
|
||||
// resultMap(dist.algebraicAdd(dist2), (r: Distribution) =>
|
||||
// r.toSparkline(20)
|
||||
// ).value
|
||||
// ).toEqual(Ok("▁▁▂▄▆████▇▆▄▄▃▃▃▂▁▁▁"));
|
||||
// });
|
||||
// test("pointwiseAdd", () => {
|
||||
// expect(
|
||||
// resultMap(dist.pointwiseAdd(dist2), (r: Distribution) =>
|
||||
// r.toSparkline(20)
|
||||
// ).value
|
||||
// ).toEqual(Ok("▁▂██▃▃▃▃▄▅▄▃▃▂▂▂▁▁▁▁"));
|
||||
// });
|
||||
// });
|
||||
|
|
|
@ -1,60 +1,21 @@
|
|||
import {
|
||||
run,
|
||||
runPartial,
|
||||
bindings,
|
||||
squiggleExpression,
|
||||
errorValueToString,
|
||||
defaultImports,
|
||||
defaultBindings,
|
||||
jsImports,
|
||||
} from "../../src/js/index";
|
||||
import { run, SquiggleValue } from "../../src/js/index";
|
||||
|
||||
export function testRun(
|
||||
x: string,
|
||||
bindings: bindings = defaultBindings,
|
||||
imports: jsImports = defaultImports
|
||||
): squiggleExpression {
|
||||
let squiggleResult = run(
|
||||
x,
|
||||
bindings,
|
||||
{
|
||||
sampleCount: 1000,
|
||||
xyPointLength: 100,
|
||||
},
|
||||
imports
|
||||
);
|
||||
if (squiggleResult.tag === "Ok") {
|
||||
return squiggleResult.value;
|
||||
export function testRun(x: string) {
|
||||
const { result, bindings } = run(x); // FIXME - set environment
|
||||
// x,
|
||||
// bindings,
|
||||
// {
|
||||
// sampleCount: 1000,
|
||||
// xyPointLength: 100,
|
||||
// },
|
||||
// imports
|
||||
// );
|
||||
|
||||
if (result.tag === "Ok") {
|
||||
return result.value;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Expected squiggle expression to evaluate but got error: ${errorValueToString(
|
||||
squiggleResult.value
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function testRunPartial(
|
||||
x: string,
|
||||
bindings: bindings = defaultBindings,
|
||||
imports: jsImports = defaultImports
|
||||
): bindings {
|
||||
let squiggleResult = runPartial(
|
||||
x,
|
||||
bindings,
|
||||
{
|
||||
sampleCount: 1000,
|
||||
xyPointLength: 100,
|
||||
},
|
||||
imports
|
||||
);
|
||||
if (squiggleResult.tag === "Ok") {
|
||||
return squiggleResult.value;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Expected squiggle expression to evaluate but got error: ${errorValueToString(
|
||||
squiggleResult.value
|
||||
)}`
|
||||
`Expected squiggle expression to evaluate but got error: ${result.value}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
93
packages/squiggle-lang/src/js/Distribution.ts
Normal file
93
packages/squiggle-lang/src/js/Distribution.ts
Normal file
|
@ -0,0 +1,93 @@
|
|||
import * as RSDistribution from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution.gen";
|
||||
import { distributionTag as Tag } from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_tag";
|
||||
import { DistributionError } from "./DistributionError";
|
||||
import { wrapPointSetDist } from "./PointSetDist";
|
||||
import { resultMap2 } from "./types";
|
||||
|
||||
type T = RSDistribution.distribution;
|
||||
export { Tag };
|
||||
|
||||
export const wrapDistribution = (value: T): Distribution => {
|
||||
const tag = RSDistribution.getTag(value);
|
||||
|
||||
return new tagToClass[tag](value);
|
||||
};
|
||||
|
||||
abstract class AbstractDistribution {
|
||||
abstract tag: Tag;
|
||||
_value: T;
|
||||
|
||||
constructor(value: T) {
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
pointSet() {
|
||||
const env: any = "TODO";
|
||||
const innerResult = RSDistribution.toPointSet(this._value, env);
|
||||
return resultMap2(
|
||||
innerResult,
|
||||
wrapPointSetDist,
|
||||
(v: RSDistribution.distributionError) => new DistributionError(v)
|
||||
);
|
||||
}
|
||||
|
||||
toString() {
|
||||
RSDistribution.toString(this._value);
|
||||
}
|
||||
|
||||
mean() {
|
||||
return RSDistribution.mean(this._value);
|
||||
}
|
||||
|
||||
inv(n: number) {
|
||||
return RSDistribution.inv(this._value, n);
|
||||
}
|
||||
|
||||
stdev() {
|
||||
return RSDistribution.stdev(this._value);
|
||||
}
|
||||
}
|
||||
|
||||
const valueMethod = <IR>(
|
||||
_this: AbstractDistribution,
|
||||
rsMethod: (v: T) => IR | null | undefined
|
||||
) => {
|
||||
const value = rsMethod(_this._value);
|
||||
if (!value) throw new Error("Internal casting error");
|
||||
return value;
|
||||
};
|
||||
|
||||
export class PointSetDistribution extends AbstractDistribution {
|
||||
tag = Tag.DtPointSet;
|
||||
|
||||
value() {
|
||||
return valueMethod(this, RSDistribution.getPointSet);
|
||||
}
|
||||
}
|
||||
|
||||
export class SampleSetDistribution extends AbstractDistribution {
|
||||
tag = Tag.DtSampleSet;
|
||||
|
||||
value() {
|
||||
return valueMethod(this, RSDistribution.getSampleSet);
|
||||
}
|
||||
}
|
||||
|
||||
export class SymbolicDistribution extends AbstractDistribution {
|
||||
tag = Tag.DtSymbolic;
|
||||
|
||||
value() {
|
||||
return valueMethod(this, RSDistribution.getSymbolic);
|
||||
}
|
||||
}
|
||||
|
||||
const tagToClass = {
|
||||
[Tag.DtPointSet]: PointSetDistribution,
|
||||
[Tag.DtSampleSet]: SampleSetDistribution,
|
||||
[Tag.DtSymbolic]: SymbolicDistribution,
|
||||
} as const;
|
||||
|
||||
export type Distribution =
|
||||
| PointSetDistribution
|
||||
| SampleSetDistribution
|
||||
| SymbolicDistribution;
|
15
packages/squiggle-lang/src/js/DistributionError.ts
Normal file
15
packages/squiggle-lang/src/js/DistributionError.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import * as RSDistributionError from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Error.gen";
|
||||
|
||||
type T = RSDistributionError.distributionError;
|
||||
|
||||
export class DistributionError {
|
||||
_value: T;
|
||||
|
||||
constructor(_value: T) {
|
||||
this._value = _value;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return RSDistributionError.toString(this._value);
|
||||
}
|
||||
}
|
13
packages/squiggle-lang/src/js/ErrorValue.ts
Normal file
13
packages/squiggle-lang/src/js/ErrorValue.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import * as RSErrorValue from "../rescript/ForTS/ForTS_Reducer_ErrorValue.gen";
|
||||
|
||||
export class ErrorValue {
|
||||
_value: RSErrorValue.reducerErrorValue;
|
||||
|
||||
constructor(_value: RSErrorValue.reducerErrorValue) {
|
||||
this._value = _value;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return RSErrorValue.toString(this._value);
|
||||
}
|
||||
}
|
11
packages/squiggle-lang/src/js/Lambda.ts
Normal file
11
packages/squiggle-lang/src/js/Lambda.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import * as RSLambda from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Lambda.gen";
|
||||
|
||||
type T = RSLambda.squiggleValue_Lambda;
|
||||
|
||||
export class Lambda {
|
||||
_value: T;
|
||||
|
||||
constructor(_value: T) {
|
||||
this._value = _value;
|
||||
}
|
||||
}
|
11
packages/squiggle-lang/src/js/LambdaDeclaration.ts
Normal file
11
packages/squiggle-lang/src/js/LambdaDeclaration.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import * as RSDeclaration from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Declaration.gen";
|
||||
|
||||
type T = RSDeclaration.squiggleValue_Declaration;
|
||||
|
||||
export class LambdaDeclaration {
|
||||
_value: T;
|
||||
|
||||
constructor(_value: T) {
|
||||
this._value = _value;
|
||||
}
|
||||
}
|
9
packages/squiggle-lang/src/js/NameSpace.ts
Normal file
9
packages/squiggle-lang/src/js/NameSpace.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import * as RSModuleValue from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Module.gen";
|
||||
|
||||
export class NameSpace {
|
||||
_value: RSModuleValue.squiggleValue_Module;
|
||||
|
||||
constructor(_value: RSModuleValue.squiggleValue_Module) {
|
||||
this._value = _value;
|
||||
}
|
||||
}
|
103
packages/squiggle-lang/src/js/PointSetDist.ts
Normal file
103
packages/squiggle-lang/src/js/PointSetDist.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
import * as _ from "lodash";
|
||||
import * as RSPointSetDist from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution.gen";
|
||||
import { pointSetDistributionTag as Tag } from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution_tag";
|
||||
|
||||
type T = RSPointSetDist.pointSetDistribution;
|
||||
|
||||
export type point = { x: number; y: number };
|
||||
type shape = {
|
||||
continuous: point[];
|
||||
discrete: point[];
|
||||
};
|
||||
|
||||
const shapePoints = (
|
||||
x: RSPointSetDist.continuousShape | RSPointSetDist.discreteShape
|
||||
): point[] => {
|
||||
let xs = x.xyShape.xs;
|
||||
let ys = x.xyShape.ys;
|
||||
return _.zipWith(xs, ys, (x, y) => ({ x, y }));
|
||||
};
|
||||
|
||||
export const wrapPointSetDist = (value: T) => {
|
||||
const tag = RSPointSetDist.getTag(value);
|
||||
|
||||
return new tagToClass[tag](value);
|
||||
};
|
||||
|
||||
abstract class AbstractPointSetDist {
|
||||
_value: T;
|
||||
|
||||
constructor(_value: T) {
|
||||
this._value = _value;
|
||||
}
|
||||
|
||||
abstract asShape(): shape;
|
||||
}
|
||||
|
||||
const valueMethod = <IR>(
|
||||
_this: AbstractPointSetDist,
|
||||
rsMethod: (v: T) => IR | null | undefined
|
||||
) => {
|
||||
const value = rsMethod(_this._value);
|
||||
if (!value) throw new Error("Internal casting error");
|
||||
return value;
|
||||
};
|
||||
|
||||
export class MixedPointSetDist extends AbstractPointSetDist {
|
||||
tag = Tag.PstMixed as const;
|
||||
|
||||
get value(): RSPointSetDist.mixedShape {
|
||||
return valueMethod(this, RSPointSetDist.getMixed);
|
||||
}
|
||||
|
||||
asShape() {
|
||||
const v = this.value;
|
||||
return {
|
||||
discrete: shapePoints(v.discrete),
|
||||
continuous: shapePoints(v.continuous),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class DiscretePointSetDist extends AbstractPointSetDist {
|
||||
tag = Tag.PstDiscrete as const;
|
||||
|
||||
get value(): RSPointSetDist.discreteShape {
|
||||
return valueMethod(this, RSPointSetDist.getDiscrete);
|
||||
}
|
||||
|
||||
asShape() {
|
||||
const v = this.value;
|
||||
return {
|
||||
discrete: shapePoints(v),
|
||||
continuous: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class ContinuousPointSetDist extends AbstractPointSetDist {
|
||||
tag = Tag.PstContinuous as const;
|
||||
|
||||
get value(): RSPointSetDist.continuousShape {
|
||||
return valueMethod(this, RSPointSetDist.getContinues);
|
||||
}
|
||||
|
||||
asShape() {
|
||||
const v = this.value;
|
||||
return {
|
||||
discrete: [],
|
||||
continuous: shapePoints(v),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const tagToClass = {
|
||||
[Tag.PstMixed]: MixedPointSetDist,
|
||||
[Tag.PstDiscrete]: DiscretePointSetDist,
|
||||
[Tag.PstContinuous]: ContinuousPointSetDist,
|
||||
} as const;
|
||||
|
||||
export type PointSetDist =
|
||||
| MixedPointSetDist
|
||||
| DiscretePointSetDist
|
||||
| ContinuousPointSetDist;
|
112
packages/squiggle-lang/src/js/Project.ts
Normal file
112
packages/squiggle-lang/src/js/Project.ts
Normal file
|
@ -0,0 +1,112 @@
|
|||
import * as RSProject from "../rescript/ForTS/ForTS_ReducerProject.gen";
|
||||
import { reducerErrorValue } from "../rescript/ForTS/ForTS_Reducer_ErrorValue.gen";
|
||||
import { environment } from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Environment.gen";
|
||||
import { ErrorValue } from "./ErrorValue";
|
||||
import { NameSpace as NameSpace } from "./NameSpace";
|
||||
import { wrapSquiggleValue } from "./SquiggleValue";
|
||||
import { resultMap2 } from "./types";
|
||||
|
||||
export class Project {
|
||||
_value: RSProject.reducerProject;
|
||||
|
||||
constructor(_value: RSProject.reducerProject) {
|
||||
this._value = _value;
|
||||
}
|
||||
|
||||
static create() {
|
||||
return new Project(RSProject.createProject());
|
||||
}
|
||||
|
||||
getSourceIds() {
|
||||
return RSProject.getSourceIds(this._value);
|
||||
}
|
||||
|
||||
setSource(sourceId: string, value: string) {
|
||||
return RSProject.setSource(this._value, sourceId, value);
|
||||
}
|
||||
|
||||
getSource(sourceId: string) {
|
||||
return RSProject.getSource(this._value, sourceId);
|
||||
}
|
||||
|
||||
touchSource(sourceId: string) {
|
||||
return RSProject.touchSource(this._value, sourceId);
|
||||
}
|
||||
|
||||
clean(sourceId: string) {
|
||||
return RSProject.clean(this._value, sourceId);
|
||||
}
|
||||
|
||||
cleanAll() {
|
||||
return RSProject.cleanAll(this._value);
|
||||
}
|
||||
|
||||
cleanResults(sourceId: string) {
|
||||
return RSProject.cleanResults(this._value, sourceId);
|
||||
}
|
||||
|
||||
cleanAllResults() {
|
||||
return RSProject.cleanAllResults(this._value);
|
||||
}
|
||||
|
||||
getIncludes(sourceId: string) {
|
||||
return resultMap2(
|
||||
RSProject.getIncludes(this._value, sourceId),
|
||||
(a) => a,
|
||||
(v: reducerErrorValue) => new ErrorValue(v)
|
||||
);
|
||||
}
|
||||
|
||||
getContinues(sourceId: string) {
|
||||
return RSProject.getContinues(this._value, sourceId);
|
||||
}
|
||||
|
||||
setContinues(sourceId: string, continues: string[]) {
|
||||
return RSProject.setContinues(this._value, sourceId, continues);
|
||||
}
|
||||
|
||||
getDependencies(sourceId: string) {
|
||||
return RSProject.getDependencies(this._value, sourceId);
|
||||
}
|
||||
|
||||
getDependents(sourceId: string) {
|
||||
return RSProject.getDependents(this._value, sourceId);
|
||||
}
|
||||
|
||||
getRunOrder() {
|
||||
return RSProject.getRunOrder(this._value);
|
||||
}
|
||||
|
||||
getRunOrderFor(sourceId: string) {
|
||||
return RSProject.getRunOrderFor(this._value, sourceId);
|
||||
}
|
||||
|
||||
parseIncludes(sourceId: string) {
|
||||
return RSProject.parseIncludes(this._value, sourceId);
|
||||
}
|
||||
|
||||
run(sourceId: string) {
|
||||
return RSProject.run(this._value, sourceId);
|
||||
}
|
||||
|
||||
runAll() {
|
||||
return RSProject.runAll(this._value);
|
||||
}
|
||||
|
||||
getBindings(sourceId: string) {
|
||||
return new NameSpace(RSProject.getBindings(this._value, sourceId));
|
||||
}
|
||||
|
||||
getResult(sourceId: string) {
|
||||
const innerResult = RSProject.getResult(this._value, sourceId);
|
||||
return resultMap2(
|
||||
innerResult,
|
||||
wrapSquiggleValue,
|
||||
(v: reducerErrorValue) => new ErrorValue(v)
|
||||
);
|
||||
}
|
||||
|
||||
setEnvironment(environment: environment) {
|
||||
RSProject.setEnvironment(this._value, environment);
|
||||
}
|
||||
}
|
18
packages/squiggle-lang/src/js/Record.ts
Normal file
18
packages/squiggle-lang/src/js/Record.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import * as RSRecord from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Record.gen";
|
||||
import { AbstractSquiggleValue, wrapSquiggleValue } from "./SquiggleValue";
|
||||
|
||||
type T = RSRecord.squiggleValue_Record;
|
||||
|
||||
export class Record {
|
||||
_value: T;
|
||||
|
||||
constructor(_value: T) {
|
||||
this._value = _value;
|
||||
}
|
||||
|
||||
entries() {
|
||||
return RSRecord.getKeyValuePairs(this._value).map(
|
||||
([k, v]) => [k, wrapSquiggleValue(v)] as const
|
||||
);
|
||||
}
|
||||
}
|
16
packages/squiggle-lang/src/js/SquiggleArray.ts
Normal file
16
packages/squiggle-lang/src/js/SquiggleArray.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import * as RSArray from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Array.gen";
|
||||
import { AbstractSquiggleValue, wrapSquiggleValue } from "./SquiggleValue";
|
||||
|
||||
type T = RSArray.squiggleValue_Array;
|
||||
|
||||
export class SquiggleArray {
|
||||
_value: T;
|
||||
|
||||
constructor(_value: T) {
|
||||
this._value = _value;
|
||||
}
|
||||
|
||||
getValues() {
|
||||
return RSArray.getValues(this._value).map(wrapSquiggleValue);
|
||||
}
|
||||
}
|
212
packages/squiggle-lang/src/js/SquiggleValue.ts
Normal file
212
packages/squiggle-lang/src/js/SquiggleValue.ts
Normal file
|
@ -0,0 +1,212 @@
|
|||
import * as RSSquiggleValue from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue.gen";
|
||||
import { squiggleValueTag as Tag } from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_tag";
|
||||
import { Distribution, wrapDistribution } from "./Distribution";
|
||||
import { Lambda } from "./Lambda";
|
||||
import { LambdaDeclaration } from "./LambdaDeclaration";
|
||||
import { NameSpace } from "./NameSpace";
|
||||
import { Record } from "./Record";
|
||||
import { SquiggleArray } from "./SquiggleArray";
|
||||
import { Type } from "./Type";
|
||||
|
||||
export { Tag };
|
||||
|
||||
type T = RSSquiggleValue.squiggleValue;
|
||||
|
||||
export const wrapSquiggleValue = (value: T): SquiggleValue => {
|
||||
const tag = RSSquiggleValue.getTag(value);
|
||||
|
||||
return new tagToClass[tag](value);
|
||||
};
|
||||
|
||||
export abstract class AbstractSquiggleValue {
|
||||
abstract tag: Tag;
|
||||
_value: T;
|
||||
|
||||
constructor(value: T) {
|
||||
this._value = value;
|
||||
}
|
||||
}
|
||||
|
||||
const valueMethod = <IR>(
|
||||
_this: AbstractSquiggleValue,
|
||||
rsMethod: (v: T) => IR | null | undefined
|
||||
) => {
|
||||
const value = rsMethod(_this._value);
|
||||
if (!value) throw new Error("Internal casting error");
|
||||
return value;
|
||||
};
|
||||
|
||||
export class ArrayValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtArray as const;
|
||||
|
||||
get value() {
|
||||
return new SquiggleArray(valueMethod(this, RSSquiggleValue.getArray));
|
||||
}
|
||||
}
|
||||
|
||||
export class ArrayStringValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtArrayString as const;
|
||||
|
||||
get value() {
|
||||
return valueMethod(this, RSSquiggleValue.getArrayString);
|
||||
}
|
||||
}
|
||||
|
||||
export class BoolValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtBool as const;
|
||||
|
||||
get value() {
|
||||
return valueMethod(this, RSSquiggleValue.getBool);
|
||||
}
|
||||
}
|
||||
|
||||
export class CallValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtCall as const;
|
||||
|
||||
get value() {
|
||||
return valueMethod(this, RSSquiggleValue.getCall);
|
||||
}
|
||||
}
|
||||
|
||||
export class DateValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtDate as const;
|
||||
|
||||
get value() {
|
||||
return valueMethod(this, RSSquiggleValue.getDate);
|
||||
}
|
||||
}
|
||||
|
||||
export class DeclarationValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtDeclaration as const;
|
||||
|
||||
get value() {
|
||||
return new LambdaDeclaration(
|
||||
valueMethod(this, RSSquiggleValue.getDeclaration)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class DistributionValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtDistribution as const;
|
||||
|
||||
get value() {
|
||||
return wrapDistribution(valueMethod(this, RSSquiggleValue.getDistribution));
|
||||
}
|
||||
}
|
||||
|
||||
export class LambdaValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtLambda as const;
|
||||
|
||||
get value() {
|
||||
return new Lambda(valueMethod(this, RSSquiggleValue.getLambda));
|
||||
}
|
||||
}
|
||||
|
||||
export class ModuleValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtModule as const;
|
||||
|
||||
get value() {
|
||||
return new NameSpace(valueMethod(this, RSSquiggleValue.getModule));
|
||||
}
|
||||
}
|
||||
|
||||
export class NumberValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtNumber as const;
|
||||
|
||||
get value() {
|
||||
return valueMethod(this, RSSquiggleValue.getNumber);
|
||||
}
|
||||
}
|
||||
|
||||
export class RecordValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtRecord as const;
|
||||
|
||||
get value() {
|
||||
return new Record(valueMethod(this, RSSquiggleValue.getRecord));
|
||||
}
|
||||
}
|
||||
|
||||
export class StringValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtString as const;
|
||||
|
||||
get value(): string {
|
||||
return valueMethod(this, RSSquiggleValue.getString);
|
||||
}
|
||||
}
|
||||
|
||||
export class SymbolValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtSymbol as const;
|
||||
|
||||
get value(): string {
|
||||
return valueMethod(this, RSSquiggleValue.getSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
export class TimeDurationValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtTimeDuration as const;
|
||||
|
||||
get value() {
|
||||
return valueMethod(this, RSSquiggleValue.getTimeDuration);
|
||||
}
|
||||
}
|
||||
|
||||
export class TypeValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtType as const;
|
||||
|
||||
get value() {
|
||||
return new Type(valueMethod(this, RSSquiggleValue.getType));
|
||||
}
|
||||
}
|
||||
|
||||
export class TypeIdentifierValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtTypeIdentifier as const;
|
||||
|
||||
get value() {
|
||||
return valueMethod(this, RSSquiggleValue.getTypeIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
export class VoidValue extends AbstractSquiggleValue {
|
||||
tag = Tag.SvtVoid as const;
|
||||
}
|
||||
|
||||
const tagToClass = {
|
||||
[Tag.SvtArray]: ArrayValue,
|
||||
[Tag.SvtArrayString]: ArrayStringValue,
|
||||
[Tag.SvtBool]: BoolValue,
|
||||
[Tag.SvtCall]: CallValue,
|
||||
[Tag.SvtDate]: DateValue,
|
||||
[Tag.SvtDeclaration]: DeclarationValue,
|
||||
[Tag.SvtDistribution]: DistributionValue,
|
||||
[Tag.SvtLambda]: LambdaValue,
|
||||
[Tag.SvtModule]: ModuleValue,
|
||||
[Tag.SvtNumber]: NumberValue,
|
||||
[Tag.SvtRecord]: RecordValue,
|
||||
[Tag.SvtString]: StringValue,
|
||||
[Tag.SvtSymbol]: SymbolValue,
|
||||
[Tag.SvtTimeDuration]: TimeDurationValue,
|
||||
[Tag.SvtType]: TypeValue,
|
||||
[Tag.SvtTypeIdentifier]: TypeIdentifierValue,
|
||||
[Tag.SvtVoid]: VoidValue,
|
||||
} as const;
|
||||
|
||||
// FIXME
|
||||
// type AnySquiggleValue = typeof tagToClass[keyof typeof tagToClass];
|
||||
export type SquiggleValue =
|
||||
| ArrayValue
|
||||
| ArrayStringValue
|
||||
| BoolValue
|
||||
| CallValue
|
||||
| DateValue
|
||||
| DeclarationValue
|
||||
| DistributionValue
|
||||
| LambdaValue
|
||||
| ModuleValue
|
||||
| NumberValue
|
||||
| RecordValue
|
||||
| StringValue
|
||||
| SymbolValue
|
||||
| TimeDurationValue
|
||||
| TypeValue
|
||||
| TypeIdentifierValue
|
||||
| VoidValue;
|
11
packages/squiggle-lang/src/js/Type.ts
Normal file
11
packages/squiggle-lang/src/js/Type.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import * as RSType from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Type.gen";
|
||||
|
||||
type T = RSType.squiggleValue_Type;
|
||||
|
||||
export class Type {
|
||||
_value: T;
|
||||
|
||||
constructor(_value: T) {
|
||||
this._value = _value;
|
||||
}
|
||||
}
|
|
@ -1,252 +1,93 @@
|
|||
import * as _ from "lodash";
|
||||
import {
|
||||
genericDist,
|
||||
continuousShape,
|
||||
discreteShape,
|
||||
environment,
|
||||
distributionError,
|
||||
toPointSet,
|
||||
distributionErrorToString,
|
||||
} from "../rescript/TypescriptInterface.gen";
|
||||
import { result, resultMap, Ok } from "./types";
|
||||
import {
|
||||
Constructors_mean,
|
||||
Constructors_stdev,
|
||||
Constructors_sample,
|
||||
Constructors_pdf,
|
||||
Constructors_cdf,
|
||||
Constructors_inv,
|
||||
Constructors_normalize,
|
||||
Constructors_isNormalized,
|
||||
Constructors_toPointSet,
|
||||
Constructors_toSampleSet,
|
||||
Constructors_truncate,
|
||||
Constructors_inspect,
|
||||
Constructors_toString,
|
||||
Constructors_toSparkline,
|
||||
Constructors_algebraicAdd,
|
||||
Constructors_algebraicMultiply,
|
||||
Constructors_algebraicDivide,
|
||||
Constructors_algebraicSubtract,
|
||||
Constructors_algebraicLogarithm,
|
||||
Constructors_algebraicPower,
|
||||
Constructors_pointwiseAdd,
|
||||
Constructors_pointwiseMultiply,
|
||||
Constructors_pointwiseDivide,
|
||||
Constructors_pointwiseSubtract,
|
||||
Constructors_pointwiseLogarithm,
|
||||
Constructors_pointwisePower,
|
||||
} from "../rescript/Distributions/DistributionOperation.gen";
|
||||
import * as RSDistribution from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution.gen";
|
||||
import { distributionTag as Tag } from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_tag";
|
||||
import { DistributionError } from "./DistributionError";
|
||||
import { wrapPointSetDist } from "./PointSetDist";
|
||||
import { resultMap2 } from "./types";
|
||||
|
||||
export type point = { x: number; y: number };
|
||||
type T = RSDistribution.distribution;
|
||||
export { Tag };
|
||||
|
||||
function shapePoints(x: continuousShape | discreteShape): point[] {
|
||||
let xs = x.xyShape.xs;
|
||||
let ys = x.xyShape.ys;
|
||||
return _.zipWith(xs, ys, (x, y) => ({ x, y }));
|
||||
}
|
||||
export type shape = {
|
||||
continuous: point[];
|
||||
discrete: point[];
|
||||
export const wrapDistribution = (value: T): Distribution => {
|
||||
const tag = RSDistribution.getTag(value);
|
||||
|
||||
return new tagToClass[tag](value);
|
||||
};
|
||||
|
||||
export class Distribution {
|
||||
t: genericDist;
|
||||
env: environment;
|
||||
abstract class AbstractDistribution {
|
||||
abstract tag: Tag;
|
||||
_value: T;
|
||||
|
||||
constructor(t: genericDist, env: environment) {
|
||||
this.t = t;
|
||||
this.env = env;
|
||||
return this;
|
||||
constructor(value: T) {
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
mapResultDist(
|
||||
r: result<genericDist, distributionError>
|
||||
): result<Distribution, distributionError> {
|
||||
return resultMap(r, (v: genericDist) => new Distribution(v, this.env));
|
||||
}
|
||||
|
||||
mean(): result<number, distributionError> {
|
||||
return Constructors_mean({ env: this.env }, this.t);
|
||||
}
|
||||
|
||||
stdev(): result<number, distributionError> {
|
||||
return Constructors_stdev({ env: this.env }, this.t);
|
||||
}
|
||||
|
||||
sample(): result<number, distributionError> {
|
||||
return Constructors_sample({ env: this.env }, this.t);
|
||||
}
|
||||
|
||||
pdf(n: number): result<number, distributionError> {
|
||||
return Constructors_pdf({ env: this.env }, this.t, n);
|
||||
}
|
||||
|
||||
cdf(n: number): result<number, distributionError> {
|
||||
return Constructors_cdf({ env: this.env }, this.t, n);
|
||||
}
|
||||
|
||||
inv(n: number): result<number, distributionError> {
|
||||
return Constructors_inv({ env: this.env }, this.t, n);
|
||||
}
|
||||
|
||||
isNormalized(): result<boolean, distributionError> {
|
||||
return Constructors_isNormalized({ env: this.env }, this.t);
|
||||
}
|
||||
|
||||
normalize(): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_normalize({ env: this.env }, this.t)
|
||||
pointSet() {
|
||||
const env: any = "TODO";
|
||||
const innerResult = RSDistribution.toPointSet(this._value, env);
|
||||
return resultMap2(
|
||||
innerResult,
|
||||
wrapPointSetDist,
|
||||
(v: RSDistribution.distributionError) => new DistributionError(v)
|
||||
);
|
||||
}
|
||||
|
||||
type() {
|
||||
return this.t.tag;
|
||||
toString() {
|
||||
RSDistribution.toString(this._value);
|
||||
}
|
||||
|
||||
pointSet(): result<shape, distributionError> {
|
||||
let pointSet = toPointSet(
|
||||
this.t,
|
||||
{
|
||||
xyPointLength: this.env.xyPointLength,
|
||||
sampleCount: this.env.sampleCount,
|
||||
},
|
||||
undefined
|
||||
);
|
||||
if (pointSet.tag === "Ok") {
|
||||
let distribution = pointSet.value;
|
||||
if (distribution.tag === "Continuous") {
|
||||
return Ok({
|
||||
continuous: shapePoints(distribution.value),
|
||||
discrete: [],
|
||||
});
|
||||
} else if (distribution.tag === "Discrete") {
|
||||
return Ok({
|
||||
discrete: shapePoints(distribution.value),
|
||||
continuous: [],
|
||||
});
|
||||
} else {
|
||||
return Ok({
|
||||
discrete: shapePoints(distribution.value.discrete),
|
||||
continuous: shapePoints(distribution.value.continuous),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return pointSet;
|
||||
}
|
||||
mean() {
|
||||
return RSDistribution.mean(this._value);
|
||||
}
|
||||
|
||||
toPointSet(): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_toPointSet({ env: this.env }, this.t)
|
||||
);
|
||||
inv(n: number) {
|
||||
return RSDistribution.inv(this._value, n);
|
||||
}
|
||||
|
||||
toSampleSet(n: number): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_toSampleSet({ env: this.env }, this.t, n)
|
||||
);
|
||||
}
|
||||
|
||||
truncate(
|
||||
left: number,
|
||||
right: number
|
||||
): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_truncate({ env: this.env }, this.t, left, right)
|
||||
);
|
||||
}
|
||||
|
||||
inspect(): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(Constructors_inspect({ env: this.env }, this.t));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
let result = Constructors_toString({ env: this.env }, this.t);
|
||||
if (result.tag === "Ok") {
|
||||
return result.value;
|
||||
} else {
|
||||
return distributionErrorToString(result.value);
|
||||
}
|
||||
}
|
||||
|
||||
toSparkline(n: number): result<string, distributionError> {
|
||||
return Constructors_toSparkline({ env: this.env }, this.t, n);
|
||||
}
|
||||
|
||||
algebraicAdd(d2: Distribution): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_algebraicAdd({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
}
|
||||
|
||||
algebraicMultiply(d2: Distribution): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_algebraicMultiply({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
}
|
||||
|
||||
algebraicDivide(d2: Distribution): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_algebraicDivide({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
}
|
||||
|
||||
algebraicSubtract(d2: Distribution): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_algebraicSubtract({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
}
|
||||
|
||||
algebraicLogarithm(
|
||||
d2: Distribution
|
||||
): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_algebraicLogarithm({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
}
|
||||
|
||||
algebraicPower(d2: Distribution): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_algebraicPower({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
}
|
||||
|
||||
pointwiseAdd(d2: Distribution): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_pointwiseAdd({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
}
|
||||
|
||||
pointwiseMultiply(d2: Distribution): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_pointwiseMultiply({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
}
|
||||
|
||||
pointwiseDivide(d2: Distribution): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_pointwiseDivide({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
}
|
||||
|
||||
pointwiseSubtract(d2: Distribution): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_pointwiseSubtract({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
}
|
||||
|
||||
pointwiseLogarithm(
|
||||
d2: Distribution
|
||||
): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_pointwiseLogarithm({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
}
|
||||
|
||||
pointwisePower(d2: Distribution): result<Distribution, distributionError> {
|
||||
return this.mapResultDist(
|
||||
Constructors_pointwisePower({ env: this.env }, this.t, d2.t)
|
||||
);
|
||||
stdev() {
|
||||
return RSDistribution.stdev(this._value);
|
||||
}
|
||||
}
|
||||
|
||||
const valueMethod = <IR>(
|
||||
_this: AbstractDistribution,
|
||||
rsMethod: (v: T) => IR | null | undefined
|
||||
) => {
|
||||
const value = rsMethod(_this._value);
|
||||
if (!value) throw new Error("Internal casting error");
|
||||
return value;
|
||||
};
|
||||
|
||||
export class PointSetDistribution extends AbstractDistribution {
|
||||
tag = Tag.DtPointSet;
|
||||
|
||||
value() {
|
||||
return valueMethod(this, RSDistribution.getPointSet);
|
||||
}
|
||||
}
|
||||
|
||||
export class SampleSetDistribution extends AbstractDistribution {
|
||||
tag = Tag.DtSampleSet;
|
||||
|
||||
value() {
|
||||
return valueMethod(this, RSDistribution.getSampleSet);
|
||||
}
|
||||
}
|
||||
|
||||
export class SymbolicDistribution extends AbstractDistribution {
|
||||
tag = Tag.DtSymbolic;
|
||||
|
||||
value() {
|
||||
return valueMethod(this, RSDistribution.getSymbolic);
|
||||
}
|
||||
}
|
||||
|
||||
const tagToClass = {
|
||||
[Tag.DtPointSet]: PointSetDistribution,
|
||||
[Tag.DtSampleSet]: SampleSetDistribution,
|
||||
[Tag.DtSymbolic]: SymbolicDistribution,
|
||||
} as const;
|
||||
|
||||
export type Distribution =
|
||||
| PointSetDistribution
|
||||
| SampleSetDistribution
|
||||
| SymbolicDistribution;
|
||||
|
|
|
@ -10,54 +10,87 @@ Instead of a global function namespace we should use modules under ForTS directl
|
|||
|
||||
*/
|
||||
|
||||
import * as _ from "lodash";
|
||||
import type {
|
||||
environment,
|
||||
expressionValue,
|
||||
externalBindings,
|
||||
errorValue,
|
||||
} from "../rescript/TypescriptInterface.gen";
|
||||
import {
|
||||
defaultEnvironment,
|
||||
evaluatePartialUsingExternalBindings,
|
||||
evaluateUsingOptions,
|
||||
foreignFunctionInterface,
|
||||
} from "../rescript/TypescriptInterface.gen";
|
||||
import { environment } from "../rescript/ForTS/ForTS_ReducerProject.gen";
|
||||
import { Project } from "./Project";
|
||||
import { SquiggleValue, Tag as SquiggleValueTag } from "./SquiggleValue";
|
||||
export { result } from "../rescript/ForTS/ForTS_Result_tag";
|
||||
export { Project, SquiggleValue };
|
||||
export { Distribution, Tag as DistributionTag } from "./Distribution";
|
||||
export { DistributionError } from "./DistributionError";
|
||||
export { Record as SquiggleRecord } from "./Record";
|
||||
export { SquiggleValueTag };
|
||||
export {
|
||||
makeSampleSetDist,
|
||||
errorValueToString,
|
||||
distributionErrorToString,
|
||||
} from "../rescript/TypescriptInterface.gen";
|
||||
export type {
|
||||
distributionError,
|
||||
declarationArg,
|
||||
declaration,
|
||||
} from "../rescript/TypescriptInterface.gen";
|
||||
export type { errorValue, externalBindings as bindings, jsImports };
|
||||
import {
|
||||
jsValueToBinding,
|
||||
jsValueToExpressionValue,
|
||||
jsValue,
|
||||
rescriptExport,
|
||||
squiggleExpression,
|
||||
convertRawToTypescript,
|
||||
lambdaValue,
|
||||
} from "./rescript_interop";
|
||||
import { result, resultMap, tag, tagged } from "./types";
|
||||
import { Distribution, shape } from "./distribution";
|
||||
environment,
|
||||
defaultEnvironment,
|
||||
} from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution.gen";
|
||||
export { ErrorValue } from "./ErrorValue";
|
||||
export { resultMap } from "./types";
|
||||
|
||||
export { Distribution, resultMap, defaultEnvironment };
|
||||
export type { result, shape, environment, lambdaValue, squiggleExpression };
|
||||
// import * as _ from "lodash";
|
||||
// import type {
|
||||
// environment,
|
||||
// expressionValue,
|
||||
// externalBindings,
|
||||
// errorValue,
|
||||
// } from "../rescript/TypescriptInterface.gen";
|
||||
// import {
|
||||
// defaultEnvironment,
|
||||
// evaluatePartialUsingExternalBindings,
|
||||
// evaluateUsingOptions,
|
||||
// foreignFunctionInterface,
|
||||
// } from "../rescript/TypescriptInterface.gen";
|
||||
// export {
|
||||
// makeSampleSetDist,
|
||||
// errorValueToString,
|
||||
// distributionErrorToString,
|
||||
// } from "../rescript/TypescriptInterface.gen";
|
||||
// export type {
|
||||
// distributionError,
|
||||
// declarationArg,
|
||||
// declaration,
|
||||
// } from "../rescript/TypescriptInterface.gen";
|
||||
// export type { errorValue, externalBindings as bindings, jsImports };
|
||||
// import {
|
||||
// jsValueToBinding,
|
||||
// jsValueToExpressionValue,
|
||||
// jsValue,
|
||||
// rescriptExport,
|
||||
// squiggleExpression,
|
||||
// convertRawToTypescript,
|
||||
// lambdaValue,
|
||||
// } from "./rescript_interop";
|
||||
// import { result, resultMap, tag, tagged } from "./types";
|
||||
// import { Distribution, shape } from "./distribution";
|
||||
|
||||
export { parse } from "./parse";
|
||||
// export { Distribution, resultMap, defaultEnvironment };
|
||||
// export type { result, shape, environment, lambdaValue, squiggleExpression };
|
||||
|
||||
export let defaultSamplingInputs: environment = {
|
||||
sampleCount: 10000,
|
||||
xyPointLength: 10000,
|
||||
};
|
||||
// export { parse } from "./parse";
|
||||
|
||||
// export let defaultSamplingInputs: environment = {
|
||||
// sampleCount: 10000,
|
||||
// xyPointLength: 10000,
|
||||
// };
|
||||
|
||||
/* Umur: All the functions below are invalid. ForTS_Reducer project is the new way to do this. */
|
||||
|
||||
export const run = (
|
||||
code: string,
|
||||
options?: {
|
||||
environment?: environment;
|
||||
}
|
||||
) => {
|
||||
const project = Project.create();
|
||||
project.setSource("main", code);
|
||||
if (options?.environment) {
|
||||
project.setEnvironment(options.environment);
|
||||
}
|
||||
project.run("main");
|
||||
const result = project.getResult("main");
|
||||
const bindings = project.getBindings("main");
|
||||
return { result, bindings };
|
||||
};
|
||||
|
||||
// export function run(
|
||||
// squiggleString: string,
|
||||
// bindings?: externalBindings,
|
||||
|
|
252
packages/squiggle-lang/src/js/oldDistribution.ts
Normal file
252
packages/squiggle-lang/src/js/oldDistribution.ts
Normal file
|
@ -0,0 +1,252 @@
|
|||
// import * as _ from "lodash";
|
||||
// import {
|
||||
// genericDist,
|
||||
// continuousShape,
|
||||
// discreteShape,
|
||||
// environment,
|
||||
// distributionError,
|
||||
// toPointSet,
|
||||
// distributionErrorToString,
|
||||
// } from "../rescript/TypescriptInterface.gen";
|
||||
// import { result, resultMap, Ok } from "./types";
|
||||
// import {
|
||||
// Constructors_mean,
|
||||
// Constructors_stdev,
|
||||
// Constructors_sample,
|
||||
// Constructors_pdf,
|
||||
// Constructors_cdf,
|
||||
// Constructors_inv,
|
||||
// Constructors_normalize,
|
||||
// Constructors_isNormalized,
|
||||
// Constructors_toPointSet,
|
||||
// Constructors_toSampleSet,
|
||||
// Constructors_truncate,
|
||||
// Constructors_inspect,
|
||||
// Constructors_toString,
|
||||
// Constructors_toSparkline,
|
||||
// Constructors_algebraicAdd,
|
||||
// Constructors_algebraicMultiply,
|
||||
// Constructors_algebraicDivide,
|
||||
// Constructors_algebraicSubtract,
|
||||
// Constructors_algebraicLogarithm,
|
||||
// Constructors_algebraicPower,
|
||||
// Constructors_pointwiseAdd,
|
||||
// Constructors_pointwiseMultiply,
|
||||
// Constructors_pointwiseDivide,
|
||||
// Constructors_pointwiseSubtract,
|
||||
// Constructors_pointwiseLogarithm,
|
||||
// Constructors_pointwisePower,
|
||||
// } from "../rescript/Distributions/DistributionOperation.gen";
|
||||
|
||||
// export type point = { x: number; y: number };
|
||||
|
||||
// function shapePoints(x: continuousShape | discreteShape): point[] {
|
||||
// let xs = x.xyShape.xs;
|
||||
// let ys = x.xyShape.ys;
|
||||
// return _.zipWith(xs, ys, (x, y) => ({ x, y }));
|
||||
// }
|
||||
// export type shape = {
|
||||
// continuous: point[];
|
||||
// discrete: point[];
|
||||
// };
|
||||
|
||||
// export class Distribution {
|
||||
// t: genericDist;
|
||||
// env: environment;
|
||||
|
||||
// constructor(t: genericDist, env: environment) {
|
||||
// this.t = t;
|
||||
// this.env = env;
|
||||
// return this;
|
||||
// }
|
||||
|
||||
// mapResultDist(
|
||||
// r: result<genericDist, distributionError>
|
||||
// ): result<Distribution, distributionError> {
|
||||
// return resultMap(r, (v: genericDist) => new Distribution(v, this.env));
|
||||
// }
|
||||
|
||||
// mean(): result<number, distributionError> {
|
||||
// return Constructors_mean({ env: this.env }, this.t);
|
||||
// }
|
||||
|
||||
// stdev(): result<number, distributionError> {
|
||||
// return Constructors_stdev({ env: this.env }, this.t);
|
||||
// }
|
||||
|
||||
// sample(): result<number, distributionError> {
|
||||
// return Constructors_sample({ env: this.env }, this.t);
|
||||
// }
|
||||
|
||||
// pdf(n: number): result<number, distributionError> {
|
||||
// return Constructors_pdf({ env: this.env }, this.t, n);
|
||||
// }
|
||||
|
||||
// cdf(n: number): result<number, distributionError> {
|
||||
// return Constructors_cdf({ env: this.env }, this.t, n);
|
||||
// }
|
||||
|
||||
// inv(n: number): result<number, distributionError> {
|
||||
// return Constructors_inv({ env: this.env }, this.t, n);
|
||||
// }
|
||||
|
||||
// isNormalized(): result<boolean, distributionError> {
|
||||
// return Constructors_isNormalized({ env: this.env }, this.t);
|
||||
// }
|
||||
|
||||
// normalize(): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_normalize({ env: this.env }, this.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// type() {
|
||||
// return this.t.tag;
|
||||
// }
|
||||
|
||||
// pointSet(): result<shape, distributionError> {
|
||||
// let pointSet = toPointSet(
|
||||
// this.t,
|
||||
// {
|
||||
// xyPointLength: this.env.xyPointLength,
|
||||
// sampleCount: this.env.sampleCount,
|
||||
// },
|
||||
// undefined
|
||||
// );
|
||||
// if (pointSet.tag === "Ok") {
|
||||
// let distribution = pointSet.value;
|
||||
// if (distribution.tag === "Continuous") {
|
||||
// return Ok({
|
||||
// continuous: shapePoints(distribution.value),
|
||||
// discrete: [],
|
||||
// });
|
||||
// } else if (distribution.tag === "Discrete") {
|
||||
// return Ok({
|
||||
// discrete: shapePoints(distribution.value),
|
||||
// continuous: [],
|
||||
// });
|
||||
// } else {
|
||||
// return Ok({
|
||||
// discrete: shapePoints(distribution.value.discrete),
|
||||
// continuous: shapePoints(distribution.value.continuous),
|
||||
// });
|
||||
// }
|
||||
// } else {
|
||||
// return pointSet;
|
||||
// }
|
||||
// }
|
||||
|
||||
// toPointSet(): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_toPointSet({ env: this.env }, this.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// toSampleSet(n: number): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_toSampleSet({ env: this.env }, this.t, n)
|
||||
// );
|
||||
// }
|
||||
|
||||
// truncate(
|
||||
// left: number,
|
||||
// right: number
|
||||
// ): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_truncate({ env: this.env }, this.t, left, right)
|
||||
// );
|
||||
// }
|
||||
|
||||
// inspect(): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(Constructors_inspect({ env: this.env }, this.t));
|
||||
// }
|
||||
|
||||
// toString(): string {
|
||||
// let result = Constructors_toString({ env: this.env }, this.t);
|
||||
// if (result.tag === "Ok") {
|
||||
// return result.value;
|
||||
// } else {
|
||||
// return distributionErrorToString(result.value);
|
||||
// }
|
||||
// }
|
||||
|
||||
// toSparkline(n: number): result<string, distributionError> {
|
||||
// return Constructors_toSparkline({ env: this.env }, this.t, n);
|
||||
// }
|
||||
|
||||
// algebraicAdd(d2: Distribution): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_algebraicAdd({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// algebraicMultiply(d2: Distribution): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_algebraicMultiply({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// algebraicDivide(d2: Distribution): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_algebraicDivide({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// algebraicSubtract(d2: Distribution): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_algebraicSubtract({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// algebraicLogarithm(
|
||||
// d2: Distribution
|
||||
// ): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_algebraicLogarithm({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// algebraicPower(d2: Distribution): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_algebraicPower({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// pointwiseAdd(d2: Distribution): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_pointwiseAdd({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// pointwiseMultiply(d2: Distribution): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_pointwiseMultiply({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// pointwiseDivide(d2: Distribution): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_pointwiseDivide({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// pointwiseSubtract(d2: Distribution): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_pointwiseSubtract({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// pointwiseLogarithm(
|
||||
// d2: Distribution
|
||||
// ): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_pointwiseLogarithm({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
|
||||
// pointwisePower(d2: Distribution): result<Distribution, distributionError> {
|
||||
// return this.mapResultDist(
|
||||
// Constructors_pointwisePower({ env: this.env }, this.t, d2.t)
|
||||
// );
|
||||
// }
|
||||
// }
|
|
@ -1,23 +1,23 @@
|
|||
import {
|
||||
errorValue,
|
||||
parse as parseRescript,
|
||||
} from "../rescript/TypescriptInterface.gen";
|
||||
import { result } from "./types";
|
||||
import { AnyPeggyNode } from "../rescript/Reducer/Reducer_Peggy/helpers";
|
||||
// import {
|
||||
// errorValue,
|
||||
// parse as parseRescript,
|
||||
// } from "../rescript/TypescriptInterface.gen";
|
||||
// import { result } from "./types";
|
||||
// import { AnyPeggyNode } from "../rescript/Reducer/Reducer_Peggy/helpers";
|
||||
|
||||
export function parse(
|
||||
squiggleString: string
|
||||
): result<AnyPeggyNode, Extract<errorValue, { tag: "RESyntaxError" }>> {
|
||||
const maybeExpression = parseRescript(squiggleString);
|
||||
if (maybeExpression.tag === "Ok") {
|
||||
return { tag: "Ok", value: maybeExpression.value as AnyPeggyNode };
|
||||
} else {
|
||||
if (
|
||||
typeof maybeExpression.value !== "object" ||
|
||||
maybeExpression.value.tag !== "RESyntaxError"
|
||||
) {
|
||||
throw new Error("Expected syntax error");
|
||||
}
|
||||
return { tag: "Error", value: maybeExpression.value };
|
||||
}
|
||||
}
|
||||
// export function parse(
|
||||
// squiggleString: string
|
||||
// ): result<AnyPeggyNode, Extract<errorValue, { tag: "RESyntaxError" }>> {
|
||||
// const maybeExpression = parseRescript(squiggleString);
|
||||
// if (maybeExpression.tag === "Ok") {
|
||||
// return { tag: "Ok", value: maybeExpression.value as AnyPeggyNode };
|
||||
// } else {
|
||||
// if (
|
||||
// typeof maybeExpression.value !== "object" ||
|
||||
// maybeExpression.value.tag !== "RESyntaxError"
|
||||
// ) {
|
||||
// throw new Error("Expected syntax error");
|
||||
// }
|
||||
// return { tag: "Error", value: maybeExpression.value };
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -1,21 +1,26 @@
|
|||
export type result<a, b> =
|
||||
| {
|
||||
tag: "Ok";
|
||||
value: a;
|
||||
}
|
||||
| {
|
||||
tag: "Error";
|
||||
value: b;
|
||||
};
|
||||
import { result } from "../rescript/ForTS/ForTS_Result_tag";
|
||||
export { result };
|
||||
|
||||
export function resultMap<a, b, c>(
|
||||
r: result<a, c>,
|
||||
mapFn: (x: a) => b
|
||||
): result<b, c> {
|
||||
r: result<a, b>,
|
||||
mapValue: (x: a) => c
|
||||
): result<c, b> {
|
||||
if (r.tag === "Ok") {
|
||||
return { tag: "Ok", value: mapFn(r.value) };
|
||||
return { tag: "Ok", value: mapValue(r.value) };
|
||||
} else {
|
||||
return r;
|
||||
return { tag: "Error", value: r.value };
|
||||
}
|
||||
}
|
||||
|
||||
export function resultMap2<a, b, c, d>(
|
||||
r: result<a, b>,
|
||||
mapValue: (x: a) => c,
|
||||
mapError: (y: b) => d
|
||||
): result<c, d> {
|
||||
if (r.tag === "Ok") {
|
||||
return { tag: "Ok", value: mapValue(r.value) };
|
||||
} else {
|
||||
return { tag: "Error", value: mapError(r.value) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Genetic Distribution happens to be abstract distribution
|
||||
@genType type distribution = DistributionTypes.genericDist
|
||||
@genType type distributionError = DistributionTypes.error
|
||||
@genType type pointSetDistribution = ForTS_Distribution_PointSetDistribution.pointSetDistribution
|
||||
@genType type sampleSetDistribution = ForTS_Distribution_SampleSetDistribution.sampleSetDistribution
|
||||
@genType type symbolicDistribution = ForTS_Distribution_SymbolicDistribution.symbolicDistribution
|
||||
|
@ -73,3 +74,11 @@ let inv = DistributionOperation.Constructors.inv
|
|||
let pdf = DistributionOperation.Constructors.pdf
|
||||
@genType
|
||||
let normalize = DistributionOperation.Constructors.normalize
|
||||
|
||||
@genType
|
||||
let toPointSet = (variant: distribution, env: environment) =>
|
||||
GenericDist.toPointSet(variant, ~sampleCount=env.sampleCount, ~xyPointLength=env.xyPointLength, ())
|
||||
|
||||
@genType
|
||||
let toString = (variant: distribution) =>
|
||||
GenericDist.toString(variant)
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
@genType type pointSetDistribution = PointSetTypes.pointSetDist
|
||||
@genType type continuousShape = PointSetTypes.continuousShape
|
||||
@genType type discreteShape = PointSetTypes.discreteShape
|
||||
@genType type mixedShape = PointSetTypes.mixedShape
|
||||
|
||||
@module("ForTS_Distribution_PointSetDistribution_tag") @scope("pointSetDistributionTag")
|
||||
external pstMixed_: int = "PstMixed"
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"outDir": "./dist",
|
||||
"declarationDir": "./dist",
|
||||
"declaration": true,
|
||||
"composite": true
|
||||
},
|
||||
"composite": true,
|
||||
"target": "ES6",
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "**/*.spec.ts", "webpack.config.js"]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user