squiggle/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem.res
2022-08-23 11:47:24 +02:00

171 lines
5.1 KiB
Plaintext

// TODO: Use actual types instead of aliases in public functions
// TODO: Use topological sorting to prevent unnecessary runs
module Bindings = Reducer_Bindings
module Continuation = ReducerInterface_Value_Continuation
module ExpressionT = Reducer_Expression_T
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
module ReducerFnT = ReducerProject_ReducerFn_T
module T = ReducerProject_ProjectItem_T
type projectItem = T.projectItem
type t = T.t
let emptyItem = T.ProjectItem({
source: "",
rawParse: None,
expression: None,
continuation: Bindings.emptyBindings,
result: None,
continues: [],
includes: []->Ok,
})
// source -> rawParse -> includes -> expression -> continuation -> result
let getSource = (T.ProjectItem(r)): T.sourceType => r.source
let getRawParse = (T.ProjectItem(r)): T.rawParseType => r.rawParse
let getExpression = (T.ProjectItem(r)): T.expressionType => r.expression
let getContinuation = (T.ProjectItem(r)): T.continuationArgumentType => r.continuation
let getResult = (T.ProjectItem(r)): T.resultType => r.result
let getContinues = (T.ProjectItem(r)): T.continuesType => r.continues
let getIncludes = (T.ProjectItem(r)): T.includesType => r.includes
let touchSource = (this: t): t => {
let T.ProjectItem(r) = emptyItem
T.ProjectItem({
...r,
includes: getIncludes(this),
continues: getContinues(this),
source: getSource(this),
})
}
let touchRawParse = (this: t): t => {
let T.ProjectItem(r) = emptyItem
T.ProjectItem({
...r,
continues: getContinues(this),
source: getSource(this),
rawParse: getRawParse(this),
includes: getIncludes(this),
})
}
let touchExpression = (this: t): t => {
let T.ProjectItem(r) = emptyItem
T.ProjectItem({
...r,
continues: getContinues(this),
source: getSource(this),
rawParse: getRawParse(this),
includes: getIncludes(this),
expression: getExpression(this),
})
}
let setSource = (T.ProjectItem(r): t, source: T.sourceArgumentType): t =>
T.ProjectItem({...r, source: source})->touchSource
let setRawParse = (T.ProjectItem(r): t, rawParse: T.rawParseArgumentType): t =>
T.ProjectItem({...r, rawParse: Some(rawParse)})->touchRawParse
let setExpression = (T.ProjectItem(r): t, expression: T.expressionArgumentType): t =>
T.ProjectItem({...r, expression: Some(expression)})->touchExpression
let setContinuation = (T.ProjectItem(r): t, continuation: T.continuationArgumentType): t => {
T.ProjectItem({...r, continuation: continuation})
}
let setResult = (T.ProjectItem(r): t, result: T.resultArgumentType): t => T.ProjectItem({
...r,
result: Some(result),
})
let cleanResults = touchExpression
let clean = (this: t): t => {
let T.ProjectItem(r) = emptyItem
T.ProjectItem({
...r,
source: getSource(this),
continuation: getContinuation(this),
result: getResult(this),
})
}
let getImmediateDependencies = (this: t): T.includesType =>
getIncludes(this)->Belt.Result.map(Js.Array2.concat(_, getContinues(this)))
let setContinues = (T.ProjectItem(r): t, continues: array<string>): t =>
T.ProjectItem({...r, continues: continues})->touchSource
let removeContinues = (T.ProjectItem(r): t): t => T.ProjectItem({...r, continues: []})->touchSource
let setIncludes = (T.ProjectItem(r): t, includes: T.includesType): t => T.ProjectItem({
...r,
includes: includes,
})
//TODO: forward parse errors to the user
let parseIncludes = (this: t): t =>
setIncludes(this, getSource(this)->ReducerProject_ParseIncludes.parseIncludes)
let doRawParse = (this: t): T.rawParseArgumentType => this->getSource->Reducer_Peggy_Parse.parse
let rawParse = (this: t): t =>
this->getRawParse->E.O2.defaultFn(() => doRawParse(this))->setRawParse(this, _)
let doBuildExpression = (this: t): T.expressionType =>
this
->getRawParse
->Belt.Option.map(o => o->Belt.Result.map(r => r->Reducer_Peggy_ToExpression.fromNode))
let buildExpression = (this: t): t => {
let withRawParse: t = this->rawParse
switch withRawParse->getExpression {
| Some(_) => withRawParse
| None =>
withRawParse
->doBuildExpression
->Belt.Option.map(setExpression(withRawParse, _))
->E.O2.defaultFn(() => withRawParse)
}
}
let wrappedReducer = (
rExpression: T.expressionArgumentType,
aContinuation: T.continuation,
accessors: ProjectAccessorsT.t,
): T.resultArgumentType => {
Belt.Result.flatMap(
rExpression,
Reducer_Expression.reduceExpressionInProject(_, aContinuation, accessors),
)
}
let doBuildResult = (
this: t,
aContinuation: T.continuation,
accessors: ProjectAccessorsT.t,
): T.resultType =>
this
->getExpression
->Belt.Option.map(
Belt.Result.flatMap(
_,
Reducer_Expression.reduceExpressionInProject(_, aContinuation, accessors),
),
)
let buildResult = (this: t, aContinuation: T.continuation, accessors: ProjectAccessorsT.t): t => {
let withExpression: t = this->buildExpression
switch withExpression->getResult {
| Some(_) => withExpression
| None =>
withExpression
->doBuildResult(aContinuation, accessors)
->Belt.Option.map(setResult(withExpression, _))
->E.O2.defaultFn(() => withExpression)
}
}
let run = buildResult