Example #1
0
        private void ParseDecimalNumber(ref TokenInfo info)
        {
            _builder.Clear();

            SkipDecimalDigits(_builder);
            if (_reader.IsNext('.'))
            {
                _builder.Append(_reader.Read() !.Value);
                SkipDecimalDigits(_builder);
            }

            if (CharUtils.AsciiLowerCase(_reader.Peek().GetValueOrDefault()) == 'e')
            {
                _builder.Append(_reader.Read() !.Value);
                if (_reader.IsNext('+') || _reader.IsNext('-'))
                {
                    _builder.Append(_reader.Read() !.Value);
                }
                SkipDecimalDigits(_builder);
            }

            info.Text = GetText(intern: true);
            if (!Options.SyntaxOptions.AcceptUnderscoreInNumberLiterals && info.Text.IndexOf('_') >= 0)
            {
                AddError(ErrorCode.ERR_UnderscoreInNumericLiteralNotSupportedInVersion);
            }
            if (!RealParser.TryParseDouble(Intern(_builder), out var result))
            {
                AddError(ErrorCode.ERR_DoubleOverflow);
            }
            info.DoubleValue = result;
        }
Example #2
0
#pragma warning restore IDE0079 // Remove unnecessary suppression
        private void ParseHexadecimalNumber(ref TokenInfo info)
        {
            _builder.Clear();
            ConsumeHexDigits();
            var isHexFloat = false;

            if (TextWindow.PeekChar() == '.')
            {
                TextWindow.AdvanceChar();
                isHexFloat = true;
                _builder.Append('.');
                ConsumeHexDigits();
            }

            if (CharUtils.AsciiLowerCase(TextWindow.PeekChar()) == 'p')
            {
                TextWindow.AdvanceChar();
                isHexFloat = true;
                _builder.Append('p');
                if (TextWindow.PeekChar() is '+' or '-')
                {
                    _builder.Append(TextWindow.NextChar());
                }
                ConsumeDecimalDigits(_builder);
            }

            var(isUnsignedLong, isSignedLong, isComplex) = (false, false, false);

            if (TextWindow.AdvanceIfMatches("ull", true))
            {
                if (isHexFloat)
                {
                    AddError(ErrorCode.ERR_LuajitSuffixInFloat);
                }
                else
                {
                    isUnsignedLong = true;
                }
            }
            else if (TextWindow.AdvanceIfMatches("ll", true))
            {
                if (isHexFloat)
                {
                    AddError(ErrorCode.ERR_LuajitSuffixInFloat);
                }
                else
                {
                    isSignedLong = true;
                }
            }
            else if (TextWindow.AdvanceIfMatches("i", true))
            {
                isComplex = true;
            }

            info.Text = TextWindow.GetText(intern: true);
            if (!_options.SyntaxOptions.AcceptUnderscoreInNumberLiterals && info.Text.IndexOf('_') >= 0)
            {
                AddError(ErrorCode.ERR_UnderscoreInNumericLiteralNotSupportedInVersion);
            }
            if (!Options.SyntaxOptions.AcceptLuaJITNumberSuffixes && (isUnsignedLong || isSignedLong || isComplex))
            {
                AddError(ErrorCode.ERR_NumberSuffixNotSupportedInVersion);
            }

            if (isUnsignedLong)
            {
                if (!ulong.TryParse(TextWindow.Intern(_builder), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var result))
                {
                    AddError(ErrorCode.ERR_NumericLiteralTooLarge);
                }

                info.ValueKind  = ValueKind.ULong;
                info.ULongValue = result;
            }
            else if (isSignedLong)
            {
                if (!long.TryParse(TextWindow.Intern(_builder), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var result))
                {
                    AddError(ErrorCode.ERR_NumericLiteralTooLarge);
                }

                info.ValueKind = ValueKind.Long;
                info.LongValue = result;
            }
            else if (isComplex)
            {
                var result = 0d;
                try
                {
                    result = HexFloat.DoubleFromHexString(TextWindow.Intern(_builder));
                }
                catch (OverflowException)
                {
                    AddError(ErrorCode.ERR_DoubleOverflow);
                }

                info.ValueKind    = ValueKind.Complex;
                info.ComplexValue = new Complex(0, result);
            }
            else if (isHexFloat || _options.SyntaxOptions.HexIntegerFormat == IntegerFormats.NotSupported)
            {
                if (!_options.SyntaxOptions.AcceptHexFloatLiterals)
                {
                    AddError(ErrorCode.ERR_HexFloatLiteralNotSupportedInVersion);
                }

                var result = 0d;
                try
                {
                    result = HexFloat.DoubleFromHexString(TextWindow.Intern(_builder));
                }
                catch (OverflowException)
                {
                    AddError(ErrorCode.ERR_DoubleOverflow);
                }
                info.ValueKind   = ValueKind.Double;
                info.DoubleValue = result;
            }
            else
            {
                if (!long.TryParse(TextWindow.Intern(_builder), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var result))
                {
                    AddError(ErrorCode.ERR_NumericLiteralTooLarge);
                }
                switch (_options.SyntaxOptions.HexIntegerFormat)
                {
                case IntegerFormats.Double:
                    info.ValueKind   = ValueKind.Double;
                    info.DoubleValue = result;
                    break;

                case IntegerFormats.Int64:
                    info.ValueKind = ValueKind.Long;
                    info.LongValue = result;
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(_options.SyntaxOptions.HexIntegerFormat);
                }
            }
        }
