PageRenderTime 180ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/rlib/parsing/makepackrat.py

https://bitbucket.org/SeanTater/pypy-bugfix-st
Python | 748 lines | 738 code | 10 blank | 0 comment | 4 complexity | 65fa0ded501b901708468e1990fd5f2e MD5 | raw file
  1. from __future__ import with_statement
  2. import py
  3. import sys
  4. from pypy.rlib.parsing.tree import Nonterminal, Symbol, RPythonVisitor
  5. from pypy.rlib.parsing.codebuilder import Codebuilder
  6. from pypy.rlib.objectmodel import we_are_translated
  7. class BacktrackException(Exception):
  8. def __init__(self, error=None):
  9. self.error = error
  10. if not we_are_translated():
  11. Exception.__init__(self, error)
  12. class TreeOptimizer(RPythonVisitor):
  13. def visit_or(self, t):
  14. if len(t.children) == 1:
  15. return self.dispatch(t.children[0])
  16. return self.general_nonterminal_visit(t)
  17. visit_commands = visit_or
  18. def visit_negation(self, t):
  19. child = self.dispatch(t.children[0])
  20. if child.symbol == "negation":
  21. child.symbol = "lookahead"
  22. return child
  23. t.children[0] = child
  24. return t
  25. def general_nonterminal_visit(self, t):
  26. for i in range(len(t.children)):
  27. t.children[i] = self.dispatch(t.children[i])
  28. return t
  29. def general_visit(self, t):
  30. return t
  31. syntax = r"""
  32. NAME:
  33. `[a-zA-Z_][a-zA-Z0-9_]*`;
  34. SPACE:
  35. ' ';
  36. COMMENT:
  37. `( *#[^\n]*\n)+`;
  38. IGNORE:
  39. `(#[^\n]*\n)|\n|\t| `;
  40. newline:
  41. COMMENT
  42. | `( *\n *)*`;
  43. REGEX:
  44. r = `\`[^\\\`]*(\\.[^\\\`]*)*\``
  45. return {Symbol('REGEX', r, None)};
  46. QUOTE:
  47. r = `'[^\']*'`
  48. return {Symbol('QUOTE', r, None)};
  49. PYTHONCODE:
  50. r = `\{[^\n\}]*\}`
  51. return {Symbol('PYTHONCODE', r, None)};
  52. EOF:
  53. !__any__;
  54. file:
  55. IGNORE*
  56. list
  57. [EOF];
  58. list:
  59. content = production+
  60. return {Nonterminal('list', content)};
  61. production:
  62. name = NAME
  63. SPACE*
  64. args = productionargs
  65. ':'
  66. IGNORE*
  67. what = or_
  68. IGNORE*
  69. ';'
  70. IGNORE*
  71. return {Nonterminal('production', [name, args, what])};
  72. productionargs:
  73. '('
  74. IGNORE*
  75. args = (
  76. NAME
  77. [
  78. IGNORE*
  79. ','
  80. IGNORE*
  81. ]
  82. )*
  83. arg = NAME
  84. IGNORE*
  85. ')'
  86. IGNORE*
  87. return {Nonterminal('productionargs', args + [arg])}
  88. | return {Nonterminal('productionargs', [])};
  89. or_:
  90. l = (commands ['|' IGNORE*])+
  91. last = commands
  92. return {Nonterminal('or', l + [last])}
  93. | commands;
  94. commands:
  95. cmd = command
  96. newline
  97. cmds = (command [newline])+
  98. return {Nonterminal('commands', [cmd] + cmds)}
  99. | command;
  100. command:
  101. simplecommand;
  102. simplecommand:
  103. return_
  104. | if_
  105. | named_command
  106. | repetition
  107. | choose
  108. | negation;
  109. return_:
  110. 'return'
  111. SPACE*
  112. code = PYTHONCODE
  113. IGNORE*
  114. return {Nonterminal('return', [code])};
  115. if_:
  116. 'do'
  117. newline
  118. cmd = command
  119. SPACE*
  120. 'if'
  121. SPACE*
  122. condition = PYTHONCODE
  123. IGNORE*
  124. return {Nonterminal('if', [cmd, condition])}
  125. | 'if'
  126. SPACE*
  127. condition = PYTHONCODE
  128. IGNORE*
  129. return {Nonterminal('if', [condition])};
  130. choose:
  131. 'choose'
  132. SPACE*
  133. name = NAME
  134. SPACE*
  135. 'in'
  136. SPACE*
  137. expr = PYTHONCODE
  138. IGNORE*
  139. cmds = commands
  140. return {Nonterminal('choose', [name, expr, cmds])};
  141. commandchain:
  142. result = simplecommand+
  143. return {Nonterminal('commands', result)};
  144. named_command:
  145. name = NAME
  146. SPACE*
  147. '='
  148. SPACE*
  149. cmd = command
  150. return {Nonterminal('named_command', [name, cmd])};
  151. repetition:
  152. what = enclosed
  153. SPACE* '?' IGNORE*
  154. return {Nonterminal('maybe', [what])}
  155. | what = enclosed
  156. SPACE*
  157. repetition = ('*' | '+')
  158. IGNORE*
  159. return {Nonterminal('repetition', [repetition, what])};
  160. negation:
  161. '!'
  162. SPACE*
  163. what = negation
  164. IGNORE*
  165. return {Nonterminal('negation', [what])}
  166. | enclosed;
  167. enclosed:
  168. '<'
  169. IGNORE*
  170. what = primary
  171. IGNORE*
  172. '>'
  173. IGNORE*
  174. return {Nonterminal('exclusive', [what])}
  175. | '['
  176. IGNORE*
  177. what = or_
  178. IGNORE*
  179. ']'
  180. IGNORE*
  181. return {Nonterminal('ignore', [what])}
  182. | ['(' IGNORE*] or_ [')' IGNORE*]
  183. | primary;
  184. primary:
  185. call | REGEX [IGNORE*] | QUOTE [IGNORE*];
  186. call:
  187. x = NAME
  188. args = arguments
  189. IGNORE*
  190. return {Nonterminal("call", [x, args])};
  191. arguments:
  192. '('
  193. IGNORE*
  194. args = (
  195. PYTHONCODE
  196. [IGNORE* ',' IGNORE*]
  197. )*
  198. last = PYTHONCODE
  199. ')'
  200. IGNORE*
  201. return {Nonterminal("args", args + [last])}
  202. | return {Nonterminal("args", [])};
  203. """
  204. class ErrorInformation(object):
  205. def __init__(self, pos, expected=None):
  206. if expected is None:
  207. expected = []
  208. self.expected = expected
  209. self.pos = pos
  210. def __str__(self):
  211. return "ErrorInformation(%s, %s)" % (self.pos, self.expected)
  212. def get_line_column(self, source):
  213. pos = self.pos
  214. assert pos >= 0
  215. uptoerror = source[:pos]
  216. lineno = uptoerror.count("\n")
  217. columnno = pos - uptoerror.rfind("\n")
  218. return lineno, columnno
  219. def nice_error_message(self, filename='<filename>', source=""):
  220. if source:
  221. lineno, columnno = self.get_line_column(source)
  222. result = [" File %s, line %s" % (filename, lineno + 1)]
  223. result.append(source.split("\n")[lineno])
  224. result.append(" " * columnno + "^")
  225. else:
  226. result.append("<couldn't get source>")
  227. if self.expected:
  228. failure_reasons = self.expected
  229. if len(failure_reasons) > 1:
  230. all_but_one = failure_reasons[:-1]
  231. last = failure_reasons[-1]
  232. expected = "%s or '%s'" % (
  233. ", ".join(["'%s'" % e for e in all_but_one]), last)
  234. else:
  235. expected = failure_reasons[0]
  236. result.append("ParseError: expected %s" % (expected, ))
  237. else:
  238. result.append("ParseError")
  239. return "\n".join(result)
  240. class Status(object):
  241. # status codes:
  242. NORMAL = 0
  243. ERROR = 1
  244. INPROGRESS = 2
  245. LEFTRECURSION = 3
  246. SOMESOLUTIONS = 4
  247. _annspecialcase_ = 'specialize:ctr_location' # polymorphic
  248. def __repr__(self):
  249. return "Status(%s, %s, %s, %s)" % (self.pos, self.result, self.error,
  250. self.status)
  251. def __init__(self):
  252. self.pos = 0
  253. self.error = None
  254. self.status = self.INPROGRESS
  255. self.result = None
  256. class ParserBuilder(RPythonVisitor, Codebuilder):
  257. def __init__(self):
  258. Codebuilder.__init__(self)
  259. self.initcode = []
  260. self.names = {}
  261. self.matchers = {}
  262. def make_parser(self):
  263. m = {'Status': Status,
  264. 'Nonterminal': Nonterminal,
  265. 'Symbol': Symbol,}
  266. exec py.code.Source(self.get_code()).compile() in m
  267. return m['Parser']
  268. def memoize_header(self, name, args):
  269. dictname = "_dict_%s" % (name, )
  270. self.emit_initcode("self.%s = {}" % (dictname, ))
  271. if args:
  272. self.emit("_key = (self._pos, %s)" % (", ".join(args)))
  273. else:
  274. self.emit("_key = self._pos")
  275. self.emit("_status = self.%s.get(_key, None)" % (dictname, ))
  276. with self.block("if _status is None:"):
  277. self.emit("_status = self.%s[_key] = Status()" % (
  278. dictname, ))
  279. with self.block("else:"):
  280. self.emit("_statusstatus = _status.status")
  281. with self.block("if _statusstatus == _status.NORMAL:"):
  282. self.emit("self._pos = _status.pos")
  283. self.emit("return _status")
  284. with self.block("elif _statusstatus == _status.ERROR:"):
  285. self.emit("raise BacktrackException(_status.error)")
  286. if self.have_call:
  287. with self.block(
  288. "elif (_statusstatus == _status.INPROGRESS or\n"
  289. " _statusstatus == _status.LEFTRECURSION):"):
  290. self.emit("_status.status = _status.LEFTRECURSION")
  291. with self.block("if _status.result is not None:"):
  292. self.emit("self._pos = _status.pos")
  293. self.emit("return _status")
  294. with self.block("else:"):
  295. self.emit("raise BacktrackException(None)")
  296. with self.block(
  297. "elif _statusstatus == _status.SOMESOLUTIONS:"):
  298. self.emit("_status.status = _status.INPROGRESS")
  299. self.emit("_startingpos = self._pos")
  300. self.start_block("try:")
  301. self.emit("_result = None")
  302. self.emit("_error = None")
  303. def memoize_footer(self, name, args):
  304. dictname = "_dict_%s" % (name, )
  305. if self.have_call:
  306. with self.block(
  307. "if _status.status == _status.LEFTRECURSION:"):
  308. with self.block("if _status.result is not None:"):
  309. with self.block("if _status.pos >= self._pos:"):
  310. self.emit("_status.status = _status.NORMAL")
  311. self.emit("self._pos = _status.pos")
  312. self.emit("return _status")
  313. self.emit("_status.pos = self._pos")
  314. self.emit("_status.status = _status.SOMESOLUTIONS")
  315. self.emit("_status.result = %s" % (self.resultname, ))
  316. self.emit("_status.error = _error")
  317. self.emit("self._pos = _startingpos")
  318. self.emit("return self._%s(%s)" % (name, ', '.join(args)))
  319. else:
  320. self.emit("assert _status.status != _status.LEFTRECURSION")
  321. self.emit("_status.status = _status.NORMAL")
  322. self.emit("_status.pos = self._pos")
  323. self.emit("_status.result = %s" % (self.resultname, ))
  324. self.emit("_status.error = _error")
  325. self.emit("return _status")
  326. self.end_block("try")
  327. with self.block("except BacktrackException, _exc:"):
  328. self.emit("_status.pos = -1")
  329. self.emit("_status.result = None")
  330. self.combine_error('_exc.error')
  331. self.emit("_status.error = _error")
  332. self.emit("_status.status = _status.ERROR")
  333. self.emit("raise BacktrackException(_error)")
  334. def choice_point(self, name=None):
  335. var = "_choice%s" % (self.namecount, )
  336. self.namecount += 1
  337. self.emit("%s = self._pos" % (var, ))
  338. return var
  339. def revert(self, var):
  340. self.emit("self._pos = %s" % (var, ))
  341. def visit_list(self, t):
  342. self.start_block("class Parser(object):")
  343. for elt in t.children:
  344. self.dispatch(elt)
  345. with self.block("def __init__(self, inputstream):"):
  346. for line in self.initcode:
  347. self.emit(line)
  348. self.emit("self._pos = 0")
  349. self.emit("self._inputstream = inputstream")
  350. if self.matchers:
  351. self.emit_regex_code()
  352. self.end_block("class")
  353. def emit_regex_code(self):
  354. for regex, matcher in self.matchers.iteritems():
  355. with self.block(
  356. "def _regex%s(self):" % (abs(hash(regex)), )):
  357. c = self.choice_point()
  358. self.emit("_runner = self._Runner(self._inputstream, self._pos)")
  359. self.emit("_i = _runner.recognize_%s(self._pos)" % (
  360. abs(hash(regex)), ))
  361. self.start_block("if _runner.last_matched_state == -1:")
  362. self.revert(c)
  363. self.emit("raise BacktrackException")
  364. self.end_block("if")
  365. self.emit("_upto = _runner.last_matched_index + 1")
  366. self.emit("_pos = self._pos")
  367. self.emit("assert _pos >= 0")
  368. self.emit("assert _upto >= 0")
  369. self.emit("_result = self._inputstream[_pos: _upto]")
  370. self.emit("self._pos = _upto")
  371. self.emit("return _result")
  372. with self.block("class _Runner(object):"):
  373. with self.block("def __init__(self, text, pos):"):
  374. self.emit("self.text = text")
  375. self.emit("self.pos = pos")
  376. self.emit("self.last_matched_state = -1")
  377. self.emit("self.last_matched_index = -1")
  378. self.emit("self.state = -1")
  379. for regex, matcher in self.matchers.iteritems():
  380. matcher = str(matcher).replace(
  381. "def recognize(runner, i)",
  382. "def recognize_%s(runner, i)" % (abs(hash(regex)), ))
  383. self.emit(str(matcher))
  384. def visit_production(self, t):
  385. name = t.children[0]
  386. if name in self.names:
  387. raise Exception("name %s appears twice" % (name, ))
  388. self.names[name] = True
  389. otherargs = t.children[1].children
  390. argswithself = ", ".join(["self"] + otherargs)
  391. argswithoutself = ", ".join(otherargs)
  392. with self.block("def %s(%s):" % (name, argswithself)):
  393. self.emit("return self._%s(%s).result" % (name, argswithoutself))
  394. self.start_block("def _%s(%s):" % (name, argswithself, ))
  395. self.namecount = 0
  396. self.resultname = "_result"
  397. self.have_call = False
  398. self.created_error = False
  399. allother = self.store_code_away()
  400. self.dispatch(t.children[-1])
  401. subsequent = self.restore_code(allother)
  402. self.memoize_header(name, otherargs)
  403. self.add_code(subsequent)
  404. self.memoize_footer(name, otherargs)
  405. self.end_block("def")
  406. def visit_or(self, t, first=False):
  407. possibilities = t.children
  408. if len(possibilities) > 1:
  409. self.start_block("while 1:")
  410. for i, p in enumerate(possibilities):
  411. c = self.choice_point()
  412. with self.block("try:"):
  413. self.dispatch(p)
  414. self.emit("break")
  415. with self.block("except BacktrackException, _exc:"):
  416. self.combine_error('_exc.error')
  417. self.revert(c)
  418. if i == len(possibilities) - 1:
  419. self.emit("raise BacktrackException(_error)")
  420. self.dispatch(possibilities[-1])
  421. if len(possibilities) > 1:
  422. self.emit("break")
  423. self.end_block("while")
  424. def visit_commands(self, t):
  425. for elt in t.children:
  426. self.dispatch(elt)
  427. def visit_maybe(self, t):
  428. c = self.choice_point()
  429. with self.block("try:"):
  430. self.dispatch(t.children[0])
  431. with self.block("except BacktrackException:"):
  432. self.revert(c)
  433. def visit_repetition(self, t):
  434. name = "_all%s" % (self.namecount, )
  435. self.namecount += 1
  436. self.emit("%s = []" % (name, ))
  437. if t.children[0] == '+':
  438. self.dispatch(t.children[1])
  439. self.emit("%s.append(_result)" % (name, ))
  440. with self.block("while 1:"):
  441. c = self.choice_point()
  442. with self.block("try:"):
  443. self.dispatch(t.children[1])
  444. self.emit("%s.append(_result)" % (name, ))
  445. with self.block("except BacktrackException, _exc:"):
  446. self.combine_error('_exc.error')
  447. self.revert(c)
  448. self.emit("break")
  449. self.emit("_result = %s" % (name, ))
  450. def visit_exclusive(self, t):
  451. self.resultname = "_enclosed"
  452. self.dispatch(t.children[0])
  453. self.emit("_enclosed = _result")
  454. def visit_ignore(self, t):
  455. resultname = "_before_discard%i" % (self.namecount, )
  456. self.namecount += 1
  457. self.emit("%s = _result" % (resultname, ))
  458. self.dispatch(t.children[0])
  459. self.emit("_result = %s" % (resultname, ))
  460. def visit_negation(self, t):
  461. c = self.choice_point()
  462. resultname = "_stored_result%i" % (self.namecount, )
  463. self.namecount += 1
  464. child = t.children[0]
  465. self.emit("%s = _result" % (resultname, ))
  466. with self.block("try:"):
  467. self.dispatch(child)
  468. with self.block("except BacktrackException:"):
  469. self.revert(c)
  470. self.emit("_result = %s" % (resultname, ))
  471. with self.block("else:"):
  472. # heuristic to get nice error messages sometimes
  473. if isinstance(child, Symbol) and child.symbol == "QUOTE":
  474. error = "self._ErrorInformation(%s, ['NOT %s'])" % (
  475. c, child.additional_info[1:-1], )
  476. else:
  477. error = "None"
  478. self.emit("raise BacktrackException(%s)" % (error, ))
  479. def visit_lookahead(self, t):
  480. resultname = "_stored_result%i" % (self.namecount, )
  481. self.emit("%s = _result" % (resultname, ))
  482. c = self.choice_point()
  483. self.dispatch(t.children[0])
  484. self.revert(c)
  485. self.emit("_result = %s" % (resultname, ))
  486. def visit_named_command(self, t):
  487. name = t.children[0]
  488. self.dispatch(t.children[1])
  489. self.emit("%s = _result" % (name, ))
  490. def visit_return(self, t):
  491. self.emit("_result = (%s)" % (t.children[0].additional_info[1:-1], ))
  492. def visit_if(self, t):
  493. if len(t.children) == 2:
  494. self.dispatch(t.children[0])
  495. with self.block("if not (%s):" % (
  496. t.children[-1].additional_info[1:-1], )):
  497. self.emit("raise BacktrackException(")
  498. self.emit(" self._ErrorInformation(")
  499. self.emit(" _startingpos, ['condition not met']))")
  500. def visit_choose(self, t):
  501. with self.block("for %s in (%s):" % (
  502. t.children[0], t.children[1].additional_info[1:-1], )):
  503. with self.block("try:"):
  504. self.dispatch(t.children[2])
  505. self.emit("break")
  506. with self.block("except BacktrackException, _exc:"):
  507. self.combine_error('_exc.error')
  508. with self.block("else:"):
  509. self.emit("raise BacktrackException(_error)")
  510. def visit_call(self, t):
  511. self.have_call = True
  512. args = ", ".join(['(%s)' % (arg.additional_info[1:-1], )
  513. for arg in t.children[1].children])
  514. if t.children[0].startswith("_"):
  515. callname = t.children[0]
  516. self.emit("_result = self.%s(%s)" % (callname, args))
  517. else:
  518. callname = "_" + t.children[0]
  519. self.emit("_call_status = self.%s(%s)" % (callname, args))
  520. self.emit("_result = _call_status.result")
  521. self.combine_error('_call_status.error')
  522. def visit_REGEX(self, t):
  523. r = t.additional_info[1:-1].replace('\\`', '`')
  524. matcher = self.get_regex(r)
  525. self.emit("_result = self._regex%s()" % (abs(hash(r)), ))
  526. def visit_QUOTE(self, t):
  527. self.emit("_result = self.__chars__(%r)" % (
  528. str(t.additional_info[1:-1]), ))
  529. def get_regex(self, r):
  530. from pypy.rlib.parsing.regexparse import parse_regex
  531. if r in self.matchers:
  532. return self.matchers[r]
  533. regex = parse_regex(r)
  534. if regex is None:
  535. raise ValueError(
  536. "%s is not a valid regular expression" % regextext)
  537. automaton = regex.make_automaton().make_deterministic()
  538. automaton.optimize()
  539. matcher = automaton.make_lexing_code()
  540. self.matchers[r] = py.code.Source(matcher)
  541. return matcher
  542. def combine_error(self, newerror):
  543. if self.created_error:
  544. self.emit(
  545. "_error = self._combine_errors(_error, %s)" % (newerror, ))
  546. else:
  547. self.emit("_error = %s" % (newerror, ))
  548. self.created_error = True
  549. class MetaPackratParser(type):
  550. def __new__(cls, name_, bases, dct):
  551. if '__doc__' not in dct or dct['__doc__'] is None:
  552. return type.__new__(cls, name_, bases, dct)
  553. from pypackrat import PyPackratSyntaxParser
  554. import sys, new, inspect
  555. frame = sys._getframe(1)
  556. source = dct['__doc__']
  557. p = PyPackratSyntaxParser(source)
  558. try:
  559. t = p.file()
  560. except BacktrackException, exc:
  561. print exc.error.nice_error_message("<docstring>", source)
  562. lineno, _ = exc.error.get_line_column(source)
  563. errorline = source.split("\n")[lineno]
  564. try:
  565. code = frame.f_code
  566. source = inspect.getsource(code)
  567. lineno_in_orig = source.split("\n").index(errorline)
  568. if lineno_in_orig >= 0:
  569. print "probable error position:"
  570. print "file:", code.co_filename
  571. print "line:", lineno_in_orig + code.co_firstlineno + 1
  572. except (IOError, ValueError):
  573. pass
  574. raise exc
  575. t = t.visit(TreeOptimizer())
  576. visitor = ParserBuilder()
  577. t.visit(visitor)
  578. pcls = visitor.make_parser()
  579. forbidden = dict.fromkeys(("__weakref__ __doc__ "
  580. "__dict__ __module__").split())
  581. initthere = "__init__" in dct
  582. #XXX XXX XXX
  583. if 'BacktrackException' not in frame.f_globals:
  584. raise Exception("must import BacktrackException")
  585. if 'Status' not in frame.f_globals:
  586. raise Exception("must import Status")
  587. result = type.__new__(cls, name_, bases, dct)
  588. for key, value in pcls.__dict__.iteritems():
  589. if isinstance(value, type):
  590. value.__module__ = result.__module__ #XXX help the annotator
  591. if isinstance(value, type(lambda: None)):
  592. value = new.function(value.func_code, frame.f_globals)
  593. if not hasattr(result, key) and key not in forbidden:
  594. setattr(result, key, value)
  595. if result.__init__ is object.__init__:
  596. result.__init__ = pcls.__dict__['__init__']
  597. result.init_parser = pcls.__dict__['__init__']
  598. result._code = visitor.get_code()
  599. return result
  600. class PackratParser(object):
  601. __metaclass__ = MetaPackratParser
  602. _ErrorInformation = ErrorInformation
  603. _BacktrackException = BacktrackException
  604. def __chars__(self, chars):
  605. #print '__chars__(%s)' % (chars, ), self._pos
  606. try:
  607. for i in range(len(chars)):
  608. if self._inputstream[self._pos + i] != chars[i]:
  609. raise BacktrackException(
  610. self._ErrorInformation(self._pos, [chars]))
  611. self._pos += len(chars)
  612. return chars
  613. except IndexError:
  614. raise BacktrackException(
  615. self._ErrorInformation(self._pos, [chars]))
  616. def __any__(self):
  617. try:
  618. result = self._inputstream[self._pos]
  619. self._pos += 1
  620. return result
  621. except IndexError:
  622. raise BacktrackException(
  623. self._ErrorInformation(self._pos, ['anything']))
  624. def _combine_errors(self, error1, error2):
  625. if error1 is None:
  626. return error2
  627. if (error2 is None or error1.pos > error2.pos or
  628. len(error2.expected) == 0):
  629. return error1
  630. elif error2.pos > error1.pos or len(error1.expected) == 0:
  631. return error2
  632. expected = []
  633. already_there = {}
  634. for ep in [error1.expected, error2.expected]:
  635. for reason in ep:
  636. if reason not in already_there:
  637. already_there[reason] = True
  638. expected.append(reason)
  639. return ErrorInformation(error1.pos, expected)
  640. def test_generate():
  641. f = py.path.local(__file__).dirpath().join("pypackrat.py")
  642. from pypackrat import PyPackratSyntaxParser
  643. p = PyPackratSyntaxParser(syntax)
  644. t = p.file()
  645. t = t.visit(TreeOptimizer())
  646. visitor = ParserBuilder()
  647. t.visit(visitor)
  648. code = visitor.get_code()
  649. content = """
  650. from pypy.rlib.parsing.tree import Nonterminal, Symbol
  651. from makepackrat import PackratParser, BacktrackException, Status
  652. %s
  653. class PyPackratSyntaxParser(PackratParser):
  654. def __init__(self, stream):
  655. self.init_parser(stream)
  656. forbidden = dict.fromkeys(("__weakref__ __doc__ "
  657. "__dict__ __module__").split())
  658. initthere = "__init__" in PyPackratSyntaxParser.__dict__
  659. for key, value in Parser.__dict__.iteritems():
  660. if key not in PyPackratSyntaxParser.__dict__ and key not in forbidden:
  661. setattr(PyPackratSyntaxParser, key, value)
  662. PyPackratSyntaxParser.init_parser = Parser.__init__.im_func
  663. """ % (code, )
  664. print content
  665. f.write(content)