//todo this is not the best choice of design, IdentityExpression.Parse does the same, this is just more intuitive. both can co-exist. /// <summary> /// In cases like: property(1,2)[0] we have chained interaction, this resolves if current <see cref="result"/> has more interactions. If so, parses them. /// </summary> /// <param name="result">The result expression</param> /// <param name="ew">The walker with position right after <see cref="result"/></param> /// <param name="caller">Internal use.</param> /// <returns></returns> public static Expression TryExpand(Expression result, ExpressionWalker ew, Type caller = null) { if (ew.Current.Token == ExpressionToken.Period) { return(IdentityExpression.Parse(ew, caller, result)); } if (ew.Current.Token == ExpressionToken.LeftBracet) { return(IndexerCallExpression.Parse(ew, result)); } if (ew.Current.Token == ExpressionToken.LeftParen) { return(CallExpression.Parse(ew, result)); } return(result); }
public static NewExpression Parse(ExpressionWalker ew) { ew.IsCurrentOrThrow(ExpressionToken.New); ew.NextOrThrow(); return(new NewExpression(CallExpression.Parse(ew))); }
public static IdentityExpression Parse(ExpressionWalker ew, Type caller = null, Expression left = null) { var ret = new IdentityExpression(); //types: //justname //justname.accessor //justname.accessor[5].second //justname.method().someval //justname.method().someval[3].thatsfar if (left == null) { ew.IsCurrentOrThrow(ExpressionToken.Literal); } if (ew.HasNext && ew.PeakNext.WhitespacesAfterMatch == 0 && ew.PeakNext.Token == ExpressionToken.Period && caller != typeof(IdentityExpression) || left != null) { var first = left ?? ParseExpression(ew, typeof(IdentityExpression)); ew.NextOrThrow(); //skip the predicted period. var next = ew.PeakNext; switch (next.Token) { //currently we are at Literal case ExpressionToken.Period: ret.Identity = new PropertyIdentity(first, Parse(ew)); return(ret); case ExpressionToken.LeftBracet: ret.Identity = new PropertyIdentity(first, IndexerCallExpression.Parse(ew)); return(ret); case ExpressionToken.LeftParen: ret.Identity = new PropertyIdentity(first, CallExpression.Parse(ew)); return(ret); default: if (left != null) { return(new IdentityExpression(new PropertyIdentity(left, Parse(ew, typeof(IdentityExpression), null)))); } if (first != null) { //just a plain single word! var right = new IdentityExpression(); if (ew.IsCurrent(ExpressionToken.Null)) { right.Identity = NullIdentity.Instance; } else { ew.IsCurrentOrThrow(ExpressionToken.Literal); right.Identity = StringIdentity.Create(ew.Current.Match); } ew.Next(); return(new IdentityExpression(new PropertyIdentity(first, right))); } goto _plain_identity; } } _plain_identity: //just a plain single word! if (ew.IsCurrent(ExpressionToken.Null)) { ret.Identity = NullIdentity.Instance; } else { ew.IsCurrentOrThrow(ExpressionToken.Literal); ret.Identity = StringIdentity.Create(ew.Current.Match); } ew.Next(); return(ret); }
public static Expression ParseExpression(ExpressionWalker ew, Type caller = null) { Expression ret = null; _retry: bool isOperatorCall = caller == typeof(OperatorExpression) || caller == typeof(RightOperatorExpression) || caller == typeof(ForeachExpression); var current = ew.Current.Token; if (current == ExpressionToken.Literal) { //cases like variable(.., variable[.., variable + .., variable if (ew.HasNext) { var peak = ew.PeakNextOrThrow().Token; if (peak == ExpressionToken.LeftParen) { ret = CallExpression.Parse(ew); } else if (peak == ExpressionToken.Period && caller != typeof(IdentityExpression) && caller != typeof(InteractableExpression)) { ret = IdentityExpression.Parse(ew); } else if (peak == ExpressionToken.LeftBracet) { ret = IndexerCallExpression.Parse(ew); } else if (peak == ExpressionToken.New) { ret = NewExpression.Parse(ew); } else if (RightOperatorExpression.IsNextAnRightUniOperation(ew, caller) && caller != typeof(RightOperatorExpression)) { ret = RightOperatorExpression.Parse(ew); } else if (OperatorExpression.IsNextAnOperation(ew) && !isOperatorCall) { ret = OperatorExpression.Parse(ew); } else { ret = IdentityExpression.Parse(ew, caller); } } else { ret = IdentityExpression.Parse(ew, caller); } } else if (LeftOperatorExpression.IsCurrentAnLeftUniOperation(ew)) { ret = LeftOperatorExpression.Parse(ew); } else if (current == ExpressionToken.NumberLiteral) { ret = NumberLiteral.Parse(ew); } else if (current == ExpressionToken.StringLiteral) { ret = StringLiteral.Parse(ew); } else if (current == ExpressionToken.LeftParen) { ret = GroupExpression.Parse(ew, ExpressionToken.LeftParen, ExpressionToken.RightParen); } else if (current == ExpressionToken.LeftBracet) { ret = ArrayExpression.Parse(ew); } else if (current == ExpressionToken.New) { ret = NewExpression.Parse(ew); } else if (current == ExpressionToken.Boolean) { ret = BooleanLiteral.Parse(ew); } else if (current == ExpressionToken.CharLiteral) { ret = CharLiteral.Parse(ew); } else if (current == ExpressionToken.Throw) { ret = ThrowExpression.Parse(ew); } else if (current == ExpressionToken.Hashtag && ew.HasNext && ew.PeakNext.Token == ExpressionToken.NumberLiteral) { ret = HashtagReferenceExpression.Parse(ew, caller); } else if (current == ExpressionToken.Null) { ret = NullIdentity.Parse(ew); } else if (current == ExpressionToken.NewLine) { ew.NextOrThrow(); goto _retry; } else { throw new UnexpectedTokenException($"Token was not expected to be a {ew.Current.Token}"); } //here we parse chained math operations while (OperatorExpression.IsCurrentAnOperation(ew) && !isOperatorCall) { if (RightOperatorExpression.IsCurrentAnRightUniOperation(ew) && caller != typeof(OperatorExpression)) { ret = RightOperatorExpression.Parse(ew, ret); } else if (OperatorExpression.IsCurrentAnOperation(ew)) { ret = OperatorExpression.Parse(ew, ret); } } return(ret); }