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

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