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

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