Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Ink / InkLibs / InkCompiler / ParsedHierarchy / DivertTarget.cs
  1. namespace Ink.Parsed
  2. {
  3. public class DivertTarget : Expression
  4. {
  5. public Divert divert;
  6. public DivertTarget (Divert divert)
  7. {
  8. this.divert = AddContent(divert);
  9. }
  10. public override void GenerateIntoContainer (Runtime.Container container)
  11. {
  12. divert.GenerateRuntimeObject();
  13. _runtimeDivert = (Runtime.Divert) divert.runtimeDivert;
  14. _runtimeDivertTargetValue = new Runtime.DivertTargetValue ();
  15. container.AddContent (_runtimeDivertTargetValue);
  16. }
  17. public override void ResolveReferences (Story context)
  18. {
  19. base.ResolveReferences (context);
  20. if( divert.isDone || divert.isEnd )
  21. {
  22. Error("Can't Can't use -> DONE or -> END as variable divert targets", this);
  23. return;
  24. }
  25. Parsed.Object usageContext = this;
  26. while (usageContext && usageContext is Expression) {
  27. bool badUsage = false;
  28. bool foundUsage = false;
  29. var usageParent = usageContext.parent;
  30. if (usageParent is BinaryExpression) {
  31. // Only allowed to compare for equality
  32. var binaryExprParent = usageParent as BinaryExpression;
  33. if (binaryExprParent.opName != "==" && binaryExprParent.opName != "!=") {
  34. badUsage = true;
  35. } else {
  36. if (!(binaryExprParent.leftExpression is DivertTarget || binaryExprParent.leftExpression is VariableReference)) {
  37. badUsage = true;
  38. }
  39. if (!(binaryExprParent.rightExpression is DivertTarget || binaryExprParent.rightExpression is VariableReference)) {
  40. badUsage = true;
  41. }
  42. }
  43. foundUsage = true;
  44. }
  45. else if( usageParent is FunctionCall ) {
  46. var funcCall = usageParent as FunctionCall;
  47. if( !funcCall.isTurnsSince && !funcCall.isReadCount ) {
  48. badUsage = true;
  49. }
  50. foundUsage = true;
  51. }
  52. else if (usageParent is Expression) {
  53. badUsage = true;
  54. foundUsage = true;
  55. }
  56. else if (usageParent is MultipleConditionExpression) {
  57. badUsage = true;
  58. foundUsage = true;
  59. } else if (usageParent is Choice && ((Choice)usageParent).condition == usageContext) {
  60. badUsage = true;
  61. foundUsage = true;
  62. } else if (usageParent is Conditional || usageParent is ConditionalSingleBranch) {
  63. badUsage = true;
  64. foundUsage = true;
  65. }
  66. if (badUsage) {
  67. Error ("Can't use a divert target like that. Did you intend to call '" + divert.target + "' as a function: likeThis(), or check the read count: likeThis, with no arrows?", this);
  68. }
  69. if (foundUsage)
  70. break;
  71. usageContext = usageParent;
  72. }
  73. // Example ink for this case:
  74. //
  75. // VAR x = -> blah
  76. //
  77. // ...which means that "blah" is expected to be a literal stitch target rather
  78. // than a variable name. We can't really intelligently recover from this (e.g. if blah happens to
  79. // contain a divert target itself) since really we should be generating a variable reference
  80. // rather than a concrete DivertTarget, so we list it as an error.
  81. if (_runtimeDivert.hasVariableTarget)
  82. Error ("Since '"+divert.target.dotSeparatedComponents+"' is a variable, it shouldn't be preceded by '->' here.");
  83. // Main resolve
  84. _runtimeDivertTargetValue.targetPath = _runtimeDivert.targetPath;
  85. // Tell hard coded (yet variable) divert targets that they also need to be counted
  86. // TODO: Only detect DivertTargets that are values rather than being used directly for
  87. // read or turn counts. Should be able to detect this by looking for other uses of containerForCounting
  88. var targetContent = this.divert.targetContent;
  89. if (targetContent != null ) {
  90. var target = targetContent.containerForCounting;
  91. if (target != null)
  92. {
  93. // Purpose is known: used directly in TURNS_SINCE(-> divTarg)
  94. var parentFunc = this.parent as FunctionCall;
  95. if( parentFunc && parentFunc.isTurnsSince ) {
  96. target.turnIndexShouldBeCounted = true;
  97. }
  98. // Unknown purpose, count everything
  99. else {
  100. target.visitsShouldBeCounted = true;
  101. target.turnIndexShouldBeCounted = true;
  102. }
  103. }
  104. // Unfortunately not possible:
  105. // https://github.com/inkle/ink/issues/538
  106. //
  107. // VAR func = -> double
  108. //
  109. // === function double(ref x)
  110. // ~ x = x * 2
  111. //
  112. // Because when generating the parameters for a function
  113. // to be called, it needs to know ahead of time when
  114. // compiling whether to pass a variable reference or value.
  115. //
  116. var targetFlow = (targetContent as FlowBase);
  117. if (targetFlow != null && targetFlow.arguments != null)
  118. {
  119. foreach(var arg in targetFlow.arguments) {
  120. if(arg.isByReference)
  121. {
  122. Error("Can't store a divert target to a knot or function that has by-reference arguments ('"+targetFlow.identifier+"' has 'ref "+arg.identifier+"').");
  123. }
  124. }
  125. }
  126. }
  127. }
  128. // Equals override necessary in order to check for CONST multiple definition equality
  129. public override bool Equals (object obj)
  130. {
  131. var otherDivTarget = obj as DivertTarget;
  132. if (otherDivTarget == null) return false;
  133. var targetStr = this.divert.target.dotSeparatedComponents;
  134. var otherTargetStr = otherDivTarget.divert.target.dotSeparatedComponents;
  135. return targetStr.Equals (otherTargetStr);
  136. }
  137. public override int GetHashCode ()
  138. {
  139. var targetStr = this.divert.target.dotSeparatedComponents;
  140. return targetStr.GetHashCode ();
  141. }
  142. Runtime.DivertTargetValue _runtimeDivertTargetValue;
  143. Runtime.Divert _runtimeDivert;
  144. }
  145. }