/// <summary>
        /// Parses an element's parameter list.
        /// </summary>
        /// <param name="elementReference">
        /// A reference to the element being created.
        /// </param>
        /// <param name="unsafeCode">
        /// Indicates whether the code is marked as unsafe.
        /// </param>
        /// <param name="openingBracketType">
        /// The type of the bracket which opens the parameter list.
        /// </param>
        /// <param name="staticMethod">
        /// Indicates whether the parameters are part of a static method.
        /// </param>
        /// <returns>
        /// Returns the collection of parameters.
        /// </returns>
        private IList<Parameter> ParseParameterList(Reference<ICodePart> elementReference, bool unsafeCode, SymbolType openingBracketType, bool staticMethod)
        {
            Param.AssertNotNull(elementReference, "elementReference");
            Param.Ignore(unsafeCode);
            Param.Ignore(openingBracketType);
            Param.Ignore(staticMethod);

            CsTokenType openingBracketTokenType = CsTokenType.OpenParenthesis;
            CsTokenType closingBracketTokenType = CsTokenType.CloseParenthesis;
            SymbolType closingBracketType = SymbolType.CloseParenthesis;

            if (openingBracketType == SymbolType.OpenSquareBracket)
            {
                openingBracketTokenType = CsTokenType.OpenSquareBracket;
                closingBracketTokenType = CsTokenType.CloseSquareBracket;
                closingBracketType = SymbolType.CloseSquareBracket;
            }
            else
            {
                Debug.Assert(openingBracketType == SymbolType.OpenParenthesis, "The opening bracket type can only be a parenthesis or a square bracket.");
            }

            // Get the opening bracket.
            Bracket openingParenthesis = this.GetBracketToken(openingBracketTokenType, openingBracketType, elementReference);
            Node<CsToken> openingParenthesisNode = this.tokens.InsertLast(openingParenthesis);

            // Get each of the parameters.
            Symbol symbol = this.GetNextSymbol(elementReference);

            List<Parameter> parameters = new List<Parameter>();

            while (symbol.SymbolType != closingBracketType)
            {
                Reference<ICodePart> parameterReference = new Reference<ICodePart>();
                Node<CsToken> previousToken = this.tokens.Last;

                // Collect attributes on the parameter.
                while (symbol.SymbolType == SymbolType.OpenSquareBracket)
                {
                    Attribute attribute = this.GetAttribute(parameterReference, unsafeCode);
                    if (attribute == null)
                    {
                        throw this.CreateSyntaxException();
                    }

                    this.tokens.Add(attribute);
                    symbol = this.GetNextSymbol(parameterReference);
                }

                ParameterModifiers modifiers = ParameterModifiers.None;

                // If there is a parameter modifier, get it.
                if (symbol.SymbolType == SymbolType.Ref)
                {
                    this.tokens.Add(this.GetToken(CsTokenType.Ref, SymbolType.Ref, parameterReference));
                    modifiers |= ParameterModifiers.Ref;
                }
                else if (symbol.SymbolType == SymbolType.Out)
                {
                    this.tokens.Add(this.GetToken(CsTokenType.Out, SymbolType.Out, parameterReference));
                    modifiers |= ParameterModifiers.Out;
                }
                else if (symbol.SymbolType == SymbolType.Params)
                {
                    this.tokens.Add(this.GetToken(CsTokenType.Params, SymbolType.Params, parameterReference));
                    modifiers |= ParameterModifiers.Params;
                }
                else if (symbol.SymbolType == SymbolType.This)
                {
                    // The this keyword indicates that this is an extension method. This is only allowed if 
                    // both of the following are true:
                    // 1. This must be the first parameter.
                    // 2. The element must be a static method.
                    if (parameters.Count == 0 && staticMethod)
                    {
                        this.tokens.Add(this.GetToken(CsTokenType.This, SymbolType.This, parameterReference));
                        modifiers |= ParameterModifiers.This;
                    }
                }

                // Get the parameter type.
                TypeToken parameterType = this.GetTypeToken(parameterReference, unsafeCode, true);

                CsToken parameterName = null;
                if (parameterType.Text.Equals("__arglist", StringComparison.Ordinal))
                {
                    // When the parameterType is __arglist, this means that there is actually no parameter type at
                    // all, and the parameter name should be set to the __arglist token.
                    parameterName = parameterType.ChildTokens.First.Value;
                    parameterType = null;

                    parameterName.ParentRef = parameterReference;
                    this.tokens.Add(parameterName);
                }
                else
                {
                    this.tokens.Add(parameterType);

                    // Get the parameter name.
                    parameterName = this.GetToken(CsTokenType.Other, SymbolType.Other, parameterReference);
                    parameterName.ParentRef = parameterReference;

                    this.tokens.Add(parameterName);
                }

                // Get the optional default value for the parameter.
                Expression defaultArgument = null;

                symbol = this.GetNextSymbol(parameterReference);
                if (symbol.SymbolType == SymbolType.Equals)
                {
                    this.tokens.Add(this.GetOperatorToken(OperatorType.Equals, parameterReference));

                    // Get the default value expression.
                    defaultArgument = this.GetNextExpression(ExpressionPrecedence.None, parameterReference, unsafeCode);
                }

                // Create the list of tokens comprising the parameter, and trim any whitespace off the beginning and end.
                CsTokenList tokenList = new CsTokenList(this.tokens, previousToken.Next, this.tokens.Last);
                tokenList.Trim();

                Parameter parameter = new Parameter(
                    parameterType,
                    parameterName.Text,
                    elementReference,
                    modifiers,
                    defaultArgument,
                    parameterType == null ? parameterName.Location : CodeLocation.Join(parameterType.Location, parameterName.Location),
                    tokenList,
                    parameterType == null ? parameterName.Generated : parameterType.Generated || parameterName.Generated);

                parameterReference.Target = parameter;
                parameters.Add(parameter);

                if (defaultArgument != null)
                {
                    IWriteableCodeUnit writeableCodeUnit = (IWriteableCodeUnit)defaultArgument;
                    writeableCodeUnit.SetParent(parameter);
                }

                // If the next symbol, is a comma, get the next parameter.
                symbol = this.GetNextSymbol(elementReference);
                if (symbol.SymbolType == SymbolType.Comma)
                {
                    this.tokens.Add(this.GetToken(CsTokenType.Comma, SymbolType.Comma, elementReference));
                    symbol = this.GetNextSymbol(elementReference);
                }
            }

            // Get the closing bracket.
            Bracket closingParenthesis = this.GetBracketToken(closingBracketTokenType, closingBracketType, elementReference);
            Node<CsToken> closingParenthesisNode = this.tokens.InsertLast(closingParenthesis);

            openingParenthesis.MatchingBracketNode = closingParenthesisNode;
            closingParenthesis.MatchingBracketNode = openingParenthesisNode;

            // Return the parameters as a read-only collection.
            return parameters.ToArray();
        }
