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 asdl import format as fmt
|
10 | from core import alloc
|
11 | from core import error
|
12 | from core import pyutil
|
13 | from core import test_lib
|
14 | from mycpp.mylib import log
|
15 | from frontend import reader
|
16 |
|
17 |
|
18 | class 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 YSH assignments."""
|
34 | line_reader = reader.StringLineReader(code_str, self.arena)
|
35 | # the OSH parser hooks into the YSH 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
|
84 | EOF
|
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
|
93 | hi)
|
94 | """)
|
95 |
|
96 | # Here docs use the Reader, so aren't allowed
|
97 | self.assertRaises(error.Parse, self._ParseOsh, """var x = $(cat <<EOF
|
98 | hi
|
99 | EOF)
|
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 |
|
162 | if __name__ == '__main__':
|
163 | unittest.main()
|