Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pyparsing/results.py: 42%

269 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:23 +0000

1# results.py 

2from collections.abc import MutableMapping, Mapping, MutableSequence, Iterator 

3import pprint 

4from weakref import ref as wkref 

5from typing import Tuple, Any 

6 

7str_type: Tuple[type, ...] = (str, bytes) 

8_generator_type = type((_ for _ in ())) 

9 

10 

11class _ParseResultsWithOffset: 

12 __slots__ = ["tup"] 

13 

14 def __init__(self, p1, p2): 

15 self.tup = (p1, p2) 

16 

17 def __getitem__(self, i): 

18 return self.tup[i] 

19 

20 def __getstate__(self): 

21 return self.tup 

22 

23 def __setstate__(self, *args): 

24 self.tup = args[0] 

25 

26 

27class ParseResults: 

28 """Structured parse results, to provide multiple means of access to 

29 the parsed data: 

30 

31 - as a list (``len(results)``) 

32 - by list index (``results[0], results[1]``, etc.) 

33 - by attribute (``results.<results_name>`` - see :class:`ParserElement.set_results_name`) 

34 

35 Example:: 

36 

37 integer = Word(nums) 

38 date_str = (integer.set_results_name("year") + '/' 

39 + integer.set_results_name("month") + '/' 

40 + integer.set_results_name("day")) 

41 # equivalent form: 

42 # date_str = (integer("year") + '/' 

43 # + integer("month") + '/' 

44 # + integer("day")) 

45 

46 # parse_string returns a ParseResults object 

47 result = date_str.parse_string("1999/12/31") 

48 

49 def test(s, fn=repr): 

50 print("{} -> {}".format(s, fn(eval(s)))) 

51 test("list(result)") 

52 test("result[0]") 

53 test("result['month']") 

54 test("result.day") 

55 test("'month' in result") 

56 test("'minutes' in result") 

57 test("result.dump()", str) 

58 

59 prints:: 

60 

61 list(result) -> ['1999', '/', '12', '/', '31'] 

62 result[0] -> '1999' 

63 result['month'] -> '12' 

64 result.day -> '31' 

65 'month' in result -> True 

66 'minutes' in result -> False 

67 result.dump() -> ['1999', '/', '12', '/', '31'] 

68 - day: '31' 

69 - month: '12' 

70 - year: '1999' 

71 """ 

72 

73 _null_values: Tuple[Any, ...] = (None, [], "", ()) 

74 

75 __slots__ = [ 

76 "_name", 

77 "_parent", 

78 "_all_names", 

79 "_modal", 

80 "_toklist", 

81 "_tokdict", 

82 "__weakref__", 

83 ] 

84 

85 class List(list): 

86 """ 

87 Simple wrapper class to distinguish parsed list results that should be preserved 

88 as actual Python lists, instead of being converted to :class:`ParseResults`: 

89 

90 LBRACK, RBRACK = map(pp.Suppress, "[]") 

91 element = pp.Forward() 

92 item = ppc.integer 

93 element_list = LBRACK + pp.delimited_list(element) + RBRACK 

94 

95 # add parse actions to convert from ParseResults to actual Python collection types 

96 def as_python_list(t): 

97 return pp.ParseResults.List(t.as_list()) 

98 element_list.add_parse_action(as_python_list) 

99 

100 element <<= item | element_list 

101 

102 element.run_tests(''' 

103 100 

104 [2,3,4] 

105 [[2, 1],3,4] 

106 [(2, 1),3,4] 

107 (2,3,4) 

108 ''', post_parse=lambda s, r: (r[0], type(r[0]))) 

109 

110 prints: 

111 

112 100 

113 (100, <class 'int'>) 

114 

115 [2,3,4] 

116 ([2, 3, 4], <class 'list'>) 

117 

118 [[2, 1],3,4] 

119 ([[2, 1], 3, 4], <class 'list'>) 

120 

121 (Used internally by :class:`Group` when `aslist=True`.) 

122 """ 

123 

124 def __new__(cls, contained=None): 

125 if contained is None: 

126 contained = [] 

127 

128 if not isinstance(contained, list): 

