PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/pyclojure/parser.py

http://github.com/eigenhombre/PyClojure
Python | 145 lines | 95 code | 26 blank | 24 comment | 13 complexity | bb9ba7ded2eed4b7283637ed561c5004 MD5 | raw file
  1. import sys
  2. import re
  3. import ply.yacc as yacc
  4. from pyclojure.lexer import PyClojureLex
  5. from pyclojure.core import Atom, Keyword, List, Vector, Map
  6. # BNF grammar for 'lisp'
  7. # sexpr : atom
  8. # | readmacro sexpr
  9. # | keyword
  10. # | float
  11. # | integer
  12. # | list
  13. # | vector
  14. # | map
  15. # | nil
  16. # sexprs : sexpr
  17. # | sexprs sexpr
  18. # list : ( sexprs )
  19. # | ( )
  20. _quiet = True
  21. class LispLogger(yacc.PlyLogger):
  22. def debug(self, *args, **kwargs):
  23. if not _quiet:
  24. super(type(self), self).debug(*args, **kwargs)
  25. def make_map(args):
  26. m = {}
  27. kvlist = [(args[i], args[i+1]) for i in range(0, len(args), 2)]
  28. for k, v in kvlist:
  29. m[k] = v
  30. return Map(m)
  31. def quote_expr(raw):
  32. return List(Atom('quote'), raw)
  33. def deref_expr(raw):
  34. return List(Atom('deref'), raw)
  35. def init_type(raw):
  36. # Due to how python types are initialized, we can just treat them
  37. # as function calls.
  38. return raw
  39. # Map from the regex that matches the atom to the function that takes
  40. # in an ast, and modifies it as specified by the macro
  41. READER_MACROS = {
  42. r'@': deref_expr,
  43. r'\'': quote_expr,
  44. r'\.': init_type,
  45. }
  46. class PyClojureParse(object):
  47. def build(self):
  48. return yacc.yacc(module=self, errorlog=LispLogger(sys.stderr))
  49. tokens = PyClojureLex.tokens
  50. tokens.remove('NUMBER')
  51. tokens.extend(('FLOAT', 'INTEGER'))
  52. def p_sexpr_nil(self, p):
  53. 'sexpr : NIL'
  54. p[0] = None
  55. def p_sexpr_atom(self, p):
  56. 'sexpr : ATOM'
  57. p[0] = Atom(p[1])
  58. def p_sexpr_readmacro(self, p):
  59. 'sexpr : READMACRO sexpr'
  60. for regex, func in READER_MACROS.items():
  61. if re.match(regex, p[1]):
  62. p[0] = func(p[2])
  63. return
  64. def p_keyword(self, p):
  65. 'sexpr : KEYWORD'
  66. p[0] = Keyword(p[1])
  67. def p_sexpr_float(self, p):
  68. 'sexpr : FLOAT'
  69. p[0] = float(p[1])
  70. def p_sexpr_integer(self, p):
  71. 'sexpr : INTEGER'
  72. p[0] = int(p[1])
  73. def p_sexpr_seq(self, p):
  74. '''
  75. sexpr : list
  76. | vector
  77. | map
  78. '''
  79. p[0] = p[1]
  80. def p_sexprs_sexpr(self, p):
  81. 'sexprs : sexpr'
  82. p[0] = p[1]
  83. def p_sexprs_sexprs_sexpr(self, p):
  84. 'sexprs : sexprs sexpr'
  85. #p[0] = ', '.join((p[1], p[2]))
  86. if type(p[1]) is list:
  87. p[0] = p[1]
  88. p[0].append(p[2])
  89. else:
  90. p[0] = [p[1], p[2]]
  91. def p_list(self, p):
  92. 'list : LPAREN sexprs RPAREN'
  93. try:
  94. p[0] = apply(List, p[2])
  95. except TypeError:
  96. p[0] = List(p[2])
  97. def p_empty_list(self, p):
  98. 'list : LPAREN RPAREN'
  99. p[0] = List()
  100. def p_vector(self, p):
  101. 'vector : LBRACKET sexprs RBRACKET'
  102. try:
  103. p[0] = apply(Vector, p[2])
  104. except TypeError:
  105. p[0] = Vector(p[2])
  106. def p_empty_vector(self, p):
  107. 'vector : LBRACKET RBRACKET'
  108. p[0] = Vector()
  109. def p_map(self, p):
  110. 'map : LBRACE sexprs RBRACE'
  111. p[0] = make_map(p[2])
  112. def p_empty_map(self, p):
  113. 'map : LBRACE RBRACE'
  114. p[0] = Map()
  115. def p_error(self, p):
  116. if p:
  117. print(p.lineno, "Syntax error in input at token '%s'" % p.value)
  118. else:
  119. print("EOF","Syntax error. No more input.")