mirror of
https://github.com/Ratstail91/Mementos.git
synced 2025-11-29 02:24:28 +11:00
243 lines
10 KiB
C#
243 lines
10 KiB
C#
using System.Collections.Generic;
|
|
|
|
namespace Ink.Parsed
|
|
{
|
|
public class FunctionCall : Expression
|
|
{
|
|
public string name { get { return _proxyDivert.target.firstComponent; } }
|
|
public Divert proxyDivert { get { return _proxyDivert; } }
|
|
public List<Expression> arguments { get { return _proxyDivert.arguments; } }
|
|
public Runtime.Divert runtimeDivert { get { return _proxyDivert.runtimeDivert; } }
|
|
public bool isChoiceCount { get { return name == "CHOICE_COUNT"; } }
|
|
public bool isTurns { get { return name == "TURNS"; } }
|
|
public bool isTurnsSince { get { return name == "TURNS_SINCE"; } }
|
|
public bool isRandom { get { return name == "RANDOM"; } }
|
|
public bool isSeedRandom { get { return name == "SEED_RANDOM"; } }
|
|
public bool isListRange { get { return name == "LIST_RANGE"; } }
|
|
public bool isListRandom { get { return name == "LIST_RANDOM"; } }
|
|
public bool isReadCount { get { return name == "READ_COUNT"; } }
|
|
|
|
public bool shouldPopReturnedValue;
|
|
|
|
public FunctionCall (Identifier functionName, List<Expression> arguments)
|
|
{
|
|
_proxyDivert = new Parsed.Divert(new Path(functionName), arguments);
|
|
_proxyDivert.isFunctionCall = true;
|
|
AddContent (_proxyDivert);
|
|
}
|
|
|
|
public override void GenerateIntoContainer (Runtime.Container container)
|
|
{
|
|
var foundList = story.ResolveList (name);
|
|
|
|
bool usingProxyDivert = false;
|
|
|
|
if (isChoiceCount) {
|
|
|
|
if (arguments.Count > 0)
|
|
Error ("The CHOICE_COUNT() function shouldn't take any arguments");
|
|
|
|
container.AddContent (Runtime.ControlCommand.ChoiceCount ());
|
|
|
|
} else if (isTurns) {
|
|
|
|
if (arguments.Count > 0)
|
|
Error ("The TURNS() function shouldn't take any arguments");
|
|
|
|
container.AddContent (Runtime.ControlCommand.Turns ());
|
|
|
|
} else if (isTurnsSince || isReadCount) {
|
|
|
|
var divertTarget = arguments [0] as DivertTarget;
|
|
var variableDivertTarget = arguments [0] as VariableReference;
|
|
|
|
if (arguments.Count != 1 || (divertTarget == null && variableDivertTarget == null)) {
|
|
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)");
|
|
return;
|
|
}
|
|
|
|
if (divertTarget) {
|
|
_divertTargetToCount = divertTarget;
|
|
AddContent (_divertTargetToCount);
|
|
|
|
_divertTargetToCount.GenerateIntoContainer (container);
|
|
} else {
|
|
_variableReferenceToCount = variableDivertTarget;
|
|
AddContent (_variableReferenceToCount);
|
|
|
|
_variableReferenceToCount.GenerateIntoContainer (container);
|
|
}
|
|
|
|
if (isTurnsSince)
|
|
container.AddContent (Runtime.ControlCommand.TurnsSince ());
|
|
else
|
|
container.AddContent (Runtime.ControlCommand.ReadCount ());
|
|
|
|
} else if (isRandom) {
|
|
if (arguments.Count != 2)
|
|
Error ("RANDOM should take 2 parameters: a minimum and a maximum integer");
|
|
|
|
// We can type check single values, but not complex expressions
|
|
for (int arg = 0; arg < arguments.Count; arg++) {
|
|
if (arguments [arg] is Number) {
|
|
var num = arguments [arg] as Number;
|
|
if (!(num.value is int)) {
|
|
string paramName = arg == 0 ? "minimum" : "maximum";
|
|
Error ("RANDOM's " + paramName + " parameter should be an integer");
|
|
}
|
|
}
|
|
|
|
arguments [arg].GenerateIntoContainer (container);
|
|
}
|
|
|
|
container.AddContent (Runtime.ControlCommand.Random ());
|
|
|
|
} else if (isSeedRandom) {
|
|
if (arguments.Count != 1)
|
|
Error ("SEED_RANDOM should take 1 parameter - an integer seed");
|
|
|
|
var num = arguments [0] as Number;
|
|
if (num && !(num.value is int)) {
|
|
Error ("SEED_RANDOM's parameter should be an integer seed");
|
|
}
|
|
|
|
arguments [0].GenerateIntoContainer (container);
|
|
|
|
container.AddContent (Runtime.ControlCommand.SeedRandom ());
|
|
|
|
} else if (isListRange) {
|
|
if (arguments.Count != 3)
|
|
Error ("LIST_RANGE should take 3 parameters - a list, a min and a max");
|
|
|
|
for (int arg = 0; arg < arguments.Count; arg++)
|
|
arguments [arg].GenerateIntoContainer (container);
|
|
|
|
container.AddContent (Runtime.ControlCommand.ListRange ());
|
|
|
|
} else if( isListRandom ) {
|
|
if (arguments.Count != 1)
|
|
Error ("LIST_RANDOM should take 1 parameter - a list");
|
|
|
|
arguments [0].GenerateIntoContainer (container);
|
|
|
|
container.AddContent (Runtime.ControlCommand.ListRandom ());
|
|
|
|
} else if (Runtime.NativeFunctionCall.CallExistsWithName (name)) {
|
|
|
|
var nativeCall = Runtime.NativeFunctionCall.CallWithName (name);
|
|
|
|
if (nativeCall.numberOfParameters != arguments.Count) {
|
|
var msg = name + " should take " + nativeCall.numberOfParameters + " parameter";
|
|
if (nativeCall.numberOfParameters > 1)
|
|
msg += "s";
|
|
Error (msg);
|
|
}
|
|
|
|
for (int arg = 0; arg < arguments.Count; arg++)
|
|
arguments [arg].GenerateIntoContainer (container);
|
|
|
|
container.AddContent (Runtime.NativeFunctionCall.CallWithName (name));
|
|
} else if (foundList != null) {
|
|
if (arguments.Count > 1)
|
|
Error ("Can currently only construct a list from one integer (or an empty list from a given list definition)");
|
|
|
|
// List item from given int
|
|
if (arguments.Count == 1) {
|
|
container.AddContent (new Runtime.StringValue (name));
|
|
arguments [0].GenerateIntoContainer (container);
|
|
container.AddContent (Runtime.ControlCommand.ListFromInt ());
|
|
}
|
|
|
|
// Empty list with given origin.
|
|
else {
|
|
var list = new Runtime.InkList ();
|
|
list.SetInitialOriginName (name);
|
|
container.AddContent (new Runtime.ListValue (list));
|
|
}
|
|
}
|
|
|
|
// Normal function call
|
|
else {
|
|
container.AddContent (_proxyDivert.runtimeObject);
|
|
usingProxyDivert = true;
|
|
}
|
|
|
|
// Don't attempt to resolve as a divert if we're not doing a normal function call
|
|
if( !usingProxyDivert ) content.Remove (_proxyDivert);
|
|
|
|
// Function calls that are used alone on a tilda-based line:
|
|
// ~ func()
|
|
// Should tidy up any returned value from the evaluation stack,
|
|
// since it's unused.
|
|
if (shouldPopReturnedValue)
|
|
container.AddContent (Runtime.ControlCommand.PopEvaluatedValue ());
|
|
}
|
|
|
|
public override void ResolveReferences (Story context)
|
|
{
|
|
base.ResolveReferences (context);
|
|
|
|
// If we aren't using the proxy divert after all (e.g. if
|
|
// it's a native function call), but we still have arguments,
|
|
// we need to make sure they get resolved since the proxy divert
|
|
// is no longer in the content array.
|
|
if (!content.Contains(_proxyDivert) && arguments != null) {
|
|
foreach (var arg in arguments)
|
|
arg.ResolveReferences (context);
|
|
}
|
|
|
|
if( _divertTargetToCount ) {
|
|
var divert = _divertTargetToCount.divert;
|
|
var attemptingTurnCountOfVariableTarget = divert.runtimeDivert.variableDivertName != null;
|
|
|
|
if( attemptingTurnCountOfVariableTarget ) {
|
|
Error("When getting the TURNS_SINCE() of a variable target, remove the '->' - i.e. it should just be TURNS_SINCE("+divert.runtimeDivert.variableDivertName+")");
|
|
return;
|
|
}
|
|
|
|
var targetObject = divert.targetContent;
|
|
if( targetObject == null ) {
|
|
if( !attemptingTurnCountOfVariableTarget ) {
|
|
Error("Failed to find target for TURNS_SINCE: '"+divert.target+"'");
|
|
}
|
|
} else {
|
|
targetObject.containerForCounting.turnIndexShouldBeCounted = true;
|
|
}
|
|
}
|
|
|
|
else if( _variableReferenceToCount ) {
|
|
var runtimeVarRef = _variableReferenceToCount.runtimeVarRef;
|
|
if( runtimeVarRef.pathForCount != null ) {
|
|
Error("Should be "+name+"(-> "+_variableReferenceToCount.name+"). Usage without the '->' only makes sense for variable targets.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static bool IsBuiltIn(string name)
|
|
{
|
|
if (Runtime.NativeFunctionCall.CallExistsWithName (name))
|
|
return true;
|
|
|
|
return name == "CHOICE_COUNT"
|
|
|| name == "TURNS_SINCE"
|
|
|| name == "TURNS"
|
|
|| name == "RANDOM"
|
|
|| name == "SEED_RANDOM"
|
|
|| name == "LIST_VALUE"
|
|
|| name == "LIST_RANDOM"
|
|
|| name == "READ_COUNT";
|
|
}
|
|
|
|
public override string ToString ()
|
|
{
|
|
var strArgs = string.Join (", ", arguments.ToStringsArray());
|
|
return string.Format ("{0}({1})", name, strArgs);
|
|
}
|
|
|
|
Parsed.Divert _proxyDivert;
|
|
Parsed.DivertTarget _divertTargetToCount;
|
|
Parsed.VariableReference _variableReferenceToCount;
|
|
}
|
|
}
|
|
|