1 #!/usr/bin/env python2
2 # Copyright 2016 Andy Chu. All rights reserved.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 """
9 arith_parse_test.py: Tests for arith_parse.py
10 """
11
12 import unittest
13
14 from _devbuild.gen.types_asdl import lex_mode_e
15 from core import error
16 from core import test_lib
17 from core import ui
18 from osh import sh_expr_eval
19 from osh import split
20 from osh import word_eval
21 from core import state
22
23 #from osh import arith_parse
24
25
26 def ParseAndEval(code_str):
27 arena = test_lib.MakeArena('<arith_parse_test.py>')
28 parse_ctx = test_lib.InitParseContext(arena=arena)
29 w_parser = test_lib.InitWordParser(code_str, arena=arena)
30
31 # This is weird but works
32 w_parser._SetNext(lex_mode_e.Arith) # Calling private method
33 anode = w_parser.a_parser.Parse()
34
35 print('node:', anode)
36
37 mem = state.Mem('', [], arena, [])
38 parse_opts, exec_opts, mutable_opts = state.MakeOpts(mem, None)
39 mem.exec_opts = exec_opts
40 state.InitMem(mem, {}, '0.1')
41
42 splitter = split.SplitContext(mem)
43 errfmt = ui.ErrorFormatter()
44
45 tilde_ev = word_eval.TildeEvaluator(mem, exec_opts)
46 word_ev = word_eval.CompletionWordEvaluator(mem, exec_opts, mutable_opts,
47 tilde_ev, splitter, errfmt)
48
49 arith_ev = sh_expr_eval.ArithEvaluator(mem, exec_opts, mutable_opts,
50 parse_ctx, arena)
51
52 arith_ev.word_ev = word_ev
53 return arith_ev.EvalToInt(anode)
54
55
56 def testEvalExpr(e, expected):
57 print('expression:', e)
58 actual = ParseAndEval(e)
59 if actual != expected:
60 raise AssertionError('%s => %r, expected %r' % (e, actual, expected))
61
62
63 def testSyntaxError(expr):
64 try:
65 actual = ParseAndEval(expr)
66 except error.Parse as e:
67 print(expr, '\t\t', e)
68 else:
69 raise AssertionError('Expected parse error: %r, got %r' %
70 (expr, actual))
71
72
73 class ArithTest(unittest.TestCase):
74 def testEval(self):
75 testEvalExpr('(7)', 7)
76
77 # Doesn't matter if you eval 2-3 first here
78 testEvalExpr('1 + 2 - 3', 0)
79
80 testEvalExpr('1 + 2 * 3', 7)
81
82 testEvalExpr('7 - 9 * (2 - 3)', 16)
83 testEvalExpr('2 * 3 * 4', 24)
84
85 testEvalExpr('2 ** 3 ** 4', 2**(3**4))
86
87 testEvalExpr('(2 ** 3) ** 4', 4096)
88
89 testEvalExpr('5', 5)
90 testEvalExpr('4 + 2', 6)
91 testEvalExpr('9 - 8 - 7', -6)
92 testEvalExpr('9 - (8 - 7)', 8)
93 testEvalExpr('(9 - 8) - 7', -6)
94 testEvalExpr('2 + 3 ** 2 * 3 + 4', 33)
95
96 testEvalExpr('4 * 3 / 2', 6)
97 testEvalExpr('3 * 2 % 4', 2)
98 testEvalExpr('+ 1', 1)
99 testEvalExpr('- 5', -5)
100 testEvalExpr('-2-3', -5)
101
102 # Comma has lower precedence
103 testEvalExpr('1 ? 2 : 3, 4 ? 5 : 6', 5)
104
105 # Two commas
106 testEvalExpr('1 , 2, 3', 3)
107
108 # TODO: fix the rest
109 return
110
111 testEvalExpr('0 = 2 > 3', 0) # => 0 > 3 => 0
112
113 # string becomes integer"
114 #testEvalExpr(['ab21xx', ':', '[^0-9]*([0-9]*)', '+', '3'], 24)
115
116 #testEvalExpr(['ab21xx', ':', '[^0-9]*([0-9]*)'], '21')
117
118 #testEvalExpr(['ab21xx', ':', '(.)'], 'a')
119
120 # integer becomes string. -3 as a string is less than '-3-'
121 #testEvalExpr(['2', '-', '5', '<', '-3-'], True)
122 #testEvalExpr(['2', '-', '5', '<', '-2-'], False)
123
124 # Arithmetic compare
125 testEvalExpr(['-3', '<', '-2'], True)
126 # String compare
127 #testEvalExpr(['-3', '<', '-2-'], False)
128
129 #testEvalExpr(['3a', ':', '(.)', '=', '1', '+', '2'], True)
130
131 # More stuff:
132 # expr / => / -- it's just a plain string
133 # expr / : . => 1
134 # expr \( / \) => / -- this is dumb
135 # expr + match => match -- + is escaping, wtf
136 #
137 #testEvalExpr(['ab21xx', ':', '[^0-9]*([0-9]*)', '+', '3'], 24)
138
139 def testEvalConstants(self):
140 # Octal constant
141 testEvalExpr('011', 9)
142
143 # Hex constant
144 testEvalExpr('0xA', 10)
145
146 # Arbitrary base constant
147 testEvalExpr('64#z', 35)
148 testEvalExpr('64#Z', 61)
149 testEvalExpr('64#@', 62)
150 testEvalExpr('64#_', 63)
151
152 def testErrors(self):
153 # Now try some bad ones
154
155 testSyntaxError('')
156 testSyntaxError(')')
157 testSyntaxError('(')
158
159 # If ( is an error, I think this should be too.
160 # For now left it out. Don't want to look up opinfo.
161 #
162 # In GNU expr, this is an error because + is escaping char!
163 #testSyntaxError('+')
164 #testSyntaxError('/')
165
166 testSyntaxError('()') # Not valid, expr also fails.
167 testSyntaxError('( 1')
168 testSyntaxError('(1 + (3 * 4)')
169 testSyntaxError('(1 + (3 * 4) 5') # Not valid, expr also fails.
170
171 testSyntaxError(';')
172 testSyntaxError('- ;')
173
174 #testSyntaxError('1 1')
175 #testSyntaxError('( 1 ) ( 2 )')
176
177 # NOTE: @ implicitly ends it now
178 #testSyntaxError('1 @ 2')
179
180
181 if __name__ == '__main__':
182 unittest.main()