| 1 | #!/usr/bin/env python
 | 
| 2 | from __future__ import print_function
 | 
| 3 | """
 | 
| 4 | arith_ast_test.py: Tests for arith_ast.py
 | 
| 5 | """
 | 
| 6 | 
 | 
| 7 | import cStringIO
 | 
| 8 | import unittest
 | 
| 9 | 
 | 
| 10 | from asdl import py_meta
 | 
| 11 | from asdl import asdl_
 | 
| 12 | from asdl import const
 | 
| 13 | from asdl import encode
 | 
| 14 | 
 | 
| 15 | from asdl import arith_ast  # module under test
 | 
| 16 | 
 | 
| 17 | # Sanity check.  Doesn't pass because this unit test exposes implementation
 | 
| 18 | # details, like the concrete classes.
 | 
| 19 | #from _tmp import arith_ast_asdl as arith_ast
 | 
| 20 | 
 | 
| 21 | 
 | 
| 22 | ArithVar = arith_ast.ArithVar
 | 
| 23 | ArithUnary = arith_ast.ArithUnary
 | 
| 24 | ArithBinary = arith_ast.ArithBinary
 | 
| 25 | Const = arith_ast.Const
 | 
| 26 | Slice = arith_ast.Slice
 | 
| 27 | arith_expr = arith_ast.arith_expr
 | 
| 28 | source_location = arith_ast.source_location
 | 
| 29 | op_id_e = arith_ast.op_id_e
 | 
| 30 | 
 | 
| 31 | cflow_e = arith_ast.cflow_e
 | 
| 32 | #cflow_t = arith_ast.cflow_t
 | 
| 33 | 
 | 
| 34 | 
 | 
| 35 | class ArithAstTest(unittest.TestCase):
 | 
| 36 | 
 | 
| 37 |   def testFieldDefaults(self):
 | 
| 38 |     s = arith_ast.Slice()
 | 
| 39 |     s.a = ArithVar('foo')
 | 
| 40 |     self.assertEqual(None, s.begin)
 | 
| 41 |     self.assertEqual(None, s.end)
 | 
| 42 |     self.assertEqual(None, s.stride)
 | 
| 43 |     print(s)
 | 
| 44 | 
 | 
| 45 |     func = arith_ast.FuncCall()
 | 
| 46 |     func.name = 'f'
 | 
| 47 |     self.assertEqual([], func.args)
 | 
| 48 |     print(func)
 | 
| 49 | 
 | 
| 50 |     t = arith_ast.token(5, 'x')
 | 
| 51 |     self.assertEqual(5, t.id)
 | 
| 52 |     self.assertEqual('x', t.value)
 | 
| 53 |     self.assertEqual(const.NO_INTEGER, t.span_id)
 | 
| 54 | 
 | 
| 55 |   def testTypeCheck(self):
 | 
| 56 |     v = ArithVar('name')
 | 
| 57 |     # Integer is not allowed
 | 
| 58 |     self.assertRaises(AssertionError, ArithVar, 1)
 | 
| 59 | 
 | 
| 60 |     v = ArithUnary(op_id_e.Minus, Const(99))
 | 
| 61 |     # Raw integer is not allowed
 | 
| 62 |     self.assertRaises(AssertionError, ArithUnary, op_id_e.Minus, 99)
 | 
| 63 | 
 | 
| 64 |     v = ArithUnary(op_id_e.Minus, Const(99))
 | 
| 65 |     # Raw integer is not allowed
 | 
| 66 |     #self.assertRaises(AssertionError, ArithUnary, op_id_e.Minus, op_id_e.Plus)
 | 
| 67 | 
 | 
| 68 |   def testExtraFields(self):
 | 
| 69 |     v = ArithVar('z')
 | 
| 70 | 
 | 
| 71 |     # TODO: Attach this to EVERY non-simple constructor?  Those are subclasses
 | 
| 72 |     # of Sum types.
 | 
| 73 |     # What about product types?
 | 
| 74 |     #print(v.xspans)
 | 
| 75 | 
 | 
| 76 |   def testEncode(self):
 | 
| 77 |     obj = arith_ast.Const(99)
 | 
| 78 |     print('Encoding into binary:')
 | 
| 79 |     print(obj)
 | 
| 80 | 
 | 
| 81 |     enc = encode.Params()
 | 
| 82 |     f = cStringIO.StringIO()
 | 
| 83 |     out = encode.BinOutput(f)
 | 
| 84 |     encode.EncodeRoot(obj, enc, out)
 | 
| 85 |     e = f.getvalue()
 | 
| 86 | 
 | 
| 87 |     #print(repr(e))
 | 
| 88 |     #print(e[0:4], e[4:8], e[8:])
 | 
| 89 | 
 | 
| 90 |     # Header is OHP version 1
 | 
| 91 |     self.assertEqual(b'OHP\x01', e[0:4])
 | 
| 92 | 
 | 
| 93 |     self.assertEqual(b'\x04', e[4:5])  # alignment 4
 | 
| 94 | 
 | 
| 95 |     # TODO: Fix after spids
 | 
| 96 |     return
 | 
| 97 |     self.assertEqual(b'\x02\x00\x00', e[5:8])  # root ref 2
 | 
