Merge pull request #657 from quantified-uncertainty/simple-units
Support "k", "M", "G", "T" and other units
This commit is contained in:
commit
493c406b99
|
@ -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))}")
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
module EV = ReducerInterface_ExpressionValue
|
||||
type expressionValue = EV.expressionValue
|
||||
|
||||
let dispatch = (call: EV.functionCall, _: DistributionOperation.env): option<
|
||||
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
||||
> => {
|
||||
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
|
||||
}
|
||||
}
|
|
@ -1,32 +1,7 @@
|
|||
module EV = ReducerInterface_ExpressionValue
|
||||
type expressionValue = EV.expressionValue
|
||||
|
||||
let dateDispatch = (call: EV.functionCall, _: DistributionOperation.env): option<
|
||||
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
||||
> => {
|
||||
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<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
||||
> => {
|
||||
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<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
||||
> => {
|
||||
switch dateDispatch(call, env) {
|
||||
| Some(r) => Some(r)
|
||||
| None =>
|
||||
switch durationDispatch(call, env) {
|
||||
| Some(r) => Some(r)
|
||||
| None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
||||
> => {
|
||||
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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user