/// <summary> /// Extracts the body of the given preprocessor directive symbol, parses it, and returns the parsed expression. /// </summary> /// <param name="parser"> /// The C# parser. /// </param> /// <param name="sourceCode"> /// The source code containing the preprocessor directive symbol. /// </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(CsParser parser, SourceCode sourceCode, Symbol preprocessorSymbol, int startIndex) { Param.AssertNotNull(parser, "parser"); Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); Debug.Assert(preprocessorSymbol.SymbolType == SymbolType.PreprocessorDirective, "The symbol is not a preprocessor directive."); string text = preprocessorSymbol.Text.Substring(startIndex, preprocessorSymbol.Text.Length - startIndex).Trim(); if (text.Length > 0) { using (StringReader reader = new StringReader(text)) { // Extract the symbols within this text. CodeLexer lexer = new CodeLexer(parser, sourceCode, new CodeReader(reader)); List<Symbol> symbolList = lexer.GetSymbols(sourceCode, null); SymbolManager directiveSymbols = new SymbolManager(symbolList); CodeParser preprocessorBodyParser = new CodeParser(parser, directiveSymbols); // Parse these symbols to create the body expression. return preprocessorBodyParser.GetNextConditionalPreprocessorExpression(sourceCode); } } // The directive has no body. return null; }
/// <summary> /// Creates an operator token from the given symbol. /// </summary> /// <param name="symbol"> /// The symbol to convert. /// </param> /// <param name="parentReference"> /// The parent code part. /// </param> /// <param name="generated"> /// Indicates whether the symbol lies within a generated code block. /// </param> /// <returns> /// Returns the operator symbol. /// </returns> private static OperatorSymbol CreateOperatorToken(Symbol symbol, Reference<ICodePart> parentReference, bool generated) { Param.AssertNotNull(symbol, "symbol"); Param.AssertNotNull(parentReference, "parentReference"); 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. Debug.Fail("Unexpected operator type"); throw new InvalidOperationException(); } // Create and return the operator. return new OperatorSymbol(symbol.Text, category, type, symbol.Location, parentReference, generated); }
/// <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(SourceCode sourceCode) { Param.AssertNotNull(sourceCode, "sourceCode"); StringBuilder text = new StringBuilder(); this.ReadToEndOfOtherSymbol(text); if (text.Length == 0) { throw new SyntaxException(sourceCode, this.marker.LineNumber); } string symbolText = text.ToString(); // Get the token location. CodeLocation 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. Symbol 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; }
private Symbol GetOperatorSymbol(char character) { Param.Ignore(character); SymbolType type = SymbolType.Other; StringBuilder 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. CodeLocation 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. Symbol 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> /// Gets and converts preprocessor directive. /// </summary> /// <param name="preprocessorSymbol"> /// The preprocessor symbol. /// </param> /// <param name="parent"> /// The parent code part. /// </param> /// <param name="generated"> /// Indicates whether the preprocessor directive lies within a block of generated code. /// </param> /// <returns> /// Returns the preprocessor directive. /// </returns> private Preprocessor GetPreprocessorDirectiveToken(Symbol preprocessorSymbol, Reference<ICodePart> parent, bool generated) { Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.AssertNotNull(parent, "parent"); Param.Ignore(generated); Debug.Assert(preprocessorSymbol != null && preprocessorSymbol.SymbolType == SymbolType.PreprocessorDirective, "Expected a preprocessor directive"); // Get the type of the preprocessor directive. int bodyIndex; string type = CsParser.GetPreprocessorDirectiveType(preprocessorSymbol, out bodyIndex); if (type == null) { throw new SyntaxException(this.document.SourceCode, preprocessorSymbol.LineNumber); } // Create the correct preprocessor object type. Preprocessor preprocessor = null; if (type == "region") { Region region = new Region(preprocessorSymbol.Text, preprocessorSymbol.Location, parent, true, generated); this.symbols.PushRegion(region); preprocessor = region; } else if (type == "endregion") { Region endregion = new Region(preprocessorSymbol.Text, preprocessorSymbol.Location, parent, false, generated); Region startregion = this.symbols.PopRegion(); if (startregion == null) { throw new SyntaxException(this.document.SourceCode, preprocessorSymbol.LineNumber); } startregion.Partner = endregion; endregion.Partner = startregion; preprocessor = endregion; } else if (type == "if") { preprocessor = this.GetConditionalCompilationDirective(preprocessorSymbol, ConditionalCompilationDirectiveType.If, bodyIndex, parent, generated); } else if (type == "elif") { preprocessor = this.GetConditionalCompilationDirective(preprocessorSymbol, ConditionalCompilationDirectiveType.Elif, bodyIndex, parent, generated); } else if (type == "else") { preprocessor = this.GetConditionalCompilationDirective(preprocessorSymbol, ConditionalCompilationDirectiveType.Else, bodyIndex, parent, generated); } else if (type == "endif") { preprocessor = this.GetConditionalCompilationDirective(preprocessorSymbol, ConditionalCompilationDirectiveType.Endif, bodyIndex, parent, generated); } else { preprocessor = new Preprocessor(preprocessorSymbol.Text, preprocessorSymbol.Location, parent, generated); } return preprocessor; }
/// <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="symbols"> /// The List of symbols we've processed. /// </param> /// <param name="sourceCode"> /// The source code file containing this directive. /// </param> /// <param name="preprocessorSymbol"> /// The symbol to check. /// </param> /// <param name="configuration"> /// The active configuration. /// </param> private void CheckForConditionalCompilationDirective(List<Symbol> symbols, SourceCode sourceCode, Symbol preprocessorSymbol, Configuration configuration) { Param.AssertNotNull(symbols, "symbols"); Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.Ignore(configuration); // Get the type of this preprocessor directive. int bodyIndex; string type = CsParser.GetPreprocessorDirectiveType(preprocessorSymbol, out bodyIndex); switch (type) { case "define": this.GetDefinePreprocessorDirective(sourceCode, preprocessorSymbol, bodyIndex); break; case "undef": this.GetUndefinePreprocessorDirective(sourceCode, preprocessorSymbol, bodyIndex); break; case "endif": if (this.conditionalDirectives.Count == 0) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } this.conditionalDirectives.Pop(); this.evaluatingSymbols = this.conditionalDirectives.Count == 0 || this.evaluatingSymbolsStatus.Pop(); break; case "else": case "elif": case "if": this.SetEvaluatingSymbolsForIfElifElse(sourceCode, preprocessorSymbol, configuration, bodyIndex, type); break; } }
/// <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. CodeLocation 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. Symbol 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 an undefine preprocessor directive from the code. /// </summary> /// <param name="sourceCode"> /// The source code being parsed. /// </param> /// <param name="preprocessorSymbol"> /// The preprocessor symbol being parsed. /// </param> /// <param name="startIndex"> /// The start index within the symbols. /// </param> private void GetUndefinePreprocessorDirective(SourceCode sourceCode, Symbol preprocessorSymbol, int startIndex) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); // Get the body of the undefine directive. LiteralExpression body = CodeParser.GetConditionalPreprocessorBodyExpression(this.parser, sourceCode, preprocessorSymbol, startIndex) as LiteralExpression; if (body == null) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } // Create the undefines list if necessary. if (this.undefines == null) { this.undefines = new Dictionary<string, string>(); } // Add the item to the list. if (!this.undefines.ContainsKey(body.Text)) { 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); } }
private bool GetOtherElementModifier(Reference<ICodePart> elementReference, string[] allowedModifiers, Dictionary<CsTokenType, CsToken> modifiers, Symbol symbol) { Param.AssertNotNull(elementReference, "elementReference"); 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)) { CsTokenType modifierType; switch (symbol.SymbolType) { case SymbolType.Abstract: modifierType = CsTokenType.Abstract; break; case SymbolType.Const: modifierType = CsTokenType.Const; break; case SymbolType.Explicit: modifierType = CsTokenType.Explicit; break; case SymbolType.Extern: modifierType = CsTokenType.Extern; break; case SymbolType.Implicit: modifierType = CsTokenType.Implicit; break; case SymbolType.New: modifierType = CsTokenType.New; break; case SymbolType.Override: modifierType = CsTokenType.Override; break; case SymbolType.Readonly: modifierType = CsTokenType.Readonly; break; case SymbolType.Sealed: modifierType = CsTokenType.Sealed; break; case SymbolType.Static: modifierType = CsTokenType.Static; break; case SymbolType.Unsafe: modifierType = CsTokenType.Unsafe; break; case SymbolType.Virtual: modifierType = CsTokenType.Virtual; break; case SymbolType.Volatile: modifierType = CsTokenType.Volatile; break; case SymbolType.Fixed: modifierType = CsTokenType.Fixed; break; case SymbolType.Other: switch (symbol.Text) { case "partial": modifierType = CsTokenType.Partial; break; case "async": modifierType = CsTokenType.Async; break; default: goto default; } break; default: throw this.CreateSyntaxException(); } CsToken modifier = this.GetToken(modifierType, symbol.SymbolType, elementReference); modifiers.Add(modifierType, modifier); this.tokens.Add(modifier); stop = false; break; } } } return !stop; }
private Symbol GetOperatorSymbol(char character) { Param.Ignore(character); SymbolType type = SymbolType.Other; StringBuilder text = new StringBuilder(); int endLineIndex = this.marker.LineNumber; bool updateEndLineIndex = false; 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(); StringBuilder checkNullCondition = new StringBuilder(); int checkIndex = 0; while (true) { if (character == '\r' || character == '\n' || character == ' ') { if(character == '\r') { endLineIndex++; } else if(character == '\n' && this.codeReader.Peek(checkIndex - 1) != '\r') { endLineIndex++; } checkNullCondition.Append(character); } else if(character == '/') { if(this.codeReader.Peek(checkIndex + 1) == '/') { this.codeReader.ReadNext(checkIndex); Symbol nextComment = this.GetComment(); checkNullCondition.Append(nextComment.Text); checkIndex = -1; } } else { break; } checkIndex++; character = this.codeReader.Peek(checkIndex); } if (character == '?') { text.Append("?"); type = SymbolType.NullCoalescingSymbol; this.codeReader.ReadNext(); } else if (character == '.') { // Check split for null conditional operator. if (!string.IsNullOrEmpty(checkNullCondition.ToString())) { text.Append(checkNullCondition.ToString()); // Advance cursor for next symbol. this.codeReader.ReadNext(checkIndex); updateEndLineIndex = true; } text.Append("."); type = SymbolType.NullConditional; this.codeReader.ReadNext(); } else if (character == '[') { if (this.codeReader.Peek(1) != ']') { // Check split for null conditional operator. if (!string.IsNullOrEmpty(checkNullCondition.ToString())) { text.Append(checkNullCondition.ToString()); // Advance cursor for next symbol. this.codeReader.ReadNext(checkIndex); updateEndLineIndex = true; } // null conditional against an opening bracket like foo?[0]; type = SymbolType.NullConditional; } } } 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); } if(!updateEndLineIndex) { endLineIndex = this.marker.LineNumber; } // Create the code location. CodeLocation location = new CodeLocation( this.marker.Index, this.marker.Index + text.Length - 1, this.marker.IndexOnLine, this.marker.IndexOnLine + text.Length - 1, this.marker.LineNumber, endLineIndex); if (updateEndLineIndex) { this.marker.LineNumber = endLineIndex; } // Create the token. Symbol 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> /// 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; Debug.Assert(adjustedStartIndex >= 0 && adjustedStartIndex < this.symbols.Count, "The adjusted start index should be within the symbol list"); 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. Symbol 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); } }
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.BitwiseCompliment; category = OperatorCategory.Unary; break; case SymbolType.Lambda: type = OperatorType.Lambda; category = OperatorCategory.Lambda; break; case SymbolType.NullConditional: type = OperatorType.NullConditional; category = OperatorCategory.Logical; 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> /// Converts a symbol to the given token type. /// </summary> /// <param name="symbol"> /// The symbol to convert. /// </param> /// <param name="tokenType"> /// The type of the token to retrieve. /// </param> /// <param name="parentReference"> /// The parent code part. /// </param> /// <returns> /// Returns the token. /// </returns> private CsToken ConvertSymbol(Symbol symbol, CsTokenType tokenType, Reference<ICodePart> parentReference) { Param.AssertNotNull(symbol, "symbol"); Param.Ignore(tokenType); Param.AssertNotNull(parentReference, "parentReference"); // Create the appropriate token based on the type of the symbol. if (symbol.SymbolType == SymbolType.WhiteSpace) { Debug.Assert(tokenType == CsTokenType.WhiteSpace, "The token type is wrong."); return new Whitespace(symbol.Text, symbol.Location, parentReference, this.symbols.Generated); } else if (symbol.SymbolType == SymbolType.Number) { Debug.Assert(tokenType == CsTokenType.Number, "The token type is wrong."); return new Number(symbol.Text, symbol.Location, parentReference, this.symbols.Generated); } else if (symbol.SymbolType == SymbolType.PreprocessorDirective) { Debug.Assert(tokenType == CsTokenType.PreprocessorDirective, "The token type is wrong."); return this.GetPreprocessorDirectiveToken(symbol, parentReference, this.symbols.Generated); } else { // Brackets are created using the GetBracketToken method. Debug.Assert(symbol.SymbolType != SymbolType.OpenParenthesis, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.CloseParenthesis, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.OpenSquareBracket, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.CloseSquareBracket, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.OpenCurlyBracket, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.CloseCurlyBracket, "Do not use this method for converting brackets."); Debug.Assert(symbol.SymbolType != SymbolType.Attribute, "Do not use this method for converting attributes."); return new CsToken(symbol.Text, tokenType, CsTokenClass.Token, symbol.Location, parentReference, this.symbols.Generated); } }
/// <summary> /// Gets the next preprocessor directive keyword. /// </summary> /// <param name="symbols"> /// The List of symbols we've processed. /// </param> /// <param name="sourceCode"> /// The source code. /// </param> /// <param name="configuration"> /// The active configuration. /// </param> /// <returns> /// Returns the next preprocessor directive keyword. /// </returns> private Symbol GetPreprocessorDirectiveSymbol(List<Symbol> symbols, SourceCode sourceCode, Configuration configuration) { Param.AssertNotNull(symbols, "symbols"); Param.AssertNotNull(sourceCode, "sourceCode"); Param.Ignore(configuration); // Find the end of the current line. StringBuilder text = new StringBuilder(); this.AdvanceToEndOfLine(text); if (text.Length == 1) { throw new SyntaxException(sourceCode, 1, Strings.UnexpectedEndOfFile); } // Create the code location. CodeLocation 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. Symbol symbol = new Symbol(text.ToString(), SymbolType.PreprocessorDirective, location); // Update the marker. this.marker.Index += text.Length; this.marker.IndexOnLine += text.Length; // If this is a conditional preprocessor symbol which resolves to false, // then we need to figure out which code is not in scope. this.CheckForConditionalCompilationDirective(symbols, sourceCode, symbol, configuration); // Return the symbol. 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"); 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. CodeLocation 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. Symbol 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 string from the code. /// </summary> /// <returns>Returns the string.</returns> private Symbol GetString() { StringBuilder text = new StringBuilder(); // Read the opening quote character and add it to the string. char quoteType = this.codeReader.ReadNext(); 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. CodeLocation 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. Symbol 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"); 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(); 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 == char.MinValue) { // No more characters in the buffer. break; } else 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. CodeLocation location = new CodeLocation(startIndex, endIndex, startIndexOnLine, endIndexOnLine, lineNumber, endLineNumber); // Create the symbol. Symbol token = new Symbol(text.ToString(), SymbolType.String, location); // Update the marker. this.marker.Index = endIndex; this.marker.IndexOnLine = endIndexOnLine; this.marker.LineNumber = endLineNumber; // Return the token. return token; }
/// <summary> /// Gets the next whitespace stream. /// </summary> /// <returns>Returns the whitespace.</returns> private Symbol GetWhitespace() { StringBuilder text = new StringBuilder(); // Get all of the characters in the whitespace. while (true) { char character = this.codeReader.Peek(); UnicodeCategory category = char.GetUnicodeCategory(character); if (character == char.MinValue || (category != UnicodeCategory.SpaceSeparator && character != '\t')) { break; } text.Append(character); // Advance past this character. this.codeReader.ReadNext(); } // Create the whitespace location object. CodeLocation 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. Symbol 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 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. CodeLocation location = new CodeLocation(startIndex, endIndex, startIndexOnLine, endIndexOnLine, lineNumber, endLineNumber); // Create the symbol object. Symbol 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> /// Extracts an if, endif, or else directive. /// </summary> /// <param name="sourceCode"> /// The source code being parsed. /// </param> /// <param name="preprocessorSymbol"> /// The preprocessor symbol being parsed. /// </param> /// <param name="configuration"> /// 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> private void SetEvaluatingSymbolsForIfElifElse(SourceCode sourceCode, Symbol preprocessorSymbol, Configuration configuration, int startIndex, string type) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.AssertNotNull(configuration, "configuration"); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); Param.AssertValidString(type, "type"); switch (type) { case "if": this.evaluatingSymbolsStatus.Push(this.evaluatingSymbols); if (this.evaluatingSymbols) { // Extract the body of the directive. Expression body = CodeParser.GetConditionalPreprocessorBodyExpression(this.parser, sourceCode, preprocessorSymbol, startIndex); if (body == null) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } // Determine whether the code under this directive needs to be skipped. this.evaluatingSymbols = this.EvaluateConditionalDirectiveExpression(sourceCode, body, configuration); } this.conditionalDirectives.Push(this.evaluatingSymbols); break; case "elif": { if (this.conditionalDirectives.Count == 0) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } bool conditionalValue = this.conditionalDirectives.Peek(); // If the #if we are part of was 'true' then we stop evaluating. if (conditionalValue) { this.evaluatingSymbols = false; } else { // If we were evaluatingSymbols before this #if started then check again now. if (this.evaluatingSymbolsStatus.Peek()) { // Extract the body of the directive. Expression body = CodeParser.GetConditionalPreprocessorBodyExpression(this.parser, sourceCode, preprocessorSymbol, startIndex); if (body == null) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } // Determine whether the code under this directive needs to be skipped. this.evaluatingSymbols = this.EvaluateConditionalDirectiveExpression(sourceCode, body, configuration); if (this.evaluatingSymbols) { this.conditionalDirectives.Pop(); this.conditionalDirectives.Push(true); } } } } break; case "else": if (this.conditionalDirectives.Count == 0) { throw new SyntaxException(sourceCode, preprocessorSymbol.LineNumber); } // If we were evaluatingSymbols before this #if started then check again now. if (this.evaluatingSymbolsStatus.Peek()) { bool conditionalValue = this.conditionalDirectives.Peek(); // If the #if we are part of was 'true' then we stop evaluating. this.evaluatingSymbols = !conditionalValue; } break; } }
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. CodeLocation 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> /// 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 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); Debug.Assert(!string.IsNullOrEmpty(numberText), "The text should not be empty"); // Create the location object. CodeLocation 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 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> /// <param name="parent"> /// The parent code part. /// </param> /// <param name="generated"> /// Indicates whether the directive lies within a block of generated code. /// </param> /// <returns> /// Returns the directive. /// </returns> private ConditionalCompilationDirective GetConditionalCompilationDirective( Symbol preprocessorSymbol, ConditionalCompilationDirectiveType type, int startIndex, Reference<ICodePart> parent, bool generated) { Param.AssertNotNull(preprocessorSymbol, "preprocessorSymbol"); Param.Ignore(type); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); Param.AssertNotNull(parent, "parent"); Param.Ignore(generated); Expression body = null; // Extract the body of the directive if necessary. if (type != ConditionalCompilationDirectiveType.Endif && startIndex < preprocessorSymbol.Text.Length) { body = CodeParser.GetConditionalPreprocessorBodyExpression(this.parser, this.document.SourceCode, preprocessorSymbol, startIndex); } // Create and return the directive. return new ConditionalCompilationDirective(preprocessorSymbol.Text, type, body, preprocessorSymbol.Location, parent, generated); }
/// <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"); 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); }