OILS / ysh / expr_parse_test.py View on Github | oilshell.org

163 lines, 92 significant
1#!/usr/bin/env python2
2"""expr_parse_test.py: Tests for expr_parse.py."""
3from __future__ import print_function
4
5import unittest
6
7from _devbuild.gen.syntax_asdl import source
8
9from asdl import format as fmt
10from core import alloc
11from core import error
12from core import pyutil
13from core import test_lib
14from mycpp.mylib import log
15from frontend import reader
16
17
18class ExprParseTest(unittest.TestCase):
19
20 def setUp(self):
21 """Done on every test."""
22 self.arena = alloc.Arena()
23 self.arena.PushSource(source.Unused(''))
24
25 loader = pyutil.GetResourceLoader()
26 ysh_grammar = pyutil.LoadYshGrammar(loader)
27
28 self.parse_ctx = test_lib.InitParseContext(arena=self.arena,
29 ysh_grammar=ysh_grammar,
30 do_lossless=True)
31
32 def _ParseOsh(self, code_str):
33 """Parse a line of OSH, which can include Oil assignments."""
34 line_reader = reader.StringLineReader(code_str, self.arena)
35 # the OSH parser hooks into the Oil parser
36 c_parser = self.parse_ctx.MakeOshParser(line_reader)
37 node = c_parser.ParseLogicalLine()
38 print('')
39 log('\t%s', code_str)
40 fmt.PrettyPrint(node)
41 print('')
42 return node
43
44 def _ParseYshExpression(self, code_str):
45 """Convenient shortcut."""
46 node = self._ParseOsh('var x = %s\n' % code_str)
47
48 def testPythonLike(self):
49 # This works.
50 node = self._ParseOsh('var x = y + 2 * 3;')
51
52 node = self._ParseOsh(r"var x = r'one\ntwo\n';")
53 node = self._ParseOsh(r"var x = $'one\ntwo\n';")
54
55 node = self._ParseOsh(r'var x = "one\\ntwo\\n";')
56
57 # These raise NotImplementedError()
58
59 node = self._ParseOsh('var x = [1,2,3];')
60 node = self._ParseYshExpression('[4+5, 6+7*8]')
61 node = self._ParseYshExpression('[]')
62
63 node = self._ParseYshExpression('[x for x in y]')
64 #node = self._ParseYshExpression('{foo: bar}')
65
66 def testShellArrays(self):
67 node = self._ParseOsh('var x = %(a b);')
68 node = self._ParseOsh(r"var x = %('c' $'string\n');")
69 node = self._ParseOsh(r"var x = %($(echo command) $(echo sub));")
70
71 # Can parse multiple arrays (this is a runtime error)
72 node = self._ParseOsh(r"var x = %(a b) * %($c ${d});")
73
74 # Can parse over multiple lines
75 node = self._ParseOsh(r"""var x = %(
76 a
77 b
78 c
79 );""")
80
81 # Test out the DisallowedLineReader
82 self.assertRaises(error.Parse, self._ParseOsh,
83 r"""var x = %($(echo command <<EOF
84EOF
85))""")
86
87 def testShellCommandSub(self):
88 node = self._ParseOsh('var x = $(echo hi);')
89 node = self._ParseOsh('var x = $(echo $(echo hi));')
90
91 # This doesn't use the Reader, so it's allowed
92 node = self._ParseOsh("""var x = $(echo
93hi)
94 """)
95
96 # Here docs use the Reader, so aren't allowed
97 self.assertRaises(error.Parse, self._ParseOsh, """var x = $(cat <<EOF
98hi
99EOF)
100 """)
101
102 node = self._ParseOsh('var x = $(echo $((1+2)));')
103 node = self._ParseOsh('var x = $(for i in 1 2 3; do echo $i; done);')
104
105 node = self._ParseOsh('var x = %(a b)')
106
107 # TODO: Recursive 'var' shouldn't be allowed!
108 return
109 node = self._ParseOsh('var x = $(var x = %(a b););')
110 node = self._ParseOsh('var x = $(var x = %(a b));')
111
112 def testOtherExpr(self):
113 """Some examples copied from pgen2/pgen2-test.sh mode-test."""
114
115 CASES = [
116 #'$/ x /',
117 # TODO: Put this back after fixing double quoted strings in expression
118 # mode.
119 #'$/ "." [a-z A-Z] y /',
120 #'$[echo hi]',
121 '$(echo hi)',
122
123 # TODO: Add these back
124 '${x}',
125 '"quoted ${x}"',
126 ]
127
128 # array literal
129 for c in CASES:
130 print('--- %s' % c)
131 node = self._ParseYshExpression(c)
132
133 def testLexer(self):
134 CASES = [
135 ("= x }", 4),
136 ("= x;}", 3),
137 ("= x; }", 3),
138 ("echo $x;}", 8),
139 ("echo $x; }", 8),
140 ("= x\n}", 3),
141 ("echo $x\n}", 8),
142 ]
143
144 for code_str, end_pos in CASES:
145 line_reader = reader.StringLineReader(code_str, self.arena)
146 cmd_parser = self.parse_ctx.MakeOshParser(line_reader)
147 lexer = cmd_parser.lexer
148
149 node = cmd_parser.ParseCommand()
150
151 # Assert that we are at the RBrace. Ie,
152 # 'x }\n'
153 # ^
154 self.assertEqual(end_pos, lexer.line_lexer.line_pos)
155
156 print("-----")
157 print("%r" % lexer.line_lexer.src_line.content)
158 print(" " * (lexer.line_lexer.line_pos + 1) + "^")
159 print("-----")
160
161
162if __name__ == '__main__':
163 unittest.main()