129 raise TypeError( 

130 "{} may only be constructed with a list," 

131 " not {}".format(cls.__name__, type(contained).__name__) 

132 ) 

133 

134 return list.__new__(cls) 

135 

136 def __new__(cls, toklist=None, name=None, **kwargs): 

137 if isinstance(toklist, ParseResults): 

138 return toklist 

139 self = object.__new__(cls) 

140 self._name = None 

141 self._parent = None 

142 self._all_names = set() 

143 

144 if toklist is None: 

145 self._toklist = [] 

146 elif isinstance(toklist, (list, _generator_type)): 

147 self._toklist = ( 

148 [toklist[:]] 

149 if isinstance(toklist, ParseResults.List) 

150 else list(toklist) 

151 ) 

152 else: 

153 self._toklist = [toklist] 

154 self._tokdict = dict() 

155 return self 

156 

157 # Performance tuning: we construct a *lot* of these, so keep this 

158 # constructor as small and fast as possible 

159 def __init__( 

160 self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance 

161 ): 

162 self._modal = modal 

163 if name is not None and name != "": 

164 if isinstance(name, int): 

165 name = str(name) 

166 if not modal: 

167 self._all_names = {name} 

168 self._name = name 

169 if toklist not in self._null_values: 

170 if isinstance(toklist, (str_type, type)): 

171 toklist = [toklist] 

172 if asList: 

173 if isinstance(toklist, ParseResults): 

174 self[name] = _ParseResultsWithOffset( 

175 ParseResults(toklist._toklist), 0 

176 ) 

177 else: 

178 self[name] = _ParseResultsWithOffset( 

179 ParseResults(toklist[0]), 0 

180 ) 

181 self[name]._name = name 

182 else: 

183 try: 

184 self[name] = toklist[0] 

185 except (KeyError, TypeError, IndexError): 

186 if toklist is not self: 

187 self[name] = toklist 

188 else: 

189 self._name = name 

190 

191 def __getitem__(self, i): 

192 if isinstance(i, (int, slice)): 

193 return self._toklist[i] 

194 else: 

195 if i not in self._all_names: 

196 return self._tokdict[i][-1][0] 

197 else: 

198 return ParseResults([v[0] for v in self._tokdict[i]]) 

199 

200 def __setitem__(self, k, v, isinstance=isinstance): 

201 if isinstance(v, _ParseResultsWithOffset): 

202 self._tokdict[k] = self._tokdict.get(k, list()) + [v] 

203 sub = v[0] 

204 elif isinstance(k, (int, slice)): 

205 self._toklist[k] = v 

206 sub = v 

207 else: 

208 self._tokdict[k] = self._tokdict.get(k, list()) + [ 

209 _ParseResultsWithOffset(v, 0) 

210 ] 

211 sub = v 

212 if isinstance(sub, ParseResults): 

213 sub._parent = wkref(self) 

214 

215 def __delitem__(self, i): 

216 if isinstance(i, (int, slice)): 

217 mylen = len(self._toklist) 

218 del self._toklist[i] 

219 

220 # convert int to slice 

221 if isinstance(i, int): 

222 if i < 0: 

223 i += mylen 

224 i = slice(i, i + 1) 

225 # get removed indices 

226 removed = list(range(*i.indices(mylen))) 

227 removed.reverse() 

228 # fixup indices in token dictionary 

229 for name, occurrences in self._tokdict.items(): 

230 for j in removed: 

231 for k, (value, position) in enumerate(occurrences): 

232 occurrences[k] = _ParseResultsWithOffset( 

233 value, position - (position > j) 

234 ) 

235 else: 

236 del self._tokdict[i] 

237 

238 def __contains__(self, k) -> bool: 

239 return k in self._tokdict 

240 

241 def __len__(self) -> int: 

242 return len(self._toklist) 

243 

244 def __bool__(self) -> bool: 

245 return not not (self._toklist or self._tokdict) 

246 

247 def __iter__(self) -> Iterator: 

248 return iter(self._toklist) 

249 

250 def __reversed__(self) -> Iterator: 

251 return iter(self._toklist[::-1]) 

252 

253 def keys(self): 

254 return iter(self._tokdict) 

255 

