def validate_get_or_set(self, subscript: ast.Subscript, index_node: ast.Index) -> IType: """ Verifies if the subscribed value is a sequence and if the index is valid to this sequence :param subscript: the python ast subscript node :param index_node: the subscript index :return: the type of the accessed value if it is valid. Type.none otherwise. """ value = self.visit(subscript.value) index = self.visit(index_node) if isinstance(value, ast.Name): value = self.get_symbol(value.id) if isinstance(index, ast.Name): index = self.get_symbol(index.id) if not isinstance(index, tuple): index = (index,) # if it is a type hint, returns the outer type if isinstance(value, IType) and all(isinstance(i, IType) for i in index): return value symbol_type: IType = self.get_type(value) index_type: IType = self.get_type(index[0]) # only sequence types can be subscribed if not isinstance(symbol_type, Collection): self._log_error( CompilerError.UnresolvedOperation( subscript.lineno, subscript.col_offset, type_id=symbol_type.identifier, operation_id=Operator.Subscript) ) return symbol_type # the sequence can't use the given type as index if not symbol_type.is_valid_key(index_type): self._log_error( CompilerError.MismatchedTypes( subscript.lineno, subscript.col_offset, actual_type_id=index_type.identifier, expected_type_id=symbol_type.valid_key.identifier) ) # it is setting a value in a sequence that doesn't allow reassign values elif isinstance(subscript.ctx, ast.Store) and not symbol_type.can_reassign_values: self._log_error( CompilerError.UnresolvedOperation( subscript.lineno, subscript.col_offset, type_id=symbol_type.identifier, operation_id=Operator.Subscript) ) return symbol_type.item_type
def validate_slice(self, subscript: ast.Subscript, slice_node: ast.Slice) -> IType: """ Verifies if the subscribed value is a sequence and if the slice is valid to this sequence :param subscript: the python ast subscript node :param slice_node: the subscript slice :return: the type of the accessed value if it is valid. Type.none otherwise. """ value = self.visit(subscript.value) lower, upper, step = (self.get_type(value) for value in self.visit(slice_node)) if step is not Type.none: # TODO: remove when slices with stride are implemented raise NotImplementedError # is not allowed to store into a slice if isinstance(subscript.ctx, ast.Store): self._log_error( CompilerError.NotSupportedOperation( subscript.lineno, subscript.col_offset, symbol_id=Operator.Subscript ) ) symbol_type: IType = self.get_type(value) # only collection types can be subscribed if not isinstance(symbol_type, Collection): self._log_error( CompilerError.UnresolvedOperation( subscript.lineno, subscript.col_offset, type_id=symbol_type.identifier, operation_id=Operator.Subscript) ) return Type.none lower = lower if lower is not Type.none else symbol_type.valid_key upper = upper if upper is not Type.none else symbol_type.valid_key # TODO: remove when slices of other sequence types are implemented if (not symbol_type.is_valid_key(lower) or not symbol_type.is_valid_key(upper) or (step is not Type.none and not symbol_type.is_valid_key(step)) ): actual: Tuple[IType, ...] = (lower, upper) if step is Type.none else (lower, upper, step) self._log_error( CompilerError.MismatchedTypes( subscript.lineno, subscript.col_offset, expected_type_id=[symbol_type.valid_key.identifier for value in actual], actual_type_id=[value.identifier for value in actual] ) ) else: return symbol_type return Type.none