private IniToken LexDefineKeyword(char c, IniTokenPosition pos) { var sb = new StringBuilder(c.ToString()); while (!char.IsWhiteSpace(CurrentChar)) { sb.Append(CurrentChar); NextChar(); } return(new IniToken(IniTokenType.DefineKeyword, pos) { StringValue = sb.ToString() }); }
private IniToken LexQuotedString(IniTokenPosition pos) { var sb = new StringBuilder(); while (CurrentChar != '"') { sb.Append(CurrentChar); NextChar(); } NextChar(); return(new IniToken(IniTokenType.StringLiteral, pos) { StringValue = sb.ToString() }); }
private (IniToken?, int nextCharIndex) ReadToken(char[] separators) { if (_currentLineCharIndex >= _currentLineText.Length) { return(null, _currentLineCharIndex); } var nextCharIndex = _currentLineCharIndex; // Skip leading trivia. while (nextCharIndex < _currentLineText.Length && separators.Contains(_currentLineText[nextCharIndex])) { nextCharIndex++; } var startIndex = nextCharIndex; var length = 0; var position = new IniTokenPosition(_fileName, _currentLine + 1, nextCharIndex + 1); while (nextCharIndex < _currentLineText.Length && !separators.Contains(_currentLineText[nextCharIndex])) { length++; nextCharIndex++; } // Skip trailing separator. if (nextCharIndex < _currentLineText.Length && separators.Contains(_currentLineText[nextCharIndex])) { nextCharIndex++; } var result = _currentLineText.AsSpan(startIndex, length).ToString(); if (result.Length == 0) { return(null, nextCharIndex); } return(new IniToken(result, position), nextCharIndex); }
public IniParseException(string message, IniTokenPosition position) : base($"({position}): {message}") { }
private IniToken LexNumber(char c, IniTokenPosition pos) { var hasDot = c == '.'; var numberValue = c.ToString(); while (char.IsDigit(CurrentChar) || CurrentChar == '.' || CurrentChar == 'v') { if (CurrentChar == '.') { if (hasDot) { // ODDITY: In CivilianProp.ini:6893, there are two dots in the number: 18.5.0 NextChar(); continue; } hasDot = true; } else if (CurrentChar == 'v') { // ODDITY: In CivilianBuilding.ini:20199, there's a "v" in the middle of a number. if (PeekChar() == '.') { NextChar(); continue; } else { break; } } numberValue += CurrentChar; NextChar(); } var tokenType = hasDot ? IniTokenType.FloatLiteral : IniTokenType.IntegerLiteral; if (CurrentChar == '%') { tokenType = IniTokenType.PercentLiteral; NextChar(); } else if (IsIdentifierChar(CurrentChar)) { var numIdentifierChars = 0; while (IsIdentifierChar(CurrentChar)) { numberValue += CurrentChar; NextChar(); numIdentifierChars++; } if (numIdentifierChars == 1 && numberValue.EndsWith("f")) { return(new IniToken(tokenType, CurrentPosition) { FloatValue = float.Parse(numberValue.TrimEnd('f')) }); } if (hasDot) { throw new IniParseException($"Invalid number: {numberValue}", CurrentPosition); } return(new IniToken(IniTokenType.Identifier, CurrentPosition) { StringValue = numberValue }); } switch (tokenType) { case IniTokenType.FloatLiteral: case IniTokenType.PercentLiteral: return(new IniToken(tokenType, pos) { FloatValue = float.Parse(numberValue) }); case IniTokenType.IntegerLiteral: var longNumber = long.Parse(numberValue); if (Math.Abs(longNumber) <= int.MaxValue) { return(new IniToken(tokenType, pos) { IntegerValue = (int)longNumber }); } return(new IniToken(tokenType, pos) { LongValue = longNumber }); default: throw new ArgumentOutOfRangeException(); } }