| 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 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
 | 
| 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()
 |