squiggle/packages/squiggle-lang/src/js/index.ts

196 lines
5.5 KiB
TypeScript
Raw Normal View History

import * as _ from "lodash";
import {
environment,
defaultEnvironment,
2022-04-29 13:50:57 +00:00
evaluatePartialUsingExternalBindings,
2022-04-29 19:02:24 +00:00
evaluateUsingOptions,
2022-04-29 13:50:57 +00:00
externalBindings,
expressionValue,
errorValue,
2022-05-10 15:52:13 +00:00
foreignFunctionInterface,
} from "../rescript/TypescriptInterface.gen";
export {
makeSampleSetDist,
errorValueToString,
distributionErrorToString,
2022-05-02 19:04:16 +00:00
distributionError,
declarationArg,
declaration,
} from "../rescript/TypescriptInterface.gen";
2022-05-10 15:52:13 +00:00
export type { errorValue, externalBindings as bindings, jsImports };
2022-04-08 19:55:04 +00:00
import {
jsValueToBinding,
2022-05-10 15:52:13 +00:00
jsValueToExpressionValue,
jsValue,
rescriptExport,
squiggleExpression,
convertRawToTypescript,
2022-05-10 15:52:13 +00:00
lambdaValue,
} from "./rescript_interop";
import { result, resultMap, tag, tagged } from "./types";
2022-05-02 18:29:59 +00:00
import { Distribution, shape } from "./distribution";
2022-04-11 03:16:31 +00:00
2022-05-10 15:52:13 +00:00
export {
Distribution,
squiggleExpression,
result,
resultMap,
shape,
lambdaValue,
environment,
2022-05-10 16:24:08 +00:00
defaultEnvironment,
2022-05-10 15:52:13 +00:00
};
2022-05-10 15:52:13 +00:00
export let defaultSamplingInputs: environment = {
sampleCount: 10000,
xyPointLength: 10000,
};
2022-04-11 03:16:31 +00:00
export function run(
squiggleString: string,
2022-04-29 13:50:57 +00:00
bindings?: externalBindings,
environment?: environment,
2022-04-29 20:29:42 +00:00
imports?: jsImports
2022-04-11 03:16:31 +00:00
): result<squiggleExpression, errorValue> {
2022-04-29 19:02:43 +00:00
let b = bindings ? bindings : defaultBindings;
2022-04-29 20:29:42 +00:00
let i = imports ? imports : defaultImports;
let e = environment ? environment : defaultEnvironment;
2022-04-29 19:02:24 +00:00
let res: result<expressionValue, errorValue> = evaluateUsingOptions(
{ externalBindings: mergeImportsWithBindings(b, i), environment: e },
2022-04-29 19:02:24 +00:00
squiggleString
);
return resultMap(res, (x) => createTsExport(x, e));
2022-04-11 03:16:31 +00:00
}
2022-04-29 13:50:57 +00:00
// Run Partial. A partial is a block of code that doesn't return a value
export function runPartial(
squiggleString: string,
2022-04-29 18:46:44 +00:00
bindings?: externalBindings,
environment?: environment,
2022-04-29 20:29:42 +00:00
imports?: jsImports
2022-04-29 13:50:57 +00:00
): result<externalBindings, errorValue> {
2022-04-29 19:02:43 +00:00
let b = bindings ? bindings : defaultBindings;
2022-04-29 20:29:42 +00:00
let i = imports ? imports : defaultImports;
let e = environment ? environment : defaultEnvironment;
2022-04-29 18:46:44 +00:00
return evaluatePartialUsingExternalBindings(
squiggleString,
mergeImportsWithBindings(b, i),
e
2022-04-29 18:46:44 +00:00
);
}
2022-05-10 15:52:13 +00:00
export function runForeign(
fn: lambdaValue,
args: jsValue[],
environment?: environment
): result<squiggleExpression, errorValue> {
let e = environment ? environment : defaultEnvironment;
let res: result<expressionValue, errorValue> = foreignFunctionInterface(
fn,
args.map(jsValueToExpressionValue),
e
);
return resultMap(res, (x) => createTsExport(x, e));
}
function mergeImportsWithBindings(
2022-04-29 18:46:44 +00:00
bindings: externalBindings,
2022-04-29 20:29:42 +00:00
imports: jsImports
2022-04-29 18:46:44 +00:00
): externalBindings {
2022-04-29 20:29:42 +00:00
let transformedImports = Object.fromEntries(
Object.entries(imports).map(([key, value]) => [
2022-04-29 18:46:44 +00:00
"$" + key,
jsValueToBinding(value),
])
);
2022-04-29 20:29:42 +00:00
return _.merge(bindings, transformedImports);
2022-04-29 13:50:57 +00:00
}
2022-04-29 20:29:42 +00:00
type jsImports = { [key: string]: jsValue };
2022-04-29 18:46:44 +00:00
2022-04-29 20:29:42 +00:00
export let defaultImports: jsImports = {};
2022-04-29 19:02:43 +00:00
export let defaultBindings: externalBindings = {};
export function mergeBindings(
allBindings: externalBindings[]
): externalBindings {
return allBindings.reduce((acc, x) => ({ ...acc, ...x }));
}
function createTsExport(
x: expressionValue,
environment: environment
): squiggleExpression {
2022-04-11 03:16:31 +00:00
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);
2022-04-11 03:16:31 +00:00
case "EvBool":
return tag("boolean", x.value);
2022-04-12 15:12:19 +00:00
case "EvCall":
return tag("call", x.value);
2022-04-25 07:20:27 +00:00
case "EvLambda":
return tag("lambda", x.value);
2022-04-11 03:16:31 +00:00
case "EvDistribution":
return tag("distribution", new Distribution(x.value, environment));
2022-04-11 03:16:31 +00:00
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);
2022-05-22 22:37:07 +00:00
case "EvDate":
return tag("date", x.value);
case "EvTimeDuration":
return tag("timeDuration", x.value);
case "EvDeclaration":
return tag("lambdaDeclaration", x.value);
case "EvTypeIdentifier":
return tag("typeIdentifier", x.value);
2022-04-11 03:16:31 +00:00
}
}