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

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