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