Skip to content

Commit

Permalink
chore: replace occurences of 'enum' by 'flag' (#3794)
Browse files Browse the repository at this point in the history
  • Loading branch information
trocher authored Feb 20, 2024
1 parent d5e8bd8 commit bc57775
Show file tree
Hide file tree
Showing 10 changed files with 32 additions and 32 deletions.
2 changes: 1 addition & 1 deletion docs/resources.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Frameworks and tooling
- `VyperDeployer – A helper smart contract to compile and test Vyper contracts in Foundry <https://github.com/pcaversaccio/snekmate/blob/main/lib/utils/VyperDeployer.sol>`_
- `🐍 snekmate – Vyper smart contract building blocks <https://github.com/pcaversaccio/snekmate>`_
- `Serpentor – A set of smart contracts tools for governance <https://github.com/yearn/serpentor>`_
- `Smart contract development frameworks and tools for Vyper on Ethreum.org <https://ethereum.org/en/developers/docs/programming-languages/python/>`_
- `Smart contract development frameworks and tools for Vyper on Ethereum.org <https://ethereum.org/en/developers/docs/programming-languages/python/>`_
- `Vyper Online Compiler - an online platform for compiling and deploying Vyper smart contracts <https://github.com/0x0077/vyper-online-compiler>`_

Security
Expand Down
2 changes: 1 addition & 1 deletion docs/types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,6 @@ All type conversions in Vyper must be made explicitly using the built-in ``conve
* Narrowing conversions (e.g., ``int256 -> int128``) check that the input is in bounds for the output type.
* Converting between bytes and int types results in sign-extension if the output type is signed. For instance, converting ``0xff`` (``bytes1``) to ``int8`` returns ``-1``.
* Converting between bytes and int types which have different sizes follows the rule of going through the closest integer type, first. For instance, ``bytes1 -> int16`` is like ``bytes1 -> int8 -> int16`` (signextend, then widen). ``uint8 -> bytes20`` is like ``uint8 -> uint160 -> bytes20`` (rotate left 12 bytes).
* Enums can be converted to and from ``uint256`` only.
* Flags can be converted to and from ``uint256`` only.

A small Python reference implementation is maintained as part of Vyper's test suite, it can be found `here <https://github.com/vyperlang/vyper/blob/c4c6afd07801a0cc0038cdd4007cc43860c54193/tests/parser/functions/test_convert.py#L318>`__. The motivation and more detailed discussion of the rules can be found `here <https://github.com/vyperlang/vyper/issues/2507>`__.
10 changes: 5 additions & 5 deletions vyper/builtins/_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def _to_int(expr, arg, out_typ):
elif is_flag_type(arg.typ):
if out_typ != UINT256_T:
_FAIL(arg.typ, out_typ, expr)
# pretend enum is uint256
# pretend flag is uint256
arg = IRnode.from_list(arg, typ=UINT256_T)
# use int_to_int rules
arg = _int_to_int(arg, out_typ)
Expand Down Expand Up @@ -442,12 +442,12 @@ def to_bytes(expr, arg, out_typ):


@_input_types(IntegerT)
def to_enum(expr, arg, out_typ):
def to_flag(expr, arg, out_typ):
if arg.typ != UINT256_T:
_FAIL(arg.typ, out_typ, expr)

if len(out_typ._enum_members) < 256:
arg = int_clamp(arg, bits=len(out_typ._enum_members), signed=False)
if len(out_typ._flag_members) < 256:
arg = int_clamp(arg, bits=len(out_typ._flag_members), signed=False)

return IRnode.from_list(arg, typ=out_typ)

Expand All @@ -469,7 +469,7 @@ def convert(expr, context):
elif out_typ == AddressT():
ret = to_address(arg_ast, arg, out_typ)
elif is_flag_type(out_typ):
ret = to_enum(arg_ast, arg, out_typ)
ret = to_flag(arg_ast, arg, out_typ)
elif is_integer_type(out_typ):
ret = to_int(arg_ast, arg, out_typ)
elif is_bytes_m_type(out_typ):
Expand Down
4 changes: 2 additions & 2 deletions vyper/codegen/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ def needs_clamp(t, encoding):
if isinstance(t, (_BytestringT, DArrayT)):
return True
if isinstance(t, FlagT):
return len(t._enum_members) < 256
return len(t._flag_members) < 256
if isinstance(t, SArrayT):
return needs_clamp(t.value_type, encoding)
if is_tuple_like(t):
Expand Down Expand Up @@ -1132,7 +1132,7 @@ def clamp_basetype(ir_node):
ir_node = unwrap_location(ir_node)

if isinstance(t, FlagT):
bits = len(t._enum_members)
bits = len(t._flag_members)
# assert x >> bits == 0
ret = int_clamp(ir_node, bits, signed=False)

Expand Down
12 changes: 6 additions & 6 deletions vyper/codegen/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,15 +212,15 @@ def parse_Name(self):
def parse_Attribute(self):
typ = self.expr._metadata["type"]

# MyEnum.foo
# MyFlag.foo
if (
isinstance(typ, FlagT)
and isinstance(self.expr.value, vy_ast.Name)
and typ.name == self.expr.value.id
):
# 0, 1, 2, .. 255
enum_id = typ._enum_members[self.expr.attr]
value = 2**enum_id # 0 => 0001, 1 => 0010, 2 => 0100, etc.
flag_id = typ._flag_members[self.expr.attr]
value = 2**flag_id # 0 => 0001, 1 => 0010, 2 => 0100, etc.
return IRnode.from_list(value, typ=typ)

# x.balance: balance of address x
Expand Down Expand Up @@ -420,7 +420,7 @@ def parse_BinOp(self):
op = shr if not left.typ.is_signed else sar
return IRnode.from_list(op(right, left), typ=new_typ)

# enums can only do bit ops, not arithmetic.
# flags can only do bit ops, not arithmetic.
assert is_numeric_type(left.typ)

with left.cache_when_complex("x") as (b1, x), right.cache_when_complex("y") as (b2, y):
Expand Down Expand Up @@ -645,10 +645,10 @@ def parse_UnaryOp(self):

if isinstance(self.expr.op, vy_ast.Invert):
if isinstance(operand.typ, FlagT):
n_members = len(operand.typ._enum_members)
n_members = len(operand.typ._flag_members)
# use (xor 0b11..1 operand) to flip all the bits in
# `operand`. `mask` could be a very large constant and
# hurt codesize, but most user enums will likely have few
# hurt codesize, but most user flags will likely have few
# enough members that the mask will not be large.
mask = (2**n_members) - 1
return IRnode.from_list(["xor", mask, operand], typ=operand.typ)
Expand Down
2 changes: 1 addition & 1 deletion vyper/semantics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Vyper abstract syntax tree (AST).
* [`primitives.py`](types/primitives.py): Address, boolean, fixed length byte, integer and decimal types
* [`shortcuts.py`](types/shortcuts.py): Helper constants for commonly used types
* [`subscriptable.py`](types/subscriptable.py): Mapping, array and tuple types
* [`user.py`](types/user.py): Enum, event, interface and struct types
* [`user.py`](types/user.py): Flag, event, interface and struct types
* [`utils.py`](types/utils.py): Functions for generating and fetching type objects
* [`analysis/`](analysis): Subpackage for type checking and syntax verification logic
* [`annotation.py`](analysis/annotation.py): Annotates statements and expressions with the appropriate type information
Expand Down
2 changes: 1 addition & 1 deletion vyper/semantics/analysis/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ def visit_Compare(self, node: vy_ast.Compare, typ: VyperType) -> None:
else:
rtyp = get_exact_type_from_node(node.right)
if isinstance(rtyp, FlagT):
# enum membership - `some_enum in other_enum`
# flag membership - `some_flag in other_flag`
ltyp = rtyp
else:
# array membership - `x in my_list_variable`
Expand Down
2 changes: 1 addition & 1 deletion vyper/semantics/analysis/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ def types_from_Name(self, node):
# when this is a type, we want to lower it
if isinstance(t, VyperType):
# TYPE_T is used to handle cases where a type can occur in call or
# attribute conditions, like Enum.foo or MyStruct({...})
# attribute conditions, like Flag.foo or MyStruct({...})
return [TYPE_T(t)]

return [t.typ]
Expand Down
2 changes: 1 addition & 1 deletion vyper/semantics/types/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ def infer_kwarg_types(self, node):
raise StructureException("Value is not callable", node)

# dispatch into get_type_member if it's dereferenced, ex.
# MyEnum.FOO
# MyFlag.FOO
def get_member(self, key, node):
if hasattr(self.typedef, "get_type_member"):
return self.typedef.get_type_member(key, node)
Expand Down
26 changes: 13 additions & 13 deletions vyper/semantics/types/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,23 @@ def __hash__(self):
return hash(id(self))


# note: enum behaves a lot like uint256, or uints in general.
# note: flag behaves a lot like uint256, or uints in general.
class FlagT(_UserType):
# this is a carveout because currently we allow dynamic arrays of
# enums, but not static arrays of enums
# flags, but not static arrays of flags
_as_darray = True
_is_prim_word = True
_as_hashmap_key = True

def __init__(self, name: str, members: dict) -> None:
if len(members.keys()) > 256:
raise FlagDeclarationException("Enums are limited to 256 members!")
raise FlagDeclarationException("Flags are limited to 256 members!")

super().__init__(members=None)

self._id = name

self._enum_members = members
self._flag_members = members

# use a VyperType for convenient access to the `get_member` function
# also conveniently checks well-formedness of the members namespace
Expand All @@ -74,8 +74,8 @@ def get_type_member(self, key: str, node: vy_ast.VyperNode) -> "VyperType":
return self

def __repr__(self):
arg_types = ",".join(repr(a) for a in self._enum_members)
return f"enum {self.name}({arg_types})"
arg_types = ",".join(repr(a) for a in self._flag_members)
return f"flag {self.name}({arg_types})"

@property
def abi_type(self):
Expand Down Expand Up @@ -107,29 +107,29 @@ def validate_comparator(self, node):
@classmethod
def from_FlagDef(cls, base_node: vy_ast.FlagDef) -> "FlagT":
"""
Generate an `Enum` object from a Vyper ast node.
Generate an `Flag` object from a Vyper ast node.
Arguments
---------
base_node : EnumDef
Vyper ast node defining the enum
base_node : FlagDef
Vyper ast node defining the flag
Returns
-------
Enum
Flag
"""
members: dict = {}

if len(base_node.body) == 1 and isinstance(base_node.body[0], vy_ast.Pass):
raise FlagDeclarationException("Enum must have members", base_node)
raise FlagDeclarationException("Flag must have members", base_node)

for i, node in enumerate(base_node.body):
if not isinstance(node, vy_ast.Expr) or not isinstance(node.value, vy_ast.Name):
raise FlagDeclarationException("Invalid syntax for enum member", node)
raise FlagDeclarationException("Invalid syntax for flag member", node)

member_name = node.value.id
if member_name in members:
raise FlagDeclarationException(
f"Enum member '{member_name}' has already been declared", node.value
f"Flag member '{member_name}' has already been declared", node.value
)

members[member_name] = i
Expand Down

0 comments on commit bc57775

Please sign in to comment.