def _generate_bit_slice(self, env: Env) -> Tuple[ast.Index, ast.TypeAnnotation]: """Generates a bit slice AST node.""" make_arg, arg_type = self._choose_env_value(env, self._not_tuple_or_array) bit_count = self._get_type_bit_count(arg_type) slice_type = self.rng.choice(['bit_slice', 'width_slice', 'dynamic_slice']) while True: start_low = 0 if slice_type == 'width_slice' else -bit_count - 1 start = ( self.rng.randrange(start_low, bit_count + 1) if self.rng.choice( (True, False)) else None) limit = ( self.rng.randrange(-bit_count - 1, bit_count + 1) if self.rng.choice( (True, False)) else None) _, width = bit_helpers.resolve_bit_slice_indices(bit_count, start, limit) if width <= 0: # Make sure we produce non-zero-width things. continue else: break if slice_type == 'width_slice': index_slice = ast.WidthSlice(self.m, self.fake_span, self._make_number(start or 0, None), self._make_type_annotation(False, width)) elif slice_type == 'bit_slice': index_slice = ast.Slice( self.m, self.fake_span, None if start is None else self._make_number(start, None), None if limit is None else self._make_number(limit, None)) else: start_arg, _ = self._choose_env_value(env, self._is_unsigned_bit_vector) index_slice = ast.WidthSlice(self.m, self.fake_span, start_arg(), self._make_type_annotation(False, width)) type_ = self._make_type_annotation(False, width) return (ast.Index(self.m, self.fake_span, make_arg(), index_slice), type_)
def _deduce_slice_type(self: ast.Index, ctx: DeduceCtx, lhs_type: ConcreteType) -> ConcreteType: """Deduces the concrete type of an Index AST node with a slice spec.""" index_slice = self.index assert isinstance(index_slice, (ast.Slice, ast.WidthSlice)), index_slice # TODO(leary): 2019-10-28 Only slicing bits types for now, and only with # number ast nodes, generalize to arrays and constant expressions. if not isinstance(lhs_type, BitsType): raise XlsTypeError(self.span, lhs_type, None, 'Value to slice is not of "bits" type.') bit_count = lhs_type.get_total_bit_count() if isinstance(index_slice, ast.WidthSlice): start = index_slice.start if isinstance(start, ast.Number) and start.type_ is None: start_type = lhs_type.to_ubits() resolved_start_type = resolve(start_type, ctx) if not bit_helpers.fits_in_bits( start.get_value_as_int(), resolved_start_type.get_total_bit_count()): raise TypeInferenceError( start.span, resolved_start_type, 'Cannot fit {} in {} bits (inferred from bits to slice).'. format(start.get_value_as_int(), resolved_start_type.get_total_bit_count())) ctx.type_info[start] = start_type else: start_type = deduce(start, ctx) # Check the start is unsigned. if start_type.signed: raise TypeInferenceError( start.span, type_=start_type, suffix='Start index for width-based slice must be unsigned.') width_type = deduce(index_slice.width, ctx) if isinstance(width_type.get_total_bit_count(), int) and isinstance( lhs_type.get_total_bit_count(), int) and width_type.get_total_bit_count( ) > lhs_type.get_total_bit_count(): raise XlsTypeError( start.span, lhs_type, width_type, 'Slice type must have <= original number of bits; attempted slice from {} to {} bits.' .format(lhs_type.get_total_bit_count(), width_type.get_total_bit_count())) # Check the width type is bits-based (no enums, since value could be out # of range of the enum values). if not isinstance(width_type, BitsType): raise TypeInferenceError( self.span, type_=width_type, suffix='Require a bits-based type for width-based slice.') # The width type is the thing returned from the width-slice. return width_type assert isinstance(index_slice, ast.Slice), index_slice limit = index_slice.limit.get_value_as_int() if index_slice.limit else None # PyType has trouble figuring out that start is definitely an Number at this # point. start = index_slice.start assert isinstance(start, (ast.Number, type(None))) start = start.get_value_as_int() if start else None _, fn_symbolic_bindings = ctx.fn_stack[-1] if isinstance(bit_count, ParametricExpression): bit_count = bit_count.evaluate(fn_symbolic_bindings) start, width = bit_helpers.resolve_bit_slice_indices( bit_count, start, limit) key = tuple(fn_symbolic_bindings.items()) ctx.type_info.add_slice_start_width(index_slice, key, (start, width)) return BitsType(signed=False, size=width)