def _generate_array_concat( self, env: Env) -> Tuple[ast.Expr, ast.TypeAnnotation]: """Returns a binary concatenation of two arrays in env. The two arrays to concatenate in env will have the same element type. Args: env: Environment of values that can be selected from for array concatenation. Precondition: There must be an array value present in env. """ make_lhs, lhs_type = self._choose_env_value( env, lambda t: isinstance(t, ast.ArrayTypeAnnotation)) assert isinstance(lhs_type, ast.ArrayTypeAnnotation), lhs_type def array_same_elem_type(t: ast.TypeAnnotation) -> bool: return (isinstance(t, ast.ArrayTypeAnnotation) and t.element_type == lhs_type.element_type) make_rhs, rhs_type = self._choose_env_value(env, array_same_elem_type) token = scanner.Token(ast.Binop.CONCAT, self.fake_span, ast.Binop.CONCAT.value) result = ast.Binop(token, make_lhs(), make_rhs()) lhs_size = self._get_array_size(lhs_type) bits_per_elem = self._get_type_bit_count(lhs_type) // lhs_size result_size = lhs_size + self._get_array_size(rhs_type) dim = self._make_number(result_size, None) result_type = ast.ArrayTypeAnnotation(self.fake_span, lhs_type.element_type, dim) self._type_bit_counts[str(result_type)] = bits_per_elem * result_size return (result, result_type)
def make_builtin_type_annotation( owner: ast.AstNodeOwner, span: span_mod.Span, tok: scanner.Token, dims: Tuple[ast.Expr, ...]) -> ast.TypeAnnotation: elem_type = ast.BuiltinTypeAnnotation(owner, span, tok_to_builtin_type(tok)) for dim in dims: elem_type = ast.ArrayTypeAnnotation(owner, span, elem_type, dim) return elem_type
def _generate_map(self, level, env: Env) -> Tuple[ast.Invocation, ast.TypeAnnotation]: """Generates an invocation of the map builtin.""" map_fn_name = self.gensym() # generate_function, in turn, can call generate_map, so we need some way of # bounding the recursion. To limit explosion, we increase level by three # (chosen empirically) instead of just one. map_fn = self.generate_function(map_fn_name, level + 3, param_count=1) self._functions.append(map_fn) map_arg_signedness, map_arg_bits = builtin_type_to_signedness_and_bits( map_fn.params[0].type_) array_size = self.rng.randrange( 1, max(2, self.options.max_width_aggregate_types // map_arg_bits)) return_type = self._make_array_type(map_fn.return_type, array_size) # Seems pretty unlikely that we'll have the exact array we need, so we'll # just create one. # TODO(b/144724970): Consider creating arrays from values in the env. def get_number(): return self._generate_number(env, map_arg_bits, map_arg_signedness) args = self._make_constant_array( tuple(get_number()[0] for i in range(array_size))) args.type_ = ast.ArrayTypeAnnotation( self.fake_span, map_fn.params[0].type_, self._make_number(array_size, None)) fn_ref = self._make_name_ref(self._make_name_def(map_fn_name)) invocation = ast.Invocation(self.fake_span, self._builtin_name_ref('map'), (args, fn_ref)) return invocation, return_type
def make_type_ref_type_annotation( owner: ast.AstNodeOwner, span: span_mod.Span, type_ref: ast.TypeRef, dims: Tuple[ast.Expr, ...], parametrics: Optional[Tuple[ast.Expr, ...]] = None) -> ast.TypeAnnotation: """Creates a type ref annotation that may be wrapped in array dimensions.""" assert dims is not None, dims elem_type = ast.TypeRefTypeAnnotation(owner, span, type_ref, parametrics) for dim in dims: elem_type = ast.ArrayTypeAnnotation(owner, span, elem_type, dim) return elem_type