OILS / osh / arith_parse_test.py View on Github | oilshell.org

183 lines, 86 significant
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"""
9arith_parse_test.py: Tests for arith_parse.py
10"""
11
12import unittest
13
14from _devbuild.gen.types_asdl import lex_mode_e
15from core import error
16from core import test_lib
17from core import ui
18from osh import sh_expr_eval
19from osh import split
20from osh import word_eval
21from core import state
22
23#from osh import arith_parse
24
25
26def 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
56def 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
63def 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
73class ArithTest(unittest.TestCase):
74
75 def testEval(self):
76 testEvalExpr('(7)', 7)
77
78 # Doesn't matter if you eval 2-3 first here
79 testEvalExpr('1 + 2 - 3', 0)
80
81 testEvalExpr('1 + 2 * 3', 7)
82
83 testEvalExpr('7 - 9 * (2 - 3)', 16)
84 testEvalExpr('2 * 3 * 4', 24)
85
86 testEvalExpr('2 ** 3 ** 4', 2**(3**4))
87
88 testEvalExpr('(2 ** 3) ** 4', 4096)
89
90 testEvalExpr('5', 5)
91 testEvalExpr('4 + 2', 6)
92 testEvalExpr('9 - 8 - 7', -6)
93 testEvalExpr('9 - (8 - 7)', 8)
94 testEvalExpr('(9 - 8) - 7', -6)
95 testEvalExpr('2 + 3 ** 2 * 3 + 4', 33)
96
97 testEvalExpr('4 * 3 / 2', 6)
98 testEvalExpr('3 * 2 % 4', 2)
99 testEvalExpr('+ 1', 1)
100 testEvalExpr('- 5', -5)
101 testEvalExpr('-2-3', -5)
102
103 # Comma has lower precedence
104 testEvalExpr('1 ? 2 : 3, 4 ? 5 : 6', 5)
105
106 # Two commas
107 testEvalExpr('1 , 2, 3', 3)
108
109 # TODO: fix the rest
110 return
111
112 testEvalExpr('0 = 2 > 3', 0) # => 0 > 3 => 0
113
114 # string becomes integer"
115 #testEvalExpr(['ab21xx', ':', '[^0-9]*([0-9]*)', '+', '3'], 24)
116
117 #testEvalExpr(['ab21xx', ':', '[^0-9]*([0-9]*)'], '21')
118
119 #testEvalExpr(['ab21xx', ':', '(.)'], 'a')
120
121 # integer becomes string. -3 as a string is less than '-3-'
122 #testEvalExpr(['2', '-', '5', '<', '-3-'], True)
123 #testEvalExpr(['2', '-', '5', '<', '-2-'], False)
124
125 # Arithmetic compare
126 testEvalExpr(['-3', '<', '-2'], True)
127 # String compare
128 #testEvalExpr(['-3', '<', '-2-'], False)
129
130 #testEvalExpr(['3a', ':', '(.)', '=', '1', '+', '2'], True)
131
132 # More stuff:
133 # expr / => / -- it's just a plain string
134 # expr / : . => 1
135 # expr \( / \) => / -- this is dumb
136 # expr + match => match -- + is escaping, wtf
137 #
138 #testEvalExpr(['ab21xx', ':', '[^0-9]*([0-9]*)', '+', '3'], 24)
139
140 def testEvalConstants(self):
141 # Octal constant
142 testEvalExpr('011', 9)
143
144 # Hex constant
145 testEvalExpr('0xA', 10)
146
147 # Arbitrary base constant
148 testEvalExpr('64#z', 35)
149 testEvalExpr('64#Z', 61)
150 testEvalExpr('64#@', 62)
151 testEvalExpr('64#_', 63)
152
153 def testErrors(self):
154 # Now try some bad ones
155
156 testSyntaxError('')
157 testSyntaxError(')')
158 testSyntaxError('(')
159
160 # If ( is an error, I think this should be too.
161 # For now left it out. Don't want to look up opinfo.
162 #
163 # In GNU expr, this is an error because + is escaping char!
164 #testSyntaxError('+')
165 #testSyntaxError('/')
166
167 testSyntaxError('()') # Not valid, expr also fails.
168 testSyntaxError('( 1')
169 testSyntaxError('(1 + (3 * 4)')
170 testSyntaxError('(1 + (3 * 4) 5') # Not valid, expr also fails.
171
172 testSyntaxError(';')
173 testSyntaxError('- ;')
174
175 #testSyntaxError('1 1')
176 #testSyntaxError('( 1 ) ( 2 )')
177
178 # NOTE: @ implicitly ends it now
179 #testSyntaxError('1 @ 2')
180
181
182if __name__ == '__main__':
183 unittest.main()