/// <summary> /// Builds list of arguments for function call. Checks for arg list expression correctness. /// Main problems: try to convert argument types to types expected by function and check that number of actual arguments correspond to expected /// </summary> /// <param name="brackets">This is token, which contains all tokens related to arg list</param> /// <param name="contexts">List of ParameterExpressions - variables which will be passed as Funtor's arguments</param> /// <param name="recommendedTypes">List of recommended types of arguments</param> /// <returns>List of Expressions which will be used as arguments for function calls</returns> private static List <Expression> BuildFunctionArgumentsList(BracketsToken brackets, List <Expression> contexts, List <Type> recommendedTypes) { int startIndex = 0; int currIndex = 0; List <Expression> arguments = new List <Expression>(); if (brackets.Tokens.Count == 0) { return(arguments); } for (; currIndex < brackets.Tokens.Count; ++currIndex) { Token currToken = brackets.Tokens[currIndex]; if (currToken is CommaToken) { if (startIndex > currIndex - 1) { throw new BuilderException(currToken.Position, BuilderException.BuilderExceptionType.FunctionArgumentsExpected); } arguments.Add(BuildExpression(new ListSegment <Token>(brackets.Tokens, startIndex, currIndex - startIndex), contexts, recommendedTypes[arguments.Count])); startIndex = currIndex + 1; } } if (startIndex > currIndex - 1) { throw new BuilderException(brackets.Tokens[currIndex].Position, BuilderException.BuilderExceptionType.FunctionArgumentsExpected); } arguments.Add(BuildExpression(new ListSegment <Token>(brackets.Tokens, startIndex, currIndex - startIndex), contexts, recommendedTypes[arguments.Count])); return(arguments); }
private static int GetParamsNumber(BracketsToken brackets) { if (brackets.Tokens.Count == 0) { return(0); } int count = 1; for (int i = 0; i < brackets.Tokens.Count; ++i) { if (brackets.Tokens[i] is CommaToken) { ++count; } } return(count); }
/// <summary> /// Processing passed token expression. This fucntion actually creates token from its string representation and adds to tokens list. /// Takes brackets into account as well. /// </summary> /// <param name="strToken">String representation of the token</param> /// <param name="brackets">List of brackets' indexes. Only () brackets are handled</param> /// <param name="result">Tokens list</param> /// <param name="index">Index of current character we're parsing</param> static void ProcessToken(StringBuilder strToken, List <int> brackets, List <Token> result, int index) { if (strToken.Length == 0) { return; } string tempToken = strToken.ToString(); Token token = Token.CreateToken(tempToken, index); if (token != null) { result.Add(token); } else if (tempToken == "(") { brackets.Add(result.Count); strToken.Remove(0, strToken.Length); return; } else if (tempToken == ")") { if (brackets.Count == 0) { throw new ParserException(index, ParserException.ParserExceptionType.InvalidBracketsOrder); } int startIndex = brackets[brackets.Count - 1]; brackets.RemoveAt(brackets.Count - 1); List <Token> bracketTokens = new List <Token>(); for (int i = startIndex; i <= result.Count - 1; ++i) { bracketTokens.Add(result[i]); } if (result.Count - 1 - startIndex >= 0) { result.RemoveRange(startIndex + 1, result.Count - 1 - startIndex); result[startIndex] = new BracketsToken(bracketTokens) { Position = index }; } else { result.Add(new BracketsToken(bracketTokens) { Position = index }); } } else { result.Add(new MemberOrConstantToken(strToken.ToString(), false) { Position = index }); } strToken.Remove(0, strToken.Length); }
/// <summary> /// Builds expressions related to Property extraction, Function call, Type conversion and Constants /// </summary> /// <param name="tokens">Tokens list</param> /// <param name="contexts">List of ParameterExpressions - variables which will be passed as Funtor's arguments</param> /// <param name="recommendedType">If not null, tryes to convert resulted type of expression to recommendedType (no 100% guarantee)</param> /// <returns>Expression</returns> private static Expression BuildMembersExpression(ListSegment <Token> tokens, List <Expression> contexts, Type recommendedType) { int state = 0; //0-separator, 1-expression, 2-function Expression result = contexts[0]; MemberOrConstantToken methodToken = null; MemberOrConstantToken conversionToken = null; for (int i = 0; i < tokens.Count; ++i) { switch (state) { case 0: { MemberOrConstantToken mcToken = tokens[i] as MemberOrConstantToken; if (mcToken != null) { if (mcToken.IsString) { if (i == 0) { result = Expression.Constant(mcToken.StrValue); } else { throw new BuilderException(mcToken.Position, BuilderException.BuilderExceptionType.UnexpectedConstant, mcToken.StrValue); } } else if (i == tokens.Count - 1 || tokens[i + 1] is PointToken) { if (i == 0 && mcToken.StrValue.Length > 2 && mcToken.StrValue.Substring(0, 3).ToLower() == "arg") { string numstr = mcToken.StrValue.Substring(3); if (numstr != string.Empty) { int num = 0; try { num = Convert.ToInt32(numstr); } catch { throw new BuilderException(mcToken.Position, BuilderException.BuilderExceptionType.WrongArgFormat); } if (num >= contexts.Count) { throw new BuilderException(mcToken.Position, BuilderException.BuilderExceptionType.ArgNumberExceedsMax); } result = contexts[num]; } } else { PropertyInfo pi = TypeUtils.GetPropertyInfo(result.Type, mcToken.StrValue); if (pi != null) { result = Expression.Property(result, pi); } else if (i == 0) { result = CreateConstantExpression(mcToken, tokens.Count == 1 ? recommendedType : null); } else { throw new BuilderException(mcToken.Position, BuilderException.BuilderExceptionType.PropertyNotExists, pi.Name); } } } else { if (i == 0 && mcToken.IsConversion) { conversionToken = mcToken; state = 2; } else { if (TypeUtils.MethodExists(result.Type, mcToken.StrValue)) { state = 2; methodToken = mcToken; } else if (i == 0) { result = CreateConstantExpression(mcToken, tokens.Count == 1 ? recommendedType : null); } else { throw new BuilderException(mcToken.Position, BuilderException.BuilderExceptionType.FunctionNotExists, mcToken.StrValue); } } } if (state == 0) { state = 1; } break; } BracketsToken brToken = tokens[i] as BracketsToken; if (brToken != null) { result = BuildExpression(new ListSegment <Token>(brToken.Tokens), contexts, null); state = 1; break; } throw new BuilderException(tokens[i].Position, BuilderException.BuilderExceptionType.IncorrectExpression); } case 1: if (tokens[i] is PointToken) { state = 0; } else { throw new BuilderException(tokens[i].Position, BuilderException.BuilderExceptionType.UnexpectedExpression); } break; case 2: { BracketsToken brToken = tokens[i] as BracketsToken; if (brToken != null) { int argsCount = GetParamsNumber(brToken); if (methodToken != null) { MethodInfo mi = TypeUtils.GetMethodInfo(result.Type, methodToken.StrValue, 0); if (mi == null) { throw new BuilderException(methodToken.Position, BuilderException.BuilderExceptionType.NoFunctionFound); } if (argsCount == 0) { result = Expression.Call(result, mi); } else { ParameterInfo[] pinfos = mi.GetParameters(); List <Type> recommendedTypes = new List <Type>(); for (int j = 0; j < pinfos.Length; ++j) { if (!pinfos[j].IsOut && !pinfos[j].IsRetval) { recommendedTypes.Add(pinfos[j].ParameterType); } else { throw new BuilderException(tokens[i].Position, BuilderException.BuilderExceptionType.ParameterTypeNotSupported, pinfos[j].Name); } } List <Expression> args = BuildFunctionArgumentsList(brToken, contexts, recommendedTypes); result = Expression.Call(result, mi, args); } } else if (conversionToken != null) { if (argsCount != 1) { throw new BuilderException(conversionToken.Position, BuilderException.BuilderExceptionType.WrongArgumentsNumber, "1 expected"); } List <Type> recommendedTypes = new List <Type>(); recommendedTypes.Add(null); List <Expression> args = BuildFunctionArgumentsList(brToken, contexts, recommendedTypes); result = conversionToken.CreateConversion(args[0]); } else { throw new BuilderException(brToken.Position, BuilderException.BuilderExceptionType.UnexpectedError); } methodToken = null; conversionToken = null; state = 1; } else { throw new BuilderException(tokens[i].Position, BuilderException.BuilderExceptionType.FunctionArgumentsExpected); } } break; } } if (state == 2) { throw new BuilderException(tokens[tokens.Count - 1].Position, BuilderException.BuilderExceptionType.FunctionArgumentsExpected); } return(result); }