OILS / opy / _regtest / src / asdl / arith_parse_test.py View on Github | oilshell.org

223 lines, 130 significant
1#!/usr/bin/env python
2from __future__ import print_function
3from asdl import tdop
4from asdl import arith_ast
5from asdl import arith_parse # module under test
6
7
8def _assertParseError(make_parser, s, error_substring=''):
9 p = make_parser(s)
10 try:
11 node = p.Parse()
12 except tdop.ParseError as e:
13 err = str(e)
14 if error_substring in err:
15 print('got expected error for %s: %s' % (s, err))
16 else:
17 raise AssertionError('Expected %r to be in %r' % (error_substring, err))
18 else:
19 raise AssertionError('%r should have failed' % s)
20
21
22def TestArith(t_parse):
23 t_parse('1+2+3', '(+ (+ 1 2) 3)')
24 t_parse('1+2*3', '(+ 1 (* 2 3))')
25 t_parse('4*(2+3)', '(* 4 (+ 2 3))')
26 t_parse('(2+3)*4', '(* (+ 2 3) 4)')
27 return
28 t_parse('1<2', '(< 1 2)')
29 t_parse('x=3', '(= x 3)')
30 t_parse('x = 2*3', '(= x (* 2 3))')
31 t_parse('x = y', '(= x y)')
32
33 t_parse('x*y - y*z', '(- (* x y) (* y z))')
34 t_parse('x/y - y%z', '(- (/ x y) (% y z))')
35
36 t_parse("x = y", "(= x y)")
37 t_parse('2 ** 3 ** 2', '(** 2 (** 3 2))')
38 t_parse('a = b = 10', '(= a (= b 10))')
39
40 t_parse('x = ((y*4)-2)', '(= x (- (* y 4) 2))')
41
42 t_parse('x - -y', '(- x (- y))')
43 t_parse("-1 * -2", "(* (- 1) (- 2))")
44 t_parse("-x * -y", "(* (- x) (- y))")
45 t_parse('x - -234', '(- x (- 234))')
46
47 # Python doesn't allow this
48 t_parse('x += y += 3', '(+= x (+= y 3))')
49
50 # This is sort of nonsensical, but bash allows it. The 1 is discarded as
51 # the first element of the comma operator.
52 t_parse('x[1,2]', '(get x (, 1 2))')
53
54 # Python doesn't have unary +
55 t_parse('+1 - +2', '(- (+ 1) (+ 2))')
56
57 # LHS
58 t_parse('f[x] += 1', '(+= (get f x) 1)')
59
60
61def TestBitwise(t_parse):
62 t_parse("~1 | ~2", "(| (~ 1) (~ 2))")
63 t_parse("x & y | a & b", "(| (& x y) (& a b))")
64 t_parse("~x ^ y", "(^ (~ x) y)")
65 t_parse("x << y | y << z", "(| (<< x y) (<< y z))")
66
67 t_parse("a ^= b-1", "(^= a (- b 1))")
68
69
70def TestLogical(t_parse):
71 t_parse("a && b || c && d", "(|| (&& a b) (&& c d))")
72 t_parse("!a && !b", "(&& (! a) (! b))")
73 t_parse("a != b && c == d", "(&& (!= a b) (== c d))")
74
75 t_parse("a > b ? 0 : 1", "(? (> a b) 0 1)")
76 t_parse("a > b ? x+1 : y+1", "(? (> a b) (+ x 1) (+ y 1))")
77
78 t_parse("1 ? true1 : 2 ? true2 : false", "(? 1 true1 (? 2 true2 false))")
79 t_parse("1 ? true1 : (2 ? true2 : false)", "(? 1 true1 (? 2 true2 false))")
80
81 t_parse("1 ? (2 ? true : false1) : false2", "(? 1 (? 2 true false1) false2)")
82 t_parse("1 ? 2 ? true : false1 : false2", "(? 1 (? 2 true false1) false2)")
83
84 # Should have higher precedence than comma
85 t_parse("x ? 1 : 2, y ? 3 : 4", "(, (? x 1 2) (? y 3 4))")
86
87
88def TestUnary(t_parse):
89 t_parse("!x", "(! x)")
90 t_parse("x--", "(post-- x)")
91 t_parse("x[1]--", "(post-- (get x 1))")
92
93 t_parse("--x", "(-- x)")
94 t_parse("++x[1]", "(++ (get x 1))")
95
96 t_parse("!x--", "(! (post-- x))")
97 t_parse("~x++", "(~ (post++ x))")
98
99 t_parse("x++ - y++", "(- (post++ x) (post++ y))")
100
101 t_parse("++x - ++y", "(- (++ x) (++ y))")
102
103 #
104 # 1. x++ f() x[] left associative
105 # f(x)[1]++ means
106 # (++ (get (call f x) 1))
107 # 2. ++x + - ! ~ right associative
108 # -++x means (- (++ x))
109
110
111def TestArrays(t_parse):
112 """Shared between shell, oil, and Python."""
113 t_parse('x[1]', '(get x 1)')
114 t_parse('x[a+b]', '(get x (+ a b))')
115
116
117def TestComma(t_parse):
118 t_parse('x=1,y=2,z=3', '(, (= x 1) (= y 2) (= z 3))')
119
120
121def TestFuncCalls(t_parse):
122 t_parse('x = y(2)*3 + y(4)*5', '(= x (+ (* (call y 2) 3) (* (call y 4) 5)))')
123
124 t_parse('x(1,2)+y(3,4)', '(+ (call x 1 2) (call y 3 4))')
125 t_parse('x(a,b,c[d])', '(call x a b (get c d))')
126 t_parse('x(1,2)*j+y(3,4)*k+z(5,6)*l',
127 '(+ (+ (* (call x 1 2) j) (* (call y 3 4) k)) (* (call z 5 6) l))')
128 t_parse('print(test(2,3))', '(call print (call test 2 3))')
129 t_parse('print("x")', '(call print x)')
130 t_parse('min(255,n*2)', '(call min 255 (* n 2))')
131 t_parse('c = pal[i*8]', '(= c (get pal (* i 8)))')
132
133
134def TestErrors(p):
135 _assertParseError(p, '}')
136 _assertParseError(p, ']')
137
138 _assertParseError(p, '{') # depends on language
139
140 _assertParseError(p, "x+1 = y", "Can't assign")
141 _assertParseError(p, "(x+1)++", "Can't assign")
142
143 # Should be an EOF error
144 _assertParseError(p, 'foo ? 1 :', 'Unexpected end')
145
146 _assertParseError(p, 'foo ? 1 ', 'expected :')
147 _assertParseError(p, '%', "can't be used in prefix position")
148
149 error_str = "can't be used in prefix"
150 _assertParseError(p, '}')
151 _assertParseError(p, '{')
152 _assertParseError(p, ']', error_str)
153
154 _assertParseError(p, '1 ( 2', "can't be called")
155 _assertParseError(p, '(x+1) ( 2 )', "can't be called")
156 #_assertParseError(p, '1 ) 2')
157
158 _assertParseError(p, '1 [ 2 ]', "can't be indexed")
159
160
161arith_expr_e = arith_ast.arith_expr_e
162#source_location = arith_ast.source_location
163#op_id_e = arith_ast.op_id_e
164
165class Visitor(object):
166 def __init__(self):
167 pass
168
169 # In Python, they do introspection on method names.
170 # method = 'visit_' + node.__class__.__name__
171 # I'm not going to bother, because I have ASDL! I want the generic visitor.
172
173 def Visit(self, node):
174 raise NotImplementedError
175
176 # Like ast.NodeVisitor().generic_visit!
177 def VisitChildren(self, node):
178 #print dir(node)
179
180 # TODO: Use node.ASDL_TYPE.GetFields()
181 # Only compound children get visited?
182 print([name for name in dir(node) if not name.startswith('_')])
183 # Call self.Visit()!
184
185
186class PrettyPrinter(Visitor):
187
188 def Visit(self, node):
189 if node.tag == arith_expr_e.ArithUnary:
190 print('ArithUnary %s' % node.child)
191 else:
192 self.VisitChildren(node)
193
194
195def t_parse(s, expected=None):
196 p = arith_parse.MakeParser(s)
197 tree = p.Parse()
198
199 print(tree)
200
201 #v = PrettyPrinter()
202 #v.Visit(tree)
203
204 #print('%-40s %s' % (s, sexpr))
205 return tree
206
207
208def main():
209 p = arith_parse.MakeParser
210
211 TestArith(t_parse)
212 return
213 TestBitwise(t_parse)
214 TestLogical(t_parse)
215 TestUnary(t_parse)
216 TestArrays(t_parse)
217 TestFuncCalls(t_parse)
218 TestComma(t_parse)
219 TestErrors(p)
220
221
222if __name__ == '__main__':
223 main()