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; }
#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); } } }
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)); } }
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; } } }
private static Boolean IsWordChar(Char ch) => CharUtils.IsInRange('a', CharUtils.AsciiLowerCase(ch), 'z') || IsDecimalChar(ch) || ch == '_';
private static Boolean IsHexChar(Char ch) => CharUtils.IsInRange('a', CharUtils.AsciiLowerCase(ch), 'f') || IsDecimalChar(ch);