Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Ink / InkLibs / InkCompiler / ParsedHierarchy / ConditionalSingleBranch.cs
  1. using System.Collections.Generic;
  2. namespace Ink.Parsed
  3. {
  4. public class ConditionalSingleBranch : Parsed.Object
  5. {
  6. // bool condition, e.g.:
  7. // { 5 == 4:
  8. // - the true branch
  9. // - the false branch
  10. // }
  11. public bool isTrueBranch { get; set; }
  12. // When each branch has its own expression like a switch statement,
  13. // this is non-null. e.g.
  14. // { x:
  15. // - 4: the value of x is four (ownExpression is the value 4)
  16. // - 3: the value of x is three
  17. // }
  18. public Expression ownExpression {
  19. get {
  20. return _ownExpression;
  21. }
  22. set {
  23. _ownExpression = value;
  24. if (_ownExpression) {
  25. AddContent (_ownExpression);
  26. }
  27. }
  28. }
  29. // In the above example, match equality of x with 4 for the first branch.
  30. // This is as opposed to simply evaluating boolean equality for each branch,
  31. // example when shouldMatchEqualtity is FALSE:
  32. // {
  33. // 3 > 2: This will happen
  34. // 2 > 3: This won't happen
  35. // }
  36. public bool matchingEquality { get; set; }
  37. public bool isElse { get; set; }
  38. public bool isInline { get; set; }
  39. public Runtime.Divert returnDivert { get; protected set; }
  40. public ConditionalSingleBranch (List<Parsed.Object> content)
  41. {
  42. // Branches are allowed to be empty
  43. if (content != null) {
  44. _innerWeave = new Weave (content);
  45. AddContent (_innerWeave);
  46. }
  47. }
  48. // Runtime content can be summarised as follows:
  49. // - Evaluate an expression if necessary to branch on
  50. // - Branch to a named container if true
  51. // - Divert back to main flow
  52. // (owner Conditional is in control of this target point)
  53. public override Runtime.Object GenerateRuntimeObject ()
  54. {
  55. // Check for common mistake, of putting "else:" instead of "- else:"
  56. if (_innerWeave) {
  57. foreach (var c in _innerWeave.content) {
  58. var text = c as Parsed.Text;
  59. if (text) {
  60. // Don't need to trim at the start since the parser handles that already
  61. if (text.text.StartsWith ("else:")) {
  62. Warning ("Saw the text 'else:' which is being treated as content. Did you mean '- else:'?", text);
  63. }
  64. }
  65. }
  66. }
  67. var container = new Runtime.Container ();
  68. // Are we testing against a condition that's used for more than just this
  69. // branch? If so, the first thing we need to do is replicate the value that's
  70. // on the evaluation stack so that we don't fully consume it, in case other
  71. // branches need to use it.
  72. bool duplicatesStackValue = matchingEquality && !isElse;
  73. if ( duplicatesStackValue )
  74. container.AddContent (Runtime.ControlCommand.Duplicate ());
  75. _conditionalDivert = new Runtime.Divert ();
  76. // else clause is unconditional catch-all, otherwise the divert is conditional
  77. _conditionalDivert.isConditional = !isElse;
  78. // Need extra evaluation?
  79. if( !isTrueBranch && !isElse ) {
  80. bool needsEval = ownExpression != null;
  81. if( needsEval )
  82. container.AddContent (Runtime.ControlCommand.EvalStart ());
  83. if (ownExpression)
  84. ownExpression.GenerateIntoContainer (container);
  85. // Uses existing duplicated value
  86. if (matchingEquality)
  87. container.AddContent (Runtime.NativeFunctionCall.CallWithName ("=="));
  88. if( needsEval )
  89. container.AddContent (Runtime.ControlCommand.EvalEnd ());
  90. }
  91. // Will pop from stack if conditional
  92. container.AddContent (_conditionalDivert);
  93. _contentContainer = GenerateRuntimeForContent ();
  94. _contentContainer.name = "b";
  95. // Multi-line conditionals get a newline at the start of each branch
  96. // (as opposed to the start of the multi-line conditional since the condition
  97. // may evaluate to false.)
  98. if (!isInline) {
  99. _contentContainer.InsertContent (new Runtime.StringValue ("\n"), 0);
  100. }
  101. if( duplicatesStackValue || (isElse && matchingEquality) )
  102. _contentContainer.InsertContent (Runtime.ControlCommand.PopEvaluatedValue (), 0);
  103. container.AddToNamedContentOnly (_contentContainer);
  104. returnDivert = new Runtime.Divert ();
  105. _contentContainer.AddContent (returnDivert);
  106. return container;
  107. }
  108. Runtime.Container GenerateRuntimeForContent()
  109. {
  110. // Empty branch - create empty container
  111. if (_innerWeave == null) {
  112. return new Runtime.Container ();
  113. }
  114. return _innerWeave.rootContainer;
  115. }
  116. public override void ResolveReferences (Story context)
  117. {
  118. _conditionalDivert.targetPath = _contentContainer.path;
  119. base.ResolveReferences (context);
  120. }
  121. Runtime.Container _contentContainer;
  122. Runtime.Divert _conditionalDivert;
  123. Expression _ownExpression;
  124. Weave _innerWeave;
  125. }
  126. }