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();
        }
Ejemplo n.º 2
0
        /// <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));
        }