/// <summary> /// Visits the function call expression tree /// </summary> /// <param name="exp"></param> public object VisitIndex(IndexExpr exp) { _callBackOnNodeStart(exp); _callBackOnNodeStart(exp.VarExp); _callBackOnNodeStart(exp.IndexExp); return null; }
/// <summary> /// Creates an index expression from the parameters supplied. /// </summary> /// <param name="varExp"></param> /// <param name="indexExp"></param> /// <param name="isAssignment"></param> /// <param name="token"></param> /// <returns></returns> public static Expr Index(Expr varExp, Expr indexExp, bool isAssignment, TokenData token) { var exp = new IndexExpr(); exp.IsAssignment = isAssignment; exp.VarExp = varExp; exp.IndexExp = indexExp; SetupContext(exp, token); return exp; }
/// <summary> /// Evaluate object[index] /// </summary> /// <returns></returns> public static object EvalIndexAccess(IndexExpr expr) { var ndxVal = expr.IndexExp.Evaluate(); var listObject = expr.VariableExp.Evaluate(); // Check for empty objects. ExceptionHelper.NotNull(expr, listObject, "indexing"); ExceptionHelper.NotNull(expr, ndxVal, "indexing"); var lobj = (LObject)listObject; // CASE 1. Access // e.g. Array: users[0] // e.g. Map: users['total'] if (!expr.IsAssignment) { var result = EvalHelper.AccessIndex(Ctx.Methods, expr, lobj, (LObject)ndxVal); return result; } // CASE 2. Assignment // e.g. Array: users[0] = 'john' // e.g. Map: users['total'] = 200 // NOTE: In this case of assignment, return back a MemberAccess object descripting what is assign var indexAccess = new IndexAccess(); indexAccess.Instance = lobj; indexAccess.MemberName = (LObject)ndxVal; return indexAccess; }
/// <summary> /// Parses an Id based expression: /// 1. user : variable /// 2. getUser() : function call /// 3. users[ : index expression /// 4. user.name : member access /// /// ASSIGNMENT: EXPRESSION: /// result = 2; result -> variableexpression /// items[0] = 'kishore'; items[0] -> indexexpression( variableexpression | name) /// getuser(); getuser() -> functionexpression() /// user.age = 30; user.age -> memberexpression( variableexpression | name/member ) /// items[0].name = 'kishore'; items[0].name -> memberexpression( indexexpression( variableexpression ) ) /// getuser()[0] = 0; getuser()[0] -> indexexpression( functionexpression ) /// user.name.last = 'kishore'; user.name.last -> memberexpression( memberexpression ) /// </summary> /// <param name="name"></param> /// <param name="existing"></param> /// <param name="isCurrentTokenAMember">Whether or not the current token is a '[', '(' or a '.'</param> /// <returns></returns> public Expr ParseIdExpression(string name = null, Expr existing = null, bool isCurrentTokenAMember = false) { Expr exp = existing; var aheadToken = isCurrentTokenAMember ? _tokenIt.NextToken : _tokenIt.Peek(); var currentName = ""; if (existing == null) { currentName = string.IsNullOrEmpty(name) ? _tokenIt.NextToken.Token.Text : name; exp = this.ToIdentExpr(currentName, _tokenIt.NextToken); } if(!isCurrentTokenAMember) _tokenIt.Advance(); int memberAccess = 0; bool isFunction = (exp.IsNodeType(NodeTypes.SysVariable) && _context.Symbols.IsFunc(((VariableExpr)exp).Name)); // CASE 1: function call without out parenthesis. if (isFunction && aheadToken.Token != Tokens.LeftParenthesis) { exp = ParseFuncExpression(exp, null); exp.Ctx = _context; return exp; } // CASE 2: Simple variable expression - e.g. result + 2 bool isMemberAccessAhead = ( aheadToken.Token == Tokens.LeftParenthesis || aheadToken.Token == Tokens.LeftBracket || aheadToken.Token == Tokens.Dot ); if( !isFunction && !isMemberAccessAhead ) { exp.Ctx = _context; return exp; } // CASE 3: Member access of some sort using either "." | "[]" | "()" // 1. result.total : Dot access // 2. result[0] : Array access // 3. add( 2, 3 ) : Function access/call var tokenData = _tokenIt.NextToken; var token = _tokenIt.NextToken.Token; var members = new List<string>(); members.Add(exp.ToQualifiedName()); while (token == Tokens.LeftParenthesis || token == Tokens.LeftBracket || token == Tokens.Dot) { // Case 2: "("- function call if (token == Tokens.LeftParenthesis) { exp = ParseFuncExpression(exp, members); } // Case 3: "[" - indexing else if (token == Tokens.LeftBracket) { _tokenIt.Advance(); _state.IndexExp++; // Get index exp ( n+1 ) or n, etc. var index = ParseExpression(Terminators.ExpBracketEnd); _tokenIt.Expect(Tokens.RightBracket); _state.IndexExp--; // Note: if = sign then property access should return a property info. // otherwise get the value of the property. bool isAssignment = _tokenIt.NextToken.Token == Tokens.Assignment; exp = new IndexExpr(exp, index, isAssignment); } // Case 4: "." - member access else if (_tokenIt.NextToken.Token == Tokens.Dot) { _tokenIt.Advance(); var member = _tokenIt.ExpectId(); // Keep list of each member name. members.Add(member); // Note: if = sign then property access should return a property info. // otherwise get the value of the property. bool isAssignment = _tokenIt.NextToken.Token == Tokens.Assignment; exp = new MemberAccessExpr(exp, member, isAssignment); } this.SetupContext(exp, tokenData); memberAccess++; // Check limit. _context.Limits.CheckParserMemberAccess(exp, memberAccess); tokenData = _tokenIt.NextToken; token = tokenData.Token; } return exp; }