|
@@ -1,4 +1,8 @@
|
|
|
-import {Parser, ParseResult} from "./parser";
|
|
|
+import {
|
|
|
+ Parser,
|
|
|
+ Renderer,
|
|
|
+ ParseOrRenderResult,
|
|
|
+} from "./parser";
|
|
|
|
|
|
import {Delta} from "../onion/delta";
|
|
|
import {UUID} from "../onion/types";
|
|
@@ -24,7 +28,7 @@ import {
|
|
|
|
|
|
|
|
|
// A parser that creates an AS-node for every CS-node, with a Corr-node in between.
|
|
|
-export class TrivialParser implements Parser {
|
|
|
+export class TrivialParser implements Parser, Renderer {
|
|
|
readonly getUuid: () => UUID;
|
|
|
|
|
|
readonly csLvl: CompositeLevel;
|
|
@@ -40,85 +44,108 @@ export class TrivialParser implements Parser {
|
|
|
this.corrLvl = compositeLvls.corrLvl;
|
|
|
}
|
|
|
|
|
|
- parse(csComposite: CompositeDelta, csParent: Version, corrParent: Version, asParent): ParseResult {
|
|
|
- // these are the new deltas in 'cs'
|
|
|
- const csDeltas = [...csComposite.iterPrimitiveDeltas()];
|
|
|
+ // We can use pretty much the same code for both parsing and rendering :)
|
|
|
+ propagate_change(sourceComposite: CompositeDelta, sourceParent: Version, corrParent: Version, targetParent: Version, targetLvl: CompositeLevel, compositeDescriptionPrefix: string) {
|
|
|
+ const sourceDeltas = [...sourceComposite.iterPrimitiveDeltas()];
|
|
|
const parentCorrDeltas = new Set(corrParent.iterPrimitiveDeltas());
|
|
|
|
|
|
- const asDeltas: Delta[] = [];
|
|
|
+ const targetDeltas: Delta[] = [];
|
|
|
const corrDeltas: Delta[] = [];
|
|
|
|
|
|
- const csOverrides = new Map();
|
|
|
- const asOverrides = new Map();
|
|
|
+ const sourceOverrides = new Map();
|
|
|
+ const targetOverrides = new Map();
|
|
|
|
|
|
- for (const csDelta of csDeltas) {
|
|
|
- if (csDelta instanceof NodeCreation) {
|
|
|
+ for (const sourceDelta of sourceDeltas) {
|
|
|
+ if (sourceDelta instanceof NodeCreation) {
|
|
|
+ const sourceCreation = sourceDelta;
|
|
|
const corrCreation = new NodeCreation(this.getUuid());
|
|
|
- const corr2Cs = new EdgeCreation(corrCreation, "cs", csDelta);
|
|
|
- const asCreation = new NodeCreation(this.getUuid());
|
|
|
- const corr2As = new EdgeCreation(corrCreation, "as", asCreation);
|
|
|
+ const corr2Source = new EdgeCreation(corrCreation, "cs", sourceCreation);
|
|
|
+ const targetCreation = new NodeCreation(this.getUuid());
|
|
|
+ const corr2Target = new EdgeCreation(corrCreation, "as", targetCreation);
|
|
|
|
|
|
- asDeltas.push(asCreation);
|
|
|
- corrDeltas.push(corrCreation, corr2Cs, corr2As);
|
|
|
+ targetDeltas.push(targetCreation);
|
|
|
+ corrDeltas.push(corrCreation, corr2Source, corr2Target);
|
|
|
}
|
|
|
- else if (csDelta instanceof NodeDeletion) {
|
|
|
- const csCreation = csDelta.creation; // the NodeCreation of the deleted cs node
|
|
|
+ else if (sourceDelta instanceof NodeDeletion) {
|
|
|
+ const sourceDeletion = sourceDelta; // alias for readability :)
|
|
|
+ const csCreation = sourceDeletion.creation; // the NodeCreation of the deleted cs node
|
|
|
|
|
|
- // csDelta will conflict with our earlier 'corr2Cs' EdgeCreation delta:
|
|
|
- const corr2Cs = csDelta.edgeTargetConflicts.find(e => parentCorrDeltas.has(e));
|
|
|
- if (corr2Cs === undefined) {
|
|
|
+ // sourceDeletion will conflict with our earlier 'corr2Source' EdgeCreation delta:
|
|
|
+ const corr2Source = sourceDeletion.edgeTargetConflicts.find(e => parentCorrDeltas.has(e));
|
|
|
+ if (corr2Source === undefined) {
|
|
|
throw new Error("Assertion failed: When a node is deleted, the deletion must be conflicting with the creation of an incoming correspondence edge.");
|
|
|
}
|
|
|
- const corrCreation = corr2Cs.getCreation().source;
|
|
|
+ const corrCreation = corr2Source.getCreation().source;
|
|
|
// corrCreation will have only one other outgoing edge:
|
|
|
- const corr2As = corrCreation.outgoingEdges.find(e => e !== corr2Cs);
|
|
|
- if (corr2As === undefined) {
|
|
|
+ const corr2Target = corrCreation.outgoingEdges.find(e => e !== corr2Source);
|
|
|
+ if (corr2Target === undefined) {
|
|
|
throw new Error("Assertion failed: The correspondence node must have two outgoing edges, one to CS and one to AS.");
|
|
|
}
|
|
|
- const asCreation = corr2As.target.getTarget();
|
|
|
- if (! (asCreation instanceof NodeCreation)) {
|
|
|
- throw new Error("Assertion failed: The target of corr2As must be the NodeCreation of the AS node.");
|
|
|
+ const targetCreation = corr2Target.target.getTarget();
|
|
|
+ if (! (targetCreation instanceof NodeCreation)) {
|
|
|
+ throw new Error("Assertion failed: The target of corr2Target must be the NodeCreation of the AS node.");
|
|
|
}
|
|
|
|
|
|
- const corrDeletion = new NodeDeletion(corrCreation, [corr2Cs, corr2As], []);
|
|
|
+ const corrDeletion = new NodeDeletion(corrCreation, [corr2Source, corr2Target], []);
|
|
|
|
|
|
// We create 2 (conflicting) asDeletions:
|
|
|
// one that is to be used only in the AS model, unaware of any CORR-stuff, and one that is to be used in the CORR model.
|
|
|
- const asDeletion = new NodeDeletion(asCreation, [], []); // only part of AS
|
|
|
- const asDeletion1 = new NodeDeletion(asCreation, [], [corrDeletion]); // only part of CORR (override)
|
|
|
+ const targetDeletion = new NodeDeletion(targetCreation, [], []); // only part of AS
|
|
|
+ const targetDeletion1 = new NodeDeletion(targetCreation, [], [corrDeletion]); // only part of CORR (override)
|
|
|
|
|
|
// We already have the deletion in the CS model, so we only need to create another one to be used in the CORR model:
|
|
|
- const csDeletion1 = new NodeDeletion(csCreation,
|
|
|
- csDelta.deletedOutgoingEdges.map(d => corrParent.findOverride("cs", d) || d),
|
|
|
- csDelta.afterIncomingEdges.map(d => corrParent.findOverride("cs", d) || d).concat(corrDeletion));
|
|
|
- // const csDeletion1 = new NodeDeletion(csCreation, [], [corrDeletion]);
|
|
|
+ const sourceDeletion1 = new NodeDeletion(csCreation,
|
|
|
+ sourceDeletion.deletedOutgoingEdges.map(d => corrParent.findOverride("cs", d) || d),
|
|
|
+ sourceDeletion.afterIncomingEdges.map(d => corrParent.findOverride("cs", d) || d).concat(corrDeletion));
|
|
|
|
|
|
- csOverrides.set(csDelta, csDeletion1);
|
|
|
- asOverrides.set(asDeletion, asDeletion1);
|
|
|
+ sourceOverrides.set(sourceDeletion, sourceDeletion1);
|
|
|
+ targetOverrides.set(targetDeletion, targetDeletion1);
|
|
|
|
|
|
- asDeltas.push(asDeletion);
|
|
|
+ targetDeltas.push(targetDeletion);
|
|
|
corrDeltas.push(corrDeletion);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- const asComposite = this.asLvl.createComposite(asDeltas, "parse:"+csComposite.getDescription());
|
|
|
+ const targetComposite = targetLvl.createComposite(targetDeltas, compositeDescriptionPrefix+":"+sourceComposite.getDescription());
|
|
|
|
|
|
// New CORR-version:
|
|
|
- const csDeltas1 = csDeltas.map(d => csOverrides.get(d) || d);
|
|
|
- const asDeltas1 = asDeltas.map(d => asOverrides.get(d) || d);
|
|
|
+ const sourceDeltas1 = sourceDeltas.map(d => sourceOverrides.get(d) || d);
|
|
|
+ const targetDeltas1 = targetDeltas.map(d => targetOverrides.get(d) || d);
|
|
|
|
|
|
// the order in which corr-deltas are put in corrComposite matters - deltas must occur after their dependencies:
|
|
|
const orderedByDependency: Delta[] = [];
|
|
|
visitPartialOrdering(
|
|
|
- [...csDeltas1, ...asDeltas1, ...corrDeltas],
|
|
|
+ [...sourceDeltas1, ...targetDeltas1, ...corrDeltas],
|
|
|
(d: Delta) => d.getDependencies(),
|
|
|
(d: Delta) => orderedByDependency.push(d));
|
|
|
- const corrComposite = this.corrLvl.createComposite(orderedByDependency, "corr-parse:"+csComposite.getDescription());
|
|
|
+ const corrComposite = this.corrLvl.createComposite(orderedByDependency, "corr-"+compositeDescriptionPrefix+":"+sourceComposite.getDescription());
|
|
|
return {
|
|
|
- corr: corrComposite,
|
|
|
- as: asComposite,
|
|
|
- csOverrides,
|
|
|
- asOverrides,
|
|
|
+ corrComposite,
|
|
|
+ targetComposite,
|
|
|
+ sourceOverrides,
|
|
|
+ targetOverrides,
|
|
|
};
|
|
|
}
|
|
|
+
|
|
|
+ parse(csComposite: CompositeDelta, csParent: Version, corrParent: Version, asParent): ParseOrRenderResult {
|
|
|
+ const {
|
|
|
+ corrComposite,
|
|
|
+ targetComposite,
|
|
|
+ sourceOverrides: csOverrides,
|
|
|
+ targetOverrides: asOverrides,
|
|
|
+ } = this.propagate_change(csComposite, csParent, corrParent, asParent, this.asLvl, "parse");
|
|
|
+
|
|
|
+ return { corrComposite, targetComposite, csOverrides, asOverrides };
|
|
|
+ }
|
|
|
+
|
|
|
+ render(asComposite: CompositeDelta, csParent: Version, corrParent: Version, asParent: Version): ParseOrRenderResult {
|
|
|
+ const {
|
|
|
+ corrComposite,
|
|
|
+ targetComposite,
|
|
|
+ sourceOverrides: asOverrides,
|
|
|
+ targetOverrides: csOverrides,
|
|
|
+ } = this.propagate_change(asComposite, asParent, corrParent, csParent, this.csLvl, "render");
|
|
|
+
|
|
|
+ return { corrComposite, targetComposite, csOverrides, asOverrides };
|
|
|
+ }
|
|
|
}
|