Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Ink / InkLibs / InkCompiler / InkParser / InkParser_Conditional.cs
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using Ink.Parsed;
  4. namespace Ink
  5. {
  6. public partial class InkParser
  7. {
  8. protected Conditional InnerConditionalContent()
  9. {
  10. var initialQueryExpression = Parse(ConditionExpression);
  11. var conditional = Parse(() => InnerConditionalContent (initialQueryExpression));
  12. if (conditional == null)
  13. return null;
  14. return conditional;
  15. }
  16. protected Conditional InnerConditionalContent(Expression initialQueryExpression)
  17. {
  18. List<ConditionalSingleBranch> alternatives;
  19. bool canBeInline = initialQueryExpression != null;
  20. bool isInline = Parse(Newline) == null;
  21. if (isInline && !canBeInline) {
  22. return null;
  23. }
  24. // Inline innards
  25. if (isInline) {
  26. alternatives = InlineConditionalBranches ();
  27. }
  28. // Multiline innards
  29. else {
  30. alternatives = MultilineConditionalBranches ();
  31. if (alternatives == null) {
  32. // Allow single piece of content within multi-line expression, e.g.:
  33. // { true:
  34. // Some content that isn't preceded by '-'
  35. // }
  36. if (initialQueryExpression) {
  37. List<Parsed.Object> soleContent = StatementsAtLevel (StatementLevel.InnerBlock);
  38. if (soleContent != null) {
  39. var soleBranch = new ConditionalSingleBranch (soleContent);
  40. alternatives = new List<ConditionalSingleBranch> ();
  41. alternatives.Add (soleBranch);
  42. // Also allow a final "- else:" clause
  43. var elseBranch = Parse (SingleMultilineCondition);
  44. if (elseBranch) {
  45. if (!elseBranch.isElse) {
  46. ErrorWithParsedObject ("Expected an '- else:' clause here rather than an extra condition", elseBranch);
  47. elseBranch.isElse = true;
  48. }
  49. alternatives.Add (elseBranch);
  50. }
  51. }
  52. }
  53. // Still null?
  54. if (alternatives == null) {
  55. return null;
  56. }
  57. }
  58. // Empty true branch - didn't get parsed, but should insert one for semantic correctness,
  59. // and to make sure that any evaluation stack values get tidied up correctly.
  60. else if (alternatives.Count == 1 && alternatives [0].isElse && initialQueryExpression) {
  61. var emptyTrueBranch = new ConditionalSingleBranch (null);
  62. emptyTrueBranch.isTrueBranch = true;
  63. alternatives.Insert (0, emptyTrueBranch);
  64. }
  65. // Like a switch statement
  66. // { initialQueryExpression:
  67. // ... match the expression
  68. // }
  69. if (initialQueryExpression) {
  70. bool earlierBranchesHaveOwnExpression = false;
  71. for (int i = 0; i < alternatives.Count; ++i) {
  72. var branch = alternatives [i];
  73. bool isLast = (i == alternatives.Count - 1);
  74. // Matching equality with initial query expression
  75. // We set this flag even for the "else" clause so that
  76. // it knows to tidy up the evaluation stack at the end
  77. // Match query
  78. if (branch.ownExpression) {
  79. branch.matchingEquality = true;
  80. earlierBranchesHaveOwnExpression = true;
  81. }
  82. // Else (final branch)
  83. else if (earlierBranchesHaveOwnExpression && isLast) {
  84. branch.matchingEquality = true;
  85. branch.isElse = true;
  86. }
  87. // Binary condition:
  88. // { trueOrFalse:
  89. // - when true
  90. // - when false
  91. // }
  92. else {
  93. if (!isLast && alternatives.Count > 2) {
  94. ErrorWithParsedObject ("Only final branch can be an 'else'. Did you miss a ':'?", branch);
  95. } else {
  96. if (i == 0)
  97. branch.isTrueBranch = true;
  98. else
  99. branch.isElse = true;
  100. }
  101. }
  102. }
  103. }
  104. // No initial query, so just a multi-line conditional. e.g.:
  105. // {
  106. // - x > 3: greater than three
  107. // - x == 3: equal to three
  108. // - x < 3: less than three
  109. // }
  110. else {
  111. for (int i = 0; i < alternatives.Count; ++i) {
  112. var alt = alternatives [i];
  113. bool isLast = (i == alternatives.Count - 1);
  114. if (alt.ownExpression == null) {
  115. if (isLast) {
  116. alt.isElse = true;
  117. } else {
  118. if (alt.isElse) {
  119. // Do we ALSO have a valid "else" at the end? Let's report the error there.
  120. var finalClause = alternatives [alternatives.Count - 1];
  121. if (finalClause.isElse) {
  122. ErrorWithParsedObject ("Multiple 'else' cases. Can have a maximum of one, at the end.", finalClause);
  123. } else {
  124. ErrorWithParsedObject ("'else' case in conditional should always be the final one", alt);
  125. }
  126. } else {
  127. ErrorWithParsedObject ("Branch doesn't have condition. Are you missing a ':'? ", alt);
  128. }
  129. }
  130. }
  131. }
  132. if (alternatives.Count == 1 && alternatives [0].ownExpression == null) {
  133. ErrorWithParsedObject ("Condition block with no conditions", alternatives [0]);
  134. }
  135. }
  136. }
  137. // TODO: Come up with water-tight error conditions... it's quite a flexible system!
  138. // e.g.
  139. // - inline conditionals must have exactly 1 or 2 alternatives
  140. // - multiline expression shouldn't have mixed existence of branch-conditions?
  141. if (alternatives == null)
  142. return null;
  143. foreach (var branch in alternatives) {
  144. branch.isInline = isInline;
  145. }
  146. var cond = new Conditional (initialQueryExpression, alternatives);
  147. return cond;
  148. }
  149. protected List<ConditionalSingleBranch> InlineConditionalBranches()
  150. {
  151. var listOfLists = Interleave<List<Parsed.Object>> (MixedTextAndLogic, Exclude (String ("|")), flatten: false);
  152. if (listOfLists == null || listOfLists.Count == 0) {
  153. return null;
  154. }
  155. var result = new List<ConditionalSingleBranch> ();
  156. if (listOfLists.Count > 2) {
  157. Error ("Expected one or two alternatives separated by '|' in inline conditional");
  158. } else {
  159. var trueBranch = new ConditionalSingleBranch (listOfLists[0]);
  160. trueBranch.isTrueBranch = true;
  161. result.Add (trueBranch);
  162. if (listOfLists.Count > 1) {
  163. var elseBranch = new ConditionalSingleBranch (listOfLists[1]);
  164. elseBranch.isElse = true;
  165. result.Add (elseBranch);
  166. }
  167. }
  168. return result;
  169. }
  170. protected List<ConditionalSingleBranch> MultilineConditionalBranches()
  171. {
  172. MultilineWhitespace ();
  173. List<object> multipleConditions = OneOrMore (SingleMultilineCondition);
  174. if (multipleConditions == null)
  175. return null;
  176. MultilineWhitespace ();
  177. return multipleConditions.Cast<ConditionalSingleBranch>().ToList();
  178. }
  179. protected ConditionalSingleBranch SingleMultilineCondition()
  180. {
  181. Whitespace ();
  182. // Make sure we're not accidentally parsing a divert
  183. if (ParseString ("->") != null)
  184. return null;
  185. if (ParseString ("-") == null)
  186. return null;
  187. Whitespace ();
  188. Expression expr = null;
  189. bool isElse = Parse(ElseExpression) != null;
  190. if( !isElse )
  191. expr = Parse(ConditionExpression);
  192. List<Parsed.Object> content = StatementsAtLevel (StatementLevel.InnerBlock);
  193. if (expr == null && content == null) {
  194. Error ("expected content for the conditional branch following '-'");
  195. // Recover
  196. content = new List<Ink.Parsed.Object> ();
  197. content.Add (new Text (""));
  198. }
  199. // Allow additional multiline whitespace, if the statements were empty (valid)
  200. // then their surrounding multiline whitespacce needs to be handled manually.
  201. // e.g.
  202. // { x:
  203. // - 1: // intentionally left blank, but newline needs to be parsed
  204. // - 2: etc
  205. // }
  206. MultilineWhitespace ();
  207. var branch = new ConditionalSingleBranch (content);
  208. branch.ownExpression = expr;
  209. branch.isElse = isElse;
  210. return branch;
  211. }
  212. protected Expression ConditionExpression()
  213. {
  214. var expr = Parse(Expression);
  215. if (expr == null)
  216. return null;
  217. DisallowIncrement (expr);
  218. Whitespace ();
  219. if (ParseString (":") == null)
  220. return null;
  221. return expr;
  222. }
  223. protected object ElseExpression()
  224. {
  225. if (ParseString ("else") == null)
  226. return null;
  227. Whitespace ();
  228. if (ParseString (":") == null)
  229. return null;
  230. return ParseSuccess;
  231. }
  232. }
  233. }