void BadNestedTerminationHandler(Parsed.Object terminatingObj) { Conditional conditional = null; for (var ancestor = terminatingObj.parent; ancestor != null; ancestor = ancestor.parent) { if (ancestor is Sequence || ancestor is Conditional) { conditional = ancestor as Conditional; break; } } var errorMsg = "Choices nested in conditionals or sequences need to explicitly divert afterwards."; // Tutorialise proper choice syntax if this looks like a single choice within a condition, e.g. // { condition: // * choice // } if (conditional != null) { var numChoices = conditional.FindAll <Choice>().Count; if (numChoices == 1) { errorMsg = "Choices with conditions should be written: '* {condition} choice'. Otherwise, " + errorMsg.ToLower(); } } Error(errorMsg, terminatingObj); }
protected Conditional InnerConditionalContent(Expression initialQueryExpression) { List<ConditionalSingleBranch> alternatives; bool canBeInline = initialQueryExpression != null; bool isInline = Newline () == null; if (isInline && !canBeInline) { return null; } // Inline innards if (isInline) { alternatives = InlineConditionalBranches (); } // Multiline innards else { alternatives = MultilineConditionalBranches (); if (alternatives == null) { // Allow single piece of content within multi-line expression, e.g.: // { true: // Some content that isn't preceded by '-' // } if (initialQueryExpression) { List<Parsed.Object> soleContent = StatementsAtLevel (StatementLevel.InnerBlock); if (soleContent != null) { var soleBranch = new ConditionalSingleBranch (soleContent); alternatives = new List<ConditionalSingleBranch> (); alternatives.Add (soleBranch); // Also allow a final "- else:" clause var elseBranch = Parse(SingleMultilineCondition); if (elseBranch) { if (!elseBranch.isElse) { ErrorWithParsedObject ("Expected an '- else:' clause here rather than an extra condition", elseBranch); elseBranch.isElse = true; } alternatives.Add (elseBranch); } } } // Still null? if (alternatives == null) { return null; } } // Like a switch statement // { initialQueryExpression: // ... match the expression // } if (initialQueryExpression) { bool earlierBranchesHaveOwnExpression = false; for (int i = 0; i < alternatives.Count; ++i) { var branch = alternatives [i]; bool isLast = (i == alternatives.Count - 1); // Match query if (branch.ownExpression) { branch.shouldMatchEquality = true; earlierBranchesHaveOwnExpression = true; } // Else (final branch) else if (earlierBranchesHaveOwnExpression && isLast) { branch.isElse = true; } // Binary condition: // { trueOrFalse: // - when true // - when false // } else { if (!isLast && alternatives.Count > 2) { ErrorWithParsedObject ("Only final branch can be an 'else'. Did you miss a ':'?", branch); } else { if (i == 0) branch.isTrueBranch = true; else branch.isElse = true; } } } } // No initial query, so just a multi-line conditional. e.g.: // { // - x > 3: greater than three // - x == 3: equal to three // - x < 3: less than three // } else { for (int i = 0; i < alternatives.Count; ++i) { var alt = alternatives [i]; bool isLast = (i == alternatives.Count - 1); if (alt.ownExpression == null) { if (isLast) { alt.isElse = true; } else { if (alt.isElse) { // Do we ALSO have a valid "else" at the end? Let's report the error there. var finalClause = alternatives [alternatives.Count - 1]; if (finalClause.isElse) { ErrorWithParsedObject ("Multiple 'else' cases. Can have a maximum of one, at the end.", finalClause); } else { ErrorWithParsedObject ("'else' case in conditional should always be the final one", alt); } } else { ErrorWithParsedObject ("Branch doesn't have condition. Are you missing a ':'? ", alt); } } } } if (alternatives.Count == 1 && alternatives [0].ownExpression == null) { ErrorWithParsedObject ("Condition block with no conditions", alternatives [0]); } } } // TODO: Come up with water-tight error conditions... it's quite a flexible system! // e.g. // - inline conditionals must have exactly 1 or 2 alternatives // - multiline expression shouldn't have mixed existence of branch-conditions? if (alternatives == null) return null; var cond = new Conditional (initialQueryExpression, alternatives); return cond; }