256 def values(self): 

257 return (self[k] for k in self.keys()) 

258 

259 def items(self): 

260 return ((k, self[k]) for k in self.keys()) 

261 

262 def haskeys(self) -> bool: 

263 """ 

264 Since ``keys()`` returns an iterator, this method is helpful in bypassing 

265 code that looks for the existence of any defined results names.""" 

266 return bool(self._tokdict) 

267 

268 def pop(self, *args, **kwargs): 

269 """ 

270 Removes and returns item at specified index (default= ``last``). 

271 Supports both ``list`` and ``dict`` semantics for ``pop()``. If 

272 passed no argument or an integer argument, it will use ``list`` 

273 semantics and pop tokens from the list of parsed tokens. If passed 

274 a non-integer argument (most likely a string), it will use ``dict`` 

275 semantics and pop the corresponding value from any defined results 

276 names. A second default return value argument is supported, just as in 

277 ``dict.pop()``. 

278 

279 Example:: 

280 

281 numlist = Word(nums)[...] 

282 print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] 

283 

284 def remove_first(tokens): 

285 tokens.pop(0) 

286 numlist.add_parse_action(remove_first) 

287 print(numlist.parse_string("0 123 321")) # -> ['123', '321'] 

288 

289 label = Word(alphas) 

290 patt = label("LABEL") + Word(nums)[1, ...] 

291 print(patt.parse_string("AAB 123 321").dump()) 

292 

293 # Use pop() in a parse action to remove named result (note that corresponding value is not 

294 # removed from list form of results) 

295 def remove_LABEL(tokens): 

296 tokens.pop("LABEL") 

297 return tokens 

298 patt.add_parse_action(remove_LABEL) 

299 print(patt.parse_string("AAB 123 321").dump()) 

300 

301 prints:: 

302 

303 ['AAB', '123', '321'] 

304 - LABEL: 'AAB' 

305 

306 ['AAB', '123', '321'] 

307 """ 

308 if not args: 

309 args = [-1] 

310 for k, v in kwargs.items(): 

311 if k == "default": 

312 args = (args[0], v) 

313 else: 

314 raise TypeError( 

315 "pop() got an unexpected keyword argument {!r}".format(k) 

316 ) 

317 if isinstance(args[0], int) or len(args) == 1 or args[0] in self: 

318 index = args[0] 

319 ret = self[index] 

320 del self[index] 

321 return ret 

322 else: 

323 defaultvalue = args[1] 

324 return defaultvalue 

325 

326 def get(self, key, default_value=None): 

327 """ 

328 Returns named result matching the given key, or if there is no 

329 such name, then returns the given ``default_value`` or ``None`` if no 

330 ``default_value`` is specified. 

331 

332 Similar to ``dict.get()``. 

333 

334 Example:: 

335 

336 integer = Word(nums) 

337 date_str = integer("year") + '/' + integer("month") + '/' + integer("day") 

338 

339 result = date_str.parse_string("1999/12/31") 

340 print(result.get("year")) # -> '1999' 

341 print(result.get("hour", "not specified")) # -> 'not specified' 

342 print(result.get("hour")) # -> None 

343 """ 

344 if key in self: 

345 return self[key] 

346 else: 

347 return default_value 

348 

349 def insert(self, index, ins_string): 

350 """ 

351 Inserts new element at location index in the list of parsed tokens. 

352 

353 Similar to ``list.insert()``. 

354 

355 Example:: 

356 

357 numlist = Word(nums)[...] 

358 print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] 

359 

360 # use a parse action to insert the parse location in the front of the parsed results 

361 def insert_locn(locn, tokens): 

362 tokens.insert(0, locn) 

363 numlist.add_parse_action(insert_locn) 

364 print(numlist.parse_string("0 123 321")) # -> [0, '0', '123', '321'] 

365 """ 

366 self._toklist.insert(index, ins_string) 

367 # fixup indices in token dictionary 

368 for name, occurrences in self._tokdict.items(): 

369 for k, (value, position) in enumerate(occurrences): 

370 occurrences[k] = _ParseResultsWithOffset( 

371 value, position + (position > index) 

372 ) 

373 

374 def append(self, item): 

