This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
2.4 KiB

  1. from lark import Lark, Transformer, Discard, v_args
  2. grammar = r"""
  3. start: statement+
  4. ?statement: rule
  5. | terminal
  6. | "parser"? "grammar" name ";" -> ignore
  7. | "options" _CODE -> ignore
  8. rule: RULE ":" expansions ";"
  9. terminal: "fragment"? TOKEN ":" term_expansions ";"
  10. ?expansions: alias ("|" alias)*
  11. ?alias: expansion ["#" name]
  12. ?term_expansions: term_alias ("|" term_alias)*
  13. ?term_alias: term_expansion ["->" name ["(" name ")"]]
  14. term_expansion: expr*
  15. ?expansion: expr*
  16. ?expr: atom OP?
  17. ?atom: "(" expansions ")"
  18. | value
  19. | _CODE -> ignore
  20. | "~" atom -> not_
  21. ?value: name
  22. | STRING -> string
  23. | REGEXP -> regexp
  24. name: RULE
  25. | TOKEN
  26. OP: /[+*][?]?|[?](?![a-z])/
  27. RULE: /[a-z][_a-zA-Z0-9]*/
  28. TOKEN: /[A-Z][_a-zA-Z0-9]*/
  29. REGEXP: /\[.*?\]|\./
  30. _STRING_INNER: /.*?/
  31. _STRING_ESC_INNER: _STRING_INNER /(?<!\\)(\\\\)*?/
  32. STRING : "'" _STRING_ESC_INNER "'"
  33. %import common.INT -> NUMBER
  34. %import common.WS
  35. COMMENT: /\s*/ "//" /[^\n]/*
  36. COMMENT2: /\/\*.*?\*\//s
  37. _CODE: /{.*?}/s
  38. %ignore WS
  39. %ignore COMMENT
  40. %ignore COMMENT2
  41. """
  42. parser = Lark(grammar, parser='lalr')
  43. class T(Transformer):
  44. def ignore(self, args):
  45. raise Discard()
  46. def expansions(self, x):
  47. return '\n | '.join(x)
  48. def term_expansions(self, x):
  49. return '\n | '.join(x)
  50. def term_alias(self, x):
  51. # TODO channel hidden -> ignore
  52. return x[0]
  53. def expansion(self, x):
  54. return "(" + ' '.join(x) + ")"
  55. def term_expansion(self, x):
  56. return "(" + ' '.join(x) + ")"
  57. @v_args(inline=True)
  58. def expr(self, expr, op):
  59. return expr + op.value
  60. @v_args(inline=True)
  61. def rule(self, name, exprs):
  62. return name + ": " + exprs
  63. @v_args(inline=True)
  64. def terminal(self, name, exprs):
  65. if not isinstance(exprs, str):
  66. breakpoint()
  67. return name + ": " + exprs
  68. @v_args(inline=True)
  69. def name(self, t):
  70. return t.value
  71. @v_args(inline=True)
  72. def string(self, t):
  73. return t.value.replace('\\', '\\\\').replace('"', '\\"').replace("'", '"')
  74. @v_args(inline=True)
  75. def regexp(self, t):
  76. return f'/{t.value}/'
  77. @v_args(inline=True)
  78. def not_(self, t):
  79. return f" /(?!){t}/ "
  80. def start(self, stmts):
  81. return '\n\n'.join(stmts)
  82. with open('SQLite.g4') as f:
  83. res = parser.parse(f.read())
  84. # print('###', res.pretty())
  85. res = T().transform(res)
  86. with open('sqlite.lark', 'w') as f:
  87. f.write(res)