| 98 | 
 | 
| 99 |     self.assertEqual(b'\x01', e[8:9])  # tag 1 is const
 | 
| 100 |     self.assertEqual(b'\x63\x00\x00', e[9:12])  # 0x63 = 99
 | 
| 101 | 
 | 
| 102 |   def testConstructorType(self):
 | 
| 103 |     n1 = ArithVar('x')
 | 
| 104 |     n2 = ArithVar(name='y')
 | 
| 105 |     print(n1)
 | 
| 106 |     print(n2)
 | 
| 107 | 
 | 
| 108 |     # Not good because not assigned?
 | 
| 109 |     n3 = ArithVar()
 | 
| 110 | 
 | 
| 111 |     # NOTE: You cannot instantiate a product type directly?  It's just used for
 | 
| 112 |     # type checking.  What about OCaml?
 | 
| 113 |     # That means you just need to create classes for the records (Constructor).
 | 
| 114 |     # They all descend from Obj.  They don't need
 | 
| 115 | 
 | 
| 116 |     n3 = ArithVar()
 | 
| 117 |     try:
 | 
| 118 |       n4 = ArithVar('x', name='X')
 | 
| 119 |     except TypeError as e:
 | 
| 120 |       pass
 | 
| 121 |     else:
 | 
| 122 |       raise AssertionError("Should have failed")
 | 
| 123 | 
 | 
| 124 |   def testProductType(self):
 | 
| 125 |     print()
 | 
| 126 |     print('-- PRODUCT --')
 | 
| 127 |     print()
 | 
| 128 | 
 | 
| 129 |     s = source_location()
 | 
| 130 |     s.path = 'hi'
 | 
| 131 |     s.line = 1
 | 
| 132 |     s.col = 2
 | 
| 133 |     s.length = 3
 | 
| 134 |     print(s)
 | 
| 135 | 
 | 
| 136 |     assert isinstance(s.ASDL_TYPE, asdl_.Product)
 | 
| 137 | 
 | 
| 138 |     # Implementation detail for dynamic type checking
 | 
| 139 |     assert isinstance(s, py_meta.CompoundObj)
 | 
| 140 | 
 | 
| 141 |   def testSimpleSumType(self):
 | 
| 142 |     # TODO: Should be op_id_i.Plus -- instance
 | 
| 143 |     # Should be op_id_s.Plus
 | 
| 144 | 
 | 
| 145 |     print()
 | 
| 146 |     print('-- SIMPLE SUM --')
 | 
| 147 |     print()
 | 
| 148 | 
 | 
| 149 |     o = op_id_e.Plus
 | 
| 150 |     assert isinstance(o, py_meta.SimpleObj)
 | 
| 151 | 
 | 
| 152 |     # Implementation detail for dynamic type checking
 | 
| 153 |     assert isinstance(o.ASDL_TYPE, asdl_.Sum)
 | 
| 154 | 
 | 
| 155 |   def testCompoundSumType(self):
 | 
| 156 |     print()
 | 
| 157 |     print('-- COMPOUND SUM --')
 | 
| 158 |     print()
 | 
| 159 | 
 | 
| 160 |     # TODO: Should be cflow_t.Break() and cflow_i.Break
 | 
| 161 |     c = arith_ast.Break()
 | 
| 162 |     assert isinstance(c, arith_ast.Break)
 | 
| 163 |     assert isinstance(c, arith_ast.cflow)
 | 
| 164 |     assert isinstance(c, py_meta.CompoundObj)
 | 
| 165 | 
 | 
| 166 |     # Implementation detail for dynamic type checking
 | 
| 167 |     assert isinstance(c.ASDL_TYPE, asdl_.Constructor), c.ASDL_TYPE
 | 
| 168 | 
 | 
| 169 |   def testOtherTypes(self):
 | 
| 170 |     c = Const(66)
 | 
| 171 |     print(c)
 | 
| 172 | 
 | 
| 173 |     print((Slice(Const(1), Const(5), Const(2))))
 | 
| 174 | 
 | 
| 175 |     print((op_id_e.Plus))
 | 
| 176 | 
 | 
| 177 |     # Class for sum type
 | 
| 178 |     print(arith_expr)
 | 
| 179 | 
 | 
| 180 |     # Invalid because only half were assigned
 | 
| 181 |     #print(ArithBinary(op_id_e.Plus, Const(5)))
 | 
| 182 | 
 | 
| 183 |     n = ArithBinary()
 | 
| 184 |     #n.CheckUnassigned()
 | 
| 185 |     n.op_id = op_id_e.Plus
 | 
| 186 |     n.left = Const(5)
 | 
| 187 |     #n.CheckUnassigned()
 | 
| 188 |     n.right = Const(6)
 | 
| 189 |     n.CheckUnassigned()
 | 
| 190 | 
 | 
| 191 |     arith_expr_e = arith_ast.arith_expr_e
 | 
| 192 |     self.assertEqual(arith_expr_e.Const, c.tag)
 | 
| 193 |     self.assertEqual(arith_expr_e.ArithBinary, n.tag)
 | 
| 194 | 
 | 
| 195 | 
 | 
| 196 | if __name__ == '__main__':
 | 
| 197 |   unittest.main()
 |