Exemplo n.º 1
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="CSharpFunctionCall" /> class by parsing a function call from
        ///     <paramref name="callString" />
        /// </summary>
        /// <param name="callString">The full call signature to parse.</param>
        /// <exception cref="System.ArgumentNullException">Thrown if <paramref name="callString" /> is <c>null</c>.</exception>
        /// <exception cref="System.ArgumentException">
        ///     Thrown if <see cref="CSharpFunctionCallValidator.Validate" /> fails to
        ///     successfully parse <paramref name="callString" />.
        /// </exception>
        public CSharpFunctionCall(string callString)
        {
            if (callString == null)
            {
                throw new ArgumentNullException("callString", "Inheritance list signature string cannot be null.");
            }

            _validatedSignature = CSharpFunctionCallValidator.Validate(callString);

            if (!_validatedSignature.Success)
            {
                throw new ArgumentException(_validatedSignature.ErrorDescription, "callString");
            }

            _fullSignature = callString;
        }
        /// <summary>
        ///     Parses and validates a string as a CSharp method call.
        /// </summary>
        /// <param name="signature">The method call signature, without a semi-colon at the end.</param>
        /// <returns>A parse/validation results object.  <see cref="CSharpFunctionCallValidationResult" /></returns>
        /// <exception cref="ArgumentNullException"><paramref name="signature"/> is <c>null</c>.</exception>
        public static CSharpFunctionCallValidationResult Validate(string signature)
        {
            if (signature == null)
            {
                throw new ArgumentNullException("signature");
            }

            var result = new CSharpFunctionCallValidationResult {
                Success = true
            };

            var explicitGenericParameters = new GenericArray <CSharpClassNameValidationResult>();
            var parameters = new GenericArray <CSharpParameterSignature>();

            var lastModifier = CSharpParameterModifier.None;

            var state = States.WaitingForFirstCharacter;

            var stateBeforeBrackets        = new Stack <States>();
            var stateBeforeGenericTypePart = new Stack <States>();
            var stateBeforeParenthesis     = new Stack <States>();
            var stateBeforeCurlyBraces     = new Stack <States>();

            string accum = "";
            int    unmatchedGenericBrackets = 0;
            int    unmatchedParenthesis     = 0;
            int    unmatchedCurlyBraces     = 0;
            int    unmatchedBrackets        = 0;
            string methodName = "";

            for (int index = 0; index < signature.Length; index++)
            {
                var c = signature[index];
                accum += c;


                if (c == 'o' || c == 'r' || c == 'n')
                {
                    int wordBoundry = index + 2;
                    int ahead       = wordBoundry + 1;

                    if (wordBoundry >= signature.Length)
                    {
                        goto afterRefOutChecks;
                    }
                    var lookAhead          = signature.Substring(index, 3);
                    var lookAheadAssertion = lookAhead == "out" || lookAhead == "ref" || lookAhead == "new";
                    if (ahead < signature.Length && !char.IsWhiteSpace(signature[ahead]))
                    {
                        goto afterRefOutChecks;
                    }

                    if (lookAheadAssertion && state == States.WaitingForParameterName &&
                        lastModifier == CSharpParameterModifier.None)
                    {
                        lastModifier = lookAhead == "out"
                            ? CSharpParameterModifier.Out
                            : (lookAhead == "ref" ? CSharpParameterModifier.Ref : CSharpParameterModifier.New);

                        accum = "";
                        index = wordBoundry;
                        state = States.WaitingForParameterName;
                        continue;
                    }
                }


afterRefOutChecks:

                if (c == '[')
                {
                    if (state == States.AccumulatingParameter || state == States.WaitingForParameterName)
                    {
                        stateBeforeBrackets.Push(States.AccumulatingParameter);
                        state = States.InBracketExpression;
                        unmatchedBrackets++;
                        continue;
                    }


                    if (state == States.InBracketExpression || state == States.InCurlyBraceExpression ||
                        state == States.InParenthesizedExpression)
                    {
                        unmatchedBrackets++;
                        continue;
                    }
                }

                if (c == ']')
                {
                    if (state == States.InBracketExpression || state == States.InCurlyBraceExpression ||
                        state == States.InParenthesizedExpression)
                    {
                        unmatchedBrackets--;
                        if (unmatchedBrackets < 0)
                        {
                            result.Success          = false;
                            result.ErrorDescription = "Unexpected closing bracket.";
                            result.ErrorIndex       = index;
                            return(result);
                        }
                        if (unmatchedBrackets == 0)
                        {
                            if (stateBeforeBrackets.Count > 0)
                            {
                                state = stateBeforeBrackets.Pop();
                            }
                            else if (state == States.InBracketExpression)
                            {
                                goto unexpectedBracket;
                            }
                        }
                        continue;

unexpectedBracket:

                        result.Success          = false;
                        result.ErrorDescription = "Unexpected closing bracket.";
                        result.ErrorIndex       = index;
                        return(result);
                    }
                }


                if (c == '{')
                {
                    if (state == States.AccumulatingParameter || state == States.WaitingForParameterName)
                    {
                        stateBeforeCurlyBraces.Push(States.AccumulatingParameter);
                        state = States.InCurlyBraceExpression;
                        unmatchedCurlyBraces++;
                        continue;
                    }

                    if (state == States.InBracketExpression || state == States.InCurlyBraceExpression ||
                        state == States.InParenthesizedExpression)
                    {
                        unmatchedCurlyBraces++;
                        continue;
                    }
                }

                if (c == '}')
                {
                    if (state == States.InBracketExpression || state == States.InCurlyBraceExpression ||
                        state == States.InParenthesizedExpression)
                    {
                        unmatchedCurlyBraces--;
                        if (unmatchedCurlyBraces < 0)
                        {
                            result.Success          = false;
                            result.ErrorDescription = "Unexpected closing brace.";
                            result.ErrorIndex       = index;
                            return(result);
                        }
                        if (unmatchedCurlyBraces == 0)
                        {
                            if (stateBeforeCurlyBraces.Count > 0)
                            {
                                state = stateBeforeCurlyBraces.Pop();
                            }
                            else if (state == States.InCurlyBraceExpression)
                            {
                                goto unexpectedCurlyBrace;
                            }
                        }

                        continue;
                    }

unexpectedCurlyBrace:

                    result.Success          = false;
                    result.ErrorDescription = "Unexpected closing brace.";
                    result.ErrorIndex       = index;
                    return(result);
                }

                if (c == ')')
                {
                    if (state == States.WaitingForParameterName && parameters.Count == 0)
                    {
                        if (lastModifier == CSharpParameterModifier.None)
                        {
                            state = States.AfterSignature;
                            accum = "";
                        }
                        //otherwise the signature is incomplete
                        continue;
                    }

                    if (state == States.InBracketExpression || state == States.InCurlyBraceExpression ||
                        state == States.InParenthesizedExpression)
                    {
                        unmatchedParenthesis--;
                        if (unmatchedParenthesis < 0)
                        {
                            result.Success          = false;
                            result.ErrorDescription = "Unexpected closing parenthesis.";
                            result.ErrorIndex       = index;
                            return(result);
                        }
                        if (unmatchedParenthesis == 0)
                        {
                            if (stateBeforeParenthesis.Count > 0)
                            {
                                state = stateBeforeParenthesis.Pop();
                            }
                            else if (state == States.InParenthesizedExpression)
                            {
                                goto unexpectedParenth;
                            }
                        }
                        continue;
                    }
                    if (state == States.AccumulatingParameter)
                    {
                        var param = accum.Substring(0, accum.Length - 1).Trim();


                        if (!CSharpIDValidator.IsValidIdentifier(param) &&
                            (lastModifier == CSharpParameterModifier.Ref || lastModifier == CSharpParameterModifier.Out))
                        {
                            result.Success          = false;
                            result.ErrorDescription =
                                "'ref' and 'out' can only be used with a direct variable reference.";
                            result.ErrorIndex = index - (accum.Length - 1);
                            return(result);
                        }


                        string err;
                        int    errIndex;

                        if (lastModifier == CSharpParameterModifier.New &&
                            !IsValidNewParameter(param, index - (accum.Length - 1), out err, out errIndex))
                        {
                            result.Success          = false;
                            result.ErrorDescription = err;
                            result.ErrorIndex       = errIndex;
                            return(result);
                        }


                        if (lastModifier == CSharpParameterModifier.None &&
                            !IsValidPlainParameter(param, index - (accum.Length - 1), out err, out errIndex))
                        {
                            result.Success          = false;
                            result.ErrorDescription = err;
                            result.ErrorIndex       = errIndex;
                            return(result);
                        }

                        parameters.Add(new CSharpParameterSignature(param, lastModifier));
                        accum        = "";
                        lastModifier = CSharpParameterModifier.None;
                        state        = States.AfterSignature;
                        continue;
                    }

unexpectedParenth:
                    result.Success          = false;
                    result.ErrorDescription = "Unexpected closing parenthesis.";
                    result.ErrorIndex       = index;
                    return(result);
                }
                if (c == '(')
                {
                    if (state == States.AccumulatingParameter || state == States.WaitingForParameterName)
                    {
                        stateBeforeParenthesis.Push(States.AccumulatingParameter);
                        state = States.InParenthesizedExpression;
                        unmatchedParenthesis++;
                        continue;
                    }
                    if (state == States.AfterExplicitGenericMethodParameters)
                    {
                        accum = "";
                        state = States.WaitingForParameterName;
                        continue;
                    }
                    if (state == States.AccumulatingMethodNamePart)
                    {
                        methodName = accum.TrimEnd('(').Trim();
                        accum      = "";
                        state      = States.WaitingForParameterName;
                        continue;
                    }

                    if (state == States.InBracketExpression || state == States.InCurlyBraceExpression ||
                        state == States.InParenthesizedExpression)
                    {
                        unmatchedParenthesis++;
                        continue;
                    }

                    result.Success          = false;
                    result.ErrorDescription = "Unexpected opening parenthesis.";
                    result.ErrorIndex       = index;
                    return(result);
                }


                if (c == ',')
                {
                    if (state == States.InBracketExpression || state == States.InCurlyBraceExpression ||
                        state == States.InParenthesizedExpression)
                    {
                        continue;
                    }

                    if (state == States.AccumulatingExplicitGenericMethodParameters)
                    {
                        var param = accum.TrimEnd(',').Trim();

                        var validate = CSharpClassNameValidator.ValidateInitialization(param, true);
                        if (!validate.Success)
                        {
                            result.Success          = false;
                            result.ErrorDescription = validate.ErrorDescription;
                            result.ErrorIndex       = (index - (accum.Length - 1)) + validate.ErrorIndex;
                            return(result);
                        }

                        explicitGenericParameters.Add(validate);

                        accum = "";
                        continue;
                    }
                    if (state == States.AccumulatingParameter)
                    {
                        var param = accum.TrimEnd(',').Trim();

                        if (!CSharpIDValidator.IsValidIdentifier(param) &&
                            (lastModifier == CSharpParameterModifier.Ref || lastModifier == CSharpParameterModifier.Out))
                        {
                            result.Success          = false;
                            result.ErrorDescription =
                                "'ref' and 'out' can only be used with a direct variable reference.";
                            result.ErrorIndex = index - (accum.Length - 1);
                            return(result);
                        }

                        string err;
                        int    errIndex;

                        if (lastModifier == CSharpParameterModifier.New &&
                            !IsValidNewParameter(param, index - (accum.Length - 1), out err, out errIndex))
                        {
                            result.Success          = false;
                            result.ErrorDescription = err;
                            result.ErrorIndex       = errIndex;
                            return(result);
                        }


                        if (lastModifier == CSharpParameterModifier.None &&
                            !IsValidPlainParameter(param, index - (accum.Length - 1), out err, out errIndex))
                        {
                            result.Success          = false;
                            result.ErrorDescription = err;
                            result.ErrorIndex       = errIndex;
                            return(result);
                        }

                        state = States.WaitingForParameterName;
                        parameters.Add(new CSharpParameterSignature(param, lastModifier));
                        lastModifier = CSharpParameterModifier.None;
                        accum        = "";
                        continue;
                    }

                    result.Success          = false;
                    result.ErrorDescription = "Unexpected ',' character.";
                    result.ErrorIndex       = index;
                    return(result);
                }
                if (c == '<')
                {
                    if (state == States.AccumulatingParameter ||
                        state == States.InCurlyBraceExpression ||
                        state == States.InParenthesizedExpression ||
                        state == States.InBracketExpression)
                    {
                        continue;
                    }
                    if (state == States.AccumulatingMethodNamePart)
                    {
                        methodName = accum.TrimEnd('<').Trim();
                        accum      = "";
                        state      = States.AccumulatingExplicitGenericMethodParameters;
                        continue;
                    }
                    if (state == States.AccumulatingExplicitGenericMethodParameters)
                    {
                        unmatchedGenericBrackets++;
                        stateBeforeGenericTypePart.Push(state);
                        state = States.AccumulatingGenericTypePart;
                        continue;
                    }
                    if (state == States.AccumulatingGenericTypePart)
                    {
                        unmatchedGenericBrackets++;
                        continue;
                    }

                    result.Success          = false;
                    result.ErrorDescription = "Unexpected '<' character.";
                    result.ErrorIndex       = index;
                    return(result);
                }
                if (c == '>')
                {
                    if (state == States.AccumulatingParameter ||
                        state == States.InCurlyBraceExpression ||
                        state == States.InParenthesizedExpression ||
                        state == States.InBracketExpression)
                    {
                        continue;
                    }
                    if (state == States.AccumulatingGenericTypePart)
                    {
                        unmatchedGenericBrackets--;
                        if (unmatchedGenericBrackets == 0)
                        {
                            state = stateBeforeGenericTypePart.Pop();
                        }
                        continue;
                    }
                    if (state == States.AccumulatingExplicitGenericMethodParameters)
                    {
                        var param = accum.Substring(0, accum.Length > 0 ? accum.Length - 1 : 0).Trim();

                        var validate = CSharpClassNameValidator.ValidateInitialization(param, true);
                        if (!validate.Success)
                        {
                            result.Success          = false;
                            result.ErrorDescription = validate.ErrorDescription;
                            result.ErrorIndex       = (index - (accum.Length - 1)) + validate.ErrorIndex;
                            return(result);
                        }

                        explicitGenericParameters.Add(validate);
                        accum = "";
                        state = States.AfterExplicitGenericMethodParameters;
                        continue;
                    }

                    result.Success          = false;
                    result.ErrorDescription = "Unexpected '>' character.";
                    result.ErrorIndex       = index;
                    return(result);
                }

                if (!char.IsWhiteSpace(c))
                {
                    if (state == States.AccumulatingParameter ||
                        state == States.AccumulatingExplicitGenericMethodParameters ||
                        state == States.AccumulatingMethodNamePart ||
                        state == States.AccumulatingGenericTypePart ||
                        state == States.InCurlyBraceExpression ||
                        state == States.InBracketExpression ||
                        state == States.InParenthesizedExpression)
                    {
                        continue;
                    }
                    if (state == States.WaitingForParameterName)
                    {
                        accum = "" + c;
                        state = States.AccumulatingParameter;
                        continue;
                    }
                    if (state == States.WaitingForFirstCharacter)
                    {
                        accum = "" + c;
                        state = States.AccumulatingMethodNamePart;
                        continue;
                    }

                    result.Success          = false;
                    result.ErrorDescription = string.Format("Unexpected '{0}' character.", c);
                    result.ErrorIndex       = index;
                    return(result);
                }
            }


            if (state != States.AfterSignature)
            {
                result.Success          = false;
                result.ErrorDescription = "Call signature incomplete.";
                result.ErrorIndex       = signature.Length - 1;
                return(result);
            }


            result.MethodName = methodName;
            result.Parameters = parameters;
            result.ExplicitGenericParameters = explicitGenericParameters;
            return(result);
        }