210 lines
5.6 KiB
TypeScript
210 lines
5.6 KiB
TypeScript
import * as _ from "lodash";
|
|
import {
|
|
samplingParams,
|
|
environment,
|
|
defaultEnvironment,
|
|
evaluatePartialUsingExternalBindings,
|
|
evaluateUsingOptions,
|
|
externalBindings,
|
|
expressionValue,
|
|
errorValue,
|
|
distributionError,
|
|
toPointSet,
|
|
continuousShape,
|
|
discreteShape,
|
|
distributionErrorToString,
|
|
internalCode,
|
|
mixedShape,
|
|
sampleSetDist,
|
|
symbolicDist,
|
|
} from "../rescript/TypescriptInterface.gen";
|
|
export {
|
|
makeSampleSetDist,
|
|
errorValueToString,
|
|
distributionErrorToString,
|
|
} from "../rescript/TypescriptInterface.gen";
|
|
export type {
|
|
samplingParams,
|
|
errorValue,
|
|
externalBindings as bindings,
|
|
jsImports,
|
|
};
|
|
import {
|
|
jsValueToBinding,
|
|
jsValue,
|
|
rescriptExport,
|
|
squiggleExpression,
|
|
convertRawToTypescript,
|
|
} from "./rescript_interop";
|
|
import { result, resultMap, tag, tagged } from "./types";
|
|
import { Distribution } from "./distribution";
|
|
|
|
export { Distribution, squiggleExpression, result, resultMap };
|
|
|
|
export let defaultSamplingInputs: samplingParams = {
|
|
sampleCount: 10000,
|
|
xyPointLength: 10000,
|
|
};
|
|
|
|
export type result<a, b> =
|
|
| {
|
|
tag: "Ok";
|
|
value: a;
|
|
}
|
|
| {
|
|
tag: "Error";
|
|
value: b;
|
|
};
|
|
|
|
export function resultMap<a, b, c>(
|
|
r: result<a, c>,
|
|
mapFn: (x: a) => b
|
|
): result<b, c> {
|
|
if (r.tag === "Ok") {
|
|
return { tag: "Ok", value: mapFn(r.value) };
|
|
} else {
|
|
return r;
|
|
}
|
|
}
|
|
|
|
function Ok<a, b>(x: a): result<a, b> {
|
|
return { tag: "Ok", value: x };
|
|
}
|
|
|
|
type tagged<a, b> = { tag: a; value: b };
|
|
|
|
function tag<a, b>(x: a, y: b): tagged<a, b> {
|
|
return { tag: x, value: y };
|
|
}
|
|
|
|
export type squiggleExpression =
|
|
| tagged<"symbol", string>
|
|
| tagged<"string", string>
|
|
| tagged<"call", string>
|
|
| tagged<"lambda", [string[], internalCode]>
|
|
| tagged<"array", squiggleExpression[]>
|
|
| tagged<"boolean", boolean>
|
|
| tagged<"distribution", Distribution>
|
|
| tagged<"number", number>
|
|
| tagged<"record", { [key: string]: squiggleExpression }>;
|
|
|
|
export function run(
|
|
squiggleString: string,
|
|
bindings?: externalBindings,
|
|
environment?: environment,
|
|
imports?: jsImports
|
|
): result<squiggleExpression, errorValue> {
|
|
let b = bindings ? bindings : defaultBindings;
|
|
let i = imports ? imports : defaultImports;
|
|
let e = environment ? environment : defaultEnvironment;
|
|
let res: result<expressionValue, errorValue> = evaluateUsingOptions(
|
|
{ externalBindings: mergeImports(b, i), environment: e },
|
|
squiggleString
|
|
);
|
|
return resultMap(res, (x) => createTsExport(x, e));
|
|
}
|
|
|
|
// Run Partial. A partial is a block of code that doesn't return a value
|
|
export function runPartial(
|
|
squiggleString: string,
|
|
bindings?: externalBindings,
|
|
environment?: environment,
|
|
imports?: jsImports
|
|
): result<externalBindings, errorValue> {
|
|
let b = bindings ? bindings : defaultBindings;
|
|
let i = imports ? imports : defaultImports;
|
|
let e = environment ? environment : defaultEnvironment;
|
|
|
|
return evaluatePartialUsingExternalBindings(
|
|
squiggleString,
|
|
mergeImports(b, i),
|
|
e
|
|
);
|
|
}
|
|
|
|
function mergeImports(
|
|
bindings: externalBindings,
|
|
imports: jsImports
|
|
): externalBindings {
|
|
let transformedImports = Object.fromEntries(
|
|
Object.entries(imports).map(([key, value]) => [
|
|
"$" + key,
|
|
jsValueToBinding(value),
|
|
])
|
|
);
|
|
return _.merge(bindings, transformedImports);
|
|
}
|
|
|
|
type jsImports = { [key: string]: jsValue };
|
|
|
|
export let defaultImports: jsImports = {};
|
|
export let defaultBindings: externalBindings = {};
|
|
|
|
function createTsExport(
|
|
x: expressionValue,
|
|
environment: environment
|
|
): squiggleExpression {
|
|
switch (x.tag) {
|
|
case "EvArray":
|
|
// genType doesn't convert anything more than 2 layers down into {tag: x, value: x}
|
|
// format, leaving it as the raw values. This converts the raw values
|
|
// directly into typescript values.
|
|
//
|
|
// The casting here is because genType is about the types of the returned
|
|
// values, claiming they are fully recursive when that's not actually the
|
|
// case
|
|
return tag(
|
|
"array",
|
|
x.value.map((arrayItem): squiggleExpression => {
|
|
switch (arrayItem.tag) {
|
|
case "EvRecord":
|
|
return tag(
|
|
"record",
|
|
_.mapValues(arrayItem.value, (recordValue: unknown) =>
|
|
convertRawToTypescript(
|
|
recordValue as rescriptExport,
|
|
environment
|
|
)
|
|
)
|
|
);
|
|
case "EvArray":
|
|
let y = arrayItem.value as unknown as rescriptExport[];
|
|
return tag(
|
|
"array",
|
|
y.map((childArrayItem) =>
|
|
convertRawToTypescript(childArrayItem, environment)
|
|
)
|
|
);
|
|
default:
|
|
return createTsExport(arrayItem, environment);
|
|
}
|
|
})
|
|
);
|
|
case "EvArrayString":
|
|
return tag("arraystring", x.value);
|
|
case "EvBool":
|
|
return tag("boolean", x.value);
|
|
case "EvCall":
|
|
return tag("call", x.value);
|
|
case "EvLambda":
|
|
return tag("lambda", x.value);
|
|
case "EvDistribution":
|
|
return tag("distribution", new Distribution(x.value, environment));
|
|
case "EvNumber":
|
|
return tag("number", x.value);
|
|
case "EvRecord":
|
|
// genType doesn't support records, so we have to do the raw conversion ourself
|
|
let result: tagged<"record", { [key: string]: squiggleExpression }> = tag(
|
|
"record",
|
|
_.mapValues(x.value, (x: unknown) =>
|
|
convertRawToTypescript(x as rescriptExport, environment)
|
|
)
|
|
);
|
|
return result;
|
|
case "EvString":
|
|
return tag("string", x.value);
|
|
case "EvSymbol":
|
|
return tag("symbol", x.value);
|
|
}
|
|
}
|