From 4e8328135d78d6b3e1bc4571c3fea86c04ee7026 Mon Sep 17 00:00:00 2001 From: Kai Bublitz Date: Sat, 14 Feb 2026 15:37:48 +0100 Subject: [PATCH 1/2] fix: Fix parser syntax for numeric literals The expression to parse numeric literals did not correctly match hex numbers like "0xAB". Also while analyzing the parser I found that it wrongfully accepted some invalid expressions such as "123x456", which lead to an exception from the num.parse call rather than the parser rejecting the input. Updated the numericLiteral expression in the parser to - match valid hex numbers by (digit() | anyOf('abcdefABCDEF')) instead of just digit().plus() - prevent matching illegal hex expressions by separating the hex part always starting with "0x" and other numerical literal that may start with several digits. - Also allowed the x to be uppercase "anyOf('xX')" in hex expressions, uppercase 0X123 is a valid literal for num.parse. Extended the test case to include some more hex literals that were previously not parsed correctly. --- lib/src/parser.dart | 19 ++++++++++--------- test/expressions_test.dart | 18 ++++++++++++------ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/src/parser.dart b/lib/src/parser.dart index f709c3c..5f3161e 100644 --- a/lib/src/parser.dart +++ b/lib/src/parser.dart @@ -19,15 +19,16 @@ class ExpressionParser { .flatten() .map((v) => Identifier(v)); - // Parse simple numeric literals: `12`, `3.4`, `.5`. - Parser get numericLiteral => ((digit() | char('.')).and() & - (digit().star() & - ((char('.') & digit().plus()) | - (char('x') & digit().plus()) | - (anyOf('Ee') & - anyOf('+-').optional() & - digit().plus())) - .optional())) + // Parse simple numeric literals: `12`, `3.4`, `.5`, `0xAB`. + Parser get numericLiteral => + ((char('0') & anyOf('xX') & (digit() | anyOf('abcdefABCDEF')).plus()) | + (digit() | char('.')).and() & + (digit().star() & + ((char('.') & digit().plus()) | + (anyOf('Ee') & + anyOf('+-').optional() & + digit().plus())) + .optional())) .flatten() .map((v) { return Literal(num.parse(v), v); diff --git a/test/expressions_test.dart b/test/expressions_test.dart index d60f804..f1a9dd9 100644 --- a/test/expressions_test.dart +++ b/test/expressions_test.dart @@ -19,18 +19,24 @@ void main() { }); test('numeric literal', () { - for (var v in ['134', '.5', '43.2', '1e3', '1E-3', '1e+0', '0x01']) { + for (var v in [ + '134', + '.5', + '43.2', + '1e3', + '1E-3', + '1e+0', + '0x01', + '0xD3', + '0X1b' + ]) { var w = parser.numericLiteral.end().parse(v); expect(w is Success, isTrue, reason: 'Failed parsing `$v`'); expect(w.value.value, num.parse(v)); expect(w.value.raw, v); } - for (var v in [ - '-134', - '.5.4', - '1e5E3', - ]) { + for (var v in ['-134', '.5.4', '1e5E3', '12x34']) { expect(parser.numericLiteral.end().parse(v) is Success, isFalse); } }); From e3c8f6c9d32a32ef1e4297a6de88a8e6e5a09cd3 Mon Sep 17 00:00:00 2001 From: Kai Bublitz Date: Sat, 14 Feb 2026 18:41:01 +0100 Subject: [PATCH 2/2] fix: Parser syntax for some more numeric expression Another issue with the parser was that decimal point and "e" could not be used in the same expression as they were parsed in different "or" branches. Updated the parser to accept variations of valid scientific notation, such as ".5e2" and "1.23e+4" Notable exception are expression with trailing floating point such as "2." or "1.e3". Those would be accepted by num.parse, but are not valid numbers in dart. --- lib/src/parser.dart | 7 ++----- test/expressions_test.dart | 8 ++++++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/src/parser.dart b/lib/src/parser.dart index 5f3161e..cc469e1 100644 --- a/lib/src/parser.dart +++ b/lib/src/parser.dart @@ -23,11 +23,8 @@ class ExpressionParser { Parser get numericLiteral => ((char('0') & anyOf('xX') & (digit() | anyOf('abcdefABCDEF')).plus()) | (digit() | char('.')).and() & - (digit().star() & - ((char('.') & digit().plus()) | - (anyOf('Ee') & - anyOf('+-').optional() & - digit().plus())) + ((digit().star() & (char('.') & digit().plus()).optional()) & + (anyOf('Ee') & anyOf('+-').optional() & digit().plus()) .optional())) .flatten() .map((v) { diff --git a/test/expressions_test.dart b/test/expressions_test.dart index f1a9dd9..a6e7d6e 100644 --- a/test/expressions_test.dart +++ b/test/expressions_test.dart @@ -26,6 +26,9 @@ void main() { '1e3', '1E-3', '1e+0', + '.1e2', + '1.23e4', + '.6e-7', '0x01', '0xD3', '0X1b' @@ -36,8 +39,9 @@ void main() { expect(w.value.raw, v); } - for (var v in ['-134', '.5.4', '1e5E3', '12x34']) { - expect(parser.numericLiteral.end().parse(v) is Success, isFalse); + for (var v in ['-134', '.5.4', '1e5E3', '5.', '12x34']) { + expect(parser.numericLiteral.end().parse(v) is Success, isFalse, + reason: 'Expected to fail parsing `$v`'); } });