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/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy index 61016ca9..8c853ff4 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy @@ -264,6 +264,9 @@ basicLiteral identifier 'identifier' = ([_a-z]+[_a-z0-9]i*) {return nodeIdentifier(text())} +unitIdentifier 'identifier' + = ([_a-zA-Z]+[_a-z0-9]i*) {return nodeIdentifier(text())} + dollarIdentifier '$identifier' = ([\$_a-z]+[\$_a-z0-9]i*) {return nodeIdentifier(text())} @@ -271,7 +274,7 @@ string 'string' = characters:("'" @([^'])* "'") {return nodeString(characters.join(''))} / characters:('"' @([^"])* '"') {return nodeString(characters.join(''))} -number = number:(float / integer) unit:identifier? +number = number:(float / integer) unit:unitIdentifier? { if (unit === null) { return number } 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_Duration.res similarity index 56% rename from packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_DateTime.res rename to packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Duration.res index fe30b0f8..a11aa745 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_DateTime.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Duration.res @@ -1,32 +1,7 @@ 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 - } -} - -let durationDispatch = (call: EV.functionCall, _: DistributionOperation.env): option< +let dispatch = (call: EV.functionCall, _: DistributionOperation.env): option< result, > => { switch call { @@ -54,17 +29,4 @@ let durationDispatch = (call: EV.functionCall, _: DistributionOperation.env): op 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 - } - } -} +} \ 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 + } +}