2022-07-25 14:34:33 +00:00
|
|
|
// TODO: Auto clean project based on topology
|
|
|
|
|
|
|
|
module Bindings = Reducer_Bindings
|
|
|
|
module Continuation = ReducerInterface_Value_Continuation
|
|
|
|
module ErrorValue = Reducer_ErrorValue
|
|
|
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
|
|
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
|
|
|
module ProjectItem = ReducerProject_ProjectItem
|
|
|
|
module T = ReducerProject_T
|
2022-08-14 14:14:14 +00:00
|
|
|
module Topology = ReducerProject_Topology
|
2022-07-25 14:34:33 +00:00
|
|
|
|
|
|
|
type t = T.t
|
|
|
|
|
|
|
|
module Private = {
|
|
|
|
type internalProject = T.Private.t
|
|
|
|
type t = T.Private.t
|
|
|
|
|
2022-08-14 14:14:14 +00:00
|
|
|
let getSourceIds = T.Private.getSourceIds
|
|
|
|
let getItem = T.Private.getItem
|
|
|
|
let getDependents = Topology.getDependents
|
|
|
|
let getDependencies = Topology.getDependencies
|
|
|
|
let getRunOrder = Topology.getRunOrder
|
|
|
|
let getRunOrderFor = Topology.getRunOrderFor
|
2022-07-25 14:34:33 +00:00
|
|
|
|
|
|
|
let createProject = () => {
|
2022-08-16 16:58:47 +00:00
|
|
|
let project: t = {
|
2022-08-26 00:01:27 +00:00
|
|
|
"iAmProject": true,
|
2022-07-25 14:34:33 +00:00
|
|
|
"items": Belt.Map.String.empty,
|
|
|
|
"stdLib": ReducerInterface_StdLib.internalStdLib,
|
|
|
|
"environment": InternalExpressionValue.defaultEnvironment,
|
2022-08-26 00:01:27 +00:00
|
|
|
"previousRunOrder": [],
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
2022-08-16 16:58:47 +00:00
|
|
|
project
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-26 00:01:27 +00:00
|
|
|
let rec touchSource_ = (project: t, sourceId: string): unit => {
|
2022-08-16 16:58:47 +00:00
|
|
|
let item = project->getItem(sourceId)
|
2022-07-25 14:34:33 +00:00
|
|
|
let newItem = ProjectItem.touchSource(item)
|
2022-08-16 16:58:47 +00:00
|
|
|
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
2022-08-16 16:58:47 +00:00
|
|
|
and touchDependents = (project: t, sourceId: string): unit => {
|
2022-08-26 00:01:27 +00:00
|
|
|
let _ = getDependents(project, sourceId)->Belt.Array.forEach(_, touchSource_(project, _))
|
|
|
|
}
|
|
|
|
|
|
|
|
let touchSource = (project: t, sourceId: string): unit => {
|
|
|
|
touchSource_(project, sourceId)
|
|
|
|
touchDependents(project, sourceId)
|
|
|
|
}
|
|
|
|
|
|
|
|
let handleNewTopology = (project: t): unit => {
|
|
|
|
let previousRunOrder = project["previousRunOrder"]
|
|
|
|
let currentRunOrder = Topology.getRunOrder(project)
|
|
|
|
let diff = Topology.runOrderDiff(currentRunOrder, previousRunOrder)
|
|
|
|
Belt.Array.forEach(diff, touchSource(project, _))
|
|
|
|
T.Private.setFieldPreviousRunOrder(project, currentRunOrder)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let getSource = (project: t, sourceId: string): option<string> =>
|
|
|
|
Belt.Map.String.get(project["items"], sourceId)->Belt.Option.map(ProjectItem.getSource)
|
2022-07-25 14:34:33 +00:00
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let setSource = (project: t, sourceId: string, value: string): unit => {
|
|
|
|
let newItem = project->getItem(sourceId)->ProjectItem.setSource(value)
|
|
|
|
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
|
|
|
touchDependents(project, sourceId)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let clean = (project: t, sourceId: string): unit => {
|
|
|
|
let newItem = project->getItem(sourceId)->ProjectItem.clean
|
|
|
|
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let cleanAll = (project: t): unit =>
|
|
|
|
getSourceIds(project)->Belt.Array.forEach(sourceId => clean(project, sourceId))
|
2022-07-25 14:34:33 +00:00
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let cleanResults = (project: t, sourceId: string): unit => {
|
|
|
|
let newItem = project->getItem(sourceId)->ProjectItem.cleanResults
|
|
|
|
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let cleanAllResults = (project: t): unit =>
|
|
|
|
getSourceIds(project)->Belt.Array.forEach(sourceId => cleanResults(project, sourceId))
|
2022-07-25 14:34:33 +00:00
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let getIncludes = (project: t, sourceId: string): ProjectItem.T.includesType =>
|
|
|
|
project->getItem(sourceId)->ProjectItem.getIncludes
|
2022-07-25 14:34:33 +00:00
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let setContinues = (project: t, sourceId: string, continues: array<string>): unit => {
|
|
|
|
let newItem = project->getItem(sourceId)->ProjectItem.setContinues(continues)
|
|
|
|
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
2022-08-26 00:01:27 +00:00
|
|
|
handleNewTopology(project)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
2022-08-16 16:58:47 +00:00
|
|
|
let getContinues = (project: t, sourceId: string): array<string> =>
|
|
|
|
ProjectItem.getContinues(project->getItem(sourceId))
|
2022-07-25 14:34:33 +00:00
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let removeContinues = (project: t, sourceId: string): unit => {
|
|
|
|
let newItem = project->getItem(sourceId)->ProjectItem.removeContinues
|
|
|
|
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
2022-08-26 00:01:27 +00:00
|
|
|
handleNewTopology(project)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let getContinuation = (project: t, sourceId: string): ProjectItem.T.continuationArgumentType =>
|
|
|
|
project->getItem(sourceId)->ProjectItem.getContinuation
|
2022-07-25 14:34:33 +00:00
|
|
|
|
|
|
|
let setContinuation = (
|
2022-08-16 16:58:47 +00:00
|
|
|
project: t,
|
2022-07-25 14:34:33 +00:00
|
|
|
sourceId: string,
|
|
|
|
continuation: ProjectItem.T.continuationArgumentType,
|
|
|
|
): unit => {
|
2022-08-16 16:58:47 +00:00
|
|
|
let newItem = project->getItem(sourceId)->ProjectItem.setContinuation(continuation)
|
|
|
|
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-25 08:43:51 +00:00
|
|
|
let getResultOption = (project: t, sourceId: string): ProjectItem.T.resultType =>
|
2022-08-16 16:58:47 +00:00
|
|
|
project->getItem(sourceId)->ProjectItem.getResult
|
2022-07-25 14:34:33 +00:00
|
|
|
|
2022-08-25 08:43:51 +00:00
|
|
|
let getResult = (project: t, sourceId: string): ProjectItem.T.resultArgumentType =>
|
|
|
|
switch getResultOption(project, sourceId) {
|
|
|
|
| None => RENeedToRun->Error
|
|
|
|
| Some(result) => result
|
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let setResult = (project: t, sourceId: string, value: ProjectItem.T.resultArgumentType): unit => {
|
|
|
|
let newItem = project->getItem(sourceId)->ProjectItem.setResult(value)
|
|
|
|
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let parseIncludes = (project: t, sourceId: string): unit => {
|
|
|
|
let newItem = project->getItem(sourceId)->ProjectItem.parseIncludes
|
|
|
|
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
2022-08-26 00:01:27 +00:00
|
|
|
handleNewTopology(project)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let rawParse = (project: t, sourceId): unit => {
|
|
|
|
let newItem = project->getItem(sourceId)->ProjectItem.rawParse
|
|
|
|
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let getStdLib = (project: t): Reducer_Bindings.t => project["stdLib"]
|
|
|
|
let setStdLib = (project: t, value: Reducer_Bindings.t): unit =>
|
|
|
|
T.Private.setFieldStdLib(project, value)
|
2022-07-25 14:34:33 +00:00
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let getEnvironment = (project: t): InternalExpressionValue.environment => project["environment"]
|
|
|
|
let setEnvironment = (project: t, value: InternalExpressionValue.environment): unit =>
|
|
|
|
T.Private.setFieldEnvironment(project, value)
|
2022-07-25 14:34:33 +00:00
|
|
|
|
2022-08-19 15:13:31 +00:00
|
|
|
let getBindings = (project: t, sourceId: string): ProjectItem.T.bindingsArgumentType => {
|
2022-08-16 16:58:47 +00:00
|
|
|
let those = project->getContinuation(sourceId)
|
|
|
|
let these = project->getStdLib
|
2022-07-25 14:34:33 +00:00
|
|
|
let ofUser = Continuation.minus(those, these)
|
2022-08-19 15:13:31 +00:00
|
|
|
ofUser
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let buildProjectAccessors = (project: t): ProjectAccessorsT.t => {
|
2022-08-15 13:18:14 +00:00
|
|
|
states: {continuation: Bindings.emptyBindings},
|
2022-08-16 16:58:47 +00:00
|
|
|
stdLib: getStdLib(project),
|
|
|
|
environment: getEnvironment(project),
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let doRunWithContinuation = (
|
2022-08-16 16:58:47 +00:00
|
|
|
project: t,
|
2022-07-25 14:34:33 +00:00
|
|
|
sourceId: string,
|
|
|
|
continuation: ProjectItem.T.continuation,
|
|
|
|
): unit => {
|
2022-08-16 16:58:47 +00:00
|
|
|
let accessors = buildProjectAccessors(project)
|
2022-08-15 13:18:14 +00:00
|
|
|
let states = accessors.states
|
2022-08-16 16:58:47 +00:00
|
|
|
let newItem = project->getItem(sourceId)->ProjectItem.run(continuation, accessors)
|
|
|
|
Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _)
|
|
|
|
setContinuation(project, sourceId, states.continuation)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type runState = (ProjectItem.T.resultArgumentType, ProjectItem.T.continuation)
|
|
|
|
|
|
|
|
let tryRunWithContinuation = (
|
2022-08-16 16:58:47 +00:00
|
|
|
project: t,
|
2022-07-25 14:34:33 +00:00
|
|
|
sourceId: string,
|
|
|
|
(rPrevResult: ProjectItem.T.resultArgumentType, continuation: ProjectItem.T.continuation),
|
|
|
|
): (ProjectItem.T.resultArgumentType, ProjectItem.T.continuation) => {
|
2022-08-25 08:43:51 +00:00
|
|
|
switch getResultOption(project, sourceId) {
|
2022-08-16 16:58:47 +00:00
|
|
|
| Some(result) => (result, getContinuation(project, sourceId)) // already ran
|
2022-07-25 14:34:33 +00:00
|
|
|
| None =>
|
|
|
|
switch rPrevResult {
|
|
|
|
| Error(error) => {
|
2022-08-16 16:58:47 +00:00
|
|
|
setResult(project, sourceId, Error(error))
|
2022-07-25 14:34:33 +00:00
|
|
|
(Error(error), continuation)
|
|
|
|
}
|
|
|
|
| Ok(_prevResult) => {
|
2022-08-16 16:58:47 +00:00
|
|
|
doRunWithContinuation(project, sourceId, continuation)
|
2022-07-25 14:34:33 +00:00
|
|
|
(
|
2022-08-25 08:43:51 +00:00
|
|
|
getResultOption(project, sourceId)->Belt.Option.getWithDefault(rPrevResult),
|
2022-08-16 16:58:47 +00:00
|
|
|
getContinuation(project, sourceId),
|
2022-07-25 14:34:33 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let runAll = (project: t): unit => {
|
|
|
|
let runOrder = Topology.getRunOrder(project)
|
|
|
|
let initialState = (Ok(InternalExpressionValue.IEvVoid), getStdLib(project))
|
2022-07-25 14:34:33 +00:00
|
|
|
let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) =>
|
2022-08-16 16:58:47 +00:00
|
|
|
tryRunWithContinuation(project, currId, currState)
|
2022-07-25 14:34:33 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-08-16 16:58:47 +00:00
|
|
|
let run = (project: t, sourceId: string): unit => {
|
|
|
|
let runOrder = Topology.getRunOrderFor(project, sourceId)
|
|
|
|
let initialState = (Ok(InternalExpressionValue.IEvVoid), getStdLib(project))
|
2022-07-25 14:34:33 +00:00
|
|
|
let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) =>
|
2022-08-16 16:58:47 +00:00
|
|
|
tryRunWithContinuation(project, currId, currState)
|
2022-07-25 14:34:33 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
let evaluate = (sourceCode: string) => {
|
|
|
|
let project = createProject()
|
|
|
|
setSource(project, "main", sourceCode)
|
|
|
|
runAll(project)
|
2022-08-16 15:07:15 +00:00
|
|
|
let those = project->getContinuation("main")
|
|
|
|
let these = project->getStdLib
|
|
|
|
let ofUser = Continuation.minus(those, these)
|
|
|
|
|
2022-08-25 08:43:51 +00:00
|
|
|
(getResultOption(project, "main")->Belt.Option.getWithDefault(IEvVoid->Ok), ofUser)
|
2022-07-25 14:34:33 +00:00
|
|
|
}
|
|
|
|
}
|