375 """ 

376 Add single element to end of ``ParseResults`` list of elements. 

377 

378 Example:: 

379 

380 numlist = Word(nums)[...] 

381 print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] 

382 

383 # use a parse action to compute the sum of the parsed integers, and add it to the end 

384 def append_sum(tokens): 

385 tokens.append(sum(map(int, tokens))) 

386 numlist.add_parse_action(append_sum) 

387 print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321', 444] 

388 """ 

389 self._toklist.append(item) 

390 

391 def extend(self, itemseq): 

392 """ 

393 Add sequence of elements to end of ``ParseResults`` list of elements. 

394 

395 Example:: 

396 

397 patt = Word(alphas)[1, ...] 

398 

399 # use a parse action to append the reverse of the matched strings, to make a palindrome 

400 def make_palindrome(tokens): 

401 tokens.extend(reversed([t[::-1] for t in tokens])) 

402 return ''.join(tokens) 

403 patt.add_parse_action(make_palindrome) 

404 print(patt.parse_string("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl' 

405 """ 

406 if isinstance(itemseq, ParseResults): 

407 self.__iadd__(itemseq) 

408 else: 

409 self._toklist.extend(itemseq) 

410 

411 def clear(self): 

412 """ 

413 Clear all elements and results names. 

414 """ 

415 del self._toklist[:] 

416 self._tokdict.clear() 

417 

418 def __getattr__(self, name): 

419 try: 

420 return self[name] 

421 except KeyError: 

422 if name.startswith("__"): 

423 raise AttributeError(name) 

424 return "" 

425 

426 def __add__(self, other) -> "ParseResults": 

427 ret = self.copy() 

428 ret += other 

429 return ret 

430 

431 def __iadd__(self, other) -> "ParseResults": 

432 if other._tokdict: 

433 offset = len(self._toklist) 

434 addoffset = lambda a: offset if a < 0 else a + offset 

435 otheritems = other._tokdict.items() 

436 otherdictitems = [ 

437 (k, _ParseResultsWithOffset(v[0], addoffset(v[1]))) 

438 for k, vlist in otheritems 

439 for v in vlist 

440 ] 

441 for k, v in otherdictitems: 

442 self[k] = v 

443 if isinstance(v[0], ParseResults): 

444 v[0]._parent = wkref(self) 

445 

446 self._toklist += other._toklist 

447 self._all_names |= other._all_names 

448 return self 

449 

450 def __radd__(self, other) -> "ParseResults": 

451 if isinstance(other, int) and other == 0: 

452 # useful for merging many ParseResults using sum() builtin 

453 return self.copy() 

454 else: 

455 # this may raise a TypeError - so be it 

456 return other + self 

457 

458 def __repr__(self) -> str: 

459 return "{}({!r}, {})".format(type(self).__name__, self._toklist, self.as_dict()) 

460 

461 def __str__(self) -> str: 

462 return ( 

463 "[" 

464 + ", ".join( 

465 [ 

466 str(i) if isinstance(i, ParseResults) else repr(i) 

467 for i in self._toklist 

468 ] 

469 ) 

470 + "]" 

471 ) 

472 

473 def _asStringList(self, sep=""): 

474 out = [] 

475 for item in self._toklist: 

476 if out and sep: 

477 out.append(sep) 

478 if isinstance(item, ParseResults): 

479 out += item._asStringList() 

480 else: 

481 out.append(str(item)) 

482 return out 

483 

484 def as_list(self) -> list: 

485 """ 

486 Returns the parse results as a nested list of matching tokens, all converted to strings. 

487 

488 Example:: 

489 

490 patt = Word(alphas)[1, ...] 

491 result = patt.parse_string("sldkj lsdkj sldkj") 

492 # even though the result prints in string-like form, it is actually a pyparsing ParseResults 

493 print(type(result), result) # -> <class 'pyparsing.ParseResults'> ['sldkj', 'lsdkj', 'sldkj'] 

494 

495 # Use as_list() to create an actual list 

496 result_list = result.as_list() 

497 print(type(result_list), result_list) # -> <class 'list'> ['sldkj', 'lsdkj', 'sldkj'] 

498 """ 

