PageRenderTime 63ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/pypy/lang/js/test/test_parser.py

https://github.com/jwal/python-tutorial
Python | 338 lines | 294 code | 44 blank | 0 comment | 16 complexity | bee71019870ce1b6931ca4cbcc919bd5 MD5 | raw file
Possible License(s): MIT, BSD-2-Clause
  1. from __future__ import division
  2. import py
  3. from pypy.rlib.parsing.ebnfparse import parse_ebnf, make_parse_function
  4. from pypy.rlib.parsing.parsing import ParseError, Rule
  5. from pypy.rlib.parsing.tree import RPythonVisitor
  6. from pypy.lang.js.jsobj import W_Object, global_context, ThrowException, empty_context
  7. from pypy.lang.js.astbuilder import ASTBuilder
  8. from pypy import conftest
  9. import sys
  10. GFILE = py.magic.autopath().dirpath().dirpath().join("jsgrammar.txt")
  11. try:
  12. t = GFILE.read(mode='U')
  13. regexs, rules, ToAST = parse_ebnf(t)
  14. except ParseError,e:
  15. print e.nice_error_message(filename=str(GFILE),source=t)
  16. raise
  17. parse_function = make_parse_function(regexs, rules, eof=True)
  18. def setstartrule(rules, start):
  19. "takes the rule start and put it on the beginning of the rules"
  20. oldpos = 0
  21. newrules = [Rule("hacked_first_symbol", [[start, "EOF"]])] + rules
  22. return newrules
  23. def get_defaultparse():
  24. return parse_function
  25. def parse_func(start=None):
  26. if start is not None:
  27. parse_function = make_parse_function(regexs, setstartrule(rules, start),
  28. eof=True)
  29. else:
  30. parse_function = get_defaultparse()
  31. def methodparse(self, text):
  32. tree = parse_function(text)
  33. if start is not None:
  34. assert tree.symbol == "hacked_first_symbol"
  35. tree = tree.children[0]
  36. tree = tree.visit(ToAST())[0]
  37. if conftest.option.view:
  38. tree.view()
  39. return tree
  40. return methodparse
  41. class CountingVisitor(RPythonVisitor):
  42. def __init__(self):
  43. self.counts = {}
  44. def general_nonterminal_visit(self, node):
  45. print node.symbol
  46. self.counts[node.symbol] = self.counts.get(node.symbol, 0) + 1
  47. for child in node.children:
  48. self.dispatch(child)
  49. def general_symbol_visit(self, node):
  50. self.counts[node.symbol] = self.counts.get(node.symbol, 0) + 1
  51. class BaseGrammarTest(object):
  52. def setup_class(cls):
  53. cls.parse = parse_func()
  54. class TestLiterals(BaseGrammarTest):
  55. def setup_class(cls):
  56. cls.parse = parse_func('literal')
  57. def test_numbers(self):
  58. for i in range(10):
  59. dc = CountingVisitor()
  60. self.parse(str(i)).visit(dc)
  61. assert dc.counts["DECIMALLITERAL"] == 1
  62. class IntEvaluationVisitor(RPythonVisitor):
  63. def general_symbol_visit(self, node):
  64. return node.additional_info
  65. def visit_DECIMALLITERAL(self, node):
  66. return int(node.additional_info)
  67. def general_nonterminal_visit(self, node):
  68. if len(node.children) == 1:
  69. return self.dispatch(node.children[0])
  70. if len(node.children) >= 3:
  71. code = [str(self.dispatch(child)) for child in node.children]
  72. while len(code) >= 3:
  73. r = self.evalop(int(code.pop(0)), code.pop(0), int(code.pop(0)))
  74. code.insert(0, r)
  75. return code[0]
  76. def visit_unaryexpression(self, node):
  77. if len(node.children) == 1:
  78. return self.dispatch(node.children[0])
  79. else:
  80. arg1 = self.dispatch(node.children[1])
  81. op = self.dispatch(node.children[0])
  82. return self.evalop(arg1,op)
  83. opmap = {'+': lambda x,y: x+y,
  84. '-': lambda x,y: x-y,
  85. '*': lambda x,y: x*y,
  86. '++': lambda x,y: x+1,
  87. '--': lambda x,y: x-1,
  88. '!': lambda x,y: not x,
  89. '~': lambda x,y: ~ x,
  90. '/': lambda x,y: x / y,
  91. '>>': lambda x,y: x>>y,
  92. '<<': lambda x,y: x<<y,
  93. '&': lambda x,y: x&y,
  94. '|': lambda x,y: x|y,
  95. '^': lambda x,y: x^y,
  96. '%': lambda x,y: x%y,
  97. }
  98. def evalop(self, arg1, op, arg2=None):
  99. return self.opmap[op](arg1, arg2)
  100. class TestExpressions(BaseGrammarTest):
  101. def setup_class(cls):
  102. cls.parse = parse_func('expression')
  103. cls.evaluator = IntEvaluationVisitor()
  104. def parse_and_evaluate(self, s):
  105. tree = self.parse(s)
  106. result1 = self.evaluator.dispatch(tree)
  107. result2 = eval(s)
  108. assert result1 == result2
  109. return tree
  110. def parse_and_compare(self, s, n):
  111. tree = self.parse(s)
  112. result1 = self.evaluator.dispatch(tree)
  113. assert result1 == n
  114. return tree
  115. def parse_and_eval_all(self, l):
  116. for i in l:
  117. self.parse_and_evaluate(i)
  118. def test_simple(self):
  119. self.parse_and_eval_all(["1",
  120. "1 + 2",
  121. "1 - 2",
  122. "1 * 2",
  123. "1 / 2",
  124. "1 >> 2",
  125. "4 % 2",
  126. "4 | 1",
  127. "4 ^ 2",
  128. ])
  129. self.parse_and_compare("++5", 6)
  130. self.parse_and_compare("~3", -4)
  131. self.parse("x = 3")
  132. self.parse("x")
  133. def test_chained(self):
  134. self.parse_and_eval_all(["1 + 2 * 3",
  135. "1 * 2 + 3",
  136. "1 - 3 - 3",
  137. "4 / 2 / 2",
  138. "2 << 4 << 4",
  139. "30 | 3 & 5",
  140. ])
  141. def test_primary(self):
  142. self.parse('this')
  143. self.parse('(x)')
  144. self.parse('((((x))))')
  145. self.parse('(x * (x * x)) + x - x')
  146. def test_array_literal(self):
  147. self.parse('[1,2,3,4]')
  148. self.parse('[1,2,]')
  149. self.parse('[1]')
  150. def test_object_literal(self):
  151. self.parse('{}')
  152. self.parse('{x:1}') #per spec {x:1,} should not be supported
  153. self.parse('{x:1,y:2}')
  154. class TestStatements(BaseGrammarTest):
  155. def setup_class(cls):
  156. cls.parse = parse_func('statement')
  157. def parse_count(self, s):
  158. "parse the expression and return the CountingVisitor"
  159. cv = CountingVisitor()
  160. self.parse(s).visit(cv)
  161. return cv.counts
  162. def test_block(self):
  163. r = self.parse_count("{x;return;true;if(x);}")
  164. assert r['block'] == 1
  165. def test_vardecl(self):
  166. r = self.parse_count("var x;")
  167. assert r['variablestatement'] == 1
  168. r = self.parse_count("var x = 2;")
  169. assert r['variablestatement'] == 1
  170. def test_empty(self):
  171. self.parse(";")
  172. for i in range(1,10):
  173. r = self.parse_count('{%s}'%(';'*i))
  174. assert r['emptystatement'] == i
  175. def test_if(self):
  176. r = self.parse_count("if(x)return;")
  177. assert r['ifstatement'] == 1
  178. assert r.get('emptystatement', 0) == 0
  179. r = self.parse_count("if(x)if(i)return;")
  180. assert r['ifstatement'] == 2
  181. r = self.parse_count("if(x)return;else return;")
  182. assert r['ifstatement'] == 1
  183. def test_iteration(self):
  184. self.parse('for(;;);')
  185. self.parse('for(x;;);')
  186. self.parse('for(;x>0;);')
  187. self.parse('for(;;x++);')
  188. self.parse('for(var x = 1;;);')
  189. self.parse('for(x in z);')
  190. self.parse('for(var x in z);')
  191. self.parse('while(1);')
  192. self.parse('do ; while(1)')
  193. def test_continue_return_break_throw(self):
  194. self.parse('return;')
  195. self.parse('return x+y;')
  196. self.parse('break;')
  197. self.parse('continue;')
  198. self.parse('break label;')
  199. self.parse('continue label;')
  200. self.parse('throw (5+5);')
  201. def test_with(self):
  202. self.parse('with(x);')
  203. def test_labeled(self):
  204. self.parse('label: x+y;')
  205. def test_switch(self):
  206. self.parse("""switch(x) {
  207. case 1: break;
  208. case 2: break;
  209. default: ;
  210. }
  211. """)
  212. self.parse("""switch(x) {
  213. case 1: break;
  214. case 2: break;
  215. default: ;
  216. case 3: break;
  217. }
  218. """)
  219. def test_try(self):
  220. self.parse('try {x;} catch (e) {x;}')
  221. self.parse('try {x;} catch (e) {x;} finally {x;}')
  222. self.parse('try {x;} finally {x;}')
  223. class TestFunctionDeclaration(BaseGrammarTest):
  224. def setup_class(cls):
  225. cls.parse = parse_func('functiondeclaration')
  226. def test_simpledecl(self):
  227. self.parse('function x () {;}')
  228. self.parse('function z (a,b,c,d,e) {;}')
  229. class TestToASTExpr(BaseGrammarTest):
  230. def setup_class(cls):
  231. cls.parse = parse_func('expression')
  232. cls.ctx = empty_context()
  233. def to_ast(self, s):
  234. return ASTBuilder().dispatch(self.parse(s))
  235. def eval_expr(self, s):
  236. ast = self.to_ast(s)
  237. w_Global = W_Object()
  238. w_Object = W_Object(Prototype=W_Object())
  239. w_Global.Put('Object', w_Object)
  240. return ast.eval(global_context(w_Global))
  241. def test_get_pos(self):
  242. from pypy.lang.js import operations
  243. from pypy.rlib.parsing.tree import Symbol
  244. astb = ASTBuilder()
  245. t = self.parse('6')
  246. assert isinstance(t, Symbol)
  247. pos = astb.get_pos(t)
  248. assert pos.lineno == 0
  249. t = self.parse('[1,]')
  250. assert not isinstance(t, Symbol)
  251. pos = astb.get_pos(t)
  252. assert pos.start == 0
  253. def test_primaryexpression(self):
  254. w_num = self.eval_expr('(6)')
  255. assert w_num.ToNumber() == 6
  256. w_num = self.eval_expr('((((6))))')
  257. assert w_num.ToNumber() == 6
  258. # w_array = self.eval_expr('[1,2,3]')
  259. # assert w_array.ToString(self.ctx) == '1,2,3'
  260. w_identifier = self.eval_expr('x')
  261. py.test.raises(ThrowException, w_identifier.GetValue)
  262. w_object = self.eval_expr('{x:1}')
  263. assert w_object.ToString(self.ctx) == '[object Object]'
  264. assert w_object.Get('x').ToNumber() == 1
  265. def test_expression(self):
  266. w_num = self.eval_expr('1 - 1 - 1')
  267. assert w_num.ToNumber() == -1
  268. w_num = self.eval_expr('-(6 * (6 * 6)) + 6 - 6')
  269. assert w_num.ToNumber() == -216
  270. w_num = self.eval_expr('++5')
  271. assert w_num.ToNumber() == 6
  272. w_num = self.eval_expr('--5')
  273. assert w_num.ToNumber() == 4
  274. w_str = self.eval_expr('"hello "+\'world\'')
  275. assert w_str.ToString(self.ctx) == 'hello world'
  276. from pypy.lang.js.jsparser import parse
  277. def test_simplesemicolon():
  278. yield parse, 'x'
  279. yield parse, 'if(1){x}'
  280. yield parse, 'function x () {}'
  281. yield parse,'if(1) {}'