- using System.Collections.Generic;
- using System.Linq;
- namespace Ink.Parsed
- {
- public abstract class Expression : Parsed.Object
- {
- public bool outputWhenComplete { get; set; }
- public override Runtime.Object GenerateRuntimeObject ()
- {
- var container = new Runtime.Container ();
-
- container.AddContent (Runtime.ControlCommand.EvalStart());
- GenerateIntoContainer (container);
-
- if (outputWhenComplete) {
- container.AddContent (Runtime.ControlCommand.EvalOutput());
- }
-
- container.AddContent (Runtime.ControlCommand.EvalEnd());
- return container;
- }
-
-
-
-
-
-
-
- public void GenerateConstantIntoContainer(Runtime.Container container)
- {
- if( _prototypeRuntimeConstantExpression == null ) {
- _prototypeRuntimeConstantExpression = new Runtime.Container ();
- GenerateIntoContainer (_prototypeRuntimeConstantExpression);
- }
- foreach (var runtimeObj in _prototypeRuntimeConstantExpression.content) {
- container.AddContent (runtimeObj.Copy());
- }
- }
- public abstract void GenerateIntoContainer (Runtime.Container container);
- Runtime.Container _prototypeRuntimeConstantExpression;
- }
- public class BinaryExpression : Expression
- {
- public Expression leftExpression;
- public Expression rightExpression;
- public string opName;
- public BinaryExpression(Expression left, Expression right, string opName)
- {
- leftExpression = AddContent(left);
- rightExpression = AddContent(right);
- this.opName = opName;
- }
- public override void GenerateIntoContainer(Runtime.Container container)
- {
- leftExpression.GenerateIntoContainer (container);
- rightExpression.GenerateIntoContainer (container);
- opName = NativeNameForOp (opName);
- container.AddContent(Runtime.NativeFunctionCall.CallWithName(opName));
- }
- public override void ResolveReferences (Story context)
- {
- base.ResolveReferences (context);
-
-
-
-
-
-
-
-
-
-
-
- if (NativeNameForOp (opName) == "?") {
- var leftUnary = leftExpression as UnaryExpression;
- if( leftUnary != null && (leftUnary.op == "not" || leftUnary.op == "!") ) {
- Error ("Using 'not' or '!' here negates '"+leftUnary.innerExpression+"' rather than the result of the '?' or 'has' operator. You need to add parentheses around the (A ? B) expression.");
- }
- }
- }
- string NativeNameForOp(string opName)
- {
- if (opName == "and")
- return "&&";
- if (opName == "or")
- return "||";
- if (opName == "mod")
- return "%";
- if (opName == "has")
- return "?";
- if (opName == "hasnt")
- return "!?";
- return opName;
- }
- public override string ToString ()
- {
- return string.Format ("({0} {1} {2})", leftExpression, opName, rightExpression);
- }
- }
- public class UnaryExpression : Expression
- {
- public Expression innerExpression;
- public string op;
-
-
- public static Expression WithInner(Expression inner, string op) {
- var innerNumber = inner as Number;
- if( innerNumber ) {
- if( op == "-" ) {
- if( innerNumber.value is int ) {
- return new Number( -((int)innerNumber.value) );
- } else if( innerNumber.value is float ) {
- return new Number( -((float)innerNumber.value) );
- }
- }
- else if( op == "!" || op == "not" ) {
- if( innerNumber.value is int ) {
- return new Number( (int)innerNumber.value == 0 );
- } else if( innerNumber.value is float ) {
- return new Number( (float)innerNumber.value == 0.0f );
- } else if( innerNumber.value is bool ) {
- return new Number( !(bool)innerNumber.value );
- }
- }
- throw new System.Exception ("Unexpected operation or number type");
- }
-
- var unary = new UnaryExpression (inner, op);
- return unary;
- }
- public UnaryExpression(Expression inner, string op)
- {
- this.innerExpression = AddContent(inner);
- this.op = op;
- }
- public override void GenerateIntoContainer(Runtime.Container container)
- {
- innerExpression.GenerateIntoContainer (container);
- container.AddContent(Runtime.NativeFunctionCall.CallWithName(nativeNameForOp));
- }
- public override string ToString ()
- {
- return nativeNameForOp + innerExpression;
- }
- string nativeNameForOp
- {
- get {
-
- if (op == "-")
- return "_";
- if (op == "not")
- return "!";
- return op;
- }
- }
- }
- public class IncDecExpression : Expression
- {
- public Identifier varIdentifier;
- public bool isInc;
- public Expression expression;
- public IncDecExpression(Identifier varIdentifier, bool isInc)
- {
- this.varIdentifier = varIdentifier;
- this.isInc = isInc;
- }
- public IncDecExpression (Identifier varIdentifier, Expression expression, bool isInc) : this(varIdentifier, isInc)
- {
- this.expression = expression;
- AddContent (expression);
- }
- public override void GenerateIntoContainer(Runtime.Container container)
- {
-
-
-
-
-
- container.AddContent (new Runtime.VariableReference (varIdentifier?.name));
-
-
-
- if (expression)
- expression.GenerateIntoContainer (container);
- else
- container.AddContent (new Runtime.IntValue (1));
-
- container.AddContent (Runtime.NativeFunctionCall.CallWithName (isInc ? "+" : "-"));
-
- _runtimeAssignment = new Runtime.VariableAssignment(varIdentifier?.name, false);
- container.AddContent (_runtimeAssignment);
- }
- public override void ResolveReferences (Story context)
- {
- base.ResolveReferences (context);
- var varResolveResult = context.ResolveVariableWithName(varIdentifier?.name, fromNode: this);
- if (!varResolveResult.found) {
- Error ("variable for "+incrementDecrementWord+" could not be found: '"+varIdentifier+"' after searching: "+this.descriptionOfScope);
- }
- _runtimeAssignment.isGlobal = varResolveResult.isGlobal;
- if (!(parent is Weave) && !(parent is FlowBase) && !(parent is ContentList)) {
- Error ("Can't use " + incrementDecrementWord + " as sub-expression");
- }
- }
- string incrementDecrementWord {
- get {
- if (isInc)
- return "increment";
- else
- return "decrement";
- }
- }
- public override string ToString ()
- {
- if (expression)
- return varIdentifier + (isInc ? " += " : " -= ") + expression.ToString ();
- else
- return varIdentifier + (isInc ? "++" : "--");
- }
- Runtime.VariableAssignment _runtimeAssignment;
- }
- public class MultipleConditionExpression : Expression
- {
- public List<Expression> subExpressions {
- get {
- return this.content.Cast<Expression> ().ToList ();
- }
- }
- public MultipleConditionExpression(List<Expression> conditionExpressions)
- {
- AddContent (conditionExpressions);
- }
- public override void GenerateIntoContainer(Runtime.Container container)
- {
-
-
- bool isFirst = true;
- foreach (var conditionExpr in subExpressions) {
- conditionExpr.GenerateIntoContainer (container);
- if (!isFirst) {
- container.AddContent (Runtime.NativeFunctionCall.CallWithName ("&&"));
- }
- isFirst = false;
- }
- }
- }
- }