def test_visit_index(self): fake_span = self.fake_span m = self.m # Make a t[i] inde xnode. t = ast.NameRef(m, fake_span, 't', ast.NameDef(m, fake_span, 't')) i = ast.NameRef(m, fake_span, 'i', ast.NameDef(m, fake_span, 'i')) index = ast.Index(m, fake_span, t, i) c = _Collector() visit(index, c) self.assertEqual(c.collected, [t, i, index])
def _make_array_type(self, element_type: ast.TypeAnnotation, array_size: int) -> ast.TypeAnnotation: """Creates an array type with the given size and element type.""" assert array_size > 0, array_size size_type = None if self.rng.random() < 0.5: # Get-or-create a module level constant for the array size. width = max(1, int(math.ceil(math.log(array_size + 1, 2)))) identifier = f'W{width}_V{array_size}' if identifier in self._constants: constant_def = self._constants[identifier] else: size_type = self._make_type_annotation(signed=False, width=width) name_def = ast.NameDef(self.m, self.fake_span, identifier) constant_def = ast.Constant( self.m, self.fake_span, name_def, self._make_number(array_size, size_type), is_public=False) name_def.definer = constant_def self._constants[identifier] = constant_def dim = ast.ConstRef(self.m, self.fake_span, identifier, constant_def.name_def) else: dim = self._make_number(array_size, None) array_type = ast_helpers.make_type_ref_type_annotation( self.m, self.fake_span, self._create_type_ref(element_type), (dim,)) return array_type
def test_stringify_type(self): fake_span = self.fake_span m = self.m number_5 = ast.Number(m, fake_span, '5') number_2 = ast.Number(m, fake_span, '2') number_3 = ast.Number(m, fake_span, '3') bits_token = Token(value=Keyword.BITS, span=fake_span) type_ = ast_helpers.make_builtin_type_annotation( m, fake_span, bits_token, (number_5, )) self.assertEqual('bits[5]', str(type_)) type_ = ast_helpers.make_builtin_type_annotation( m, fake_span, Token(value=Keyword.U32, span=fake_span), (number_5, )) self.assertEqual('u32[5]', str(type_)) # "no-volume" bits array. # TODO(leary): 2020-08-24 delete bits in favor of uN type_ = ast_helpers.make_builtin_type_annotation( m, fake_span, bits_token, ()) self.assertEqual('bits', str(type_)) # TypeRef with dims. my_type_tok = Token(TokenKind.IDENTIFIER, value='MyType', span=fake_span) name_def = ast.NameDef(m, fake_span, 'MyType') type_def = ast.TypeDef(m, fake_span, name_def, type_, public=False) type_ref = ast.TypeRef(m, fake_span, my_type_tok.value, type_def) type_ = ast_helpers.make_type_ref_type_annotation( m, fake_span, type_ref, (number_2, number_3)) self.assertEqual('MyType[2][3]', str(type_))
def test_type_annotation_properties(self): m = self.m fake_span = self.fake_span number_5 = ast.Number(m, fake_span, '5') number_2 = ast.Number(m, fake_span, '2') number_3 = ast.Number(m, fake_span, '3') bits_token = Token(value=Keyword.BITS, span=fake_span) un_token = Token(value=Keyword.UN, span=fake_span) u32_token = Token(value=Keyword.U32, span=fake_span) type_ = ast_helpers.make_builtin_type_annotation( m, fake_span, bits_token, (number_5, )) self.assertEqual('bits[5]', str(type_)) type_ = ast_helpers.make_builtin_type_annotation( m, fake_span, bits_token, (number_5, number_2)) self.assertIsInstance(type_, ast.ArrayTypeAnnotation) self.assertEqual('bits[5][2]', str(type_)) type_ = ast_helpers.make_builtin_type_annotation( m, fake_span, u32_token, ()) self.assertEqual('u32', str(type_)) type_ = ast_helpers.make_builtin_type_annotation( m, fake_span, u32_token, (number_3, )) self.assertIsInstance(type_, ast.ArrayTypeAnnotation) self.assertEqual('u32[3]', str(type_)) type_ = ast_helpers.make_builtin_type_annotation( m, fake_span, un_token, (number_2, )) self.assertEqual('uN[2]', str(type_)) type_ = ast_helpers.make_builtin_type_annotation( m, fake_span, un_token, (number_2, number_3)) self.assertIsInstance(type_, ast.ArrayTypeAnnotation) self.assertEqual('uN[2][3]', str(type_)) # TODO(leary): 2020-08-24 delete bits in favor of uN # "no-volume" bits array. type_ = ast_helpers.make_builtin_type_annotation( m, fake_span, bits_token, ()) self.assertEqual('bits', str(type_)) # TypeRef with dims. name_def = ast.NameDef(m, fake_span, 'MyType') type_def = ast.TypeDef(m, fake_span, name_def, type_, public=False) type_ref = ast.TypeRef(m, fake_span, 'MyType', type_def) type_ = ast_helpers.make_type_ref_type_annotation( m, fake_span, type_ref, (number_2, number_3)) self.assertIsInstance(type_, ast.ArrayTypeAnnotation) self.assertEqual('MyType[2][3]', str(type_)) type_ = ast.TupleTypeAnnotation( m, fake_span, (ast_helpers.make_builtin_type_annotation(m, fake_span, bits_token, (number_5, )), ast_helpers.make_builtin_type_annotation(m, fake_span, bits_token, (number_2, )))) self.assertIsInstance(type_, ast.TupleTypeAnnotation) self.assertEqual('(bits[5], bits[2])', str(type_))
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_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 _generate_expr(self, env: Env, level: int) -> Tuple[ast.Expr, ast.TypeAnnotation]: """Generates an expression AST node and returns it.""" if self.should_nest(level): identifier = self.gensym() name_def = ast.NameDef(self.m, self.fake_span, identifier) choices = collections.OrderedDict() if self.options.emit_loops: choices[self._generate_counted_for] = 1.0 choices[self._generate_tuple_or_index] = 1.0 choices[self._generate_concat] = 1.0 choices[self._generate_binop] = 1.0 choices[self._generate_unop] = 1.0 choices[self._generate_unop_builtin] = 1.0 choices[self._generate_one_hot_select_builtin] = 1.0 choices[self._generate_number] = 1.0 choices[self._generate_bit_slice] = 1.0 if not self._codegen_ops_only: choices[self._generate_bitwise_reduction] = 1.0 choices[self._generate_cast_bits_to_array] = 1.0 # If maps recurse with equal probability, then the output will grow # exponentially with level, so we need to scale inversely. choices[lambda env: self._generate_map(level, env)] = 1.0 / (10**level) rng_choices = getattr(self.rng, 'choices') while True: expr_generator = rng_choices( population=list(choices.keys()), weights=list(choices.values()), k=1)[0] try: rhs, rhs_type = expr_generator(env) except EmptyEnvError: # Try a different generator that may be more accepting of env values. del choices[expr_generator] if not choices: # If we ran out of things to try, bail. return self._generate_retval(env) continue else: break new_env = collections.OrderedDict(env) new_env[identifier] = ( lambda: self._make_name_ref(name_def)), rhs_type, False body, body_type = self._generate_expr(new_env, level + 1) name_def_tree = ast.NameDefTree(self.m, self.fake_span, name_def) let = ast.Let( self.m, self.fake_span, name_def_tree, rhs_type, rhs, body, const=None) return let, body_type else: # Should not nest any more -- select return values. return self._generate_retval(env)
def test_visit_unop(self): fake_span = self.fake_span m = self.m i_def = ast.NameDef(m, fake_span, 'i') i_ref = ast.NameRef(m, fake_span, 'i', i_def) negated = ast.Unop(m, fake_span, ast.UnopKind.NEG, i_ref) c = _Collector() visit(negated, c) self.assertEqual(c.collected, [i_ref, negated])
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_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 generate_function(self, name: Text, level: int = 0, param_count: int = None) -> ast.Function: if param_count is None: param_count = int(math.ceil(self.rng.weibullvariate(1, 1.15) * 4)) params = self._generate_params(param_count) body, body_type = self._generate_body(level, params) return ast.Function(self.m, self.fake_span, ast.NameDef(self.m, self.fake_span, name), parametric_bindings=(), params=params, return_type=body_type, body=body, public=False)
def _generate_param(self) -> ast.Param: identifier = self.gensym() type_ = self._generate_bits_type() name_def = ast.NameDef(self.m, self.fake_span, identifier) return ast.Param(self.m, name_def, type_)
def _make_name_def(self, identifier: Text) -> ast.NameDef: return ast.NameDef(self.m, self.fake_span, identifier)