private object ParseValue() { if (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.String) { object v = _tokenizer.TokenText; _tokenizer.GetNextToken(); return v; } if (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.Number) { string number = _tokenizer.TokenText; ExpressionTokenizer.Position p0 = _tokenizer.CurrentPosition; _tokenizer.GetNextToken(); ExpressionTokenizer.Position p1 = new ExpressionTokenizer.Position( _tokenizer.CurrentPosition.CharIndex - 1); if (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.Dot) { number += "."; _tokenizer.GetNextToken(); if (_tokenizer.CurrentToken != ExpressionTokenizer.TokenType.Number) { throw BuildParseError("Fractional part expected.", _tokenizer.CurrentPosition); } number += _tokenizer.TokenText; _tokenizer.GetNextToken(); p1 = _tokenizer.CurrentPosition; try { return Double.Parse(number, CultureInfo.InvariantCulture); } catch (OverflowException) { throw BuildParseError("Value was either too large or too" + " small for type 'double'.", p0, p1); } } else { try { return Int32.Parse(number, CultureInfo.InvariantCulture); } catch (OverflowException) { try { return long.Parse(number, CultureInfo.InvariantCulture); } catch (OverflowException) { throw BuildParseError("Value was either too large or too" + " small for type 'long'.", p0, p1); } } } } if (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.Minus) { _tokenizer.GetNextToken(); // unary minus ExpressionTokenizer.Position p0 = _tokenizer.CurrentPosition; object v = ParseValue(); ExpressionTokenizer.Position p1 = _tokenizer.CurrentPosition; if (!SyntaxCheckOnly()) { if (v is int) { return -((int) v); } if (v is long) { return -((long) v); } if (v is double) { return -((double) v); } throw BuildParseError(string.Format(CultureInfo.InvariantCulture, ResourceUtils.GetString("NA1040"), GetSimpleTypeName(v.GetType())), p0, p1); } return null; } if (_tokenizer.IsKeyword("not")) { _tokenizer.GetNextToken(); // unary boolean not ExpressionTokenizer.Position p0 = _tokenizer.CurrentPosition; object v = ParseValue(); ExpressionTokenizer.Position p1 = _tokenizer.CurrentPosition; if (!SyntaxCheckOnly()) { bool value = (bool)SafeConvert(typeof(bool), v, "the argument of 'not' operator", p0, p1); return !value; } return null; } if (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.LeftParen) { _tokenizer.GetNextToken(); object v = ParseExpression(); if (_tokenizer.CurrentToken != ExpressionTokenizer.TokenType.RightParen) { throw BuildParseError("')' expected.", _tokenizer.CurrentPosition); } _tokenizer.GetNextToken(); return v; } if (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.Keyword) { ExpressionTokenizer.Position p0 = _tokenizer.CurrentPosition; string functionOrPropertyName = _tokenizer.TokenText; if (functionOrPropertyName == "if") { return ParseConditional(); } if (functionOrPropertyName == "true") { _tokenizer.GetNextToken(); return true; } if (functionOrPropertyName == "false") { _tokenizer.GetNextToken(); return false; } // don't ignore whitespace - properties shouldn't be written with spaces in them _tokenizer.IgnoreWhitespace = false; _tokenizer.GetNextToken(); ArrayList args = new ArrayList(); bool isFunction = false; // gather function or property name if (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.DoubleColon) { isFunction = true; functionOrPropertyName += "::"; _tokenizer.GetNextToken(); if (_tokenizer.CurrentToken != ExpressionTokenizer.TokenType.Keyword) { throw BuildParseError("Function name expected.", p0, _tokenizer.CurrentPosition); } functionOrPropertyName += _tokenizer.TokenText; _tokenizer.GetNextToken(); } else { while (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.Dot || _tokenizer.CurrentToken == ExpressionTokenizer.TokenType.Minus || _tokenizer.CurrentToken == ExpressionTokenizer.TokenType.Keyword || _tokenizer.CurrentToken == ExpressionTokenizer.TokenType.Number) { functionOrPropertyName += _tokenizer.TokenText; _tokenizer.GetNextToken(); } } _tokenizer.IgnoreWhitespace = true; // if we've stopped on a whitespace - advance to the next token if (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.Whitespace) { _tokenizer.GetNextToken(); } MethodInfo function = null; if (isFunction) { if ( _tokenizer.CurrentToken != ExpressionTokenizer.TokenType.LeftParen) { throw BuildParseError("'(' expected.", _tokenizer.CurrentPosition); } _tokenizer.GetNextToken(); int currentArgument = 0; while (_tokenizer.CurrentToken != ExpressionTokenizer.TokenType.RightParen && _tokenizer.CurrentToken != ExpressionTokenizer.TokenType.EOF) { ExpressionTokenizer.Position beforeArgument = _tokenizer.CurrentPosition; object e = ParseExpression(); ExpressionTokenizer.Position afterArgument = _tokenizer.CurrentPosition; args.Add (new FunctionArgument(functionOrPropertyName, currentArgument, e, beforeArgument, afterArgument)); currentArgument++; if (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.RightParen) break; if (_tokenizer.CurrentToken != ExpressionTokenizer.TokenType.Comma) throw BuildParseError("',' expected.", _tokenizer.CurrentPosition); _tokenizer.GetNextToken(); } if (_tokenizer.CurrentToken != ExpressionTokenizer.TokenType.RightParen) { throw BuildParseError("')' expected.", _tokenizer.CurrentPosition); } _tokenizer.GetNextToken(); if (!SyntaxCheckOnly()) { FunctionArgument[] functionArgs = new FunctionArgument[args.Count]; args.CopyTo(0, functionArgs, 0, args.Count); // lookup function matching name and argument count try { function = TypeFactory.LookupFunction(functionOrPropertyName, functionArgs, Project); } catch (BuildException ex) { throw BuildParseError(ex.Message, p0, _tokenizer.CurrentPosition); } ParameterInfo[] formalParameters = function.GetParameters (); args.Clear (); for (int i = 0; i < functionArgs.Length; i++) { FunctionArgument arg = functionArgs[i]; ParameterInfo pi = formalParameters[i]; object convertedValue = SafeConvert(pi.ParameterType, arg.Value, string.Format(CultureInfo.InvariantCulture, "argument {1} ({0}) of {2}()", pi.Name, arg.Index, arg.Name), arg.BeforeArgument, arg.AfterArgument); args.Add(convertedValue); } } } try { if (!SyntaxCheckOnly()) { if (isFunction) { return EvaluateFunction(function, args.ToArray ()); } else { return EvaluateProperty(functionOrPropertyName); } } else { return null; // this is needed because of short-circuit evaluation } } catch (Exception e) { if (isFunction) { throw BuildParseError("Function call failed.", p0, _tokenizer.CurrentPosition, e); } else { throw BuildParseError("Property evaluation failed.", p0, _tokenizer.CurrentPosition, e); } } } return UnexpectedToken(); }
/// <summary> /// Looks up a function by name and argument count. /// </summary> /// <param name="functionName">The name of the function to lookup, including namespace prefix.</param> /// <param name="args">The argument of the function to lookup.</param> /// <param name="project">The <see cref="Project" /> in which the function is invoked.</param> /// <returns> /// A <see cref="MethodInfo" /> representing the function, or /// <see langword="null" /> if a function with the given name and /// arguments does not exist. /// </returns> internal static MethodInfo LookupFunction(string functionName, FunctionArgument[] args, Project project) { object function = _methodInfoCollection[functionName]; if (function == null) throw new BuildException(string.Format(CultureInfo.InvariantCulture, ResourceUtils.GetString("NA1052"), functionName)); MethodInfo mi = function as MethodInfo; if (mi != null) { if (mi.GetParameters ().Length == args.Length) { CheckDeprecation(functionName, mi, project); return mi; } } else { ArrayList matches = (ArrayList) function; for (int i = 0; i < matches.Count; i++) { mi = (MethodInfo) matches [i]; if (mi.GetParameters ().Length == args.Length) { CheckDeprecation(functionName, mi, project); return mi; } } } throw new BuildException(string.Format(CultureInfo.InvariantCulture, ResourceUtils.GetString("NA1044"), functionName, args.Length)); }