OILS
/
osh
/
arith_parse_test.py
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()
|