protected Parsed.Return ReturnStatement() { Whitespace (); var returnOrDone = Parse(Identifier); if (returnOrDone != "return") { return null; } Whitespace (); var expr = Parse(Expression); var returnObj = new Return (expr); return returnObj; }
public override Runtime.Object GenerateRuntimeObject() { Return foundReturn = null; if (isFunction) { CheckForDisallowedFunctionFlowControl(); } // Non-functon: Make sure knots and stitches don't attempt to use Return statement else if (flowLevel == FlowLevel.Knot || flowLevel == FlowLevel.Stitch) { foundReturn = Find <Return> (); if (foundReturn != null) { Error("Return statements can only be used in knots that are declared as functions: == function " + this.name + " ==", foundReturn); } } var container = new Runtime.Container(); container.name = name; // Count visits on all knots and stitches container.visitsShouldBeCounted = true; container.turnIndexShouldBeCounted = true; GenerateArgumentVariableAssignments(container); // Run through content defined for this knot/stitch: // - First of all, any initial content before a sub-stitch // or any weave content is added to the main content container // - The first inner knot/stitch is automatically entered, while // the others are only accessible by an explicit divert // - The exception to this rule is if the knot/stitch takes // parameters, in which case it can't be auto-entered. // - Any Choices and Gathers (i.e. IWeavePoint) found are // processsed by GenerateFlowContent. int contentIdx = 0; while (content != null && contentIdx < content.Count) { Parsed.Object obj = content [contentIdx]; // Inner knots and stitches if (obj is FlowBase) { var childFlow = (FlowBase)obj; var childFlowRuntime = childFlow.runtimeObject; // First inner stitch - automatically step into it // 20/09/2016 - let's not auto step into knots if (contentIdx == 0 && !childFlow.hasParameters && this.flowLevel == FlowLevel.Knot) { _startingSubFlowDivert = new Runtime.Divert(); container.AddContent(_startingSubFlowDivert); _startingSubFlowRuntime = childFlowRuntime; } // Check for duplicate knots/stitches with same name var namedChild = (Runtime.INamedContent)childFlowRuntime; Runtime.INamedContent existingChild = null; if (container.namedContent.TryGetValue(namedChild.name, out existingChild)) { var errorMsg = string.Format("{0} already contains flow named '{1}' (at {2})", this.GetType().Name, namedChild.name, (existingChild as Runtime.Object).debugMetadata); Error(errorMsg, childFlow); } container.AddToNamedContentOnly(namedChild); } // Other content (including entire Weaves that were grouped in the constructor) // At the time of writing, all FlowBases have a maximum of one piece of "other content" // and it's always the root Weave else { container.AddContent(obj.runtimeObject); } contentIdx++; } // CHECK FOR FINAL LOOSE ENDS! // Notes: // - Functions don't need to terminate - they just implicitly return // - If return statement was found, don't continue finding warnings for missing control flow, // since it's likely that a return statement has been used instead of a ->-> or something, // or the writer failed to mark the knot as a function. // - _rootWeave may be null if it's a knot that only has stitches if (flowLevel != FlowLevel.Story && !this.isFunction && _rootWeave != null && foundReturn == null) { _rootWeave.ValidateTermination(WarningInTermination); } return(container); }