Example #3
0
        private string ParseShortString()
        {
            _builder.Clear();
            var delim = TextWindow.NextChar();

            LorettaDebug.Assert(delim is '"' or '\'' or '`');

            char ch;

            while (!IsAtEnd(ch = TextWindow.PeekChar()) && ch != delim)
            {
                var charStart = TextWindow.Position;
                switch (ch)
                {
                    #region Escapes

                case '\\':
                {
                    var escapeStart = TextWindow.Position;
                    TextWindow.AdvanceChar();

                    switch (ch = TextWindow.PeekChar())
                    {
                    case '\n':
                    case '\r':
                    {
                        _builder.Append(TextWindow.NextChar());
                        char ch2;
                        if (CharUtils.IsNewLine(ch2 = TextWindow.PeekChar()) &&
                            ch != ch2)
                        {
                            _builder.Append(TextWindow.NextChar());
                        }
                        break;
                    }

                    case 'a':
                        TextWindow.AdvanceChar();
                        _builder.Append('\a');
                        break;

                    case 'b':
                        TextWindow.AdvanceChar();
                        _builder.Append('\b');
                        break;

                    case 'f':
                        TextWindow.AdvanceChar();
                        _builder.Append('\f');
                        break;

                    case 'n':
                        TextWindow.AdvanceChar();
                        _builder.Append('\n');
                        break;

                    case 'r':
                        TextWindow.AdvanceChar();
                        _builder.Append('\r');
                        break;

                    case 't':
                        TextWindow.AdvanceChar();
                        _builder.Append('\t');
                        break;

                    case 'v':
                        TextWindow.AdvanceChar();
                        _builder.Append('\v');
                        break;

                    case '\\':
                        TextWindow.AdvanceChar();
                        _builder.Append('\\');
                        break;

                    case '\'':
                        TextWindow.AdvanceChar();
                        _builder.Append('\'');
                        break;

                    case '"':
                        TextWindow.AdvanceChar();
                        _builder.Append('"');
                        break;

                    case 'z':
                        TextWindow.AdvanceChar();

                        while (CharUtils.IsWhitespace(TextWindow.PeekChar()))
                        {
                            TextWindow.AdvanceChar();
                        }

                        if (!_options.SyntaxOptions.AcceptWhitespaceEscape)
                        {
                            AddError(escapeStart, TextWindow.Position - escapeStart, ErrorCode.ERR_WhitespaceEscapeNotSupportedInVersion);
                        }
                        break;

                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                    {
                        var parsedCharInteger = parseDecimalInteger(escapeStart);
                        if (parsedCharInteger != char.MaxValue)
                        {
                            _builder.Append(parsedCharInteger);
                        }
                        break;
                    }

                    case 'x':
                    {
                        TextWindow.AdvanceChar();
                        var parsedCharInteger = parseHexadecimalEscapeInteger(escapeStart);
                        if (parsedCharInteger != char.MaxValue)
                        {
                            _builder.Append(parsedCharInteger);
                        }

                        if (!_options.SyntaxOptions.AcceptHexEscapesInStrings)
                        {
                            AddError(escapeStart, TextWindow.Position - escapeStart, ErrorCode.ERR_HexStringEscapesNotSupportedInVersion);
                        }
                    }
                    break;

                    case 'u':
                    {
                        TextWindow.AdvanceChar();
                        var parsed = parseUnicodeEscape(escapeStart);
                        _builder.Append(parsed);

                        if (!_options.SyntaxOptions.AcceptUnicodeEscape)
                        {
                            AddError(escapeStart, TextWindow.Position - escapeStart, ErrorCode.ERR_UnicodeEscapesNotSupportedLuaInVersion);
                        }
                    }
                    break;

                    default:
                        if (!_options.SyntaxOptions.AcceptInvalidEscapes)
                        {
                            // Skip the character after the escape.
                            TextWindow.AdvanceChar();
                            AddError(escapeStart, TextWindow.Position - escapeStart, ErrorCode.ERR_InvalidStringEscape);
                        }
                        break;
                    }
                }
                break;

                    #endregion Escapes

                case '\n':
                case '\r':
                {
                    _builder.Append(TextWindow.NextChar());
                    char ch2;
                    if (CharUtils.IsNewLine(ch2 = TextWindow.PeekChar()) &&
                        ch != ch2)
                    {
                        _builder.Append(TextWindow.NextChar());
                    }

                    AddError(charStart, TextWindow.Position - charStart, ErrorCode.ERR_UnescapedLineBreakInString);
                }
                break;

                default:
                    _builder.Append(TextWindow.NextChar());
                    break;
                }
            }

            if (TextWindow.PeekChar() == delim)
            {
                TextWindow.AdvanceChar();
            }
            else
            {
                AddError(ErrorCode.ERR_UnfinishedString);
            }

            return(TextWindow.Intern(_builder));

            char parseDecimalInteger(int start)
            {
                var  readChars = 0;
                var  num       = 0;
                char ch;

                while (readChars < 3 && CharUtils.IsDecimal(ch = TextWindow.PeekChar()))
                {
                    TextWindow.AdvanceChar();
                    num = (num * 10) + (ch - '0');
                    readChars++;
                }

                if (readChars < 1 || num > 255)
                {
                    AddError(start, TextWindow.Position - start, ErrorCode.ERR_InvalidStringEscape);
                    return(char.MaxValue);
                }

                return((char)num);
            }

            ulong parseHexadecimalNumber(int start, int maxDigits, ErrorCode lessThanZeroErrorCode)
            {
                var readChars = 0;
                var num       = 0L;

                while (readChars < maxDigits)
                {
                    var peek = TextWindow.PeekChar();
                    if (CharUtils.IsDecimal(peek))
                    {
                        TextWindow.AdvanceChar();
                        num = (num << 4) | (uint)(peek - '0');
                    }
                    else if (CharUtils.IsHexadecimal(peek))
                    {
                        TextWindow.AdvanceChar();
                        num = (num << 4) | (uint)(10 + CharUtils.AsciiLowerCase(peek) - 'a');
                    }
                    else
                    {
                        break;
                    }
                    readChars++;
                }

                if (readChars < 1)
                {
                    AddError(start, TextWindow.Position - start, lessThanZeroErrorCode);
                    return(0UL);
                }

                return((ulong)num);
            }

            char parseHexadecimalEscapeInteger(int start) =>
            (char)parseHexadecimalNumber(start, 2, ErrorCode.ERR_InvalidStringEscape);

            string parseUnicodeEscape(int start)
            {
                var missingOpeningBrace = TextWindow.PeekChar() is not '{';

                if (!missingOpeningBrace)
                {
                    TextWindow.AdvanceChar();
                }

                var codepoint = parseHexadecimalNumber(start, 16, ErrorCode.ERR_HexDigitExpected);

                var missingClosingBrace = TextWindow.PeekChar() is not '}';

                if (!missingClosingBrace)
                {
                    TextWindow.AdvanceChar();
                }

                if (missingOpeningBrace)
                {
                    AddError(start, TextWindow.Position - start, ErrorCode.ERR_UnicodeEscapeMissingOpenBrace);
                }
                if (missingClosingBrace)
                {
                    AddError(start, TextWindow.Position - start, ErrorCode.ERR_UnicodeEscapeMissingCloseBrace);
                }
                if (codepoint > 0x10FFFF)
                {
                    AddError(start, TextWindow.Position - start, ErrorCode.ERR_EscapeTooLarge, "10FFFF");
                    codepoint = 0x10FFFF;
                }

                // Return the codepoint itself if it's in the BMP.
                // NOTE: It *is* technically incorrect to consider a surrogate
                // an Unicode codepoint but Lua accepts it so we do it as well.
                if (codepoint <= 0xFFFF)
                {
                    return(char.ToString((char)codepoint));
                }

                return(char.ConvertFromUtf32((int)codepoint));
            }
        }
