Skip to content

Commit 3e1696b

Browse files
committed
Fix bad error reporting on partial matches.
This patch addresses an error reported in #26, where calling `json.loads('[ ,]') would report an error on column 4, not column 3. The reason for this had to do with the way the optional whitespace (sp*) rule was coded in the grammar, and a bug in the underlying parser generator (glop), where if you had a rule like (a ?())* and you matched a and not b, the errposition wouldn't be properly rolled back before the conditional expression. That bug was fixed in glop v0.6.2; this CL regenerates the JSON5 parser with that version of the parser generator, and then adds json5-specific tests to check for the correct position reporting.
1 parent 71ae0b3 commit 3e1696b

File tree

2 files changed

+24
-17
lines changed

2 files changed

+24
-17
lines changed

json5/parser.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ def _star(self, rule, vs=None):
100100
rule()
101101
if self.failed:
102102
self._rewind(p)
103+
if p < self.errpos:
104+
self.errpos = p
103105
break
104106
else:
105107
vs.append(self.val)
@@ -127,12 +129,12 @@ def _ch(self, ch):
127129
else:
128130
self._fail()
129131

130-
def _str(self, s, l):
131-
p = self.pos
132-
if (p + l <= self.end) and self.msg[p:p + l] == s:
133-
self._succeed(s, self.pos + l)
134-
else:
135-
self._fail()
132+
def _str(self, s):
133+
for ch in s:
134+
self._ch(ch)
135+
if self.failed:
136+
return
137+
self.val = s
136138

137139
def _range(self, i, j):
138140
p = self.pos
@@ -232,36 +234,35 @@ def _comment_(self):
232234
self._choose([self._comment__c0_, self._comment__c1_])
233235

234236
def _comment__c0_(self):
235-
self._seq([lambda: self._str('//', 2),
237+
self._seq([lambda: self._str('//'),
236238
lambda: self._star(self._comment__c0__s1_p_)])
237239

238240
def _comment__c0__s1_p_(self):
239241
self._seq([lambda: self._not(self._eol_), self._anything_])
240242

241243
def _comment__c1_(self):
242-
self._seq([lambda: self._str('/*', 2), self._comment__c1__s1_,
243-
lambda: self._str('*/', 2)])
244+
self._seq([lambda: self._str('/*'), self._comment__c1__s1_,
245+
lambda: self._str('*/')])
244246

245247
def _comment__c1__s1_(self):
246248
self._star(lambda: self._seq([self._comment__c1__s1_p__s0_, self._anything_]))
247249

248250
def _comment__c1__s1_p__s0_(self):
249-
self._not(lambda: self._str('*/', 2))
251+
self._not(lambda: self._str('*/'))
250252

251253
def _value_(self):
252254
self._choose([self._value__c0_, self._value__c1_, self._value__c2_,
253255
self._value__c3_, self._value__c4_, self._value__c5_,
254256
self._value__c6_])
255257

256258
def _value__c0_(self):
257-
self._seq([lambda: self._str('null', 4), lambda: self._succeed('None')])
259+
self._seq([lambda: self._str('null'), lambda: self._succeed('None')])
258260

259261
def _value__c1_(self):
260-
self._seq([lambda: self._str('true', 4), lambda: self._succeed('True')])
262+
self._seq([lambda: self._str('true'), lambda: self._succeed('True')])
261263

262264
def _value__c2_(self):
263-
self._seq([lambda: self._str('false', 5),
264-
lambda: self._succeed('False')])
265+
self._seq([lambda: self._str('false'), lambda: self._succeed('False')])
265266

266267
def _value__c3_(self):
267268
self._push('value__c3')
@@ -745,10 +746,10 @@ def _num_literal__c1__s0_(self):
745746
self._opt(lambda: self._ch('+'))
746747

747748
def _num_literal__c3_(self):
748-
self._str('Infinity', 8)
749+
self._str('Infinity')
749750

750751
def _num_literal__c4_(self):
751-
self._str('NaN', 3)
752+
self._str('NaN')
752753

753754
def _dec_literal_(self):
754755
self._choose([self._dec_literal__c0_, self._dec_literal__c1_,
@@ -826,7 +827,7 @@ def _hex_literal_(self):
826827
self._pop('hex_literal')
827828

828829
def _hex_literal__s0_(self):
829-
self._choose([lambda: self._str('0x', 2), lambda: self._str('0X', 2)])
830+
self._choose([lambda: self._str('0x'), lambda: self._str('0X')])
830831

831832
def _hex_literal__s1_(self):
832833
self._bind(lambda: self._plus(self._hex_), 'hs')

tests/lib_test.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ def test_arrays(self):
4343
self.check('[0,1]', [0, 1])
4444
self.check('[ 0 , 1 ]', [0, 1])
4545

46+
try:
47+
json5.loads('[ ,]')
48+
self.fail()
49+
except ValueError as e:
50+
self.assertIn('Unexpected "," at column 3', str(e))
51+
4652
def test_bools(self):
4753
self.check('true', True)
4854
self.check('false', False)

0 commit comments

Comments
 (0)