/// <summary> /// Visits the function call expression tree /// </summary> /// <param name="exp"></param> public object VisitMemberAccess(MemberAccessExpr exp) { return null; }
/// <summary> /// Creates a function call expression. /// </summary> /// <param name="nameExpr"></param> /// <param name="parameters"></param> /// <param name="token"></param> /// <returns></returns> public static Expr MemberAccess(Expr nameExpr, string memberName, bool isAssignment, TokenData token) { var exp = new MemberAccessExpr(); exp.IsAssignment = isAssignment; exp.VarExp = nameExpr; exp.MemberName = memberName; SetupContext(exp, token); return exp; }
/// <summary> /// Either external function or member name. /// </summary> /// <returns></returns> public object VisitMemberAccess(MemberAccessExpr expr) { var memberAccess = MemberHelper.GetMemberAccess(expr, this.Ctx, expr.VarExp, expr.MemberName, this); if (expr.IsAssignment) return memberAccess; // NOTES: // 1. If property on a built in type && not assignment then just return the value of the property // 2. It's done here instead because there is no function/method call on a property. if (memberAccess.IsPropertyAccessOnBuiltInType()) { var result = FunctionHelper.CallMemberOnBasicType(this.Ctx, expr, memberAccess, null, null, this); return result; } if (memberAccess.IsPropertyAccessOnClass() || memberAccess.IsFieldAccessOnClass()) { var result = FunctionHelper.CallMemberOnClass(this.Ctx, expr, memberAccess, null, null, this); return result; } if (memberAccess.IsModuleAccess()) { var result = MemberHelper.ResolveSymbol(memberAccess.Scope, expr.MemberName); return result; } return memberAccess; }
/// <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; }