Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Ink / InkLibs / InkCompiler / ParsedHierarchy / FunctionCall.cs
  1. using System.Collections.Generic;
  2. namespace Ink.Parsed
  3. {
  4. public class FunctionCall : Expression
  5. {
  6. public string name { get { return _proxyDivert.target.firstComponent; } }
  7. public Divert proxyDivert { get { return _proxyDivert; } }
  8. public List<Expression> arguments { get { return _proxyDivert.arguments; } }
  9. public Runtime.Divert runtimeDivert { get { return _proxyDivert.runtimeDivert; } }
  10. public bool isChoiceCount { get { return name == "CHOICE_COUNT"; } }
  11. public bool isTurns { get { return name == "TURNS"; } }
  12. public bool isTurnsSince { get { return name == "TURNS_SINCE"; } }
  13. public bool isRandom { get { return name == "RANDOM"; } }
  14. public bool isSeedRandom { get { return name == "SEED_RANDOM"; } }
  15. public bool isListRange { get { return name == "LIST_RANGE"; } }
  16. public bool isListRandom { get { return name == "LIST_RANDOM"; } }
  17. public bool isReadCount { get { return name == "READ_COUNT"; } }
  18. public bool shouldPopReturnedValue;
  19. public FunctionCall (Identifier functionName, List<Expression> arguments)
  20. {
  21. _proxyDivert = new Parsed.Divert(new Path(functionName), arguments);
  22. _proxyDivert.isFunctionCall = true;
  23. AddContent (_proxyDivert);
  24. }
  25. public override void GenerateIntoContainer (Runtime.Container container)
  26. {
  27. var foundList = story.ResolveList (name);
  28. bool usingProxyDivert = false;
  29. if (isChoiceCount) {
  30. if (arguments.Count > 0)
  31. Error ("The CHOICE_COUNT() function shouldn't take any arguments");
  32. container.AddContent (Runtime.ControlCommand.ChoiceCount ());
  33. } else if (isTurns) {
  34. if (arguments.Count > 0)
  35. Error ("The TURNS() function shouldn't take any arguments");
  36. container.AddContent (Runtime.ControlCommand.Turns ());
  37. } else if (isTurnsSince || isReadCount) {
  38. var divertTarget = arguments [0] as DivertTarget;
  39. var variableDivertTarget = arguments [0] as VariableReference;
  40. if (arguments.Count != 1 || (divertTarget == null && variableDivertTarget == null)) {
  41. Error ("The " + name + "() function should take one argument: a divert target to the target knot, stitch, gather or choice you want to check. e.g. TURNS_SINCE(-> myKnot)");
  42. return;
  43. }
  44. if (divertTarget) {
  45. _divertTargetToCount = divertTarget;
  46. AddContent (_divertTargetToCount);
  47. _divertTargetToCount.GenerateIntoContainer (container);
  48. } else {
  49. _variableReferenceToCount = variableDivertTarget;
  50. AddContent (_variableReferenceToCount);
  51. _variableReferenceToCount.GenerateIntoContainer (container);
  52. }
  53. if (isTurnsSince)
  54. container.AddContent (Runtime.ControlCommand.TurnsSince ());
  55. else
  56. container.AddContent (Runtime.ControlCommand.ReadCount ());
  57. } else if (isRandom) {
  58. if (arguments.Count != 2)
  59. Error ("RANDOM should take 2 parameters: a minimum and a maximum integer");
  60. // We can type check single values, but not complex expressions
  61. for (int arg = 0; arg < arguments.Count; arg++) {
  62. if (arguments [arg] is Number) {
  63. var num = arguments [arg] as Number;
  64. if (!(num.value is int)) {
  65. string paramName = arg == 0 ? "minimum" : "maximum";
  66. Error ("RANDOM's " + paramName + " parameter should be an integer");
  67. }
  68. }
  69. arguments [arg].GenerateIntoContainer (container);
  70. }
  71. container.AddContent (Runtime.ControlCommand.Random ());
  72. } else if (isSeedRandom) {
  73. if (arguments.Count != 1)
  74. Error ("SEED_RANDOM should take 1 parameter - an integer seed");
  75. var num = arguments [0] as Number;
  76. if (num && !(num.value is int)) {
  77. Error ("SEED_RANDOM's parameter should be an integer seed");
  78. }
  79. arguments [0].GenerateIntoContainer (container);
  80. container.AddContent (Runtime.ControlCommand.SeedRandom ());
  81. } else if (isListRange) {
  82. if (arguments.Count != 3)
  83. Error ("LIST_RANGE should take 3 parameters - a list, a min and a max");
  84. for (int arg = 0; arg < arguments.Count; arg++)
  85. arguments [arg].GenerateIntoContainer (container);
  86. container.AddContent (Runtime.ControlCommand.ListRange ());
  87. } else if( isListRandom ) {
  88. if (arguments.Count != 1)
  89. Error ("LIST_RANDOM should take 1 parameter - a list");
  90. arguments [0].GenerateIntoContainer (container);
  91. container.AddContent (Runtime.ControlCommand.ListRandom ());
  92. } else if (Runtime.NativeFunctionCall.CallExistsWithName (name)) {
  93. var nativeCall = Runtime.NativeFunctionCall.CallWithName (name);
  94. if (nativeCall.numberOfParameters != arguments.Count) {
  95. var msg = name + " should take " + nativeCall.numberOfParameters + " parameter";
  96. if (nativeCall.numberOfParameters > 1)
  97. msg += "s";
  98. Error (msg);
  99. }
  100. for (int arg = 0; arg < arguments.Count; arg++)
  101. arguments [arg].GenerateIntoContainer (container);
  102. container.AddContent (Runtime.NativeFunctionCall.CallWithName (name));
  103. } else if (foundList != null) {
  104. if (arguments.Count > 1)
  105. Error ("Can currently only construct a list from one integer (or an empty list from a given list definition)");
  106. // List item from given int
  107. if (arguments.Count == 1) {
  108. container.AddContent (new Runtime.StringValue (name));
  109. arguments [0].GenerateIntoContainer (container);
  110. container.AddContent (Runtime.ControlCommand.ListFromInt ());
  111. }
  112. // Empty list with given origin.
  113. else {
  114. var list = new Runtime.InkList ();
  115. list.SetInitialOriginName (name);
  116. container.AddContent (new Runtime.ListValue (list));
  117. }
  118. }
  119. // Normal function call
  120. else {
  121. container.AddContent (_proxyDivert.runtimeObject);
  122. usingProxyDivert = true;
  123. }
  124. // Don't attempt to resolve as a divert if we're not doing a normal function call
  125. if( !usingProxyDivert ) content.Remove (_proxyDivert);
  126. // Function calls that are used alone on a tilda-based line:
  127. // ~ func()
  128. // Should tidy up any returned value from the evaluation stack,
  129. // since it's unused.
  130. if (shouldPopReturnedValue)
  131. container.AddContent (Runtime.ControlCommand.PopEvaluatedValue ());
  132. }
  133. public override void ResolveReferences (Story context)
  134. {
  135. base.ResolveReferences (context);
  136. // If we aren't using the proxy divert after all (e.g. if
  137. // it's a native function call), but we still have arguments,
  138. // we need to make sure they get resolved since the proxy divert
  139. // is no longer in the content array.
  140. if (!content.Contains(_proxyDivert) && arguments != null) {
  141. foreach (var arg in arguments)
  142. arg.ResolveReferences (context);
  143. }
  144. if( _divertTargetToCount ) {
  145. var divert = _divertTargetToCount.divert;
  146. var attemptingTurnCountOfVariableTarget = divert.runtimeDivert.variableDivertName != null;
  147. if( attemptingTurnCountOfVariableTarget ) {
  148. Error("When getting the TURNS_SINCE() of a variable target, remove the '->' - i.e. it should just be TURNS_SINCE("+divert.runtimeDivert.variableDivertName+")");
  149. return;
  150. }
  151. var targetObject = divert.targetContent;
  152. if( targetObject == null ) {
  153. if( !attemptingTurnCountOfVariableTarget ) {
  154. Error("Failed to find target for TURNS_SINCE: '"+divert.target+"'");
  155. }
  156. } else {
  157. targetObject.containerForCounting.turnIndexShouldBeCounted = true;
  158. }
  159. }
  160. else if( _variableReferenceToCount ) {
  161. var runtimeVarRef = _variableReferenceToCount.runtimeVarRef;
  162. if( runtimeVarRef.pathForCount != null ) {
  163. Error("Should be "+name+"(-> "+_variableReferenceToCount.name+"). Usage without the '->' only makes sense for variable targets.");
  164. }
  165. }
  166. }
  167. public static bool IsBuiltIn(string name)
  168. {
  169. if (Runtime.NativeFunctionCall.CallExistsWithName (name))
  170. return true;
  171. return name == "CHOICE_COUNT"
  172. || name == "TURNS_SINCE"
  173. || name == "TURNS"
  174. || name == "RANDOM"
  175. || name == "SEED_RANDOM"
  176. || name == "LIST_VALUE"
  177. || name == "LIST_RANDOM"
  178. || name == "READ_COUNT";
  179. }
  180. public override string ToString ()
  181. {
  182. var strArgs = string.Join (", ", arguments.ToStringsArray());
  183. return string.Format ("{0}({1})", name, strArgs);
  184. }
  185. Parsed.Divert _proxyDivert;
  186. Parsed.DivertTarget _divertTargetToCount;
  187. Parsed.VariableReference _variableReferenceToCount;
  188. }
  189. }