def get_index_type(self, node): if isinstance(node, vy_ast.Int): if node.value < 0: raise ArrayIndexException("Vyper does not support negative indexing", node) if node.value < 0 or node.value >= self.length: raise ArrayIndexException("Index out of range", node) return self.value_type
def validate_index_type(self, node): if not isinstance(node, vy_ast.Int): raise InvalidType("Tuple indexes must be literals", node) if node.value < 0: raise ArrayIndexException("Vyper does not support negative indexing", node) if node.value >= self.length: raise ArrayIndexException("Index out of range", node)
def validate_index_type(self, node): if isinstance(node, vy_ast.Int): if node.value < 0: raise ArrayIndexException("Vyper does not support negative indexing", node) if node.value >= self.length: raise ArrayIndexException("Index out of range", node) else: validation.utils.validate_expected_type(node, IntegerAbstractType())
def get_index_value(node: vy_ast.Index) -> int: """ Return the literal value for a `Subscript` index. Arguments --------- node : vy_ast.Index Vyper ast node from the `slice` member of a Subscript node. Must be an `Index` object (Vyper does not support `Slice` or `ExtSlice`). Returns ------- int Literal integer value. """ if not isinstance(node.get("value"), vy_ast.Int): if hasattr(node, "value"): # even though the subscript is an invalid type, first check if it's a valid _something_ # this gives a more accurate error in case of e.g. a typo in a constant variable name try: get_possible_types_from_node(node.value) except StructureException: # StructureException is a very broad error, better to raise InvalidType in this case pass raise InvalidType("Subscript must be a literal integer", node) if node.value.value <= 0: raise ArrayIndexException("Subscript must be greater than 0", node) return node.value.value
def get_index_value(node: vy_ast.Index) -> int: """ Return the literal value for a `Subscript` index. Arguments --------- node : vy_ast.Index Vyper ast node from the `slice` member of a Subscript node. Must be an `Index` object (Vyper does not support `Slice` or `ExtSlice`). Returns ------- int Literal integer value. """ if not isinstance(node.get("value"), vy_ast.Int): raise InvalidType("Subscript must be a literal integer", node) if node.value.value <= 0: raise ArrayIndexException("Subscript must be greater than 0", node) return node.value.value
def add_variable_offset(parent, key, pos, array_bounds_check=True): typ, location = parent.typ, parent.location if isinstance(typ, TupleLike): if isinstance(typ, StructType): if not isinstance(key, str): raise TypeMismatch( f"Expecting a member variable access; cannot access element {key}", pos) if key not in typ.members: raise TypeMismatch( f"Object does not have member variable {key}", pos) subtype = typ.members[key] attrs = list(typ.tuple_keys()) if key not in attrs: raise TypeMismatch( f"Member {key} not found. Only the following available: " + " ".join(attrs), pos) index = attrs.index(key) annotation = key else: if not isinstance(key, int): raise TypeMismatch( f"Expecting a static index; cannot access element {key}", pos) attrs = list(range(len(typ.members))) index = key annotation = None if location == 'storage': return LLLnode.from_list( [ 'add', ['sha3_32', parent], LLLnode.from_list(index, annotation=annotation) ], typ=subtype, location='storage', ) elif location == 'storage_prehashed': return LLLnode.from_list( [ 'add', parent, LLLnode.from_list(index, annotation=annotation) ], typ=subtype, location='storage', ) elif location in ('calldata', 'memory'): offset = 0 for i in range(index): offset += 32 * get_size_of_type(typ.members[attrs[i]]) return LLLnode.from_list(['add', offset, parent], typ=typ.members[key], location=location, annotation=annotation) else: raise TypeMismatch("Not expecting a member variable access", pos) elif isinstance(typ, MappingType): if isinstance(key.typ, ByteArrayLike): if not isinstance(typ.keytype, ByteArrayLike) or ( typ.keytype.maxlen < key.typ.maxlen): raise TypeMismatch( "Mapping keys of bytes cannot be cast, use exact same bytes type of: " f"{str(typ.keytype)}", pos, ) subtype = typ.valuetype if len(key.args[0].args) >= 3: # handle bytes literal. sub = LLLnode.from_list([ 'seq', key, [ 'sha3', ['add', key.args[0].args[-1], 32], ['mload', key.args[0].args[-1]] ] ]) else: sub = LLLnode.from_list([ 'sha3', ['add', key.args[0].value, 32], ['mload', key.args[0].value] ]) else: subtype = typ.valuetype sub = base_type_conversion(key, key.typ, typ.keytype, pos=pos) if location == 'storage': return LLLnode.from_list(['sha3_64', parent, sub], typ=subtype, location='storage') elif location in ('memory', 'calldata'): raise TypeMismatch( "Can only have fixed-side arrays in memory, not mappings", pos) elif isinstance(typ, ListType): subtype = typ.subtype k = unwrap_location(key) if not is_base_type(key.typ, ('int128', 'uint256')): raise TypeMismatch(f'Invalid type for array index: {key.typ}', pos) if not array_bounds_check: sub = k elif key.typ.is_literal: # note: BaseType always has is_literal attr # perform the check at compile time and elide the runtime check. if key.value < 0 or key.value >= typ.count: raise ArrayIndexException( 'Array index determined to be out of bounds. ' f'Index is {key.value} but array size is {typ.count}', pos) sub = k else: # this works, even for int128. for int128, since two's-complement # is used, if the index is negative, (unsigned) LT will interpret # it as a very large number, larger than any practical value for # an array index, and the clamp will throw an error. sub = ['uclamplt', k, typ.count] if location == 'storage': return LLLnode.from_list(['add', ['sha3_32', parent], sub], typ=subtype, location='storage', pos=pos) elif location == 'storage_prehashed': return LLLnode.from_list(['add', parent, sub], typ=subtype, location='storage', pos=pos) elif location in ('calldata', 'memory'): offset = 32 * get_size_of_type(subtype) return LLLnode.from_list(['add', ['mul', offset, sub], parent], typ=subtype, location=location, pos=pos) else: raise TypeMismatch("Not expecting an array access ", pos) else: raise TypeMismatch( f"Cannot access the child of a constant variable! {typ}", pos)