diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res index 82ae328d..2e7b3ec5 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res @@ -232,6 +232,7 @@ describe("Peggy parse", () => { }) describe("unit", () => { testParse("1m", "{(::fromUnit_m 1)}") + testParse("1M", "{(::fromUnit_M 1)}") testParse("1m+2cm", "{(::add (::fromUnit_m 1) (::fromUnit_cm 2))}") }) }) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Date.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Date.res new file mode 100644 index 00000000..dc04a474 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Date.res @@ -0,0 +1,27 @@ +module EV = ReducerInterface_ExpressionValue +type expressionValue = EV.expressionValue + +let dispatch = (call: EV.functionCall, _: DistributionOperation.env): option< + result, +> => { + switch call { + | ("toString", [EvDate(t)]) => EV.EvString(DateTime.Date.toString(t))->Ok->Some + | ("makeDateFromYear", [EvNumber(year)]) => + switch DateTime.Date.makeFromYear(year) { + | Ok(t) => EV.EvDate(t)->Ok->Some + | Error(e) => Reducer_ErrorValue.RETodo(e)->Error->Some + } + | ("dateFromNumber", [EvNumber(f)]) => EV.EvDate(DateTime.Date.fromFloat(f))->Ok->Some + | ("toNumber", [EvDate(f)]) => EV.EvNumber(DateTime.Date.toFloat(f))->Ok->Some + | ("subtract", [EvDate(d1), EvDate(d2)]) => + switch DateTime.Date.subtract(d1, d2) { + | Ok(d) => EV.EvTimeDuration(d)->Ok + | Error(e) => Error(RETodo(e)) + }->Some + | ("subtract", [EvDate(d1), EvTimeDuration(d2)]) => + EV.EvDate(DateTime.Date.subtractDuration(d1, d2))->Ok->Some + | ("add", [EvDate(d1), EvTimeDuration(d2)]) => + EV.EvDate(DateTime.Date.addDuration(d1, d2))->Ok->Some + | _ => None + } +} \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_DateTime.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_DateTime.res deleted file mode 100644 index 334bee6c..00000000 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_DateTime.res +++ /dev/null @@ -1,105 +0,0 @@ -module EV = ReducerInterface_ExpressionValue -type expressionValue = EV.expressionValue - -let dateDispatch = (call: EV.functionCall, _: DistributionOperation.env): option< - result, -> => { - switch call { - | ("toString", [EvDate(t)]) => EV.EvString(DateTime.Date.toString(t))->Ok->Some - | ("makeDateFromYear", [EvNumber(year)]) => - switch DateTime.Date.makeFromYear(year) { - | Ok(t) => EV.EvDate(t)->Ok->Some - | Error(e) => Reducer_ErrorValue.RETodo(e)->Error->Some - } - | ("dateFromNumber", [EvNumber(f)]) => EV.EvDate(DateTime.Date.fromFloat(f))->Ok->Some - | ("toNumber", [EvDate(f)]) => EV.EvNumber(DateTime.Date.toFloat(f))->Ok->Some - | ("subtract", [EvDate(d1), EvDate(d2)]) => - switch DateTime.Date.subtract(d1, d2) { - | Ok(d) => EV.EvTimeDuration(d)->Ok - | Error(e) => Error(RETodo(e)) - }->Some - | ("subtract", [EvDate(d1), EvTimeDuration(d2)]) => - EV.EvDate(DateTime.Date.subtractDuration(d1, d2))->Ok->Some - | ("add", [EvDate(d1), EvTimeDuration(d2)]) => - EV.EvDate(DateTime.Date.addDuration(d1, d2))->Ok->Some - | _ => None - } -} - -module ScientificUnit = { - let nameToMultiplier = str => - switch str { - | "n" => Some(1E-9) - | "m" => Some(1E-3) - | "k" => Some(1E3) - | "M" => Some(1E6) - | "B" => Some(1E9) - | "G" => Some(1E9) - | "T" => Some(1E12) - | "P" => Some(1E15) - | _ => None - } - - let getMultiplier = (r: string) => { - let match = Js.String2.match_(r, %re(`/fromUnit_([_a-zA-Z]*)/`)) - switch match { - | Some([_, unit]) => nameToMultiplier(unit) - | _ => None - } - } -} - -let durationDispatch = (call: EV.functionCall, _: DistributionOperation.env): option< - result, -> => { - switch call { - | ( - ("fromUnit_n" - | "fromUnit_m" - | "fromUnit_k" - | "fromUnit_M" - | "fromUnit_B" - | "fromUnit_G" - | "fromUnit_T" - | "fromUnit_P") as op, - [EvNumber(f)], - ) => - op->ScientificUnit.getMultiplier->E.O2.fmap(multiplier => EV.EvNumber(f *. multiplier)->Ok) - | ("toString", [EvTimeDuration(t)]) => EV.EvString(DateTime.Duration.toString(t))->Ok->Some - | ("minutes", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromMinutes(f))->Ok->Some - | ("fromUnit_minutes", [EvNumber(f)]) => - EV.EvTimeDuration(DateTime.Duration.fromMinutes(f))->Ok->Some - | ("hours", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromHours(f))->Ok->Some - | ("fromUnit_hours", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromHours(f))->Ok->Some - | ("days", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromDays(f))->Ok->Some - | ("fromUnit_days", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromDays(f))->Ok->Some - | ("years", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromYears(f))->Ok->Some - | ("fromUnit_years", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromYears(f))->Ok->Some - | ("toHours", [EvTimeDuration(f)]) => EV.EvNumber(DateTime.Duration.toHours(f))->Ok->Some - | ("toMinutes", [EvTimeDuration(f)]) => EV.EvNumber(DateTime.Duration.toMinutes(f))->Ok->Some - | ("toDays", [EvTimeDuration(f)]) => EV.EvNumber(DateTime.Duration.toDays(f))->Ok->Some - | ("toYears", [EvTimeDuration(f)]) => EV.EvNumber(DateTime.Duration.toYears(f))->Ok->Some - | ("add", [EvTimeDuration(d1), EvTimeDuration(d2)]) => - EV.EvTimeDuration(DateTime.Duration.add(d1, d2))->Ok->Some - | ("subtract", [EvTimeDuration(d1), EvTimeDuration(d2)]) => - EV.EvTimeDuration(DateTime.Duration.subtract(d1, d2))->Ok->Some - | ("multiply", [EvTimeDuration(d1), EvNumber(d2)]) => - EV.EvTimeDuration(DateTime.Duration.multiply(d1, d2))->Ok->Some - | ("divide", [EvTimeDuration(d1), EvNumber(d2)]) => - EV.EvTimeDuration(DateTime.Duration.divide(d1, d2))->Ok->Some - | _ => None - } -} - -let dispatch = (call: EV.functionCall, env: DistributionOperation.env): option< - result, -> => { - switch dateDispatch(call, env) { - | Some(r) => Some(r) - | None => - switch durationDispatch(call, env) { - | Some(r) => Some(r) - | None => None - } - } -} diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Duration.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Duration.res new file mode 100644 index 00000000..a11aa745 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Duration.res @@ -0,0 +1,32 @@ +module EV = ReducerInterface_ExpressionValue +type expressionValue = EV.expressionValue + +let dispatch = (call: EV.functionCall, _: DistributionOperation.env): option< + result, +> => { + switch call { + | ("toString", [EvTimeDuration(t)]) => EV.EvString(DateTime.Duration.toString(t))->Ok->Some + | ("minutes", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromMinutes(f))->Ok->Some + | ("fromUnit_minutes", [EvNumber(f)]) => + EV.EvTimeDuration(DateTime.Duration.fromMinutes(f))->Ok->Some + | ("hours", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromHours(f))->Ok->Some + | ("fromUnit_hours", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromHours(f))->Ok->Some + | ("days", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromDays(f))->Ok->Some + | ("fromUnit_days", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromDays(f))->Ok->Some + | ("years", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromYears(f))->Ok->Some + | ("fromUnit_years", [EvNumber(f)]) => EV.EvTimeDuration(DateTime.Duration.fromYears(f))->Ok->Some + | ("toHours", [EvTimeDuration(f)]) => EV.EvNumber(DateTime.Duration.toHours(f))->Ok->Some + | ("toMinutes", [EvTimeDuration(f)]) => EV.EvNumber(DateTime.Duration.toMinutes(f))->Ok->Some + | ("toDays", [EvTimeDuration(f)]) => EV.EvNumber(DateTime.Duration.toDays(f))->Ok->Some + | ("toYears", [EvTimeDuration(f)]) => EV.EvNumber(DateTime.Duration.toYears(f))->Ok->Some + | ("add", [EvTimeDuration(d1), EvTimeDuration(d2)]) => + EV.EvTimeDuration(DateTime.Duration.add(d1, d2))->Ok->Some + | ("subtract", [EvTimeDuration(d1), EvTimeDuration(d2)]) => + EV.EvTimeDuration(DateTime.Duration.subtract(d1, d2))->Ok->Some + | ("multiply", [EvTimeDuration(d1), EvNumber(d2)]) => + EV.EvTimeDuration(DateTime.Duration.multiply(d1, d2))->Ok->Some + | ("divide", [EvTimeDuration(d1), EvNumber(d2)]) => + EV.EvTimeDuration(DateTime.Duration.divide(d1, d2))->Ok->Some + | _ => None + } +} \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res index 7e9448f0..d045040a 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res @@ -14,15 +14,27 @@ type expressionValue = ExpressionValue.expressionValue Map external calls of Reducer */ +// I expect that it's important to build this first, so it doesn't get recalculated for each tryRegistry() call. +let registry = FunctionRegistry_Library.registry + +let tryRegistry = ((fnName, args): ExpressionValue.functionCall, env) => { + FunctionRegistry_Core.Registry.matchAndRun(~registry, ~fnName, ~args, ~env)->E.O2.fmap( + E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)), + ) +} + let dispatch = (call: ExpressionValue.functionCall, environment, chain): result< expressionValue, 'e, -> => - switch ReducerInterface_GenericDistribution.dispatch(call, environment) { - | Some(r) => r - | None => - ReducerInterface_DateTime.dispatch(call, environment) |> E.O.default(chain(call, environment)) - } +> => { + E.A.O.firstSomeFn([ + () => ReducerInterface_GenericDistribution.dispatch(call, environment), + () => ReducerInterface_Date.dispatch(call, environment), + () => ReducerInterface_Duration.dispatch(call, environment), + () => ReducerInterface_Number.dispatch(call, environment), + () => tryRegistry(call, environment), + ])->E.O2.default(chain(call, environment)) +} /* If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally. diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index dc827805..7e3493b7 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -350,20 +350,5 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result< | GenDistError(err) => Error(REDistributionError(err)) } -// I expect that it's important to build this first, so it doesn't get recalculated for each tryRegistry() call. -let registry = FunctionRegistry_Library.registry - -let tryRegistry = ((fnName, args): ExpressionValue.functionCall, env) => { - FunctionRegistry_Core.Registry.matchAndRun(~registry, ~fnName, ~args, ~env)->E.O2.fmap( - E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)), - ) -} - -let dispatch = (call: ExpressionValue.functionCall, environment) => { - let regularDispatch = - dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue) - switch regularDispatch { - | Some(x) => Some(x) - | None => tryRegistry(call, environment) - } -} +let dispatch = (call: ExpressionValue.functionCall, environment) => + dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Number.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Number.res new file mode 100644 index 00000000..5cef930e --- /dev/null +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Number.res @@ -0,0 +1,45 @@ +module EV = ReducerInterface_ExpressionValue +type expressionValue = EV.expressionValue + +module ScientificUnit = { + let nameToMultiplier = str => + switch str { + | "n" => Some(1E-9) + | "m" => Some(1E-3) + | "k" => Some(1E3) + | "M" => Some(1E6) + | "B" => Some(1E9) + | "G" => Some(1E9) + | "T" => Some(1E12) + | "P" => Some(1E15) + | _ => None + } + + let getMultiplier = (r: string) => { + let match = Js.String2.match_(r, %re(`/fromUnit_([_a-zA-Z]*)/`)) + switch match { + | Some([_, unit]) => nameToMultiplier(unit) + | _ => None + } + } +} + +let dispatch = (call: EV.functionCall, _: DistributionOperation.env): option< + result, +> => { + switch call { + | ( + ("fromUnit_n" + | "fromUnit_m" + | "fromUnit_k" + | "fromUnit_M" + | "fromUnit_B" + | "fromUnit_G" + | "fromUnit_T" + | "fromUnit_P") as op, + [EvNumber(f)], + ) => + op->ScientificUnit.getMultiplier->E.O2.fmap(multiplier => EV.EvNumber(f *. multiplier)->Ok) + | _ => None + } +}