- using System;
- using Ink.Parsed;
- using System.Collections.Generic;
- namespace Ink
- {
- public partial class InkParser
- {
- protected class InfixOperator
- {
- public string type;
- public int precedence;
- public bool requireWhitespace;
- public InfixOperator(string type, int precedence, bool requireWhitespace) {
- this.type = type;
- this.precedence = precedence;
- this.requireWhitespace = requireWhitespace;
- }
- public override string ToString ()
- {
- return type;
- }
- }
- protected Parsed.Object TempDeclarationOrAssignment()
- {
- Whitespace ();
- bool isNewDeclaration = ParseTempKeyword();
- Whitespace ();
- Identifier varIdentifier = null;
- if (isNewDeclaration) {
- varIdentifier = (Identifier)Expect (IdentifierWithMetadata, "variable name");
- } else {
- varIdentifier = Parse(IdentifierWithMetadata);
- }
- if (varIdentifier == null) {
- return null;
- }
- Whitespace();
-
- bool isIncrement = ParseString ("+") != null;
- bool isDecrement = ParseString ("-") != null;
- if (isIncrement && isDecrement) Error ("Unexpected sequence '+-'");
- if (ParseString ("=") == null) {
-
- if (isNewDeclaration) Error ("Expected '='");
- return null;
- }
- Expression assignedExpression = (Expression)Expect (Expression, "value expression to be assigned");
- if (isIncrement || isDecrement) {
- var result = new IncDecExpression (varIdentifier, assignedExpression, isIncrement);
- return result;
- } else {
- var result = new VariableAssignment (varIdentifier, assignedExpression);
- result.isNewTemporaryDeclaration = isNewDeclaration;
- return result;
- }
- }
- protected void DisallowIncrement (Parsed.Object expr)
- {
- if (expr is Parsed.IncDecExpression)
- Error ("Can't use increment/decrement here. It can only be used on a ~ line");
- }
- protected bool ParseTempKeyword()
- {
- var ruleId = BeginRule ();
- if (Parse (Identifier) == "temp") {
- SucceedRule (ruleId);
- return true;
- } else {
- FailRule (ruleId);
- return false;
- }
- }
- protected Parsed.Return ReturnStatement()
- {
- Whitespace ();
- var returnOrDone = Parse(Identifier);
- if (returnOrDone != "return") {
- return null;
- }
- Whitespace ();
- var expr = Parse(Expression);
- var returnObj = new Return (expr);
- return returnObj;
- }
- protected Expression Expression() {
- return Expression(minimumPrecedence:0);
- }
-
-
-
-
-
-
-
-
-
-
-
- protected Expression Expression(int minimumPrecedence)
- {
- Whitespace ();
-
- var expr = ExpressionUnary ();
- if (expr == null) {
- return null;
- }
- Whitespace ();
-
- while(true) {
- var ruleId = BeginRule ();
-
- var infixOp = ParseInfixOperator ();
- if (infixOp != null && infixOp.precedence > minimumPrecedence) {
-
- var expectationMessage = string.Format("right side of '{0}' expression", infixOp.type);
- var multiaryExpr = Expect (() => ExpressionInfixRight (left: expr, op: infixOp), expectationMessage);
- if (multiaryExpr == null) {
-
- FailRule (ruleId);
- return null;
- }
- expr = SucceedRule(ruleId, multiaryExpr) as Parsed.Expression;
- continue;
- }
- FailRule (ruleId);
- break;
- }
- Whitespace ();
- return expr;
- }
- protected Expression ExpressionUnary()
- {
-
-
-
- var divertTarget = Parse (ExpressionDivertTarget);
- if (divertTarget != null) {
- return divertTarget;
- }
- var prefixOp = (string) OneOf (String ("-"), String ("!"));
-
-
-
-
- if (prefixOp == null) {
- prefixOp = Parse(ExpressionNot);
- }
- Whitespace ();
-
-
- var expr = OneOf (ExpressionList, ExpressionParen, ExpressionFunctionCall, ExpressionVariableName, ExpressionLiteral) as Expression;
-
- if (expr == null && prefixOp != null) {
- expr = ExpressionUnary ();
- }
- if (expr == null)
- return null;
- if (prefixOp != null) {
- expr = UnaryExpression.WithInner(expr, prefixOp);
- }
- Whitespace ();
- var postfixOp = (string) OneOf (String ("++"), String ("--"));
- if (postfixOp != null) {
- bool isInc = postfixOp == "++";
- if (!(expr is VariableReference)) {
- Error ("can only increment and decrement variables, but saw '" + expr + "'");
-
- } else {
-
- var varRef = (VariableReference)expr;
- expr = new IncDecExpression(varRef.identifier, isInc);
- }
- }
- return expr;
- }
- protected string ExpressionNot()
- {
- var id = Identifier ();
- if (id == "not") {
- return id;
- }
- return null;
- }
- protected Expression ExpressionLiteral()
- {
- return (Expression) OneOf (ExpressionFloat, ExpressionInt, ExpressionBool, ExpressionString);
- }
- protected Expression ExpressionDivertTarget()
- {
- Whitespace ();
- var divert = Parse(SingleDivert);
- if (divert == null)
- return null;
- if (divert.isThread)
- return null;
- Whitespace ();
- return new DivertTarget (divert);
- }
- protected Number ExpressionInt()
- {
- int? intOrNull = ParseInt ();
- if (intOrNull == null) {
- return null;
- } else {
- return new Number (intOrNull.Value);
- }
- }
- protected Number ExpressionFloat()
- {
- float? floatOrNull = ParseFloat ();
- if (floatOrNull == null) {
- return null;
- } else {
- return new Number (floatOrNull.Value);
- }
- }
- protected StringExpression ExpressionString()
- {
- var openQuote = ParseString ("\"");
- if (openQuote == null)
- return null;
-
-
- parsingStringExpression = true;
- List<Parsed.Object> textAndLogic = Parse (MixedTextAndLogic);
- Expect (String ("\""), "close quote for string expression");
- parsingStringExpression = false;
- if (textAndLogic == null) {
- textAndLogic = new List<Ink.Parsed.Object> ();
- textAndLogic.Add (new Parsed.Text (""));
- }
- else if (textAndLogic.Exists (c => c is Divert))
- Error ("String expressions cannot contain diverts (->)");
- return new StringExpression (textAndLogic);
- }
- protected Number ExpressionBool()
- {
- var id = Parse(Identifier);
- if (id == "true") {
- return new Number (true);
- } else if (id == "false") {
- return new Number (false);
- }
- return null;
- }
- protected Expression ExpressionFunctionCall()
- {
- var iden = Parse(IdentifierWithMetadata);
- if (iden == null)
- return null;
- Whitespace ();
- var arguments = Parse(ExpressionFunctionCallArguments);
- if (arguments == null) {
- return null;
- }
- return new FunctionCall(iden, arguments);
- }
- protected List<Expression> ExpressionFunctionCallArguments()
- {
- if (ParseString ("(") == null)
- return null;
-
- ParseRule commas = Exclude (String (","));
- var arguments = Interleave<Expression>(Expression, commas);
- if (arguments == null) {
- arguments = new List<Expression> ();
- }
- Whitespace ();
- Expect (String (")"), "closing ')' for function call");
- return arguments;
- }
- protected Expression ExpressionVariableName()
- {
- List<Identifier> path = Interleave<Identifier> (IdentifierWithMetadata, Exclude (Spaced (String ("."))));
- if (path == null || Story.IsReservedKeyword (path[0].name) )
- return null;
- return new VariableReference (path);
- }
- protected Expression ExpressionParen()
- {
- if (ParseString ("(") == null)
- return null;
- var innerExpr = Parse(Expression);
- if (innerExpr == null)
- return null;
- Whitespace ();
- Expect (String(")"), "closing parenthesis ')' for expression");
- return innerExpr;
- }
- protected Expression ExpressionInfixRight(Parsed.Expression left, InfixOperator op)
- {
- Whitespace ();
- var right = Parse(() => Expression (op.precedence));
- if (right) {
-
-
- var expr = new BinaryExpression (left, right, op.type);
- return expr;
- }
- return null;
- }
- private InfixOperator ParseInfixOperator()
- {
- foreach (var op in _binaryOperators) {
- int ruleId = BeginRule ();
- if (ParseString (op.type) != null) {
- if (op.requireWhitespace) {
- if (Whitespace () == null) {
- FailRule (ruleId);
- continue;
- }
- }
- return (InfixOperator) SucceedRule(ruleId, op);
- }
- FailRule (ruleId);
- }
- return null;
- }
- protected Parsed.List ExpressionList ()
- {
- Whitespace ();
- if (ParseString ("(") == null)
- return null;
- Whitespace ();
-
-
-
-
-
-
- List<Identifier> memberNames = SeparatedList (ListMember, Spaced (String (",")));
- Whitespace ();
-
-
- if (ParseString (")") == null)
- return null;
- return new List (memberNames);
- }
- protected Identifier ListMember ()
- {
- Whitespace ();
- Identifier identifier = Parse (IdentifierWithMetadata);
- if (identifier == null)
- return null;
- var dot = ParseString (".");
- if (dot != null) {
- Identifier identifier2 = Expect (IdentifierWithMetadata, "element name within the set " + identifier) as Identifier;
- identifier.name = identifier.name + "." + identifier2?.name;
- }
- Whitespace ();
- return identifier;
- }
- void RegisterExpressionOperators()
- {
- _maxBinaryOpLength = 0;
- _binaryOperators = new List<InfixOperator> ();
-
-
- RegisterBinaryOperator ("&&", precedence:1);
- RegisterBinaryOperator ("||", precedence:1);
- RegisterBinaryOperator ("and", precedence:1, requireWhitespace: true);
- RegisterBinaryOperator ("or", precedence:1, requireWhitespace: true);
- RegisterBinaryOperator ("==", precedence:2);
- RegisterBinaryOperator (">=", precedence:2);
- RegisterBinaryOperator ("<=", precedence:2);
- RegisterBinaryOperator ("<", precedence:2);
- RegisterBinaryOperator (">", precedence:2);
- RegisterBinaryOperator ("!=", precedence:2);
-
- RegisterBinaryOperator ("?", precedence: 3);
- RegisterBinaryOperator ("has", precedence: 3, requireWhitespace:true);
- RegisterBinaryOperator ("!?", precedence: 3);
- RegisterBinaryOperator ("hasnt", precedence: 3, requireWhitespace: true);
- RegisterBinaryOperator ("^", precedence: 3);
- RegisterBinaryOperator ("+", precedence:4);
- RegisterBinaryOperator ("-", precedence:5);
- RegisterBinaryOperator ("*", precedence:6);
- RegisterBinaryOperator ("/", precedence:7);
- RegisterBinaryOperator ("%", precedence:8);
- RegisterBinaryOperator ("mod", precedence:8, requireWhitespace:true);
- }
- void RegisterBinaryOperator(string op, int precedence, bool requireWhitespace = false)
- {
- _binaryOperators.Add(new InfixOperator (op, precedence, requireWhitespace));
- _maxBinaryOpLength = Math.Max (_maxBinaryOpLength, op.Length);
- }
- List<InfixOperator> _binaryOperators;
- int _maxBinaryOpLength;
- }
- }