def test_match(self): m = ast.Module('test') b = parser.Bindings(None) b.add('x', ast.BuiltinNameDef(m, 'x')) e = self.parse_expression('match x { u32:42 => u32:64, _ => u32:42 }', bindings=b) self.assertIsInstance(e, ast.Match)
def test_simple_number(self): m = ast.Module('test') n = ast.Number(m, self.fake_span, '42') self.assertEmpty(n.children) collector = Collector() cpp_ast_visitor.visit(n, collector) self.assertEqual(collector.visited, [n])
def test_module_with_constant(self): m = cpp_ast.Module('test') name_def = cpp_ast.NameDef(m, self.fake_span, 'MOL') number = cpp_ast.Number(m, self.fake_span, '42') constant_def = cpp_ast.Constant(m, name_def, number) m.add_top(constant_def) self.assertEqual(str(m), 'const MOL = 42;')
def test_array_of_numbers(self): m = ast.Module('test') n0 = ast.Number(m, self.fake_span, '42') n1 = ast.Number(m, self.fake_span, '64') a = ast.Array(m, self.fake_span, [n0, n1], False) collector = Collector() cpp_ast_visitor.visit(a, collector) self.assertEqual(collector.visited, [n0, n1, a])
def test_cast(self): m = ast.Module('test') b = parser.Bindings(None) b.add('foo', ast.BuiltinNameDef(m, 'foo')) e = self.parse_expression('foo() as u32', bindings=b) self.assertIsInstance(e, ast.Cast) self.assertIsInstance(e.expr, ast.Invocation) self.assertIsInstance(e.type_, ast.TypeAnnotation)
def test_double_negation(self): m = ast.Module('test') b = parser.Bindings(None) b.add('x', ast.BuiltinNameDef(m, 'x')) e = self.parse_expression('!!x', bindings=b) self.assertIsInstance(e, ast.Unop) self.assertIsInstance(e.operand, ast.Unop) self.assertIsInstance(e.operand.operand, ast.NameRef) self.assertEqual(e.operand.operand.identifier, 'x')
def generate_function_in_module( self, fname: Text, mname: Text) -> Tuple[ast.Function, ast.Module]: """Generates a function named "fname" in a module named "mname".""" self.m = ast.Module(mname) f = self.generate_function(fname) top = tuple(self._type_defs) + tuple(self._functions) + (f, ) for item in top: self.m.add_top(item) return f, self.m
def test_match_freevars(self): text = """match x { y => z }""" m = ast.Module('test') b = parser.Bindings(None) for identifier in ('x', 'y', 'z'): b.add(identifier, ast.BuiltinNameDef(m, identifier)) n = self.parse_expression(text, bindings=b) freevars = n.get_free_variables(n.span.start) self.assertEqual(freevars.keys(), {'x', 'y', 'z'})
def test_ternary(self): m = ast.Module('test') b = parser.Bindings(m, None) e = self.parse_expression('u32:42 if true else u32:24', bindings=b) self.assertIsInstance(e, ast.Ternary) self.assertIsInstance(e.consequent, ast.Number) self.assertEqual(e.consequent.value, '42') self.assertIsInstance(e.alternate, ast.Number) self.assertEqual(e.alternate.value, '24') self.assertIsInstance(e.test, ast.Number) self.assertEqual(e.test.value, 'true')
def test_import(self): program = """ import thing """ m = ast.Module('test') bindings = parser.Bindings(None) fparse = lambda p, bindings: p.parse_module(bindings) m = self._parse_internal(program, bindings, fparse) self.assertIsInstance(m.top[0], ast.Import) fake_pos = Pos(self.fake_filename, 0, 0) fake_span = Span(fake_pos, fake_pos) self.assertIsInstance(bindings.resolve_node(m, 'thing', fake_span), ast.Import)
def test_named_tuple_vs_tuple_compatibility(self): u32 = ConcreteType.U32 u8 = ConcreteType.U8 m = ast.Module('test') fake_pos = Pos('fake.x', 0, 0) fake_span = Span(fake_pos, fake_pos) name_def = ast.NameDef(m, fake_span, 'fake') s = ast.Struct(m, fake_span, name_def, (), (), False) named = TupleType((('x', u32), ('y', u8)), struct=s) unnamed = TupleType((u32, u8)) self.assertTrue(named.compatible_with(unnamed)) self.assertNotEqual(named, unnamed) self.assertEqual(named.tuple_names, ('x', 'y'))
def test_array(self): m = ast.Module('test') b = parser.Bindings(None) for identifier in 'a b c d'.split(): b.add(identifier, ast.BuiltinNameDef(m, identifier)) e = self.parse_expression('[a, b, c, d]', bindings=b) self.assertIsInstance(e, ast.Array) a = e self.assertLen(a.members, 4) self.assertIsInstance(a.members[0], ast.NameRef) self.assertIsInstance(a.members[1], ast.NameRef) self.assertIsInstance(a.members[2], ast.NameRef) self.assertIsInstance(a.members[3], ast.NameRef)
def test_for_freevars(self): program = """for (i, accum): (u32, u32) in range(4) { let new_accum: u32 = accum + i + j; new_accum }(u32:0)""" m = ast.Module('test') b = parser.Bindings(None) b.add('range', ast.BuiltinNameDef(m, 'range')) b.add('j', ast.BuiltinNameDef(m, 'j')) e = self.parse_expression(program, bindings=b) self.assertIsInstance(e, ast.For) self.assertEqual(e.span.start, Pos(self.fake_filename, lineno=0, colno=3)) freevars = e.get_free_variables(e.span.start) self.assertCountEqual(freevars.keys(), ['j', 'range'])
def test_logical_operator_binding(self): m = ast.Module('test') b = parser.Bindings(None) b.add('a', ast.BuiltinNameDef(m, 'a')) b.add('b', ast.BuiltinNameDef(m, 'b')) b.add('c', ast.BuiltinNameDef(m, 'c')) e = self.parse_expression('!a || !b && c', bindings=b) # This should group as: # ((!a) || ((!b) && c)) self.assertTrue(e.kind, ast.BinopKind.LOGICAL_OR) self.assertTrue(e.lhs.kind, ast.UnopKind.INV) self.assertTrue(e.rhs.kind, ast.BinopKind.LOGICAL_AND) self.assertEqual(e.rhs.lhs.kind, ast.UnopKind.INV) self.assertIsInstance(e.rhs.rhs, ast.NameRef) self.assertEqual(e.rhs.rhs.identifier, 'c')
def test_logical_equality(self): m = ast.Module('test') b = parser.Bindings(None) b.add('a', ast.BuiltinNameDef(m, 'a')) b.add('b', ast.BuiltinNameDef(m, 'b')) b.add('f', ast.BuiltinNameDef(m, 'f')) e = self.parse_expression('a ^ !b == f()', bindings=b) # This should group as: # ((a) ^ (!b)) == (f()) self.assertEqual(e.kind, ast.BinopKind.EQ) self.assertTrue(e.lhs.kind, ast.BinopKind.XOR) self.assertTrue(e.lhs.rhs.kind, ast.UnopKind.INV) self.assertIsInstance(e.rhs, ast.Invocation) self.assertIsInstance(e.rhs.callee, ast.NameRef) self.assertEqual(e.rhs.callee.identifier, 'f')
def _parse_internal( self, program: Text, bindings: Optional[parser.Bindings], fparse: Callable[[parser.Parser, parser.Bindings], TypeVar('T')] ) -> TypeVar('T'): m = ast.Module('test') if bindings is None else bindings.module with fakefs_test_util.scoped_fakefs(self.fake_filename, program): s = scanner.Scanner(self.fake_filename, program) b = bindings or parser.Bindings(m, None) try: e = fparse(parser.Parser(s, 'test_module'), b) except parser.ParseError as e: parser_helpers.pprint_positional_error(e) raise self.assertTrue(s.at_eof(), msg=s.peek()) return e
def test_identity_function(self): m = cpp_ast.Module('test') name_def_x = cpp_ast.NameDef(m, self.fake_span, 'x') name_ref_x = cpp_ast.NameRef(m, self.fake_span, 'x', name_def_x) type_u32 = cpp_ast.BuiltinTypeAnnotation(m, self.fake_span, cpp_ast.BuiltinType.U32) param_x = cpp_ast.Param(m, name_def_x, type_u32) name_def_f = cpp_ast.NameDef(m, self.fake_span, 'f') params = (param_x, ) f = cpp_ast.Function(m, self.fake_span, name_def_f, (), params, type_u32, name_ref_x, public=False) self.assertEqual(str(f), 'fn f(x: u32) -> u32 {\n x\n}')
def test_bad_enum_ref(self): program = """ enum MyEnum : u1 { FOO = 0 } fn my_fun() -> MyEnum { FOO // Should be qualified as MyEnum::FOO! } """ m = ast.Module('test') bindings = parser.Bindings(m, None) fparse = lambda p, bindings: p.parse_module(bindings) with self.assertRaises(CppParseError) as cm: self._parse_internal(program, bindings, fparse) self.assertIn('Cannot find a definition for name: \'FOO\'', str(cm.exception))
def test_for(self): program = textwrap.dedent(""" let accum: u32 = 0; let accum: u32 = for (i, accum): (u32, u32) in range(4) { let new_accum: u32 = accum + i; new_accum }(accum); accum """) m = ast.Module('test') b = parser.Bindings(None) b.add('range', ast.BuiltinNameDef(m, 'range')) e = self.parse_expression(program, bindings=b) self.assertIsInstance(e, ast.Let) self.assertIsInstance(e.body, ast.Let) self.assertIsInstance(e.body.rhs, ast.For) for_ = e.body.rhs self.assertIsInstance(for_.init, ast.NameRef) self.assertIsNot(for_.init.name_def, for_.names.tree[1].get_leaf())
def test_parse_name_def_tree(self): text = '(a, (b, (c, d), e), f)' fparse = lambda p, b: p._parse_name_def_tree(b) m = ast.Module('test') bindings = parser.Bindings(m) ndt = self._parse_internal(text, bindings, fparse) self.assertIsInstance(ndt, ast.NameDefTree) self.assertLen(ndt.tree, 3) self.assertIsInstance(ndt.tree[0], ast.NameDefTree) self.assertTrue(ndt.tree[0].is_leaf()) self.assertIsInstance(ndt.tree[2], ast.NameDefTree) self.assertTrue(ndt.tree[2].is_leaf()) self.assertEqual( ndt.tree[0].span, Span(Pos(self.fake_filename, 0, 1), Pos(self.fake_filename, 0, 2))) self.assertEqual( ndt.tree[2].span, Span(Pos(self.fake_filename, 0, 20), Pos(self.fake_filename, 0, 21))) self.assertNotEqual(ndt.tree[2].span, ndt.tree[0].span)
def test_parse_name_def_tree(self): text = 'let (a, (b, (c, d), e), f) = x; a' m = ast.Module('test') bindings = parser.Bindings() bindings.add('x', ast.BuiltinNameDef(m, 'x')) let = self.parse_expression(text, bindings) self.assertIsInstance(let, ast.Let) ndt = let.name_def_tree self.assertIsInstance(ndt, ast.NameDefTree) self.assertLen(ndt.tree, 3) self.assertIsInstance(ndt.tree[0], ast.NameDefTree) self.assertTrue(ndt.tree[0].is_leaf()) self.assertIsInstance(ndt.tree[2], ast.NameDefTree) self.assertTrue(ndt.tree[2].is_leaf()) self.assertEqual( ndt.tree[0].span, Span(Pos(self.fake_filename, 0, 5), Pos(self.fake_filename, 0, 6))) self.assertEqual( ndt.tree[2].span, Span(Pos(self.fake_filename, 0, 24), Pos(self.fake_filename, 0, 25))) self.assertNotEqual(ndt.tree[2].span, ndt.tree[0].span)
def test_ndt_preorder(self): fake_pos = self.fake_pos fake_span = Span(fake_pos, fake_pos) m = ast.Module('test') t = ast.NameDef(m, fake_span, 't') u = ast.NameDef(m, fake_span, 'u') wrapped_t = ast.NameDefTree(m, fake_span, t) wrapped_u = ast.NameDefTree(m, fake_span, u) interior = ast.NameDefTree(m, fake_span, (wrapped_t, wrapped_u)) outer = ast.NameDefTree(m, fake_span, (interior, )) walk_data = [] def walk(item: ast.NameDefTree, level: int, i: int): walk_data.append((item, level, i)) ast_helpers.do_preorder(outer, walk) self.assertLen(walk_data, 3) self.assertEqual(walk_data[0], (interior, 1, 0)) self.assertEqual(walk_data[1], (wrapped_t, 2, 0)) self.assertEqual(walk_data[2], (wrapped_u, 2, 1))
def test_bindings_stack(self): m = ast.Module('test') top = parser.Bindings(None) leaf0 = parser.Bindings(top) leaf1 = parser.Bindings(top) a = ast.BuiltinNameDef(m, 'a') b = ast.BuiltinNameDef(m, 'b') c = ast.BuiltinNameDef(m, 'c') top.add('a', a) leaf0.add('b', b) leaf1.add('c', c) pos = Pos(self.fake_filename, lineno=0, colno=0) span = Span(pos, pos) self.assertEqual(leaf0.resolve(m, 'a', span), a) self.assertEqual(leaf1.resolve(m, 'a', span), a) self.assertEqual(top.resolve(m, 'a', span), a) with self.assertRaises(CppParseError): top.resolve(m, 'b', span) with self.assertRaises(CppParseError): leaf1.resolve(m, 'b', span) with self.assertRaises(CppParseError): leaf0.resolve(m, 'c', span) self.assertEqual(leaf0.resolve(m, 'b', span), b) self.assertEqual(leaf1.resolve(m, 'c', span), c)
def test_format_binop(self): m = ast.Module('test') fake_pos = self.fake_pos fake_span = Span(fake_pos, fake_pos) le = ast.Binop(m, fake_span, ast.BinopKind.LE, self.five, self.five) self.assertEqual('(5) <= (5)', str(le))
def setUp(self): super().setUp() self.m = ast.Module('test')
def test_binop(self): m = cpp_ast.Module('test') ft = cpp_ast.Number(m, self.fake_span, '42') sf = cpp_ast.Number(m, self.fake_span, '64') add = cpp_ast.Binop(m, self.fake_span, cpp_ast.BinopKind.ADD, ft, sf) self.assertEqual(str(add), '(42) + (64)')
def test_constant_array(self): m = ast.Module('test') b = parser.Bindings(m, None) e = self.parse_expression('u32[2]:[u32:0, u32:1]', bindings=b) self.assertIsInstance(e, ast.ConstantArray)