public Token ConsumeToken(StringWalker w)
        {
            CodePos pos     = w.Position;
            string  content = w.ConsumeWhile(char.IsLetterOrDigit);

            return(new Token(pos, TokenType.Keyword, content));
        }
Example #2
0
        public Token ConsumeToken(StringWalker w)
        {
            CodePos startPos = w.Position;

            // Skip the opening quote, after asserting that it is indeed
            // a quote.
            char openingQuote = w.Peek();

            if (openingQuote != '"')
            {
                throw new CompileErrorException(w.Position, "StringRule.ConsumeToken() called, but it didn't start on a quote.");
            }
            w.Consume(1);

            var strContent = new StringBuilder();

            while (w.Peek() != '"')
            {
                char c = w.Peek();

                // If it's a backslash, it must be an escape sequence.
                if (c == '\\')
                {
                    // Skip the backslash, then use the next char
                    // to determine which character this escape sequence
                    // represents
                    w.Consume(1);
                    char codeChar   = w.Consume(1)[0];
                    char resultChar = codeChar switch
                    {
                        '\\' => '\\',
                        '"' => '"',
                        'n' => '\n',
                        'r' => '\r',
                        _ => throw new CompileErrorException(w.Position, $"Invalid escape sequence \\{codeChar}")
                    };

                    strContent.Append(resultChar);
                    continue;
                }

                strContent.Append(w.Consume(1));
            }

            // Skip the ending quote
            w.Consume(1);
            return(new Token(
                       startPos,
                       TokenType.String,
                       strContent.ToString()
                       ));
        }
    }
Example #3
0
        public IEnumerable <Token> ToTokens(IEnumerable <char> src)
        {
            var walker = new StringWalker(src);
            var rules  = new ILexerRule[]
            {
                new NumberRule(),
                new KeywordRule(_keywords),
                new WordRule(),
                new StringRule(),
                new SingleCharSymbolRule()
            };

            while (!walker.IsEmpty())
            {
                char c = walker.Peek();

                // Skip all whitespace
                if (char.IsWhiteSpace(c))
                {
                    walker.Consume(1);
                    continue;
                }

                // Get the standard rules out of the way first.
                bool handledByStandardRule = false;
                foreach (var rule in rules)
                {
                    if (rule.IsStartOfToken(walker))
                    {
                        handledByStandardRule = true;
                        yield return(rule.ConsumeToken(walker));

                        break;
                    }
                }

                if (handledByStandardRule)
                {
                    continue;
                }

                // TODO: multi-character symbol tokens
                // TODO: Special cases go here

                // We didn't find any rule that matches what we're seeing,
                // so throw an error.
                CodePos pos = walker.Position;
                throw new CompileErrorException(pos, $"Unexpected character '{c}'");
            }
        }
        public Token ConsumeToken(StringWalker w)
        {
            CodePos pos         = w.Position;
            string  sign        = ConsumeSign();
            string  wholePart   = ConsumeWholePart();
            string  decimalPart = ConsumeDecimalPart();
            string  content     = $"{sign}{wholePart}{decimalPart}";

            return(new Token(pos, TokenType.Number, content));

            string ConsumeSign() => w.Peek() == '-'
        ? w.Consume(1)
        : "";

            string ConsumeWholePart() => w.ConsumeWhile(char.IsDigit);

            string ConsumeDecimalPart()
            {
                if (w.IsEmpty() || w.Peek() != '.')
                {
                    return("");
                }

                string decimalPoint = w.Consume(1);
                string digits       = w.ConsumeWhile(char.IsDigit);

                // If there is nothing after the decimal point, that's an error
                if (digits.Length == 0)
                {
                    throw new CompileErrorException(w.Position, "There must be digits after the decimal point");
                }

                // There can only be one decimal point in the number.  If there's
                // another, that's an error.
                if (!w.IsEmpty() && w.Peek() == '.')
                {
                    throw new CompileErrorException(w.Position, "A number may only have one decimal point");
                }

                return($".{digits}");
            }
        }
 public CompileErrorException(CodePos pos, string message)
     : base($"Line {pos.LineNumber}, char {pos.CharNumber}: {message}")
 {
     Position = pos;
 }
Example #6
0
 public Token(CodePos position, TokenType type, string content)
 {
     Position = position;
     Type     = type;
     Content  = content;
 }