/// <summary> /// Reads an expression wrapped in parenthesis. /// </summary> /// <param name="sourceCode"> /// The source code containing the expression. /// </param> /// <param name="parentReference"> /// The parent code part. /// </param> /// <returns> /// Returns the expression. /// </returns> private ParenthesizedExpression GetConditionalPreprocessorParenthesizedExpression(SourceCode sourceCode, Reference <ICodePart> parentReference) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(parentReference, "parentReference"); // Get the opening parenthesis. this.AdvanceToNextConditionalDirectiveCodeSymbol(parentReference); Symbol firstSymbol = this.symbols.Peek(1); if (firstSymbol == null || firstSymbol.SymbolType != SymbolType.OpenParenthesis) { throw new SyntaxException(sourceCode, firstSymbol.LineNumber); } Reference <ICodePart> expressionReference = new Reference <ICodePart>(); this.symbols.Advance(); Bracket openParenthesis = new Bracket(firstSymbol.Text, CsTokenType.OpenParenthesis, firstSymbol.Location, expressionReference, this.symbols.Generated); Node <CsToken> openParenthesisNode = this.tokens.InsertLast(openParenthesis); // Get the inner expression. Expression innerExpression = this.GetNextConditionalPreprocessorExpression(sourceCode, ExpressionPrecedence.None); if (innerExpression == null) { throw new SyntaxException(sourceCode, firstSymbol.LineNumber); } // Get the closing parenthesis. this.AdvanceToNextConditionalDirectiveCodeSymbol(expressionReference); Symbol symbol = this.symbols.Peek(1); if (symbol == null || symbol.SymbolType != SymbolType.CloseParenthesis) { throw new SyntaxException(sourceCode, firstSymbol.LineNumber); } this.symbols.Advance(); Bracket closeParenthesis = new Bracket(symbol.Text, CsTokenType.CloseParenthesis, symbol.Location, expressionReference, this.symbols.Generated); Node <CsToken> closeParenthesisNode = this.tokens.InsertLast(closeParenthesis); openParenthesis.MatchingBracketNode = closeParenthesisNode; closeParenthesis.MatchingBracketNode = openParenthesisNode; // Create the token list for the expression. CsTokenList partialTokens = new CsTokenList(this.tokens, openParenthesisNode, this.tokens.Last); // Create and return the expression. ParenthesizedExpression expression = new ParenthesizedExpression(partialTokens, innerExpression); expressionReference.Target = expression; return(expression); }
/// <summary> /// Parses an attribute. /// </summary> /// <param name="parentReference"> /// The parent code unit. /// </param> /// <param name="unsafeCode"> /// Indicates whether the attribute lies within a block of unsafe code. /// </param> /// <param name="masterDocument"> /// The master document object. /// </param> /// <returns> /// Returns the attribute. /// </returns> internal Attribute ParseAttribute(Reference<ICodePart> parentReference, bool unsafeCode, CsDocument masterDocument) { Param.AssertNotNull(parentReference, "parentReference"); Param.Ignore(unsafeCode); Param.AssertNotNull(masterDocument, "masterDocument"); Debug.Assert(this.document == null, "A CodeParser instance may only be used once."); this.document = masterDocument; Reference<ICodePart> attributeReference = new Reference<ICodePart>(); // Get the first symbol and make sure it is the right type. Symbol firstSymbol = this.symbols.Peek(1); Debug.Assert(firstSymbol != null && firstSymbol.SymbolType == SymbolType.OpenSquareBracket, "Expected an opening square bracket"); // The list of attribute expressions in the attribute. List<AttributeExpression> attributeExpressions = new List<AttributeExpression>(); // Move past the opening square bracket. Bracket openingBracket = new Bracket(firstSymbol.Text, CsTokenType.OpenAttributeBracket, firstSymbol.Location, attributeReference, this.symbols.Generated); Node<CsToken> openingBracketNode = this.tokens.InsertLast(openingBracket); this.symbols.Advance(); // Get each of the child attribute expressions within this attribute. while (true) { // Move to the next symbol. this.AdvanceToNextCodeSymbol(attributeReference); Symbol symbol = this.symbols.Peek(1); if (symbol == null) { throw new SyntaxException(this.document.SourceCode, firstSymbol.LineNumber); } // Check the type. If this is the closing bracket then we are done. if (symbol.SymbolType == SymbolType.CloseSquareBracket) { Bracket closingBracket = new Bracket(symbol.Text, CsTokenType.CloseAttributeBracket, symbol.Location, attributeReference, this.symbols.Generated); Node<CsToken> closingBracketNode = this.tokens.InsertLast(closingBracket); this.symbols.Advance(); openingBracket.MatchingBracketNode = closingBracketNode; closingBracket.MatchingBracketNode = openingBracketNode; break; } // Check to see if there is a target specified. LiteralExpression target = null; this.AdvanceToNextCodeSymbol(attributeReference); symbol = this.symbols.Peek(1); if (symbol == null) { throw new SyntaxException(this.document.SourceCode, firstSymbol.LineNumber); } Node<CsToken> previousTokenNode = this.tokens.Last; Reference<ICodePart> attributeExpressionReference = new Reference<ICodePart>(); if (symbol.SymbolType == SymbolType.Other || symbol.SymbolType == SymbolType.Return) { // Peek ahead to the next symbol and check if it's a colon. int index = this.GetNextCodeSymbolIndex(2); if (index != -1) { Symbol colon = this.symbols.Peek(index); if (colon.SymbolType == SymbolType.Colon) { // This is a target. Get the literal target expression and move past the colon. // Change the type of the target symbol to OTHER so that it will be parsed // correctly by the literal expression parser. symbol.SymbolType = SymbolType.Other; // Get the literal expression. Reference<ICodePart> targetReference = new Reference<ICodePart>(); target = this.GetLiteralExpression(targetReference, unsafeCode); Debug.Assert(target != null, "We should always succeed getting a Literal here since we have already seen a type of Other."); targetReference.Target = target; // Add the colon. this.AdvanceToNextCodeSymbol(attributeExpressionReference); this.tokens.Add(new CsToken(colon.Text, CsTokenType.AttributeColon, colon.Location, attributeExpressionReference, this.symbols.Generated)); this.symbols.Advance(); this.AdvanceToNextCodeSymbol(attributeExpressionReference); } } } // Now get the attribute call expression. Expression initialization = this.GetNextExpression(ExpressionPrecedence.None, attributeExpressionReference, unsafeCode); if (initialization == null) { throw new SyntaxException(this.document.SourceCode, firstSymbol.LineNumber); } // Create and add the attribute expression. Debug.Assert(previousTokenNode.Next != null, "Nothing was added to the token list!"); AttributeExpression attributeExpression = new AttributeExpression( new CsTokenList(this.tokens, previousTokenNode.Next, this.tokens.Last), target, initialization); attributeExpressions.Add(attributeExpression); attributeExpressionReference.Target = attributeExpression; // Get the next item, which must either be a comma or the closing attribute bracket. this.AdvanceToNextCodeSymbol(attributeReference); symbol = this.symbols.Peek(1); if (symbol == null) { throw new SyntaxException(this.document.SourceCode, firstSymbol.LineNumber); } if (symbol.SymbolType == SymbolType.Comma) { // Add the comma and continue. this.tokens.Add(this.GetToken(CsTokenType.Comma, SymbolType.Comma, attributeReference)); } else if (symbol.SymbolType != SymbolType.CloseSquareBracket) { // This type of symbol is unexpected. throw new SyntaxException(this.document.SourceCode, firstSymbol.LineNumber); } } // Get the location of the attribute. CodeLocation location = CsToken.JoinLocations(this.tokens.First, this.tokens.Last); // Create and return the attribute. Attribute attribute = new Attribute( this.tokens, location, parentReference, attributeExpressions.ToArray(), this.tokens.First.Value.Generated || this.tokens.Last.Value.Generated); attributeReference.Target = attribute; return attribute; }
private MasterList<CsToken> GetGenericArgumentList(Reference<ICodePart> genericTypeReference, bool unsafeCode, CsToken name, int startIndex, out int endIndex) { Param.AssertNotNull(genericTypeReference, "genericTypeReference"); Param.Ignore(unsafeCode); Param.Ignore(name); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); endIndex = -1; MasterList<CsToken> genericArgumentListTokens = null; // Move past whitespace and comments. int index = startIndex; while (true) { Symbol next = this.symbols.Peek(index); if (next == null || (next.SymbolType != SymbolType.WhiteSpace && next.SymbolType != SymbolType.EndOfLine && next.SymbolType != SymbolType.SingleLineComment && next.SymbolType != SymbolType.MultiLineComment && next.SymbolType != SymbolType.PreprocessorDirective)) { break; } ++index; } // The next symbol should be an opening bracket, if this is a generic. Symbol symbol = this.symbols.Peek(index); if (symbol != null && symbol.SymbolType == SymbolType.LessThan) { // This might be a generic. Assume that it is and start creating tokens. genericArgumentListTokens = new MasterList<CsToken>(); // Add the name if one was provided. if (name != null) { genericArgumentListTokens.Add(name); } Node<CsToken> openingGenericBracketNode = null; // Add everything up to the opening bracket into the token list. for (int i = startIndex; i <= index; ++i) { symbol = this.symbols.Peek(i); Debug.Assert(symbol != null, "The next symbol should not be null"); if (symbol.SymbolType == SymbolType.LessThan) { if (openingGenericBracketNode != null) { // This is not a generic statement. return null; } Bracket openingGenericBracket = new Bracket( symbol.Text, CsTokenType.OpenGenericBracket, symbol.Location, genericTypeReference, this.symbols.Generated); openingGenericBracketNode = genericArgumentListTokens.InsertLast(openingGenericBracket); } else { genericArgumentListTokens.Add(this.ConvertSymbol(symbol, TokenTypeFromSymbolType(symbol.SymbolType), genericTypeReference)); } } // Loop through the rest of the symbols. while (true) { symbol = this.symbols.Peek(++index); if (symbol == null) { // The code ran out before we found the end of the generic. throw new SyntaxException(this.document.SourceCode, name.LineNumber); } else if (symbol.SymbolType == SymbolType.GreaterThan) { if (openingGenericBracketNode == null) { // This is not a generic statement. return null; } // This is the end of the generic statement. Add the closing bracket to the token list. Bracket closingGenericBracket = new Bracket( symbol.Text, CsTokenType.CloseGenericBracket, symbol.Location, genericTypeReference, this.symbols.Generated); Node<CsToken> closingGenericBracketNode = genericArgumentListTokens.InsertLast(closingGenericBracket); ((Bracket)openingGenericBracketNode.Value).MatchingBracketNode = closingGenericBracketNode; closingGenericBracket.MatchingBracketNode = openingGenericBracketNode; endIndex = index; break; } else if (symbol.SymbolType == SymbolType.Out || symbol.SymbolType == SymbolType.In) { // Get the in or out keyword. genericArgumentListTokens.Add( this.ConvertSymbol(symbol, symbol.SymbolType == SymbolType.In ? CsTokenType.In : CsTokenType.Out, genericTypeReference)); } else if (symbol.SymbolType == SymbolType.Other) { int lastIndex = 0; Reference<ICodePart> wordReference = new Reference<ICodePart>(); CsToken word = this.GetTypeTokenAux(wordReference, genericTypeReference, unsafeCode, true, false, index, out lastIndex); if (word == null) { throw new SyntaxException(this.document.SourceCode, symbol.LineNumber); } // Advance the index to the end of the token. index = lastIndex; // Add the token. genericArgumentListTokens.Add(word); } else if (symbol.SymbolType == SymbolType.WhiteSpace || symbol.SymbolType == SymbolType.EndOfLine || symbol.SymbolType == SymbolType.SingleLineComment || symbol.SymbolType == SymbolType.MultiLineComment || symbol.SymbolType == SymbolType.PreprocessorDirective) { // Add these to the token list. genericArgumentListTokens.Add(this.ConvertSymbol(symbol, TokenTypeFromSymbolType(symbol.SymbolType), genericTypeReference)); } else if (symbol.SymbolType == SymbolType.Comma) { genericArgumentListTokens.Add(this.ConvertSymbol(symbol, CsTokenType.Comma, genericTypeReference)); } else if (symbol.SymbolType == SymbolType.OpenSquareBracket) { // An attribute on the generic type. genericArgumentListTokens.Add(this.GetAttribute(genericTypeReference, unsafeCode)); } else { // Any other symbol signifies that this is not a generic statement. genericArgumentListTokens = null; break; } } } return genericArgumentListTokens; }
/// <summary> /// Reads an expression wrapped in parenthesis. /// </summary> /// <param name="sourceCode"> /// The source code containing the expression. /// </param> /// <param name="parentReference"> /// The parent code part. /// </param> /// <returns> /// Returns the expression. /// </returns> private ParenthesizedExpression GetConditionalPreprocessorParenthesizedExpression(SourceCode sourceCode, Reference<ICodePart> parentReference) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(parentReference, "parentReference"); // Get the opening parenthesis. this.AdvanceToNextConditionalDirectiveCodeSymbol(parentReference); Symbol firstSymbol = this.symbols.Peek(1); if (firstSymbol == null || firstSymbol.SymbolType != SymbolType.OpenParenthesis) { throw new SyntaxException(sourceCode, firstSymbol.LineNumber); } Reference<ICodePart> expressionReference = new Reference<ICodePart>(); this.symbols.Advance(); Bracket openParenthesis = new Bracket(firstSymbol.Text, CsTokenType.OpenParenthesis, firstSymbol.Location, expressionReference, this.symbols.Generated); Node<CsToken> openParenthesisNode = this.tokens.InsertLast(openParenthesis); // Get the inner expression. Expression innerExpression = this.GetNextConditionalPreprocessorExpression(sourceCode, ExpressionPrecedence.None); if (innerExpression == null) { throw new SyntaxException(sourceCode, firstSymbol.LineNumber); } // Get the closing parenthesis. this.AdvanceToNextConditionalDirectiveCodeSymbol(expressionReference); Symbol symbol = this.symbols.Peek(1); if (symbol == null || symbol.SymbolType != SymbolType.CloseParenthesis) { throw new SyntaxException(sourceCode, firstSymbol.LineNumber); } this.symbols.Advance(); Bracket closeParenthesis = new Bracket(symbol.Text, CsTokenType.CloseParenthesis, symbol.Location, expressionReference, this.symbols.Generated); Node<CsToken> closeParenthesisNode = this.tokens.InsertLast(closeParenthesis); openParenthesis.MatchingBracketNode = closeParenthesisNode; closeParenthesis.MatchingBracketNode = openParenthesisNode; // Create the token list for the expression. CsTokenList partialTokens = new CsTokenList(this.tokens, openParenthesisNode, this.tokens.Last); // Create and return the expression. ParenthesizedExpression expression = new ParenthesizedExpression(partialTokens, innerExpression); expressionReference.Target = expression; return expression; }
/// <summary> /// Parses the iterators from a for-statement. /// </summary> /// <param name="statementReference"> /// A reference to the statement being created. /// </param> /// <param name="unsafeCode"> /// Indicates whether the code is located within an unsafe block. /// </param> /// <param name="openParenthesis"> /// The opening parenthesis. /// </param> /// <param name="openParenthesisNode"> /// The opening parenthesis node. /// </param> /// <returns> /// Returns the list of iterators. /// </returns> private List<Expression> ParseForStatementIterators( Reference<ICodePart> statementReference, bool unsafeCode, Bracket openParenthesis, Node<CsToken> openParenthesisNode) { Param.AssertNotNull(statementReference, "statementReference"); Param.Ignore(unsafeCode); Param.AssertNotNull(openParenthesis, "openParenthesis"); Param.AssertNotNull(openParenthesisNode, "openParenthesisNode"); // Get the iterators. List<Expression> iterators = new List<Expression>(); while (true) { // Check the type of the next symbol. Symbol symbol = this.GetNextSymbol(statementReference); if (symbol.SymbolType == SymbolType.CloseParenthesis) { // This is the end of the iterator list. Add the parenthesis and break. Bracket closeParenthesis = this.GetBracketToken(CsTokenType.CloseParenthesis, SymbolType.CloseParenthesis, statementReference); Node<CsToken> closeParenthesisNode = this.tokens.InsertLast(closeParenthesis); openParenthesis.MatchingBracketNode = closeParenthesisNode; closeParenthesis.MatchingBracketNode = openParenthesisNode; break; } // Get the next iterator expression. Expression iterator = this.GetNextExpression(ExpressionPrecedence.None, statementReference, unsafeCode); if (iterator == null || iterator.Tokens.First == null) { throw new SyntaxException(this.document.SourceCode, symbol.LineNumber); } // Add the initializer to the list. iterators.Add(iterator); // If the next symbol is a comma, save it. symbol = this.GetNextSymbol(statementReference); if (symbol.SymbolType == SymbolType.Comma) { this.tokens.Add(this.GetToken(CsTokenType.Comma, SymbolType.Comma, statementReference)); } else if (symbol.SymbolType != SymbolType.CloseParenthesis) { // If it's not a comma it must be a closing parenthesis. throw new SyntaxException(this.document.SourceCode, symbol.LineNumber); } } return iterators; }
/// <summary> /// Gets array brackets symbol for a type token, if they exist. /// </summary> /// <param name="typeTokenReference"> /// A reference to the type token. /// </param> /// <param name="typeTokens"> /// The tokens within the type token. /// </param> /// <param name="startIndex"> /// The start index within the symbols. /// </param> private void GetTypeTokenArrayBrackets(Reference<ICodePart> typeTokenReference, MasterList<CsToken> typeTokens, ref int startIndex) { Param.AssertNotNull(typeTokenReference, "typeTokenReference"); Param.AssertNotNull(typeTokens, "typeTokens"); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); int index = this.GetNextCodeSymbolIndex(startIndex); if (index != -1) { Symbol symbol = this.symbols.Peek(index); if (symbol.SymbolType == SymbolType.OpenSquareBracket) { // Add the tokens up to this point. for (int i = startIndex; i <= index - 1; ++i) { Symbol symbolToConvert = this.symbols.Peek(startIndex); typeTokens.Add(this.ConvertSymbol(symbolToConvert, TokenTypeFromSymbolType(symbolToConvert.SymbolType), typeTokenReference)); ++startIndex; } // Now collect the brackets. Node<CsToken> openingBracketNode = null; while (true) { symbol = this.symbols.Peek(startIndex); if (symbol.SymbolType == SymbolType.WhiteSpace || symbol.SymbolType == SymbolType.EndOfLine || symbol.SymbolType == SymbolType.SingleLineComment || symbol.SymbolType == SymbolType.MultiLineComment || symbol.SymbolType == SymbolType.PreprocessorDirective) { typeTokens.Add(this.ConvertSymbol(symbol, TokenTypeFromSymbolType(symbol.SymbolType), typeTokenReference)); ++startIndex; } else if (symbol.SymbolType == SymbolType.Number) { typeTokens.Add(this.ConvertSymbol(symbol, CsTokenType.Number, typeTokenReference)); ++startIndex; } else if (symbol.SymbolType == SymbolType.Other) { // Could be a constant or a reference to a constant. typeTokens.Add(this.ConvertSymbol(symbol, CsTokenType.Other, typeTokenReference)); ++startIndex; } else if (symbol.SymbolType == SymbolType.Dot) { // Could be a dot in here like: int a[Constants.DefaultSize]; typeTokens.Add(this.ConvertSymbol(symbol, CsTokenType.Other, typeTokenReference)); ++startIndex; } else if (symbol.SymbolType == SymbolType.Comma) { typeTokens.Add(this.ConvertSymbol(symbol, CsTokenType.Comma, typeTokenReference)); ++startIndex; } else if (symbol.SymbolType == SymbolType.OpenSquareBracket) { if (openingBracketNode != null) { throw new SyntaxException(this.document.SourceCode, symbol.LineNumber); } Bracket openingBracket = new Bracket(symbol.Text, CsTokenType.OpenSquareBracket, symbol.Location, typeTokenReference, this.symbols.Generated); openingBracketNode = typeTokens.InsertLast(openingBracket); ++startIndex; } else if (symbol.SymbolType == SymbolType.CloseSquareBracket) { if (openingBracketNode == null) { throw new SyntaxException(this.document.SourceCode, symbol.LineNumber); } Bracket closingBracket = new Bracket(symbol.Text, CsTokenType.CloseSquareBracket, symbol.Location, typeTokenReference, this.symbols.Generated); Node<CsToken> closingBracketNode = typeTokens.InsertLast(closingBracket); ++startIndex; ((Bracket)openingBracketNode.Value).MatchingBracketNode = closingBracketNode; closingBracket.MatchingBracketNode = openingBracketNode; openingBracketNode = null; // Check whether the next character is another opening bracket. int temp = this.GetNextCodeSymbolIndex(startIndex); if (temp != -1 && this.symbols.Peek(temp).SymbolType != SymbolType.OpenSquareBracket) { break; } } else { if (openingBracketNode != null) { throw new SyntaxException(this.document.SourceCode, symbol.LineNumber); } break; } } } } }
/// <summary> /// Gets friendly output text for "opening" or "closing", depending on the type of the bracket. /// </summary> /// <param name="bracket"> /// The bracket. /// </param> /// <returns> /// Returns the opening or closing text. /// </returns> private static string GetOpeningOrClosingBracketText(Bracket bracket) { Param.AssertNotNull(bracket, "bracket"); switch (bracket.CsTokenType) { case CsTokenType.OpenAttributeBracket: case CsTokenType.OpenCurlyBracket: case CsTokenType.OpenGenericBracket: case CsTokenType.OpenParenthesis: case CsTokenType.OpenSquareBracket: return Strings.Opening; case CsTokenType.CloseAttributeBracket: case CsTokenType.CloseCurlyBracket: case CsTokenType.CloseGenericBracket: case CsTokenType.CloseParenthesis: case CsTokenType.CloseSquareBracket: return Strings.Closing; default: Debug.Fail("Invalid bracket type."); return string.Empty; } }