/// <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;
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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;
        }
예제 #4
0
        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;
        }
예제 #5
0
        /// <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;
        }
예제 #6
0
        /// <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;
            }
        }
예제 #7
0
        /// <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;
        }
예제 #8
0
        /// <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;
        }
예제 #10
0
        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);
            }
        }
예제 #12
0
        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;
        }
예제 #13
0
        /// <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);
            }
        }
예제 #14
0
        /// <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;
        }
예제 #15
0
        /// <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;
        }
예제 #16
0
        /// <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;
        }
예제 #17
0
        /// <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;
        }
예제 #18
0
        /// <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;
        }
예제 #19
0
        /// <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;
        }
예제 #20
0
        /// <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;
            }
        }
예제 #21
0
        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;
        }
예제 #22
0
        /// <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;
        }
예제 #23
0
        /// <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;
        }
예제 #24
0
        /// <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);
        }