Example #2
0
        /// <summary>
        /// Fills in the details of the set accessor.
        /// </summary>
        /// <param name="parent">
        /// The parent of the accessor.
        /// </param>
        private void FillSetAccessorDetails(CsElement parent)
        {
            Param.AssertNotNull(parent, "parent");

            Reference<ICodePart> accessorReference = new Reference<ICodePart>(this);

            Property property = parent as Property;
            if (property != null)
            {
                // Set accessors on properties do not have a return type but have an 
                // implied input parameter.
                this.returnType = CreateVoidTypeToken(accessorReference);

                this.parameters = new[]
                                      {
                                          new Parameter(
                                              property.ReturnType, 
                                              "value", 
                                              accessorReference, 
                                              ParameterModifiers.None, 
                                              null, 
                                              CodeLocation.Empty, 
                                              null, 
                                              property.ReturnType.Generated)
                                      };
            }
            else
            {
                // Set accessors on indexers do not have a return type but, but have the input
                // parameters of the parent indexer.
                Indexer indexer = (Indexer)parent;

                this.returnType = CreateVoidTypeToken(accessorReference);

                Parameter[] tempParameters = new Parameter[indexer.Parameters.Count + 1];
                int i = 0;
                foreach (Parameter parameter in indexer.Parameters)
                {
                    tempParameters[i++] = parameter;
                }

                // Add the implicit value parameter since this is a set accessor.
                tempParameters[i] = new Parameter(
                    indexer.ReturnType, "value", accessorReference, ParameterModifiers.None, null, CodeLocation.Empty, null, indexer.ReturnType.Generated);

                this.parameters = tempParameters;
            }
        }
        /// <summary>
        /// Parses an anonymous method or lambda expression's parameter list.
        /// </summary>
        /// <param name="elementReference">
        /// A reference to the element being created.
        /// </param>
        /// <param name="unsafeCode">
        /// Indicates whether the code is marked as unsafe.
        /// </param>
        /// <returns>
        /// Returns the collection of parameters.
        /// </returns>
        private ICollection<Parameter> ParseAnonymousMethodParameterList(Reference<ICodePart> elementReference, bool unsafeCode)
        {
            Param.AssertNotNull(elementReference, "elementReference");
            Param.Ignore(unsafeCode);

            // Get the opening bracket.
            Bracket openingParenthesis = this.GetBracketToken(CsTokenType.OpenParenthesis, SymbolType.OpenParenthesis, elementReference);
            Node<CsToken> openingParenthesisNode = this.tokens.InsertLast(openingParenthesis);

            List<Parameter> parameters = new List<Parameter>();

            // Get each of the parameters.
            Symbol symbol = this.GetNextSymbol(elementReference);

            while (symbol.SymbolType != SymbolType.CloseParenthesis)
            {
                Reference<ICodePart> parameterReference = new Reference<ICodePart>();
                Node<CsToken> previousToken = this.tokens.Last;

                ParameterModifiers modifiers = ParameterModifiers.None;

                // If there is a parameter modifier, get it.
                if (symbol.SymbolType == SymbolType.Ref)
                {
                    this.tokens.Add(this.GetToken(CsTokenType.Ref, SymbolType.Ref, parameterReference));
                    modifiers |= ParameterModifiers.Ref;
                }
                else if (symbol.SymbolType == SymbolType.Out)
                {
                    this.tokens.Add(this.GetToken(CsTokenType.Out, SymbolType.Out, parameterReference));
                    modifiers |= ParameterModifiers.Out;
                }
                else if (symbol.SymbolType == SymbolType.Params)
                {
                    this.tokens.Add(this.GetToken(CsTokenType.Params, SymbolType.Params, parameterReference));
                    modifiers |= ParameterModifiers.Params;
                }

                // The first token is either the parameter type in an explicit parameter list, or the parameter name
                // in an implicit parameter list.
                TypeToken firstToken = this.GetTypeToken(parameterReference, unsafeCode, true);

                // Peek ahead and look at the type of the next token.
                int index = this.GetNextCodeSymbolIndex(1);
                if (index == -1)
                {
                    throw this.CreateSyntaxException();
                }

                symbol = this.symbols.Peek(index);
                if (symbol.SymbolType == SymbolType.Comma || symbol.SymbolType == SymbolType.CloseParenthesis)
                {
                    // There is no type.
                    if (firstToken.ChildTokens.Count > 1)
                    {
                        throw this.CreateSyntaxException();
                    }

                    CsToken nameToken = firstToken.ChildTokens.First.Value;
                    nameToken.ParentRef = parameterReference;
                    this.tokens.Add(nameToken);

                    Parameter parameter = new Parameter(
                        null,
                        nameToken.Text,
                        elementReference,
                        modifiers,
                        null,
                        nameToken.Location,
                        new CsTokenList(this.tokens, previousToken.Next, this.tokens.Last),
                        nameToken.Generated);

                    parameterReference.Target = parameter;
                    parameters.Add(parameter);
                }
                else
                {
                    // There is a type and a name.
                    this.tokens.Add(firstToken);

                    // Get the parameter name.
                    CsToken nameToken = this.GetToken(CsTokenType.Other, SymbolType.Other, parameterReference);
                    this.tokens.Add(nameToken);

                    Parameter parameter = new Parameter(
                        firstToken,
                        nameToken.Text,
                        elementReference,
                        modifiers,
                        null,
                        CodeLocation.Join(firstToken.Location, nameToken.Location),
                        new CsTokenList(this.tokens, previousToken.Next, this.tokens.Last),
                        firstToken.Generated || nameToken.Generated);

                    parameterReference.Target = parameter;
                    parameters.Add(parameter);
                }

                // If the next symbol is a comma, get the next parameter.
                symbol = this.GetNextSymbol(elementReference);
                if (symbol.SymbolType == SymbolType.Comma)
                {
                    this.tokens.Add(this.GetToken(CsTokenType.Comma, SymbolType.Comma, elementReference));
                    symbol = this.GetNextSymbol(elementReference);
                }
            }

            // Get the closing bracket.
            Bracket closingParenthesis = this.GetBracketToken(CsTokenType.CloseParenthesis, SymbolType.CloseParenthesis, elementReference);
            Node<CsToken> closingParenthesisNode = this.tokens.InsertLast(closingParenthesis);

            openingParenthesis.MatchingBracketNode = closingParenthesisNode;
            closingParenthesis.MatchingBracketNode = openingParenthesisNode;

            return parameters;
        }
        /// <summary>
        /// Adds a parameter to the expression.
        /// </summary>
        /// <param name="parameter">
        /// The parameter to add.
        /// </param>
        internal void AddParameter(Parameter parameter)
        {
            Param.AssertNotNull(parameter, "parameter");

            if (this.parameters == null)
            {
                this.parameters = new List<Parameter>();
            }

            this.parameters.Add(parameter);
        }