Skip to content

Commit 6ea4c0a

Browse files
fix incorrect parsing of signed hex/oct/bin
1 parent 968f347 commit 6ea4c0a

File tree

2 files changed

+27
-9
lines changed

2 files changed

+27
-9
lines changed

lib/src/tokenizer.dart

+18-9
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,15 @@ class KdlTokenizer {
159159
this.index += 1;
160160
} else if (c != null && RegExp(r"[0-9\-+]").hasMatch(c)) {
161161
var n = _charAt(this.index + 1);
162+
var n2 = _charAt(this.index + 2);
162163
if (c == '0' && n != null && RegExp("[box]").hasMatch(n)) {
163164
this.index += 2;
164165
this.buffer = '';
165-
switch (n) {
166-
case 'b': _setContext(KdlTokenizerContext.binary); break;
167-
case 'o': _setContext(KdlTokenizerContext.octal); break;
168-
case 'x': _setContext(KdlTokenizerContext.hexadecimal); break;
169-
}
166+
_setContext(_integerContext(n));
167+
} else if ((c == '-' || c == '+') && n == '0' && RegExp("[box]").hasMatch(n2)) {
168+
this.index += 3;
169+
this.buffer = c;
170+
_setContext(_integerContext(n2));
170171
} else {
171172
_setContext(KdlTokenizerContext.decimal);
172173
this.index += 1;
@@ -388,6 +389,14 @@ class KdlTokenizer {
388389
this.previousContext = null;
389390
}
390391

392+
_integerContext(String n) {
393+
switch (n) {
394+
case 'b': return KdlTokenizerContext.binary;
395+
case 'o': return KdlTokenizerContext.octal;
396+
case 'x': return KdlTokenizerContext.hexadecimal;
397+
}
398+
}
399+
391400
_parseDecimal(String s) {
392401
if (RegExp("[.eE]").hasMatch(s)) {
393402
_checkFloat(s);
@@ -410,17 +419,17 @@ class KdlTokenizer {
410419
}
411420

412421
_parseHexadecimal(String s) {
413-
if (!RegExp(r"^[0-9a-fA-F][0-9a-fA-F_]*$").hasMatch(s)) throw "Invalid hexadecimal: ${s}";
422+
if (!RegExp(r"^[+-]?[0-9a-fA-F][0-9a-fA-F_]*$").hasMatch(s)) throw "Invalid hexadecimal: ${s}";
414423
return [KdlToken.INTEGER, _parseInteger(_munchUnderscores(s), 16)];
415424
}
416425

417426
_parseOctal(String s) {
418-
if (!RegExp(r"^[0-7][0-7_]*$").hasMatch(s)) throw "Invalid octal: ${s}";
427+
if (!RegExp(r"^[+-]?[0-7][0-7_]*$").hasMatch(s)) throw "Invalid octal: ${s}";
419428
return [KdlToken.INTEGER, _parseInteger(_munchUnderscores(s), 8)];
420429
}
421430

422431
_parseBinary(String s) {
423-
if (!RegExp(r"^[01][01_]*$").hasMatch(s)) throw "Invalid binary: ${s}";
432+
if (!RegExp(r"^[+-]?[01][01_]*$").hasMatch(s)) throw "Invalid binary: ${s}";
424433
return [KdlToken.INTEGER, _parseInteger(_munchUnderscores(s), 2)];
425434
}
426435

@@ -441,7 +450,7 @@ class KdlTokenizer {
441450
case r'\/': return "/";
442451
default: throw "Unexpected escape '${match.group(0)}'";
443452
}
444-
}).replaceAllMapped(RegExp(r"\\u\{[0-9a-fA-F]{0,6}\}"), (match) {
453+
}).replaceAllMapped(RegExp(r"\\u\{[0-9a-fA-F]{1,6}\}"), (match) {
445454
String m = match.group(0) ?? '';
446455
int i = int.parse(m.substring(3, m.length - 1), radix: 16);
447456
if (i < 0 || i > 0x10FFFF) {

test/tokenizer_test.dart

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ void main() {
4444

4545
test('integer', () {
4646
expect(KdlTokenizer("123").nextToken(), equals([KdlToken.INTEGER, 123]));
47+
expect(KdlTokenizer("0x0123456789abcdef").nextToken(), equals([KdlToken.INTEGER, 0x0123456789abcdef]));
48+
expect(KdlTokenizer("0o01234567").nextToken(), equals([KdlToken.INTEGER, 342391]));
49+
expect(KdlTokenizer("0b101001").nextToken(), equals([KdlToken.INTEGER, 41]));
50+
expect(KdlTokenizer("-0x0123456789abcdef").nextToken(), equals([KdlToken.INTEGER, -0x0123456789abcdef]));
51+
expect(KdlTokenizer("-0o01234567").nextToken(), equals([KdlToken.INTEGER, -342391]));
52+
expect(KdlTokenizer("-0b101001").nextToken(), equals([KdlToken.INTEGER, -41]));
53+
expect(KdlTokenizer("+0x0123456789abcdef").nextToken(), equals([KdlToken.INTEGER, 0x0123456789abcdef]));
54+
expect(KdlTokenizer("+0o01234567").nextToken(), equals([KdlToken.INTEGER, 342391]));
55+
expect(KdlTokenizer("+0b101001").nextToken(), equals([KdlToken.INTEGER, 41]));
4756
});
4857

4958
test('float', () {

0 commit comments

Comments
 (0)