Simple dateTime integration

This commit is contained in:
Ozzie Gooen 2022-05-22 18:37:07 -04:00
parent 4dd79eb018
commit 364190dc7b
7 changed files with 153 additions and 4 deletions

View File

@ -189,6 +189,18 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
{expression.value.map((r) => `"${r}"`).join(", ")} {expression.value.map((r) => `"${r}"`).join(", ")}
</VariableBox> </VariableBox>
); );
case "date":
return (
<VariableBox heading="Date" showTypes={showTypes}>
{expression.value.toString()}
</VariableBox>
);
case "timeDuration":
return (
<VariableBox heading="Time Duration" showTypes={showTypes}>
<NumberShower precision={3} number={expression.value} />
</VariableBox>
);
case "lambda": case "lambda":
return ( return (
<FunctionChart <FunctionChart

View File

@ -181,5 +181,9 @@ function createTsExport(
return tag("string", x.value); return tag("string", x.value);
case "EvSymbol": case "EvSymbol":
return tag("symbol", x.value); return tag("symbol", x.value);
case "EvDate":
return tag("date", x.value);
case "EvTimeDuration":
return tag("timeDuration", x.value);
} }
} }

View File

@ -55,6 +55,14 @@ export type rescriptExport =
| { | {
TAG: 9; // EvSymbol TAG: 9; // EvSymbol
_0: string; _0: string;
}
| {
TAG: 10; // EvDate
_0: Date;
}
| {
TAG: 11; // EvTimeDuration
_0: number;
}; };
type rescriptDist = type rescriptDist =
@ -86,7 +94,9 @@ export type squiggleExpression =
| tagged<"boolean", boolean> | tagged<"boolean", boolean>
| tagged<"distribution", Distribution> | tagged<"distribution", Distribution>
| tagged<"number", number> | tagged<"number", number>
| tagged<"record", { [key: string]: squiggleExpression }>; | tagged<"date", Date>
| tagged<"timeDuration", number>
| tagged<"record", { [key: string]: squiggleExpression }>
export { lambdaValue }; export { lambdaValue };
@ -127,6 +137,10 @@ export function convertRawToTypescript(
return tag("string", result._0); return tag("string", result._0);
case 9: // EvSymbol case 9: // EvSymbol
return tag("symbol", result._0); return tag("symbol", result._0);
case 10: // EvDate
return tag("date", result._0);
case 11: // EvTimeDuration
return tag("number", result._0);
} }
} }

View File

@ -0,0 +1,62 @@
module ExpressionValue = ReducerInterface_ExpressionValue
type expressionValue = ExpressionValue.expressionValue
let dateDispatch = (call: ExpressionValue.functionCall, env: DistributionOperation.env): option<
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
> => {
switch call {
| ("toString", [EvDate(t)]) => EvString(E.Date.toString(t))->Ok->Some
| ("makeDateFromYear", [EvNumber(year)]) =>
EvDate(E.Date.makeWithYM(~year, ~month=0.0, ()))->Ok->Some
| ("fromMilliseconds", [EvNumber(f)]) => EvDate(E.Date.fromFloat(f))->Ok->Some
| ("toMilliseconds", [EvDate(f)]) => EvNumber(E.Date.toFloat(f))->Ok->Some
| ("subtract", [EvDate(d1), EvDate(d2)]) =>
switch E.Date.subtract(d1, d2) {
| Ok(d) => EvTimeDuration(d)->Ok
| Error(e) => Error(RETodo(e))
}->Some
| ("subtract", [EvDate(d1), EvTimeDuration(d2)]) =>
EvDate(E.Date.subtractDuration(d1, d2))->Ok->Some
| ("add", [EvDate(d1), EvTimeDuration(d2)]) => EvDate(E.Date.addDuration(d1, d2))->Ok->Some
| _ => None
}
}
let durationDispatch = (call: ExpressionValue.functionCall, env: DistributionOperation.env): option<
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
> => {
switch call {
| ("toString", [EvTimeDuration(t)]) => EvString(E.Duration.toString(t))->Ok->Some
| ("hours", [EvNumber(f)]) => EvTimeDuration(E.Duration.fromHours(f))->Ok->Some
| ("years", [EvNumber(f)]) => EvTimeDuration(E.Duration.fromYears(f))->Ok->Some
| ("toHours", [EvTimeDuration(f)]) => EvNumber(E.Duration.toHours(f))->Ok->Some
| ("toYears", [EvTimeDuration(f)]) => EvNumber(E.Duration.toYears(f))->Ok->Some
| (
("add" | "subtract" | "multiply" | "divide") as op,
[EvTimeDuration(d1), EvTimeDuration(d2)],
) => {
let op = switch op {
| "subtract" => E.Duration.subtract
| "multiply" => E.Duration.multiply
| "divide" => E.Duration.divide
| "add"
| _ => E.Duration.add
}
EvTimeDuration(op(d1, d2))->Ok->Some
}
| _ => None
}
}
let dispatch = (call: ExpressionValue.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
}
}
}

View File

