public IToken Produce()
        {
            var context = this.Context;
            var text    = context.Text;
            var length  = context.Length;

            var c = text[context.Index];

            if (c == ':')
            {
                var nameCharsCount = 0;
                var initialIndex   = context.Index;
                var index          = initialIndex + 1;
                var column         = context.Column + 1;

                while (true)
                {
                    if (index == length)
                    {
                        break;
                    }

                    c = text[index];

                    if (c == ':')
                    {
                        ThrowBadKeywordException(context.Line, context.Column);
                    }

                    if (!TinyLispHelper.IsAcceptableSymbolNameChar(c))
                    {
                        break;
                    }

                    nameCharsCount++;
                    index++;
                    column++;
                }

                if (nameCharsCount == 0)
                {
                    ThrowBadKeywordException(context.Line, context.Column);
                }

                var delta       = index - initialIndex;
                var keywordName = text.Substring(initialIndex, delta);
                var token       = new KeywordToken(
                    keywordName,
                    new Position(context.Line, context.Column),
                    delta);
                context.Advance(delta, 0, column);
                return(token);
            }
            else
            {
                return(null);
            }
        }
Example #2
0
        public IToken Produce()
        {
            var context = this.Context;
            var text    = context.Text;

            var c           = text[context.Index];
            var punctuation = TinyLispHelper.TryCharToPunctuation(c);

            if (punctuation.HasValue)
            {
                var position = new Position(Context.Line, Context.Column);
                context.AdvanceByChar();
                return(new LispPunctuationToken(
                           punctuation.Value,
                           position,
                           1));
            }

            return(null);
        }
Example #3
0
        private static Keyword CreateKeyword(string name)
        {
            var validName = TinyLispHelper.IsValidSymbolName(name, true);

            if (!validName)
            {
                throw new ArgumentException($"Invalid keyword name: '{name}'.", nameof(name));
            }

            var realName = GetRealName(name);
            var have     = Symbols.TryGetValue(realName, out var existing);

            if (have)
            {
                return((Keyword)existing);
            }

            var @new = new Keyword(realName);

            RegisterSymbol(@new);
            return(@new);
        }
Example #4
0
        private static Symbol CreateSymbol(string name)
        {
            var validName = TinyLispHelper.IsValidSymbolName(name, false);

            if (!validName)
            {
                throw new ArgumentException($"Invalid symbol name: '{name}'.", nameof(name));
            }

            var realName = GetRealName(name);
            var have     = Symbols.TryGetValue(realName, out var existing);

            if (have)
            {
                return(existing);
            }

            var @new = new Symbol(realName);

            RegisterSymbol(@new);
            return(@new);
        }
Example #5
0
        public IToken Produce()
        {
            var context = this.Context;
            var text    = context.Text;
            var length  = context.Length;

            var c = text[context.Index];

            if (TinyLispHelper.IsAcceptableSymbolNameChar(c))
            {
                var gotSign    = c == '+' || c == '-';
                var pureDigits = 0;
                if (!gotSign)
                {
                    pureDigits = LexingHelper.IsDigit(c) ? 1 : 0;
                }

                var gotNonDigits = false;

                var initialIndex  = context.Index;
                var initialColumn = context.Column;

                var index  = initialIndex + 1;
                var column = context.Column + 1;


                while (true)
                {
                    if (index == length)
                    {
                        break;
                    }

                    c = text[index];

                    if (c == ':')
                    {
                        throw new LexingException("Bad symbol name.", new Position(context.Line, context.Column));
                    }

                    if (!TinyLispHelper.IsAcceptableSymbolNameChar(c))
                    {
                        break;
                    }

                    if (LexingHelper.IsDigit(c))
                    {
                        if (!gotNonDigits)
                        {
                            pureDigits++;
                        }
                    }
                    else
                    {
                        gotNonDigits = true;
                        pureDigits   = 0;
                    }

                    index++;
                    column++;
                }

                var couldBeInt = pureDigits > 0;

                if (couldBeInt)
                {
                    throw new LexingException("Symbol producer delivered an integer.", new Position(context.Line, context.Column));
                }

                var delta       = index - initialIndex;
                var str         = text.Substring(initialIndex, delta); // todo: use ReadOnlySpan<char> instead of Substring everywhere.
                var symbolToken = new LispSymbolToken(str, new Position(context.Line, initialColumn), delta);
                context.Advance(delta, 0, column);
                return(symbolToken);
            }
            else
            {
                return(null);
            }
        }