private Symbol GetOperatorSymbol(char character) { Param.Ignore(character); SymbolType type = SymbolType.Other; var text = new StringBuilder(); if (character == '.') { text.Append("."); type = SymbolType.Dot; this.codeReader.ReadNext(); } else if (character == '~') { text.Append("~"); type = SymbolType.Tilde; this.codeReader.ReadNext(); } else if (character == '+') { text.Append("+"); type = SymbolType.Plus; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '+') { text.Append("+"); type = SymbolType.Increment; this.codeReader.ReadNext(); } else if (character == '=') { text.Append("="); type = SymbolType.PlusEquals; this.codeReader.ReadNext(); } } else if (character == '-') { text.Append("-"); type = SymbolType.Minus; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '-') { text.Append("-"); type = SymbolType.Decrement; this.codeReader.ReadNext(); } else if (character == '=') { text.Append("="); type = SymbolType.MinusEquals; this.codeReader.ReadNext(); } else if (character == '>') { text.Append(">"); type = SymbolType.Pointer; this.codeReader.ReadNext(); } } else if (character == '*') { text.Append("*"); type = SymbolType.Multiplication; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("*"); type = SymbolType.MultiplicationEquals; this.codeReader.ReadNext(); } } else if (character == '/') { text.Append("/"); type = SymbolType.Division; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.DivisionEquals; this.codeReader.ReadNext(); } } else if (character == '|') { text.Append("|"); type = SymbolType.LogicalOr; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.OrEquals; this.codeReader.ReadNext(); } else if (character == '|') { text.Append("|"); type = SymbolType.ConditionalOr; this.codeReader.ReadNext(); } } else if (character == '&') { text.Append("&"); type = SymbolType.LogicalAnd; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.AndEquals; this.codeReader.ReadNext(); } else if (character == '&') { text.Append("&"); type = SymbolType.ConditionalAnd; this.codeReader.ReadNext(); } } else if (character == '^') { text.Append("^"); type = SymbolType.LogicalXor; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.XorEquals; this.codeReader.ReadNext(); } } else if (character == '!') { text.Append("!"); type = SymbolType.Not; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.NotEquals; this.codeReader.ReadNext(); } } else if (character == '%') { text.Append("%"); type = SymbolType.Mod; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.ModEquals; this.codeReader.ReadNext(); } } else if (character == '=') { text.Append("="); type = SymbolType.Equals; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.ConditionalEquals; this.codeReader.ReadNext(); } else if (character == '>') { text.Append(">"); type = SymbolType.Lambda; this.codeReader.ReadNext(); } } else if (character == '<') { text.Append("<"); type = SymbolType.LessThan; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.LessThanOrEquals; this.codeReader.ReadNext(); } else if (character == '<') { text.Append("<"); type = SymbolType.LeftShift; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.LeftShiftEquals; this.codeReader.ReadNext(); } } } else if (character == '>') { text.Append(">"); type = SymbolType.GreaterThan; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '=') { text.Append("="); type = SymbolType.GreaterThanOrEquals; this.codeReader.ReadNext(); } // Note: The right-shift symbol confuses the parsing of generics. // If there are two greater-thans in a row then this may be a right-shift // symbol, but we cannot create it as such right now because it may also // be a couple of closing generic symbols in a row. This will have to be // parsed out in the code. If this is a right-shift-equals then this will // be created as three separate symbols, two greater-thans and then an // equals. Later on we will recombine these. } else if (character == '?') { text.Append("?"); type = SymbolType.QuestionMark; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == '?') { text.Append("?"); type = SymbolType.NullCoalescingSymbol; this.codeReader.ReadNext(); } } else if (character == ':') { text.Append(":"); type = SymbolType.Colon; this.codeReader.ReadNext(); character = this.codeReader.Peek(); if (character == ':') { text.Append(":"); type = SymbolType.QualifiedAlias; this.codeReader.ReadNext(); } } // Make sure we have a symbol now. if (text == null || text.Length == 0) { throw new SyntaxException(this.source, this.marker.LineNumber); } // Create the code location. var location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the token. var symbol = new Symbol(text.ToString(), type, location); // Update the marker. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the symbol. return symbol; }
/// <summary> /// Extracts the body of the given preprocessor directive symbol, parses it, and returns the parsed expression. /// </summary> /// <param name="document">The parent document.</param> /// <param name="code">The source code.</param> /// <param name="parentProxy">Represents the parent item.</param> /// <param name="languageService">The C# language service.</param> /// <param name="preprocessorDefinitions">Optional preprocessor definitions.</param> /// <param name="preprocessorSymbol">The preprocessor directive symbol.</param> /// <param name="startIndex">The index of the start of the expression body within the text string.</param> /// <returns>Returns the expression.</returns> internal static Expression GetConditionalPreprocessorBodyExpression( CsDocument document, Code code, CodeUnitProxy parentProxy, CsLanguageService languageService, IDictionary<string, object> preprocessorDefinitions, Symbol preprocessorSymbol, int startIndex) { Param.AssertNotNull(document, "document"); Param.AssertNotNull(code, "code"); Param.AssertNotNull(parentProxy, "parentProxy"); Param.AssertNotNull(languageService, "languageService"); Param.Ignore(preprocessorDefinitions); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); CsLanguageService.Debug.Assert(preprocessorSymbol.SymbolType == SymbolType.PreprocessorDirective, "The symbol is not a preprocessor directive."); string text = preprocessorSymbol.Text.Substring(startIndex, preprocessorSymbol.Text.Length - startIndex).TrimEnd(null); if (text.Length > 0) { // Trim off the whitespace at the beginning and advance the start index. int trimIndex = 0; for (int i = 0; i < text.Length; ++i) { if (char.IsWhiteSpace(text[i])) { ++trimIndex; } else { break; } } if (trimIndex > 0) { text = text.Substring(trimIndex, text.Length - trimIndex); startIndex += trimIndex; } if (text.Length > 0) { // Extract the symbols within this text. Code preprocessorCode = new Code(text, "Preprocessor", "Preprocessor"); var lexer = new CodeLexer( languageService, preprocessorCode, new CodeReader(preprocessorCode), preprocessorSymbol.Location.StartPoint.Index + startIndex, preprocessorSymbol.Location.StartPoint.IndexOnLine + startIndex, preprocessorSymbol.Location.StartPoint.LineNumber); List<Symbol> symbolList = lexer.GetSymbols(document, null); var directiveSymbols = new SymbolManager(symbolList); var preprocessorBodyParser = new CodeParser(languageService, document, directiveSymbols, preprocessorDefinitions); // Parse these symbols to create the body expression. return preprocessorBodyParser.GetNextConditionalPreprocessorExpression(document, parentProxy); } } // The directive has no body. return null; }
/// <summary> /// Gets an undefine preprocessor directive from the code. /// </summary> /// <param name="document">The parent document.</param> /// <param name="preprocessorSymbol">The preprocessor symbol being parsed.</param> /// <param name="startIndex">The start index within the symbols.</param> /// <param name="preprocessorDefinitions">Optional preprocessor definitions.</param> private void GetUndefinePreprocessorDirective(CsDocument document, Symbol preprocessorSymbol, int startIndex, IDictionary<string, object> preprocessorDefinitions) { Param.AssertNotNull(document, "document"); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); Param.Ignore(preprocessorDefinitions); var expressionProxy = new CodeUnitProxy(document); // Get the body of the undefine directive. LiteralExpression body = CodeParser.GetConditionalPreprocessorBodyExpression( document, this.source, expressionProxy, this.languageService, preprocessorDefinitions, preprocessorSymbol, startIndex) as LiteralExpression; if (body == null) { throw new SyntaxException(document, preprocessorSymbol.LineNumber); } // Create the undefines list if necessary. if (this.undefines == null) { this.undefines = new Dictionary<string, string>(); } // Add the item to the list. this.undefines.Add(body.Text, body.Text); // Remove the item from the defines list if it exists. if (this.defines != null) { this.defines.Remove(body.Text); } }
/// <summary> /// Peeks ahead to the next non-Token symbol, without moving the index. /// </summary> /// <param name="symbol">The current symbol.</param> /// <returns>Gets the next non-Token symbol.</returns> private LexicalElement PeekNonTokenSymbol(Symbol symbol) { Param.AssertNotNull(symbol, "symbol"); if (symbol.SymbolType == SymbolType.WhiteSpace) { return new Whitespace(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } else if (symbol.SymbolType == SymbolType.EndOfLine) { return new EndOfLine(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } else if (symbol.SymbolType == SymbolType.SingleLineComment) { return new SingleLineComment(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } else if (symbol.SymbolType == SymbolType.MultiLineComment) { return new MultilineComment(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } else if (symbol.SymbolType == SymbolType.PreprocessorDirective) { return this.PeekPreprocessorDirective(symbol, this.symbols.Generated); } else if (symbol.SymbolType == SymbolType.SkippedSection) { return new SkippedSection(this.document, symbol.Location, this.symbols.Generated, symbol.Text); } return null; }
private static bool GetOperatorType(Symbol symbol, out OperatorType type, out OperatorCategory category) { Param.AssertNotNull(symbol, "symbol"); bool isOperator = true; switch (symbol.SymbolType) { case SymbolType.LogicalAnd: type = OperatorType.LogicalAnd; category = OperatorCategory.Logical; break; case SymbolType.LogicalOr: type = OperatorType.LogicalOr; category = OperatorCategory.Logical; break; case SymbolType.LogicalXor: type = OperatorType.LogicalXor; category = OperatorCategory.Logical; break; case SymbolType.ConditionalAnd: type = OperatorType.ConditionalAnd; category = OperatorCategory.Logical; break; case SymbolType.ConditionalOr: type = OperatorType.ConditionalOr; category = OperatorCategory.Logical; break; case SymbolType.NullCoalescingSymbol: type = OperatorType.NullCoalescingSymbol; category = OperatorCategory.Logical; break; case SymbolType.Equals: type = OperatorType.Equals; category = OperatorCategory.Assignment; break; case SymbolType.AndEquals: type = OperatorType.AndEquals; category = OperatorCategory.Assignment; break; case SymbolType.OrEquals: type = OperatorType.OrEquals; category = OperatorCategory.Assignment; break; case SymbolType.PlusEquals: type = OperatorType.PlusEquals; category = OperatorCategory.Assignment; break; case SymbolType.MinusEquals: type = OperatorType.MinusEquals; category = OperatorCategory.Assignment; break; case SymbolType.MultiplicationEquals: type = OperatorType.MultiplicationEquals; category = OperatorCategory.Assignment; break; case SymbolType.DivisionEquals: type = OperatorType.DivisionEquals; category = OperatorCategory.Assignment; break; case SymbolType.ModEquals: type = OperatorType.ModEquals; category = OperatorCategory.Assignment; break; case SymbolType.XorEquals: type = OperatorType.XorEquals; category = OperatorCategory.Assignment; break; case SymbolType.LeftShiftEquals: type = OperatorType.LeftShiftEquals; category = OperatorCategory.Assignment; break; case SymbolType.RightShiftEquals: type = OperatorType.RightShiftEquals; category = OperatorCategory.Assignment; break; case SymbolType.ConditionalEquals: type = OperatorType.ConditionalEquals; category = OperatorCategory.Relational; break; case SymbolType.NotEquals: type = OperatorType.NotEquals; category = OperatorCategory.Relational; break; case SymbolType.LessThan: type = OperatorType.LessThan; category = OperatorCategory.Relational; break; case SymbolType.GreaterThan: type = OperatorType.GreaterThan; category = OperatorCategory.Relational; break; case SymbolType.LessThanOrEquals: type = OperatorType.LessThanOrEquals; category = OperatorCategory.Relational; break; case SymbolType.GreaterThanOrEquals: type = OperatorType.GreaterThanOrEquals; category = OperatorCategory.Relational; break; case SymbolType.Plus: type = OperatorType.Plus; category = OperatorCategory.Arithmetic; break; case SymbolType.Minus: type = OperatorType.Minus; category = OperatorCategory.Arithmetic; break; case SymbolType.Multiplication: type = OperatorType.Multiplication; category = OperatorCategory.Arithmetic; break; case SymbolType.Division: type = OperatorType.Division; category = OperatorCategory.Arithmetic; break; case SymbolType.Mod: type = OperatorType.Mod; category = OperatorCategory.Arithmetic; break; case SymbolType.LeftShift: type = OperatorType.LeftShift; category = OperatorCategory.Shift; break; case SymbolType.RightShift: type = OperatorType.RightShift; category = OperatorCategory.Shift; break; case SymbolType.Increment: type = OperatorType.Increment; category = OperatorCategory.IncrementDecrement; break; case SymbolType.Decrement: type = OperatorType.Decrement; category = OperatorCategory.IncrementDecrement; break; case SymbolType.QuestionMark: type = OperatorType.ConditionalQuestionMark; category = OperatorCategory.Conditional; break; case SymbolType.Colon: type = OperatorType.ConditionalColon; category = OperatorCategory.Conditional; break; case SymbolType.Pointer: type = OperatorType.Pointer; category = OperatorCategory.Reference; break; case SymbolType.Dot: type = OperatorType.MemberAccess; category = OperatorCategory.Reference; break; case SymbolType.QualifiedAlias: type = OperatorType.QualifiedAlias; category = OperatorCategory.Reference; break; case SymbolType.Not: type = OperatorType.Not; category = OperatorCategory.Unary; break; case SymbolType.Tilde: type = OperatorType.BitwiseComplement; category = OperatorCategory.Unary; break; case SymbolType.Lambda: type = OperatorType.Lambda; category = OperatorCategory.Lambda; break; default: // Assign random values. type = OperatorType.AddressOf; category = OperatorCategory.Arithmetic; // Signal that the symbol is not an operator. isOperator = false; break; } return isOperator; }
/// <summary> /// Gets an unknown symbol type. /// </summary> /// <param name="sourceCode">The source code containing the symbols.</param> /// <returns>Returns the item.</returns> private Symbol GetOtherSymbol(Code sourceCode) { Param.AssertNotNull(sourceCode, "sourceCode"); var text = new StringBuilder(); this.ReadToEndOfOtherSymbol(text); if (text.Length == 0) { throw new SyntaxException(sourceCode, 1); } string symbolText = text.ToString(); // Get the token location. var location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the symbol. var symbol = new Symbol( symbolText, CodeLexer.GetOtherSymbolType(symbolText), location); // Reset the marker index. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the symbol. return symbol; }
/// <summary> /// Combines a range of symbols into a single symbol. /// </summary> /// <param name="startIndex">The start peek index of the first symbol to combine.</param> /// <param name="endIndex">The end peek index of the last symbol to combine.</param> /// <param name="text">The text for the new symbol.</param> /// <param name="type">The type of the new symbol.</param> public void Combine(int startIndex, int endIndex, string text, SymbolType type) { Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); Param.AssertGreaterThanOrEqualTo(endIndex, startIndex, "endIndex"); Param.AssertValidString(text, "text"); Param.Ignore(type); // Adjust the indexes. int adjustedStartIndex = startIndex + this.index; int adjustedEndIndex = endIndex + this.index; CsLanguageService.Debug.Assert(adjustedStartIndex >= 0 && adjustedStartIndex < this.symbols.Count, "The adjusted start index should be within the symbol list"); CsLanguageService.Debug.Assert(adjustedEndIndex >= 0 && adjustedEndIndex < this.symbols.Count, "The adjusted end index should be within the symbol list"); // Map the new location of the combined symbol. CodeLocation location = CodeLocation.Join( this.symbols[adjustedStartIndex].Location, this.symbols[adjustedEndIndex].Location); // Create the new symbol. var symbol = new Symbol(text, type, location); // Replace the first symbol. this.symbols[adjustedStartIndex] = symbol; // Remove the rest of the symbols. ++adjustedStartIndex; if (adjustedStartIndex <= adjustedEndIndex) { this.symbols.RemoveRange(adjustedStartIndex, adjustedEndIndex - adjustedStartIndex + 1); } }
/// <summary> /// Gets the next string from the code. /// </summary> /// <returns>Returns the string.</returns> private Symbol GetString() { var text = new StringBuilder(); // Read the opening quote character and add it to the string. char quoteType = this.codeReader.ReadNext(); CsLanguageService.Debug.Assert(quoteType == '\'' || quoteType == '\"', "Expected a quote character"); text.Append(quoteType); bool slash = false; // Read through to the end of the string. while (true) { char character = this.codeReader.Peek(); if (character == char.MinValue || (character == quoteType && !slash)) { // This is the end of the string. Add the character and quit. text.Append(character); this.codeReader.ReadNext(); break; } if (character == '\\') { slash = !slash; } else { slash = false; if (character == '\r' || character == '\n') { // We've hit the end of the line. Just exit. break; } } text.Append(character); // Advance past this character. this.codeReader.ReadNext(); } // Create the code location. var location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the symbol. var symbol = new Symbol(text.ToString(), SymbolType.String, location); // Update the marker. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the symbol. return symbol; }
/// <summary> /// Gets the next literal string from the code. /// </summary> /// <param name="text">The text buffer to add the string text to.</param> /// <returns>Returns the literal string.</returns> private Symbol GetLiteralString(StringBuilder text) { Param.AssertNotNull(text, "text"); CsLanguageService.Debug.Assert(text.Length == 1 && text[0] == '@', "Expected an @ symbol"); // Initialize the location of the start of the string. int startIndex = this.marker.Index; int endIndex = this.marker.Index; int startIndexOnLine = this.marker.IndexOnLine; int endIndexOnLine = this.marker.IndexOnLine; int lineNumber = this.marker.LineNumber; int endLineNumber = this.marker.LineNumber; // Get the opening string character to determine what type of string this is. char stringType = this.codeReader.Peek(); CsLanguageService.Debug.Assert(stringType == '\'' || stringType == '\"', "Expected a quote character"); // Add the opening quote character and move past it. text.Append(stringType); this.codeReader.ReadNext(); // Advance the end indexes past the literal character and the open quote character. endIndex += 2; endIndexOnLine += 2; while (true) { char character = this.codeReader.Peek(); if (character == stringType) { // Read the character and add it to the text buffer. this.codeReader.ReadNext(); text.Append(character); ++endIndex; ++endIndexOnLine; // If the next character is also the same string type, then this is internal to the string. character = this.codeReader.Peek(); if (character == stringType) { // Also move past this character and add it. this.codeReader.ReadNext(); text.Append(character); ++endIndex; ++endIndexOnLine; continue; } else { // This is the end of the string. We're done now. break; } } else if (character == '\r' || character == '\n') { if (stringType == '\'') { // This is a syntax error in the code as single-quoted literal strings // cannot allowed to span across multiple lines, although double-quoted // strings can. throw new SyntaxException(this.source, this.marker.LineNumber); } else if (character == '\n') { ++endLineNumber; endIndexOnLine = -1; } else if (character == '\r') { // Just move past this character without adding it. this.codeReader.ReadNext(); continue; } } this.codeReader.ReadNext(); text.Append(character); ++endIndex; ++endIndexOnLine; } // Make sure the end index is correct now. if (text.Length <= 2 || text[text.Length - 1] != stringType) { throw new SyntaxException(this.source, this.marker.LineNumber); } // Create the location object. var location = new CodeLocation( startIndex, endIndex, startIndexOnLine, endIndexOnLine, lineNumber, endLineNumber); // Create the symbol. var token = new Symbol(text.ToString(), SymbolType.String, location); // Update the marker. this.marker.Index = endIndex + 1; this.marker.IndexOnLine = endIndexOnLine + 1; this.marker.LineNumber = endLineNumber; // Return the token. return token; }
private Symbol GetNewLine() { Symbol symbol = null; char character = this.codeReader.Peek(); if (character != char.MinValue) { // Get the character this.codeReader.ReadNext(); // Save the original start and end indexes of the newline character. int startIndex = this.marker.Index; int endIndex = this.marker.Index; // Check if this is an \r\n sequence in which case we need to adjust the end index. if (character == '\r') { character = this.codeReader.Peek(); if (character == '\n') { this.codeReader.ReadNext(); ++this.marker.Index; ++endIndex; } } // Create the code location. var location = new CodeLocation( startIndex, endIndex, this.marker.IndexOnLine, this.marker.IndexOnLine + (endIndex - startIndex), this.marker.LineNumber, this.marker.LineNumber); // Create the symbol. symbol = new Symbol("\n", SymbolType.EndOfLine, location); // Update the marker. ++this.marker.Index; ++this.marker.LineNumber; this.marker.IndexOnLine = 0; } return symbol; }
/// <summary> /// Gets the next whitespace stream. /// </summary> /// <returns>Returns the whitespace.</returns> private Symbol GetWhitespace() { var text = new StringBuilder(); // Get all of the characters in the whitespace. while (true) { char character = this.codeReader.Peek(); if (character == char.MinValue || (character != ' ' && character != '\t')) { break; } text.Append(character); // Advance past this character. this.codeReader.ReadNext(); } // Create the whitespace location object. var location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the whitespace object. var whitespace = new Symbol(text.ToString(), SymbolType.WhiteSpace, location); // Update the marker. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the whitespace object. return whitespace; }
/// <summary> /// Gets the next conditional compilation directive from the code. /// </summary> /// <param name="preprocessorSymbol">The symbol representing the directive.</param> /// <param name="type">The type of the conditional compilation directive.</param> /// <param name="startIndex">The start index of the body of the directive.</param> /// <returns>Returns the directive.</returns> private ConditionalCompilationDirective GetConditionalCompilationDirective(Symbol preprocessorSymbol, PreprocessorType type, int startIndex) { Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.Ignore(type); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); Expression body = null; var directiveProxy = new CodeUnitProxy(this.document); // Extract the body of the directive if necessary. if (type != PreprocessorType.Endif && startIndex < preprocessorSymbol.Text.Length) { body = CodeParser.GetConditionalPreprocessorBodyExpression( this.document, this.lexer.SourceCode, directiveProxy, this.languageService, this.preprocessorDefinitions, preprocessorSymbol, startIndex); } // Create and return the directive. switch (type) { case PreprocessorType.If: return new IfDirective(preprocessorSymbol.Text, directiveProxy, body); case PreprocessorType.Elif: return new ElifDirective(preprocessorSymbol.Text, directiveProxy, body); case PreprocessorType.Else: return new ElseDirective(preprocessorSymbol.Text, directiveProxy, body); case PreprocessorType.Endif: return new EndifDirective(preprocessorSymbol.Text, directiveProxy, body); default: CsLanguageService.Debug.Fail("Not a conditional preprocessor type."); return null; } }
/// <summary> /// Gets and converts preprocessor directive. /// </summary> /// <param name="preprocessorSymbol">The preprocessor symbol.</param> /// <param name="generated">Indicates whether the preprocessor directive lies within a block of generated code.</param> /// <returns>Returns the preprocessor directive.</returns> private PreprocessorDirective PeekPreprocessorDirective(Symbol preprocessorSymbol, bool generated) { Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.Ignore(generated); CsLanguageService.Debug.Assert(preprocessorSymbol != null && preprocessorSymbol.SymbolType == SymbolType.PreprocessorDirective, "Expected a preprocessor directive"); // Get the type of the preprocessor directive. int bodyIndex; string type = CsLanguageService.GetPreprocessorDirectiveType(preprocessorSymbol, out bodyIndex); if (type == null) { throw new SyntaxException(this.document, preprocessorSymbol.LineNumber); } // Create the correct preprocessor object type. PreprocessorDirective preprocessor = null; if (type == "region") { var region = new RegionDirective(this.document, preprocessorSymbol.Text, preprocessorSymbol.Location, generated); this.symbols.PushRegion(region); preprocessor = region; } else if (type == "endregion") { var endregion = new EndRegionDirective(this.document, preprocessorSymbol.Text, preprocessorSymbol.Location, generated); RegionDirective startregion = this.symbols.PopRegion(); if (startregion == null) { throw new SyntaxException(this.document, preprocessorSymbol.LineNumber); } startregion.Partner = endregion; endregion.Partner = startregion; preprocessor = endregion; } else if (type == "if") { preprocessor = this.GetConditionalCompilationDirective(preprocessorSymbol, PreprocessorType.If, bodyIndex); } else if (type == "elif") { preprocessor = this.GetConditionalCompilationDirective(preprocessorSymbol, PreprocessorType.Elif, bodyIndex); } else if (type == "else") { preprocessor = this.GetConditionalCompilationDirective(preprocessorSymbol, PreprocessorType.Else, bodyIndex); } else if (type == "endif") { preprocessor = this.GetConditionalCompilationDirective(preprocessorSymbol, PreprocessorType.Endif, bodyIndex); } else if (type == "pragma") { preprocessor = new PragmaDirective(this.document, preprocessorSymbol.Text, preprocessorSymbol.Location, generated); } else if (type == "define") { preprocessor = new DefineDirective(this.document, preprocessorSymbol.Text, preprocessorSymbol.Location, generated); } else if (type == "undef") { preprocessor = new UndefDirective(this.document, preprocessorSymbol.Text, preprocessorSymbol.Location, generated); } else if (type == "line") { preprocessor = new LineDirective(this.document, preprocessorSymbol.Text, preprocessorSymbol.Location, generated); } else if (type == "error") { preprocessor = new ErrorDirective(this.document, preprocessorSymbol.Text, preprocessorSymbol.Location, generated); } else if (type == "warning") { preprocessor = new WarningDirective(this.document, preprocessorSymbol.Text, preprocessorSymbol.Location, generated); } else { throw this.CreateSyntaxException(); } return preprocessor; }
/// <summary> /// Gets and converts preprocessor directive. /// </summary> /// <param name="parentProxy">Represents the parent of the token.</param> /// <param name="preprocessorSymbol">The preprocessor symbol.</param> /// <param name="generated">Indicates whether the preprocessor directive lies within a block of generated code.</param> /// <returns>Returns the preprocessor directive.</returns> private PreprocessorDirective GetPreprocessorDirective(CodeUnitProxy parentProxy, Symbol preprocessorSymbol, bool generated) { Param.Ignore(parentProxy); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.Ignore(generated); PreprocessorDirective preprocessor = this.PeekPreprocessorDirective(preprocessorSymbol, generated); if (parentProxy != null) { parentProxy.Children.Add(preprocessor); } return preprocessor; }
/// <summary> /// Reads, creates, and moves past a symbol. /// </summary> /// <param name="text">The symbol text.</param> /// <param name="type">The type of the symbol.</param> /// <returns>Returns the symbol.</returns> private Symbol CreateAndMovePastSymbol(string text, SymbolType type) { Param.AssertValidString(text, "text"); Param.Ignore(type); this.codeReader.ReadNext(); Symbol symbol = new Symbol(text, type, CodeLocationFromMarker(this.marker)); ++this.marker.Index; ++this.marker.IndexOnLine; return symbol; }
/// <summary> /// Gets the next literal keyword token from the code. /// </summary> /// <param name="text">The text buffer to add the string text to.</param> /// <returns>Returns the literal keyword token.</returns> private Symbol GetLiteralKeyword(StringBuilder text) { Param.AssertNotNull(text, "text"); CsLanguageService.Debug.Assert(text.Length > 0 && text[0] == '@', "Expected an @ character"); // Advance to the end of the token. this.ReadToEndOfOtherSymbol(text); if (text.Length == 1) { // Nothing was read. throw new SyntaxException(this.source, this.marker.LineNumber); } // Get the token location. var location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the symbol. var symbol = new Symbol(text.ToString(), SymbolType.Other, location); // Reset the marker index. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the symbol. return symbol; }
/// <summary> /// Gets the next number. /// </summary> /// <returns>Returns the number.</returns> private Symbol GetNumber() { // The last index of the number. int endIndex = -1; // The first few characters in the number tell us the type of the number. char character = this.codeReader.Peek(); if (character == '-' || character == '+') { // This could be a number starting with a negative or positive sign. // If that's true, the next character must be a digit between 0 and 9. character = this.codeReader.Peek(1); if (character >= '0' && character <= '9') { endIndex = this.GetPositiveNumber(this.marker.Index + 1); } } else { // Get the body of the number. endIndex = this.GetPositiveNumber(this.marker.Index); } // Create the NumberSymbol now. Symbol number = null; // Make sure a number was found. if (endIndex >= this.marker.Index) { // Get the text string for this number. int length = endIndex - this.marker.Index + 1; string numberText = this.codeReader.ReadString(length); CsLanguageService.Debug.Assert(!string.IsNullOrEmpty(numberText), "The text should not be empty"); // Create the location object. var location = new CodeLocation( this.marker.Index, this.marker.Index + length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + length - 1, this.marker.LineNumber, this.marker.LineNumber); number = new Symbol(numberText, SymbolType.Number, location); // Update the marker. this.marker.Index += length; this.marker.IndexOnLine += length; } return number; }
/// <summary> /// Gets the next multi-line comment. /// </summary> /// <param name="text">The buffer to add the text to.</param> /// <returns>Returns the comment.</returns> private Symbol GetMultiLineComment(StringBuilder text) { Param.AssertNotNull(text, "text"); // Initialize the location of the start of the comment. Add one to the end indexes since we know the // comment starts with /*, which is two characters long. int startIndex = this.marker.Index; int endIndex = this.marker.Index + 1; int startIndexOnLine = this.marker.IndexOnLine; int endIndexOnLine = this.marker.IndexOnLine + 1; int lineNumber = this.marker.LineNumber; int endLineNumber = this.marker.LineNumber; // Initialize loop trackers. bool asterisk = false; bool first = false; // Find the end of the comment. while (true) { char character = this.codeReader.Peek(); if (character == char.MinValue) { break; } // Add the character and move the index past it. text.Append(this.codeReader.ReadNext()); if (asterisk && character == '/') { // This is the end of the comment. break; } else { if (character == '*') { if (first) { // Mark the asterisk. asterisk = true; } else { first = true; } } else { // This is not an asterisk. asterisk = false; // Check for newlines. if (character == '\n') { ++endLineNumber; endIndexOnLine = -1; } else if (character == '\r') { // Peek at the next character and check the type. character = this.codeReader.Peek(); if (character != '\n') { ++endLineNumber; endIndexOnLine = -1; } } } } ++endIndex; ++endIndexOnLine; } // Create the location object. var location = new CodeLocation( startIndex, endIndex, startIndexOnLine, endIndexOnLine, lineNumber, endLineNumber); // Create the symbol object. var symbol = new Symbol(text.ToString(), SymbolType.MultiLineComment, location); // Update the marker. this.marker.Index = endIndex + 1; this.marker.IndexOnLine = endIndexOnLine + 1; this.marker.LineNumber = endLineNumber; // Return the symbol. return symbol; }
/// <summary> /// Gets the type of the given preprocessor symbol. /// </summary> /// <param name="preprocessor">The preprocessor symbol.</param> /// <param name="bodyIndex">Returns the start index of the body of the preprocessor.</param> /// <returns>Returns the type or null if the type cannot be determined.</returns> internal static string GetPreprocessorDirectiveType(Symbol preprocessor, out int bodyIndex) { Param.AssertNotNull(preprocessor, "preprocessor"); CsLanguageService.Debug.Assert(preprocessor.SymbolType == SymbolType.PreprocessorDirective, "Expected a preprocessor directive"); // Get the preprocessor type. This is the second word in the statement. bodyIndex = -1; int startIndex = -1; int endIndex = -1; // Move to the start of the second word. for (int i = 1; i < preprocessor.Text.Length; ++i) { if (char.IsLetter(preprocessor.Text[i])) { startIndex = i; break; } } if (startIndex == -1) { return null; } // Move to the end of the word. for (endIndex = startIndex; endIndex < preprocessor.Text.Length; ++endIndex) { if (!char.IsLetter(preprocessor.Text[endIndex])) { break; } } --endIndex; if (endIndex < startIndex) { return null; } // The body start index is just past the endIndex. bodyIndex = endIndex + 1; // Get the word. return preprocessor.Text.Substring(startIndex, endIndex - startIndex + 1); }
/// <summary> /// Gets the next Xml header line from the code. /// </summary> /// <param name="text">The buffer in which to store the text.</param> /// <returns>Returns the Xml header line.</returns> private Symbol GetXmlHeaderLine(StringBuilder text) { Param.AssertNotNull(text, "text"); // Find the end of the current line. this.AdvanceToEndOfLine(text); // Create the code location. var location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, this.marker.LineNumber); // Create the symbol. var symbol = new Symbol(text.ToString(), SymbolType.XmlHeaderLine, location); // Update the marker. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // Return the symbol. return symbol; }
/// <summary> /// Gets the next non-Token symbol. /// </summary> /// <param name="typeTokenProxy">Proxy object for the TypeToken being created.</param> /// <param name="symbol">The current symbol.</param> /// <returns>Returns the non-Token symbol.</returns> private bool GatherNonTokenSymbol(CodeUnitProxy typeTokenProxy, Symbol symbol) { Param.AssertNotNull(typeTokenProxy, "typeTokenProxy"); Param.AssertNotNull(symbol, "symbol"); LexicalElement item = this.PeekNonTokenSymbol(symbol); if (item != null) { typeTokenProxy.Children.Add(item); return true; } return false; }
/// <summary> /// Checks the given preprocessor symbol to determine whether it is a conditional preprocessor directive. /// If so, determines whether we should skip past code which is out of scope. /// </summary> /// <param name="document">The parent document.</param> /// <param name="preprocessorSymbol">The symbol to check.</param> /// <param name="preprocessorDefinitions">The active configuration.</param> /// <returns>Returns the collection of symbols found while processing the directive.</returns> private ICollection<Symbol> CheckForConditionalCompilationDirective(CsDocument document, Symbol preprocessorSymbol, IDictionary<string, object> preprocessorDefinitions) { Param.AssertNotNull(document, "document"); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.Ignore(preprocessorDefinitions); List<Symbol> symbols = new List<Symbol>(); while (true) { // Get the type of this preprocessor directive. int bodyIndex; string type = CsLanguageService.GetPreprocessorDirectiveType(preprocessorSymbol, out bodyIndex); if (type == "define") { this.GetDefinePreprocessorDirective(document, preprocessorSymbol, bodyIndex, preprocessorDefinitions); break; } else if (type == "undef") { this.GetUndefinePreprocessorDirective(document, preprocessorSymbol, bodyIndex, preprocessorDefinitions); break; } else if (type == "endif") { // Pop this conditional directive off of the stack. if (this.conditionalDirectives.Count == 0) { throw new SyntaxException(document, preprocessorSymbol.LineNumber); } this.conditionalDirectives.Pop(); break; } else { // Extract an if, endif, or else directive. bool skip; if (!this.GetIfElsePreprocessorDirectives( document, preprocessorSymbol, preprocessorDefinitions, bodyIndex, type, out skip)) { // Check whether the code needs to be skipped. if (skip) { // We will skip all code between this conditional preprocessor symbol and the next one. StringBuilder skippedSectionText = new StringBuilder(); CodeLocation startLocation = null; CodeLocation endLocation = null; Symbol endSymbol = null; int subConditionalPreprocessorCount = 0; while (true) { // Get the next symbol. IList<Symbol> symbolList = this.GetSymbol(document, preprocessorDefinitions, false); if (symbolList == null || symbolList.Count != 1) { throw new SyntaxException(document, preprocessorSymbol.LineNumber); } Symbol symbol = symbolList[0]; // Check whether this is another preprocessor. if (symbol.SymbolType == SymbolType.PreprocessorDirective) { // Check to see if this is a conditional preprocessor symbol, which indicates that we have // reached the end of out-of-scope code. type = CsLanguageService.GetPreprocessorDirectiveType(symbol, out bodyIndex); if (type == "if") { ++subConditionalPreprocessorCount; } else if (subConditionalPreprocessorCount > 0 && type == "endif") { --subConditionalPreprocessorCount; } else if (subConditionalPreprocessorCount == 0 && (type == "elif" || type == "else" || type == "endif")) { // Reset the markers to the start of this preprocessor symbol. this.marker.Index = symbol.Location.StartPoint.Index; this.marker.IndexOnLine = symbol.Location.StartPoint.IndexOnLine; this.marker.LineNumber = symbol.Location.StartPoint.LineNumber; // Break from this loop. endSymbol = symbol; break; } } skippedSectionText.Append(symbol.Text); if (startLocation == null) { startLocation = symbol.Location; } endLocation = symbol.Location; } if (skippedSectionText.Length > 0) { symbols.Add(new Symbol(skippedSectionText.ToString(), SymbolType.SkippedSection, CodeLocation.Join(startLocation, endLocation))); } if (endSymbol != null) { symbols.Add(endSymbol); preprocessorSymbol = endSymbol; } else { break; } } else { // Indicate that this conditional directive has been entered. if (this.conditionalDirectives.Count == 0) { throw new SyntaxException(document, preprocessorSymbol.LineNumber); } this.conditionalDirectives.Pop(); this.conditionalDirectives.Push(true); break; } } else { break; } } } return symbols; }
private Token ConvertTokenSymbol(Symbol symbol, TokenType tokenType) { Param.AssertNotNull(symbol, "symbol"); Param.Ignore(tokenType); switch (symbol.SymbolType) { case SymbolType.Abstract: return new AbstractToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.As: return new AsToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Base: return new BaseToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Break: return new BreakToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Case: return new CaseToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Catch: return new CatchToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Checked: return new CheckedToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Class: return new ClassToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.CloseCurlyBracket: return new CloseCurlyBracketToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.CloseParenthesis: return new CloseParenthesisToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.CloseSquareBracket: return new CloseSquareBracketToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Colon: switch (tokenType) { case TokenType.BaseColon: return new BaseColonToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.LabelColon: return new LabelColonToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.WhereColon: return new WhereColonToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } break; case SymbolType.Comma: return new CommaToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Const: return new ConstToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Continue: return new ContinueToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Default: if (tokenType == TokenType.DefaultValue) { return new DefaultValueToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } return new DefaultToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Delegate: return new DelegateToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Do: return new DoToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Else: return new ElseToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Enum: return new EnumToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Equals: if (tokenType == TokenType.Equals) { return new EqualsToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } break; case SymbolType.Event: return new EventToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Explicit: return new ExplicitToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Extern: if (tokenType == TokenType.ExternDirective) { return new ExternDirectiveToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } return new ExternToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.False: return new FalseToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Finally: return new FinallyToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Fixed: return new FixedToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.For: return new ForToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Foreach: return new ForeachToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Goto: return new GotoToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.If: return new IfToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Implicit: return new ImplicitToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.In: return new InToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Interface: return new InterfaceToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Internal: return new InternalToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Is: return new IsToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Lock: return new LockToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Namespace: return new NamespaceToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.New: return new NewToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Null: return new NullToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Number: return new NumberToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.OpenCurlyBracket: return new OpenCurlyBracketToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.OpenParenthesis: return new OpenParenthesisToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.OpenSquareBracket: return new OpenSquareBracketToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Operator: return new OperatorToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Other: switch (tokenType) { case TokenType.Add: return new AddToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Alias: return new AliasToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Ascending: return new AscendingToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.By: return new ByToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Descending: return new DescendingToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Equals: return new EqualsToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.From: return new FromToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Get: return new GetToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Group: return new GroupToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Into: return new IntoToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Join: return new JoinToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Let: return new LetToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Literal: return new LiteralToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.On: return new OnToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.OrderBy: return new OrderByToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Partial: return new PartialToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Remove: return new RemoveToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Select: return new SelectToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Set: return new SetToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Where: return new WhereToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case TokenType.Yield: return new YieldToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } break; case SymbolType.Out: return new OutToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Override: return new OverrideToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Params: return new ParamsToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Private: return new PrivateToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Protected: return new ProtectedToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Public: return new PublicToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Readonly: return new ReadonlyToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Ref: return new RefToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Return: return new ReturnToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Sealed: return new SealedToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Semicolon: return new SemicolonToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Sizeof: return new SizeofToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Stackalloc: return new StackallocToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Static: return new StaticToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.String: return new StringToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Struct: return new StructToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Switch: return new SwitchToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.This: return new ThisToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Throw: return new ThrowToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Tilde: if (tokenType == TokenType.DestructorTilde) { return new DestructorTildeToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } break; case SymbolType.True: return new TrueToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Try: return new TryToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Typeof: return new TypeofToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Unchecked: return new UncheckedToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Unsafe: return new UnsafeToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Using: if (tokenType == TokenType.UsingDirective) { return new UsingDirectiveToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } return new UsingToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Virtual: return new VirtualToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.Volatile: return new VolatileToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); case SymbolType.While: if (tokenType == TokenType.WhileDo) { return new WhileDoToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } return new WhileToken(this.document, symbol.Text, symbol.Location, this.symbols.Generated); } CsLanguageService.Debug.Fail("Cannot create a token of the given symbol type using this method."); return null; }
/// <summary> /// Extracts an if, endif, or else directive. /// </summary> /// <param name="document">The parent document.</param> /// <param name="preprocessorSymbol">The preprocessor symbol being parsed.</param> /// <param name="preprocessorDefinitions">The current code configuration.</param> /// <param name="startIndex">The start index of the item within the symbols.</param> /// <param name="type">The type of the preprocessor symbol.</param> /// <param name="skip">Returns a value indicating whether the item should be skipped.</param> /// <returns>Returns a value indicating whether to ignore the item.</returns> private bool GetIfElsePreprocessorDirectives( CsDocument document, Symbol preprocessorSymbol, IDictionary<string, object> preprocessorDefinitions, int startIndex, string type, out bool skip) { Param.AssertNotNull(document, "document"); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.AssertNotNull(preprocessorDefinitions, "preprocessorDefinitions"); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); Param.AssertValidString(type, "type"); bool ignore = false; skip = false; if (type == "if") { // Add this directive to the stack and indicate that it has not been entered. this.conditionalDirectives.Push(false); // Extract the body of the directive. var expressionProxy = new CodeUnitProxy(document); Expression body = CodeParser.GetConditionalPreprocessorBodyExpression( document, this.source, expressionProxy, this.languageService, preprocessorDefinitions, preprocessorSymbol, startIndex); if (body == null) { throw new SyntaxException(document, preprocessorSymbol.LineNumber); } // Determine whether the code under this directive needs to be skipped because it is out of scope. skip = !this.EvaluateConditionalDirectiveExpression(document, body, preprocessorDefinitions); } else if (type == "elif") { if (this.conditionalDirectives.Count == 0) { throw new SyntaxException(document, preprocessorSymbol.LineNumber); } bool entered = this.conditionalDirectives.Peek(); if (entered) { skip = true; } else { // Extract the body of the directive. var expressionProxy = new CodeUnitProxy(document); Expression body = CodeParser.GetConditionalPreprocessorBodyExpression( document, this.source, expressionProxy, this.languageService, preprocessorDefinitions, preprocessorSymbol, startIndex); if (body != null) { // Determine whether the code under this directive needs to be skipped because it is out of scope. skip = !this.EvaluateConditionalDirectiveExpression(document, body, preprocessorDefinitions); } } } else if (type == "else") { if (this.conditionalDirectives.Count == 0) { throw new SyntaxException(document, preprocessorSymbol.LineNumber); } bool entered = this.conditionalDirectives.Peek(); if (entered) { skip = true; } } else { // This is not a conditional preprocessor directive. ignore = true; } return ignore; }
private OperatorSymbolToken CreateOperatorSymbolToken(Symbol symbol, OperatorType? hint, bool generated) { Param.AssertNotNull(symbol, "symbol"); Param.Ignore(hint); Param.Ignore(generated); // Get the type of the operator. OperatorType type; OperatorCategory category; if (!GetOperatorType(symbol, out type, out category)) { // This should never happen unless there is a bug in the code. CsLanguageService.Debug.Fail("Unexpected operator type"); throw new InvalidOperationException(); } if (hint != null) { if (hint == OperatorType.Dereference && type == OperatorType.Multiplication) { type = OperatorType.Dereference; category = OperatorCategory.Reference; } else if (hint == OperatorType.AddressOf && type == OperatorType.LogicalAnd) { type = OperatorType.AddressOf; category = OperatorCategory.Reference; } } // Create the appropriate operator token based on the type. switch (type) { case OperatorType.AddressOf: return new AddressOfOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.AndEquals: return new AndEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.BitwiseComplement: return new BitwiseComplementOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.ConditionalAnd: return new ConditionalAndOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.ConditionalColon: return new ConditionalColonOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.ConditionalEquals: return new ConditionalEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.ConditionalOr: return new ConditionalOrOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.ConditionalQuestionMark: return new ConditionalQuestionMarkOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Decrement: return new DecrementOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Dereference: return new DereferenceOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Division: return new DivisionOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.DivisionEquals: return new DivisionEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Equals: return new EqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.GreaterThan: return new GreaterThanOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.GreaterThanOrEquals: return new GreaterThanOrEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Increment: return new IncrementOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Lambda: return new LambdaOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.LeftShift: return new LeftShiftOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.LeftShiftEquals: return new LeftShiftEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.LessThan: return new LessThanOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.LessThanOrEquals: return new LessThanOrEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.LogicalAnd: return new LogicalAndOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.LogicalOr: return new LogicalOrOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.LogicalXor: return new LogicalXorOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.MemberAccess: return new MemberAccessOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Minus: return new MinusOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.MinusEquals: return new MinusEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Mod: return new ModOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.ModEquals: return new ModEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Multiplication: return new MultiplicationOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.MultiplicationEquals: return new MultiplicationEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Negative: return new NegativeOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Not: return new NotOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.NotEquals: return new NotEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.NullCoalescingSymbol: return new NullCoalescingSymbolOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.OrEquals: return new OrEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Plus: return new PlusOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.PlusEquals: return new PlusEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Pointer: return new PointerOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.Positive: return new PositiveOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.QualifiedAlias: return new QualifiedAliasOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.RightShift: return new RightShiftOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.RightShiftEquals: return new RightShiftEqualsOperator(this.document, symbol.Text, symbol.Location, generated); case OperatorType.XorEquals: return new XorEqualsOperator(this.document, symbol.Text, symbol.Location, generated); default: CsLanguageService.Debug.Fail("Invalid operator type"); return null; } }
private bool GetOtherElementModifier(CodeUnitProxy elementProxy, string[] allowedModifiers, Dictionary<TokenType, Token> modifiers, Symbol symbol) { Param.AssertNotNull(elementProxy, "elementProxy"); Param.Ignore(allowedModifiers); Param.AssertNotNull(modifiers, "modifiers"); Param.AssertNotNull(symbol, "symbol"); bool stop = true; // If the modifier is one of the allowed modifiers, store it. Otherwise, we are done. if (allowedModifiers != null) { for (int i = 0; i < allowedModifiers.Length; ++i) { if (string.Equals(symbol.Text, allowedModifiers[i], StringComparison.Ordinal)) { TokenType modifierType; switch (symbol.SymbolType) { case SymbolType.Abstract: modifierType = TokenType.Abstract; break; case SymbolType.Const: modifierType = TokenType.Const; break; case SymbolType.Explicit: modifierType = TokenType.Explicit; break; case SymbolType.Extern: modifierType = TokenType.Extern; break; case SymbolType.Implicit: modifierType = TokenType.Implicit; break; case SymbolType.New: modifierType = TokenType.New; break; case SymbolType.Override: modifierType = TokenType.Override; break; case SymbolType.Readonly: modifierType = TokenType.Readonly; break; case SymbolType.Sealed: modifierType = TokenType.Sealed; break; case SymbolType.Static: modifierType = TokenType.Static; break; case SymbolType.Unsafe: modifierType = TokenType.Unsafe; break; case SymbolType.Virtual: modifierType = TokenType.Virtual; break; case SymbolType.Volatile: modifierType = TokenType.Volatile; break; case SymbolType.Fixed: modifierType = TokenType.Fixed; break; case SymbolType.Other: if (symbol.Text != "partial") { goto default; } modifierType = TokenType.Partial; break; default: throw this.CreateSyntaxException(); } Token modifier = this.GetToken(elementProxy, modifierType, symbol.SymbolType); modifiers.Add(modifierType, modifier); stop = false; break; } } } return !stop; }