@ -20,6 +20,8 @@ type rec expressionValue =
| EvRecord(record) | EvRecord(record)
| EvString(string) | EvString(string)
| EvSymbol(string) | EvSymbol(string)
| EvDate(Js.Date.t)
| EvTimeDuration(float)
and record = Js.Dict.t<expressionValue> and record = Js.Dict.t<expressionValue>
and externalBindings = record and externalBindings = record
and lambdaValue = { and lambdaValue = {
@ -51,6 +53,8 @@ let rec toString = aValue =>
| EvSymbol(aString) => `:${aString}` | EvSymbol(aString) => `:${aString}`
| EvRecord(aRecord) => aRecord->toStringRecord | EvRecord(aRecord) => aRecord->toStringRecord
| EvDistribution(dist) => GenericDist.toString(dist) | EvDistribution(dist) => GenericDist.toString(dist)
| EvDate(date) => E.Date.toString(date)
| EvTimeDuration(t) => E.Duration.toString(t)
} }
and toStringRecord = aRecord => { and toStringRecord = aRecord => {
let pairs = let pairs =
@ -73,6 +77,8 @@ let toStringWithType = aValue =>
| EvRecord(_) => `Record::${toString(aValue)}` | EvRecord(_) => `Record::${toString(aValue)}`
| EvString(_) => `String::${toString(aValue)}` | EvString(_) => `String::${toString(aValue)}`
| EvSymbol(_) => `Symbol::${toString(aValue)}` | EvSymbol(_) => `Symbol::${toString(aValue)}`
| EvDate(_) => `Date::${toString(aValue)}`
| EvTimeDuration(_) => `Date::${toString(aValue)}`
} }
let argsToString = (args: array<expressionValue>): string => { let argsToString = (args: array<expressionValue>): string => {
@ -116,6 +122,8 @@ type expressionValueType =
| EvtRecord | EvtRecord
| EvtString | EvtString
| EvtSymbol | EvtSymbol
| EvtDate
| EvtTimeDuration
type functionCallSignature = CallSignature(string, array<expressionValueType>) type functionCallSignature = CallSignature(string, array<expressionValueType>)
type functionDefinitionSignature = type functionDefinitionSignature =
@ -133,6 +141,8 @@ let valueToValueType = value =>
| EvRecord(_) => EvtRecord | EvRecord(_) => EvtRecord
| EvString(_) => EvtArray | EvString(_) => EvtArray
| EvSymbol(_) => EvtSymbol | EvSymbol(_) => EvtSymbol
| EvDate(_) => EvtDate
| EvTimeDuration(_) => EvtTimeDuration
} }
let functionCallToCallSignature = (functionCall: functionCall): functionCallSignature => { let functionCallToCallSignature = (functionCall: functionCall): functionCallSignature => {
@ -152,6 +162,8 @@ let valueTypeToString = (valueType: expressionValueType): string =>
| EvtRecord => `Record` | EvtRecord => `Record`
| EvtString => `String` | EvtString => `String`
| EvtSymbol => `Symbol` | EvtSymbol => `Symbol`
| EvtDate => `Date`
| EvtTimeDuration => `Duration`
} }
let functionCallSignatureToString = (functionCallSignature: functionCallSignature): string => { let functionCallSignatureToString = (functionCallSignature: functionCallSignature): string => {

View File

@ -18,9 +18,11 @@ let dispatch = (call: ExpressionValue.functionCall, environment, chain): result<
expressionValue, expressionValue,
'e, 'e,
> => > =>
ReducerInterface_GenericDistribution.dispatch(call, environment) |> E.O.default( switch ReducerInterface_GenericDistribution.dispatch(call, environment) {
chain(call, environment), | Some(r) => r
) | None =>
ReducerInterface_DateTime.dispatch(call, environment) |> E.O.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. If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally.

View File

@ -833,3 +833,46 @@ module JsArray = {
|> Js.Array.map(O.toExn("Warning: This should not have happened")) |> Js.Array.map(O.toExn("Warning: This should not have happened"))
let filter = Js.Array.filter let filter = Js.Array.filter
} }
module Duration = {
//Stores in Unix milliseconds
type t = float
let minute = Belt.Float.fromInt(60 * 1000)
let hour = Belt.Float.fromInt(60 * 60 * 1000)
let day = Belt.Float.fromInt(24 * 60 * 60 * 1000)
let year = Belt.Float.fromInt(24 * 60 * 60 * 1000 * 365)
let fromFloat = (f: float): t => f
let toFloat = (d: t): float => d
let fromHours = (h: float): t => h *. hour
let fromDays = (d: float): t => d *. day
let fromYears = (y: float): t => y *. year
let toHours = (t: t): float => t /. hour
let toDays = (t: t): float => t /. day
let toYears = (t: t): float => t /. year
let toString = (t: t) => `${Float.with2DigitsPrecision(t)}ms`
let add = (t1, t2): t => t1 +. t2
let subtract = (t1, t2): t => t1 -. t2
let multiply = (t1, t2): t => t1 *. t2
let divide = (t1, t2): t => t1 /. t2
}
module Date = {
type t = Js.Date.t
type year
let makeWithYM = Js.Date.makeWithYM
let toString = Js.Date.toString
let fromFloat = Js.Date.fromFloat
let toFloat = Js.Date.getTime
let fmap = (t: t, fn: float => float) => t->toFloat->fn->fromFloat
let subtract = (t1: t, t2: t) => {
let (f1, f2) = (toFloat(t1), toFloat(t2))
let diff = f1 -. f2
if diff < 0.0 {
Error("Cannot subtract a date by one that is in its future")
} else {
Ok(Duration.fromFloat(diff))
}
}
let addDuration = (t: t, duration: Duration.t) => fmap(t, t => t +. duration)
let subtractDuration = (t: t, duration: Duration.t) => fmap(t, t => t -. duration)
}