499 return [ 

500 res.as_list() if isinstance(res, ParseResults) else res 

501 for res in self._toklist 

502 ] 

503 

504 def as_dict(self) -> dict: 

505 """ 

506 Returns the named parse results as a nested dictionary. 

507 

508 Example:: 

509 

510 integer = Word(nums) 

511 date_str = integer("year") + '/' + integer("month") + '/' + integer("day") 

512 

513 result = date_str.parse_string('12/31/1999') 

514 print(type(result), repr(result)) # -> <class 'pyparsing.ParseResults'> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) 

515 

516 result_dict = result.as_dict() 

517 print(type(result_dict), repr(result_dict)) # -> <class 'dict'> {'day': '1999', 'year': '12', 'month': '31'} 

518 

519 # even though a ParseResults supports dict-like access, sometime you just need to have a dict 

520 import json 

521 print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable 

522 print(json.dumps(result.as_dict())) # -> {"month": "31", "day": "1999", "year": "12"} 

523 """ 

524 

525 def to_item(obj): 

526 if isinstance(obj, ParseResults): 

527 return obj.as_dict() if obj.haskeys() else [to_item(v) for v in obj] 

528 else: 

529 return obj 

530 

531 return dict((k, to_item(v)) for k, v in self.items()) 

532 

533 def copy(self) -> "ParseResults": 

534 """ 

535 Returns a new copy of a :class:`ParseResults` object. 

536 """ 

537 ret = ParseResults(self._toklist) 

538 ret._tokdict = self._tokdict.copy() 

539 ret._parent = self._parent 

540 ret._all_names |= self._all_names 

541 ret._name = self._name 

542 return ret 

543 

544 def get_name(self): 

545 r""" 

546 Returns the results name for this token expression. Useful when several 

547 different expressions might match at a particular location. 

548 

549 Example:: 

550 

551 integer = Word(nums) 

552 ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") 

553 house_number_expr = Suppress('#') + Word(nums, alphanums) 

554 user_data = (Group(house_number_expr)("house_number") 

555 | Group(ssn_expr)("ssn") 

556 | Group(integer)("age")) 

557 user_info = user_data[1, ...] 

558 

559 result = user_info.parse_string("22 111-22-3333 #221B") 

560 for item in result: 

561 print(item.get_name(), ':', item[0]) 

562 

563 prints:: 

564 

565 age : 22 

566 ssn : 111-22-3333 

567 house_number : 221B 

568 """ 

569 if self._name: 

570 return self._name 

571 elif self._parent: 

572 par = self._parent() 

573 

574 def find_in_parent(sub): 

575 return next( 

576 ( 

577 k 

578 for k, vlist in par._tokdict.items() 

579 for v, loc in vlist 

580 if sub is v 

581 ), 

582 None, 

583 ) 

584 

585 return find_in_parent(self) if par else None 

586 elif ( 

587 len(self) == 1 

588 and len(self._tokdict) == 1 

589 and next(iter(self._tokdict.values()))[0][1] in (0, -1) 

590 ): 

591 return next(iter(self._tokdict.keys())) 

592 else: 

593 return None 

594 

595 def dump(self, indent="", full=True, include_list=True, _depth=0) -> str: 

596 """ 

597 Diagnostic method for listing out the contents of 

598 a :class:`ParseResults`. Accepts an optional ``indent`` argument so 

599 that this string can be embedded in a nested display of other data. 

600 

601 Example:: 

602 

603 integer = Word(nums) 

604 date_str = integer("year") + '/' + integer("month") + '/' + integer("day") 

605 

606 result = date_str.parse_string('1999/12/31') 

607 print(result.dump()) 

608 

609 prints:: 

610 

611 ['1999', '/', '12', '/', '31'] 

612 - day: '31' 

613 - month: '12' 

614 - year: '1999' 

615 """ 

616 out = [] 

617 NL = "\n" 

618 out.append(indent + str(self.as_list()) if include_list else "") 

619 

620 if full: 

621 if self.haskeys(): 

622 items = sorted((str(k), v) for k, v in self.items()) 

623 for k, v in items: 

624 if out: 

625 out.append(NL) 

