|
@@ -0,0 +1,179 @@
|
|
|
+import * as React from "react";
|
|
|
+import * as Mantine from "@mantine/core";
|
|
|
+
|
|
|
+import {newVersionedModel, VersionedModelState} from "./versioned_model";
|
|
|
+import {TrivialParser} from "../parser/trivial_parser";
|
|
|
+import {Version} from "../onion/version";
|
|
|
+import {GraphState} from "../onion/graph_state";
|
|
|
+import {CompositeDelta} from "../onion/composite_delta";
|
|
|
+
|
|
|
+// Pure function
|
|
|
+// Replays all deltas in a version to compute the graph state of that version.
|
|
|
+function getGraphState(version: Version): GraphState {
|
|
|
+ const graphState = new GraphState();
|
|
|
+ for (const d of [...version].reverse()) {
|
|
|
+ graphState.exec(d);
|
|
|
+ }
|
|
|
+ return graphState;
|
|
|
+}
|
|
|
+
|
|
|
+export function newCorrespondence({generateUUID, primitiveRegistry, cs, as}) {
|
|
|
+ const {initialState, getCurrentVersion, getReducer: getReducerOrig, getReactComponents} = newVersionedModel({readonly: true, generateUUID, primitiveRegistry});
|
|
|
+
|
|
|
+ const parser = new TrivialParser(primitiveRegistry, generateUUID);
|
|
|
+
|
|
|
+ // Mapping from correspondence model version to CS and AS model version.
|
|
|
+ const corrMap: Map<Version, {csVersion: Version, asVersion: Version}> = new Map([
|
|
|
+ [initialState.version, {csVersion: cs.initialState.version, asVersion: as.initialState.version}]
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // Mapping from CS to correspondence
|
|
|
+ const parseMap: Map<Version, Version> = new Map([[cs.initialState.version, initialState.version]]);
|
|
|
+
|
|
|
+ // Mapping from AS to correspondence
|
|
|
+ const renderMap: Map<Version, Version> = new Map([[as.initialState.version, initialState.version]]);
|
|
|
+
|
|
|
+ function getReducer(setCorrState, csReducer, asReducer) {
|
|
|
+ const {
|
|
|
+ gotoVersion: gotoVersionOrig,
|
|
|
+ createAndGotoNewVersion,
|
|
|
+ undo,
|
|
|
+ redo,
|
|
|
+ } = getReducerOrig(setCorrState);
|
|
|
+
|
|
|
+ const parse = (csDeltas, description: string) => {
|
|
|
+ const csParentVersion = cs.getCurrentVersion();
|
|
|
+ const corrParentVersion = parseMap.get(csParentVersion)!;
|
|
|
+ const asParentVersion = corrMap.get(corrParentVersion)!.asVersion;
|
|
|
+
|
|
|
+ const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(getGraphState);
|
|
|
+
|
|
|
+ const {corrDeltas, asDeltas} = parser.parse(csDeltas, csGS, corrGS, asGS);
|
|
|
+
|
|
|
+ const csVersion = csReducer.createAndGotoNewVersion(csDeltas, description);
|
|
|
+ const corrVersion = createAndGotoNewVersion(corrDeltas, "cs:"+description, corrParentVersion);
|
|
|
+ const asVersion = asDeltas.length > 0 ? asReducer.createAndGotoNewVersion(asDeltas, "parse:"+description, asParentVersion) : asParentVersion;
|
|
|
+
|
|
|
+ corrMap.set(corrVersion, {csVersion, asVersion});
|
|
|
+ parseMap.set(csVersion, corrVersion);
|
|
|
+ renderMap.set(asVersion, corrVersion);
|
|
|
+ };
|
|
|
+ const render = (asDeltas, description: string) => {
|
|
|
+ const asParentVersion = as.getCurrentVersion();
|
|
|
+ const corrParentVersion = renderMap.get(asParentVersion)!;
|
|
|
+ const csParentVersion = corrMap.get(corrParentVersion)!.csVersion;
|
|
|
+
|
|
|
+ const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(getGraphState);
|
|
|
+
|
|
|
+ const {corrDeltas, csDeltas} = parser.render(asDeltas, csGS, corrGS, asGS);
|
|
|
+
|
|
|
+ const csVersion = csDeltas.length > 0 ? csReducer.createAndGotoNewVersion(csDeltas, "render:"+description) : csParentVersion;
|
|
|
+ const corrVersion = createAndGotoNewVersion(corrDeltas, "as:"+description);
|
|
|
+ const asVersion = asReducer.createAndGotoNewVersion(asDeltas, description);
|
|
|
+
|
|
|
+ corrMap.set(corrVersion, {csVersion, asVersion});
|
|
|
+ parseMap.set(csVersion, corrVersion);
|
|
|
+ renderMap.set(asVersion, corrVersion);
|
|
|
+ };
|
|
|
+ const parseExistingVersion = (csVersion: Version) => {
|
|
|
+ for (const [csParentVersion, compositeDelta] of csVersion.parents) {
|
|
|
+
|
|
|
+ const csDeltas = (compositeDelta as CompositeDelta).deltas;
|
|
|
+ const description = compositeDelta.getDescription();
|
|
|
+
|
|
|
+ if (!parseMap.has(csParentVersion)) {
|
|
|
+ parseExistingVersion(csParentVersion);
|
|
|
+ }
|
|
|
+
|
|
|
+ const corrParentVersion = parseMap.get(csParentVersion);
|
|
|
+ if (corrParentVersion === undefined) {
|
|
|
+ console.log("Cannot parse - no parent CORR version");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ const asParentVersion = corrMap.get(corrParentVersion)?.asVersion;
|
|
|
+ if (asParentVersion === undefined) {
|
|
|
+ console.log("Cannot parse - no parent AS version");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(getGraphState);
|
|
|
+
|
|
|
+ const {corrDeltas, asDeltas} = parser.parse(csDeltas, csGS, corrGS, asGS);
|
|
|
+ const corrVersion = createAndGotoNewVersion(corrDeltas, "cs:"+description, corrParentVersion);
|
|
|
+ const asVersion = asDeltas.length > 0 ? asReducer.createAndGotoNewVersion(asDeltas, "parse:"+description, asParentVersion) : asParentVersion;
|
|
|
+
|
|
|
+ corrMap.set(corrVersion, {csVersion, asVersion});
|
|
|
+ parseMap.set(csVersion, corrVersion);
|
|
|
+ renderMap.set(asVersion, corrVersion);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ const renderExistingVersion = (asVersion: Version) => {
|
|
|
+ for (const [asParentVersion, compositeDelta] of asVersion.parents) {
|
|
|
+
|
|
|
+ const asDeltas = (compositeDelta as CompositeDelta).deltas;
|
|
|
+ const description = compositeDelta.getDescription();
|
|
|
+
|
|
|
+ if (!renderMap.has(asParentVersion)) {
|
|
|
+ parseExistingVersion(asParentVersion);
|
|
|
+ }
|
|
|
+
|
|
|
+ const corrParentVersion = renderMap.get(asParentVersion);
|
|
|
+ if (corrParentVersion === undefined) {
|
|
|
+ console.log("Cannot parse - no parent CORR version");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ const csParentVersion = corrMap.get(corrParentVersion)?.csVersion;
|
|
|
+ if (csParentVersion === undefined) {
|
|
|
+ console.log("Cannot parse - no parent CS version");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(getGraphState);
|
|
|
+
|
|
|
+ const {corrDeltas, csDeltas} = parser.render(asDeltas, csGS, corrGS, asGS);
|
|
|
+ const corrVersion = createAndGotoNewVersion(corrDeltas, "as:"+description, corrParentVersion);
|
|
|
+ const csVersion = csDeltas.length > 0 ? csReducer.createAndGotoNewVersion(csDeltas, "parse:"+description, csParentVersion) : asParentVersion;
|
|
|
+
|
|
|
+ corrMap.set(corrVersion, {csVersion, asVersion});
|
|
|
+ parseMap.set(csVersion, corrVersion);
|
|
|
+ renderMap.set(asVersion, corrVersion);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ const gotoVersion = (corrVersion: Version) => {
|
|
|
+ const {csVersion, asVersion} = corrMap.get(corrVersion)!;
|
|
|
+ csReducer.gotoVersion(csVersion);
|
|
|
+ gotoVersionOrig(corrVersion);
|
|
|
+ asReducer.gotoVersion(asVersion);
|
|
|
+ };
|
|
|
+ const getParseRenderButtons = (csState: VersionedModelState, asState: VersionedModelState) => {
|
|
|
+ const parseButton =
|
|
|
+ <Mantine.Button compact
|
|
|
+ disabled={parseMap.has(csState.version)}
|
|
|
+ onClick={() => parseExistingVersion(csState.version)}
|
|
|
+ >Parse</Mantine.Button>;
|
|
|
+ const renderButton =
|
|
|
+ <Mantine.Button compact
|
|
|
+ disabled={renderMap.has(asState.version)}
|
|
|
+ onClick={() => renderExistingVersion(asState.version)}
|
|
|
+ >Render</Mantine.Button>;
|
|
|
+ return {parseButton, renderButton};
|
|
|
+ };
|
|
|
+
|
|
|
+ return {
|
|
|
+ parse,
|
|
|
+ render,
|
|
|
+ gotoVersion,
|
|
|
+ undo,
|
|
|
+ redo,
|
|
|
+ getParseRenderButtons,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return {
|
|
|
+ initialState,
|
|
|
+ getCurrentVersion,
|
|
|
+ getReducer,
|
|
|
+ getReactComponents,
|
|
|
+ };
|
|
|
+}
|