Example #4
0
        private void ParseHexadecimalNumber(ref TokenInfo info)
        {
            _builder.Clear();
            skipHexDigits();
            var isHexFloat = false;

            if (_reader.IsNext('.'))
            {
                isHexFloat = true;
                _builder.Append(_reader.Read() !.Value);
                skipHexDigits();
            }

            if (CharUtils.AsciiLowerCase(_reader.Peek().GetValueOrDefault()) == 'p')
            {
                isHexFloat = true;
                _builder.Append(_reader.Read() !.Value);
                if (_reader.IsNext('+') || _reader.IsNext('-'))
                {
                    _builder.Append(_reader.Read() !.Value);
                }
                SkipDecimalDigits(_builder);
            }

            if (isHexFloat && !Options.SyntaxOptions.AcceptHexFloatLiterals)
            {
                AddError(ErrorCode.ERR_HexFloatLiteralNotSupportedInVersion);
            }

            info.Text = GetText(intern: true);
            if (!Options.SyntaxOptions.AcceptUnderscoreInNumberLiterals && info.Text.IndexOf('_') >= 0)
            {
                AddError(ErrorCode.ERR_UnderscoreInNumericLiteralNotSupportedInVersion);
            }

            var result = 0d;

            try
            {
                result = HexFloat.DoubleFromHexString(Intern(_builder));
            }
            catch (OverflowException)
            {
                AddError(ErrorCode.ERR_DoubleOverflow);
            }
            info.DoubleValue = result;

            void skipHexDigits()
            {
                char digit;

                while (CharUtils.IsHexadecimal(digit = _reader.Peek().GetValueOrDefault()) || digit == '_')
                {
                    if (digit != '_')
                    {
                        _builder.Append(digit);
                    }
                    _reader.Position += 1;
                }
            }
        }
Example #5
0
 private static Boolean IsWordChar(Char ch) =>
 CharUtils.IsInRange('a', CharUtils.AsciiLowerCase(ch), 'z') || IsDecimalChar(ch) || ch == '_';
Example #6
0
 private static Boolean IsHexChar(Char ch) =>
 CharUtils.IsInRange('a', CharUtils.AsciiLowerCase(ch), 'f') || IsDecimalChar(ch);