private LexResult LexNumber() { Debug.Assert(SyntaxUtils.IsNumeric(Buffer.Peek()) || Buffer.Peek() == '.'); CppTokenKind kind; char first = Buffer.Peek(0); char second = Buffer.Peek(1); bool dotSeen = false; if (first == '0') { if (second == 'x' || second == 'X') { // Hex kind = CppTokenKind.HexLiteral; Buffer.AdvanceColumns(2); // Skip 0[xX] } else if (second == 'b' || second == 'B') { // Binary kind = CppTokenKind.BinaryLiteral; Buffer.AdvanceColumns(2); // Skip 0[bB] } else { // Octal kind = CppTokenKind.OctalLiteral; } } else if (first == '.') { Debug.Assert(SyntaxUtils.IsNumeric(second)); kind = CppTokenKind.IntegerFloatLiteral; Buffer.AdvanceColumn(); dotSeen = true; } else { Debug.Assert(SyntaxUtils.IsNumeric(first)); kind = CppTokenKind.IntegerLiteral; } // @NOTE(final): We never set the DecimalHexLiteral kind initially, // as every hex decimal always starts as a normal hex literal! Debug.Assert(kind != CppTokenKind.HexadecimalFloatLiteral); // First number part int firstLiteralPos = Buffer.TextPosition.Index; bool readNextLiteral = false; do { readNextLiteral = false; int s = Buffer.TextPosition.Index; switch (kind) { case CppTokenKind.IntegerLiteral: case CppTokenKind.IntegerFloatLiteral: if (SyntaxUtils.IsNumeric(Buffer.Peek())) { Buffer.AdvanceColumnsWhile(SyntaxUtils.IsNumeric); } else { AddError(Buffer.TextPosition, $"Expect integer literal, but got '{Buffer.Peek()}'", kind.ToString()); } break; case CppTokenKind.OctalLiteral: if (SyntaxUtils.IsOctal(Buffer.Peek())) { Buffer.AdvanceColumnsWhile(SyntaxUtils.IsOctal); } else { AddError(Buffer.TextPosition, $"Expect octal literal, but got '{Buffer.Peek()}'", kind.ToString()); } break; case CppTokenKind.HexLiteral: if (SyntaxUtils.IsHex(Buffer.Peek())) { Buffer.AdvanceColumnsWhile(SyntaxUtils.IsHex); } else { AddError(Buffer.TextPosition, $"Expect hex literal, but got '{Buffer.Peek()}'", kind.ToString()); } break; case CppTokenKind.BinaryLiteral: if (SyntaxUtils.IsBinary(Buffer.Peek())) { Buffer.AdvanceColumnsWhile(SyntaxUtils.IsBinary); } else { AddError(Buffer.TextPosition, $"Expect binary literal, but got '{Buffer.Peek()}'", kind.ToString()); } break; default: AddError(Buffer.TextPosition, $"Unsupported token kind '{kind}' for integer literal on {Buffer}", kind.ToString()); break; } bool hadIntegerLiteral = Buffer.TextPosition.Index > s; if (kind != CppTokenKind.IntegerFloatLiteral && kind != CppTokenKind.HexadecimalFloatLiteral) { // @NOTE(final): Single quotes (') are allowed as separators for any non-decimal literal char check0 = Buffer.Peek(); if (check0 == '\'') { if (!hadIntegerLiteral) { AddError(Buffer.TextPosition, $"Too many single quote escape in integer literal, expect any integer literal but got '{Buffer.Peek()}'", kind.ToString()); return(new LexResult(kind, false)); } Buffer.AdvanceColumn(); readNextLiteral = true; } } } while (!Buffer.IsEOF && readNextLiteral); // Validate any literal after starting dot if (dotSeen) { if (firstLiteralPos == Buffer.TextPosition.Index) { AddError(Buffer.TextPosition, $"Expect any integer literal after starting dot, but got '{Buffer.Peek()}'", kind.ToString()); return(new LexResult(kind, false)); } } // Dot separator if ((!dotSeen) && ((kind == CppTokenKind.IntegerLiteral) || (kind == CppTokenKind.HexLiteral) || (kind == CppTokenKind.OctalLiteral) )) { char check0 = Buffer.Peek(); if (check0 == '.') { dotSeen = true; Buffer.AdvanceColumn(); if (kind == CppTokenKind.IntegerLiteral || kind == CppTokenKind.OctalLiteral) { kind = CppTokenKind.IntegerFloatLiteral; } else { Debug.Assert(kind == CppTokenKind.HexLiteral); kind = CppTokenKind.HexadecimalFloatLiteral; } } else if (SyntaxUtils.IsExponentPrefix(check0)) { if (kind == CppTokenKind.IntegerLiteral || kind == CppTokenKind.OctalLiteral) { kind = CppTokenKind.IntegerFloatLiteral; } else { Debug.Assert(kind == CppTokenKind.HexLiteral); kind = CppTokenKind.HexadecimalFloatLiteral; } } } // Decimal after dot separator if ((kind != CppTokenKind.IntegerFloatLiteral) && (kind != CppTokenKind.HexadecimalFloatLiteral)) { // Integer suffix if (SyntaxUtils.IsIntegerSuffix(Buffer.Peek())) { Buffer.AdvanceColumnsWhile(SyntaxUtils.IsIntegerSuffix, 3); } } else { if (kind == CppTokenKind.IntegerFloatLiteral) { // Float decimal if (SyntaxUtils.IsNumeric(Buffer.Peek())) { Buffer.AdvanceColumnsWhile(SyntaxUtils.IsNumeric); } if (Buffer.Peek() == 'e' || Buffer.Peek() == 'E') { AdvanceExponent('e'); } } else { // Hex decimal Debug.Assert(kind == CppTokenKind.HexadecimalFloatLiteral); if (SyntaxUtils.IsHex(Buffer.Peek())) { Buffer.AdvanceColumnsWhile(SyntaxUtils.IsHex); } if (Buffer.Peek() == 'p' || Buffer.Peek() == 'P') { AdvanceExponent('e'); } } // Float suffix if (SyntaxUtils.IsFloatSuffix(Buffer.Peek())) { Buffer.AdvanceColumn(); } } return(new LexResult(kind, true)); }