feat: support binary octal and hexadecimal integer literals
This commit is contained in:
@@ -411,6 +411,35 @@ lex :: proc(
|
||||
case:
|
||||
if value >= '0' && value <= '9' {
|
||||
start := cursor
|
||||
base: byte
|
||||
if value == '0' && cursor+1 < len(bytes) {
|
||||
switch bytes[cursor+1] {
|
||||
case 'b', 'B': base = 2
|
||||
case 'o', 'O': base = 8
|
||||
case 'x', 'X': base = 16
|
||||
}
|
||||
}
|
||||
if base != 0 {
|
||||
cursor += 2
|
||||
digits_start := cursor
|
||||
valid := true
|
||||
for cursor < len(bytes) && is_identifier_continue(bytes[cursor]) {
|
||||
digit := bytes[cursor]
|
||||
valid = valid && is_hex_digit(digit) && (base == 16 || digit-'0' < base)
|
||||
cursor += 1
|
||||
}
|
||||
if !valid || cursor == digits_start {
|
||||
id := source.add(
|
||||
diagnostics,
|
||||
source.Span{file=source_file.id, start=source.Offset(start), end=source.Offset(cursor)},
|
||||
"invalid digits in prefixed integer literal",
|
||||
)
|
||||
append_token(&stream, source_file, .Invalid, start, cursor, diagnostic=id)
|
||||
} else {
|
||||
append_token(&stream, source_file, .Integer, start, cursor)
|
||||
}
|
||||
continue
|
||||
}
|
||||
for cursor < len(bytes) && bytes[cursor] >= '0' && bytes[cursor] <= '9' {
|
||||
cursor += 1
|
||||
}
|
||||
|
||||
@@ -239,6 +239,7 @@ parse_type_constant :: proc(parser: ^Parser) -> (u64, bool) {
|
||||
advance(parser)
|
||||
value, ok := parse_integer_magnitude(token_text(parser, tok))
|
||||
if !ok {
|
||||
source.add(parser.diagnostics, tok.span, "integer literal magnitude does not fit in u64")
|
||||
return 0, false
|
||||
}
|
||||
if negative {
|
||||
@@ -906,21 +907,37 @@ parse_anonymous_struct_type_expr :: proc(parser: ^Parser) -> ast.Expr_Id {
|
||||
}
|
||||
|
||||
parse_integer_magnitude :: proc(text: string) -> (u64, bool) {
|
||||
base := u64(10)
|
||||
digits := text
|
||||
if len(text) >= 2 && text[0] == '0' {
|
||||
switch text[1] {
|
||||
case 'b', 'B': base = 2
|
||||
case 'o', 'O': base = 8
|
||||
case 'x', 'X': base = 16
|
||||
}
|
||||
if base != 10 {
|
||||
digits = text[2:]
|
||||
}
|
||||
}
|
||||
value: u64
|
||||
for byte in transmute([]byte)text {
|
||||
if byte < '0' || byte > '9' {
|
||||
for byte in transmute([]byte)digits {
|
||||
if !(byte >= '0' && byte <= '9' || byte >= 'a' && byte <= 'f' || byte >= 'A' && byte <= 'F') {
|
||||
return 0, false
|
||||
}
|
||||
next, overflow := intrinsics.overflow_mul(value, u64(10))
|
||||
digit := u64(decode_hex_digit(byte))
|
||||
if digit >= base {
|
||||
return 0, false
|
||||
}
|
||||
next, overflow := intrinsics.overflow_mul(value, base)
|
||||
if overflow {
|
||||
return 0, false
|
||||
}
|
||||
value, overflow = intrinsics.overflow_add(next, u64(byte-'0'))
|
||||
value, overflow = intrinsics.overflow_add(next, digit)
|
||||
if overflow {
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
return value, len(text) > 0
|
||||
return value, len(digits) > 0
|
||||
}
|
||||
|
||||
parse_primary :: proc(parser: ^Parser, nesting: int) -> ast.Expr_Id {
|
||||
|
||||
Reference in New Issue
Block a user