626 out.append("{}{}- {}: ".format(indent, (" " * _depth), k)) 

627 if isinstance(v, ParseResults): 

628 if v: 

629 out.append( 

630 v.dump( 

631 indent=indent, 

632 full=full, 

633 include_list=include_list, 

634 _depth=_depth + 1, 

635 ) 

636 ) 

637 else: 

638 out.append(str(v)) 

639 else: 

640 out.append(repr(v)) 

641 if any(isinstance(vv, ParseResults) for vv in self): 

642 v = self 

643 for i, vv in enumerate(v): 

644 if isinstance(vv, ParseResults): 

645 out.append( 

646 "\n{}{}[{}]:\n{}{}{}".format( 

647 indent, 

648 (" " * (_depth)), 

649 i, 

650 indent, 

651 (" " * (_depth + 1)), 

652 vv.dump( 

653 indent=indent, 

654 full=full, 

655 include_list=include_list, 

656 _depth=_depth + 1, 

657 ), 

658 ) 

659 ) 

660 else: 

661 out.append( 

662 "\n%s%s[%d]:\n%s%s%s" 

663 % ( 

664 indent, 

665 (" " * (_depth)), 

666 i, 

667 indent, 

668 (" " * (_depth + 1)), 

669 str(vv), 

670 ) 

671 ) 

672 

673 return "".join(out) 

674 

675 def pprint(self, *args, **kwargs): 

676 """ 

677 Pretty-printer for parsed results as a list, using the 

678 `pprint <https://docs.python.org/3/library/pprint.html>`_ module. 

679 Accepts additional positional or keyword args as defined for 

680 `pprint.pprint <https://docs.python.org/3/library/pprint.html#pprint.pprint>`_ . 

681 

682 Example:: 

683 

684 ident = Word(alphas, alphanums) 

685 num = Word(nums) 

686 func = Forward() 

687 term = ident | num | Group('(' + func + ')') 

688 func <<= ident + Group(Optional(delimited_list(term))) 

689 result = func.parse_string("fna a,b,(fnb c,d,200),100") 

690 result.pprint(width=40) 

691 

692 prints:: 

693 

694 ['fna', 

695 ['a', 

696 'b', 

697 ['(', 'fnb', ['c', 'd', '200'], ')'], 

698 '100']] 

699 """ 

700 pprint.pprint(self.as_list(), *args, **kwargs) 

701 

702 # add support for pickle protocol 

703 def __getstate__(self): 

704 return ( 

705 self._toklist, 

706 ( 

707 self._tokdict.copy(), 

708 self._parent is not None and self._parent() or None, 

709 self._all_names, 

710 self._name, 

711 ), 

712 ) 

713 

714 def __setstate__(self, state): 

715 self._toklist, (self._tokdict, par, inAccumNames, self._name) = state 

716 self._all_names = set(inAccumNames) 

717 if par is not None: 

718 self._parent = wkref(par) 

719 else: 

720 self._parent = None 

721 

722 def __getnewargs__(self): 

723 return self._toklist, self._name 

724 

725 def __dir__(self): 

726 return dir(type(self)) + list(self.keys()) 

727 

728 @classmethod 

729 def from_dict(cls, other, name=None) -> "ParseResults": 

730 """ 

731 Helper classmethod to construct a ``ParseResults`` from a ``dict``, preserving the 

732 name-value relations as results names. If an optional ``name`` argument is 

733 given, a nested ``ParseResults`` will be returned. 

734 """ 

735 

736 def is_iterable(obj): 

737 try: 

738 iter(obj) 

739 except Exception: 

740 return False 

741 else: 

742 return not isinstance(obj, str_type) 

743 

744 ret = cls([]) 

745 for k, v in other.items(): 

746 if isinstance(v, Mapping): 

747 ret += cls.from_dict(v, name=k) 

748 else: 

749 ret += cls([v], name=k, asList=is_iterable(v)) 

750 if name is not None: 

751 ret = cls([ret], name=name) 

752 return ret 

753 

754 asList = as_list 

755 asDict = as_dict 

756 getName = get_name 

757 

758 

759MutableMapping.register(ParseResults) 

760MutableSequence.register(ParseResults)