public Sequence(List <ContentList> elementContentLists, SequenceType sequenceType) { this.sequenceType = sequenceType; this.sequenceElements = new List <Parsed.Object> (); foreach (var elementContentList in elementContentLists) { var contentObjs = elementContentList.content; Parsed.Object seqElObject = null; // Don't attempt to create a weave for the sequence element // if the content list is empty. Weaves don't like it! if (contentObjs == null || contentObjs.Count == 0) { seqElObject = elementContentList; } else { seqElObject = new Weave(contentObjs); } this.sequenceElements.Add(seqElObject); AddContent(seqElObject); } }
List<Parsed.Object> SplitWeaveAndSubFlowContent(List<Parsed.Object> contentObjs) { var weaveObjs = new List<Parsed.Object> (); var subFlowObjs = new List<Parsed.Object> (); _subFlowsByName = new Dictionary<string, FlowBase> (); foreach (var obj in contentObjs) { var subFlow = obj as FlowBase; if (subFlow) { if (_firstChildFlow == null) _firstChildFlow = subFlow; subFlowObjs.Add (obj); _subFlowsByName [subFlow.name] = subFlow; } else { weaveObjs.Add (obj); } } var finalContent = new List<Parsed.Object> (); if (weaveObjs.Count > 0) { _rootWeave = new Weave (weaveObjs, 0); finalContent.Add (_rootWeave); } if (subFlowObjs.Count > 0) { finalContent.AddRange (subFlowObjs); } return finalContent; }
List <Parsed.Object> SplitWeaveAndSubFlowContent(List <Parsed.Object> contentObjs) { var weaveObjs = new List <Parsed.Object> (); var subFlowObjs = new List <Parsed.Object> (); _subFlowsByName = new Dictionary <string, FlowBase> (); foreach (var obj in contentObjs) { var subFlow = obj as FlowBase; if (subFlow) { subFlowObjs.Add(obj); _subFlowsByName [subFlow.name] = subFlow; } else { weaveObjs.Add(obj); } } var finalContent = new List <Parsed.Object> (); if (weaveObjs.Count > 0) { _rootWeave = new Weave(weaveObjs, 0); finalContent.Add(_rootWeave); } if (subFlowObjs.Count > 0) { finalContent.AddRange(subFlowObjs); } return(finalContent); }
public ConditionalSingleBranch(List<Parsed.Object> content) { // Branches are allowed to be empty if (content != null) { _innerWeave = new Weave (content); AddContent (_innerWeave); } }
public ConditionalSingleBranch(List <Parsed.Object> content) { // Branches are allowed to be empty if (content != null) { _innerWeave = new Weave(content); AddContent(_innerWeave); } }
void ConstructWeaveHierarchyFromIndentation() { // Find nested indentation and convert to a proper object hierarchy // (i.e. indented content is replaced with a Weave object that contains // that nested content) int contentIdx = 0; while (contentIdx < content.Count) { Parsed.Object obj = content [contentIdx]; // Choice or Gather if (obj is IWeavePoint) { var weavePoint = (IWeavePoint)obj; var weaveIndentIdx = weavePoint.indentationDepth - 1; // Inner level indentation - recurse if (weaveIndentIdx > baseIndentIndex) { // Step through content until indent jumps out again int innerWeaveStartIdx = contentIdx; while (contentIdx < content.Count) { var innerWeaveObj = content [contentIdx] as IWeavePoint; if (innerWeaveObj != null) { var innerIndentIdx = innerWeaveObj.indentationDepth - 1; if (innerIndentIdx <= baseIndentIndex) { break; } } contentIdx++; } int weaveContentCount = contentIdx - innerWeaveStartIdx; var weaveContent = content.GetRange(innerWeaveStartIdx, weaveContentCount); content.RemoveRange(innerWeaveStartIdx, weaveContentCount); var weave = new Weave(weaveContent, weaveIndentIdx); InsertContent(innerWeaveStartIdx, weave); // Continue iteration from this point contentIdx = innerWeaveStartIdx; } } contentIdx++; } }
// Add nested block at a greater indentation level public void AddRuntimeForNestedWeave(Weave nestedResult) { // Add this inner block to current container // (i.e. within the main container, or within the last defined Choice/Gather) AddGeneralRuntimeContent(nestedResult.rootContainer); // Now there's a deeper indentation level, the previous weave point doesn't // count as a loose end (since it will have content to go to) if (previousWeavePoint != null) { looseEnds.Remove(previousWeavePoint); addContentToPreviousWeavePoint = false; } }
List <Parsed.Object> SplitWeaveAndSubFlowContent(List <Parsed.Object> contentObjs, bool isRootStory) { var weaveObjs = new List <Parsed.Object> (); var subFlowObjs = new List <Parsed.Object> (); _subFlowsByName = new Dictionary <string, FlowBase> (); foreach (var obj in contentObjs) { var subFlow = obj as FlowBase; if (subFlow) { if (_firstChildFlow == null) { _firstChildFlow = subFlow; } subFlowObjs.Add(obj); _subFlowsByName [subFlow.identifier?.name] = subFlow; } else { weaveObjs.Add(obj); } } // Implicit final gather in top level story for ending without warning that you run out of content if (isRootStory) { weaveObjs.Add(new Gather(null, 1)); weaveObjs.Add(new Divert(new Path(Identifier.Done))); } var finalContent = new List <Parsed.Object> (); if (weaveObjs.Count > 0) { _rootWeave = new Weave(weaveObjs, 0); finalContent.Add(_rootWeave); } if (subFlowObjs.Count > 0) { finalContent.AddRange(subFlowObjs); } return(finalContent); }
void PassLooseEndsToAncestors() { if (looseEnds.Count == 0) { return; } // Search for Weave ancestor to pass loose ends to for gathering. // There are two types depending on whether the current weave // is separated by a conditional or sequence. // - An "inner" weave is one that is directly connected to the current // weave - i.e. you don't have to pass through a conditional or // sequence to get to it. We're allowed to pass all loose ends to // one of these. // - An "outer" weave is one that is outside of a conditional/sequence // that the current weave is nested within. We're only allowed to // pass gathers (i.e. 'normal flow') loose ends up there, not normal // choices. The rule is that choices have to be diverted explicitly // by the author since it's ambiguous where flow should go otherwise. // // e.g.: // // - top <- e.g. outer weave // {true: // * choice <- e.g. inner weave // * * choice 2 // more content <- e.g. current weave // * choice 2 // } // - more of outer weave // Weave closestInnerWeaveAncestor = null; Weave closestOuterWeaveAncestor = null; // Find inner and outer ancestor weaves as defined above. bool nested = false; for (var ancestor = this.parent; ancestor != null; ancestor = ancestor.parent) { // Found ancestor? var weaveAncestor = ancestor as Weave; if (weaveAncestor != null) { if (!nested && closestInnerWeaveAncestor == null) { closestInnerWeaveAncestor = weaveAncestor; } if (nested && closestOuterWeaveAncestor == null) { closestOuterWeaveAncestor = weaveAncestor; } } // Weaves nested within Sequences or Conditionals are // "sealed" - any loose ends require explicit diverts. if (ancestor is Sequence || ancestor is Conditional) { nested = true; } } // No weave to pass loose ends to at all? if (closestInnerWeaveAncestor == null && closestOuterWeaveAncestor == null) { return; } // Follow loose end passing logic as defined above for (int i = looseEnds.Count - 1; i >= 0; i--) { var looseEnd = looseEnds[i]; bool received = false; // This weave is nested within a conditional or sequence: // - choices can only be passed up to direct ancestor ("inner") weaves // - gathers can be passed up to either, but favour the closer (inner) weave // if there is one if (nested) { if (looseEnd is Choice && closestInnerWeaveAncestor != null) { closestInnerWeaveAncestor.ReceiveLooseEnd(looseEnd); received = true; } else if (!(looseEnd is Choice)) { var receivingWeave = closestInnerWeaveAncestor ?? closestOuterWeaveAncestor; if (receivingWeave != null) { receivingWeave.ReceiveLooseEnd(looseEnd); received = true; } } } // No nesting, all loose ends can be safely passed up else { closestInnerWeaveAncestor.ReceiveLooseEnd(looseEnd); received = true; } if (received) { looseEnds.RemoveAt(i); } } }
void ConstructWeaveHierarchyFromIndentation() { // Find nested indentation and convert to a proper object hierarchy // (i.e. indented content is replaced with a Weave object that contains // that nested content) int contentIdx = 0; while (contentIdx < content.Count) { Parsed.Object obj = content [contentIdx]; // Choice or Gather if (obj is IWeavePoint) { var weavePoint = (IWeavePoint)obj; var weaveIndentIdx = weavePoint.indentationDepth - 1; // Inner level indentation - recurse if (weaveIndentIdx > baseIndentIndex) { // Step through content until indent jumps out again int innerWeaveStartIdx = contentIdx; while (contentIdx < content.Count) { var innerWeaveObj = content [contentIdx] as IWeavePoint; if (innerWeaveObj != null) { var innerIndentIdx = innerWeaveObj.indentationDepth - 1; if (innerIndentIdx <= baseIndentIndex) { break; } } contentIdx++; } int weaveContentCount = contentIdx - innerWeaveStartIdx; var weaveContent = content.GetRange (innerWeaveStartIdx, weaveContentCount); content.RemoveRange (innerWeaveStartIdx, weaveContentCount); var weave = new Weave (weaveContent, weaveIndentIdx); InsertContent (innerWeaveStartIdx, weave); // Continue iteration from this point contentIdx = innerWeaveStartIdx; } } contentIdx++; } }
// Add nested block at a greater indentation level public void AddRuntimeForNestedWeave(Weave nestedResult) { // Add this inner block to current container // (i.e. within the main container, or within the last defined Choice/Gather) AddGeneralRuntimeContent (nestedResult.rootContainer); // Now there's a deeper indentation level, the previous weave point doesn't // count as a loose end (since it will have content to go to) if (previousWeavePoint != null) { looseEnds.Remove ((Parsed.Object)previousWeavePoint); addContentToPreviousWeavePoint = false; } }