diff --git a/packages/components/src/lib/plotParser.ts b/packages/components/src/lib/plotParser.ts index 5b7ca31d..033ac2a3 100644 --- a/packages/components/src/lib/plotParser.ts +++ b/packages/components/src/lib/plotParser.ts @@ -1,5 +1,5 @@ +import * as yup from "yup"; import { Distribution, result, squiggleExpression } from "@quri/squiggle-lang"; -import { flattenResult, resultBind } from "./utility"; export type LabeledDistribution = { name: string; distribution: Distribution }; @@ -15,76 +15,47 @@ function ok(x: a): result { return { tag: "Ok", value: x }; } -function parseString(expr: squiggleExpression): result { - if (expr.tag === "string") { - return ok(expr.value); - } else { - return error("Expression was not string"); - } -} - -function parseRecord( - expr: squiggleExpression -): result<{ [key: string]: squiggleExpression }, string> { - if (expr.tag === "record") { - return ok(expr.value); - } else { - return error("Expression was not a record"); - } -} - -function parseDistribution( - expr: squiggleExpression -): result { - if (expr.tag === "distribution") { - return ok(expr.value); - } else { - return error("Expression was not a distribution"); - } -} - -function parseArray( - expr: squiggleExpression -): result { - if (expr.tag === "array") { - return ok(expr.value); - } else { - return error("Expression was not a distribution"); - } -} - -function parseField( - record: { [key: string]: squiggleExpression }, - field: string, - parser: (expr: squiggleExpression) => result -): result { - if (record[field]) { - return parser(record[field]); - } else { - return error("record does not have field " + field); - } -} - -function parseLabeledDistribution( - x: squiggleExpression -): result { - return resultBind(parseRecord(x), (record) => - resultBind(parseField(record, "name", parseString), (name) => - resultBind( - parseField(record, "distribution", parseDistribution), - (distribution) => ok({ name, distribution }) - ) - ) - ); -} +const schema = yup + .object() + .strict() + .noUnknown() + .shape({ + distributions: yup.object().shape({ + tag: yup.mixed().oneOf(["array"]), + value: yup + .array() + .of( + yup.object().shape({ + tag: yup.mixed().oneOf(["record"]), + value: yup.object().shape({ + name: yup.object().shape({ + tag: yup.mixed().oneOf(["string"]), + value: yup.string().required(), + }), + distribution: yup.object().shape({ + tag: yup.mixed().oneOf(["distribution"]), + value: yup.mixed(), + }), + }), + }) + ) + .required(), + }), + }); export function parsePlot(record: { [key: string]: squiggleExpression; }): result { - return resultBind(parseField(record, "distributions", parseArray), (array) => - resultBind( - flattenResult(array.map(parseLabeledDistribution)), - (distributions) => ok({ distributions }) - ) - ); + try { + const plotRecord = schema.validateSync(record); + return ok({ + distributions: plotRecord.distributions.value.map((x) => ({ + name: x.value.name.value, + distribution: x.value.distribution.value, + })), + }); + } catch (e) { + const message = e instanceof Error ? e.message : "Unknown error"; + return error(message); + } }