We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Cannot use empty for an array inside an event log
### What's your issue about?

The following code:

```python
event Foo:
    a: bytes32[2]

@external
def test():
    log Foo(empty(bytes32[2]))
```

Produces the following error:

```python
File "/home/computer/code/python/vyper/vyper/parser/events.py", line 208, in pack_args_by_32
    for arg2 in arg.elements:
AttributeError: 'LLLnode' object has no attribute 'elements'
```

The issue happens with any array type.

### How can it be fixed?
I think that this code should compile, so we need to look at what's happening in parser that prevents it.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `vyper/parser/events.py`
Content:
```
1 from vyper import ast as vy_ast
2 from vyper.exceptions import TypeMismatch
3 from vyper.parser.expr import Expr
4 from vyper.parser.lll_node import LLLnode
5 from vyper.parser.parser_utils import (
6     base_type_conversion,
7     getpos,
8     make_byte_array_copier,
9     make_setter,
10     unwrap_location,
11     zero_pad,
12 )
13 from vyper.types.types import (
14     BaseType,
15     ByteArrayLike,
16     ListType,
17     get_size_of_type,
18 )
19 from vyper.utils import bytes_to_int, ceil32, keccak256
20 
21 
22 def pack_logging_topics(event_id, args, expected_topics, context, pos):
23     topics = [event_id]
24     code_pos = pos
25     for pos, expected_topic in enumerate(expected_topics):
26         expected_type = expected_topic.typ
27         arg = args[pos]
28         value = Expr(arg, context).lll_node
29         arg_type = value.typ
30 
31         if isinstance(arg_type, ByteArrayLike) and isinstance(expected_type, ByteArrayLike):
32             if arg_type.maxlen > expected_type.maxlen:
33                 raise TypeMismatch(
34                     f"Topic input bytes are too big: {arg_type} {expected_type}", code_pos
35                 )
36 
37             if isinstance(arg, (vy_ast.Str, vy_ast.Bytes)):
38                 # for literals, generate the topic at compile time
39                 value = arg.value
40                 if isinstance(value, str):
41                     value = value.encode()
42                 topics.append(bytes_to_int(keccak256(value)))
43 
44             elif value.location == "memory":
45                 topics.append(["sha3", ["add", value, 32], ["mload", value]])
46 
47             else:
48                 # storage or calldata
49                 placeholder = context.new_internal_variable(value.typ)
50                 placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location="memory")
51                 copier = make_byte_array_copier(
52                     placeholder_node,
53                     LLLnode.from_list("_sub", typ=value.typ, location=value.location),
54                 )
55                 lll_node = [
56                     "with",
57                     "_sub",
58                     value,
59                     ["seq", copier, ["sha3", ["add", placeholder, 32], ["mload", placeholder]]],
60                 ]
61                 topics.append(lll_node)
62 
63         elif isinstance(arg_type, ListType) and isinstance(expected_type, ListType):
64             size = get_size_of_type(value.typ) * 32
65             if value.location == "memory":
66                 topics.append(["sha3", value, size])
67 
68             else:
69                 # storage or calldata
70                 placeholder = context.new_internal_variable(value.typ)
71                 placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location="memory")
72                 setter = make_setter(placeholder_node, value, "memory", value.pos)
73                 lll_node = ["seq", setter, ["sha3", placeholder, size]]
74                 topics.append(lll_node)
75 
76         else:
77             if arg_type != expected_type:
78                 raise TypeMismatch(
79                     f"Invalid type for logging topic, got {arg_type} expected {expected_type}",
80                     value.pos,
81                 )
82             value = unwrap_location(value)
83             value = base_type_conversion(value, arg_type, expected_type, pos=code_pos)
84             topics.append(value)
85 
86     return topics
87 
88 
89 def pack_args_by_32(
90     holder,
91     maxlen,
92     arg,
93     typ,
94     context,
95     placeholder,
96     dynamic_offset_counter=None,
97     datamem_start=None,
98     pos=None,
99 ):
100     """
101     Copy necessary variables to pre-allocated memory section.
102 
103     :param holder: Complete holder for all args
104     :param maxlen: Total length in bytes of the full arg section (static + dynamic).
105     :param arg: Current arg to pack
106     :param context: Context of arg
107     :param placeholder: Static placeholder for static argument part.
108     :param dynamic_offset_counter: position counter stored in static args.
109     :param dynamic_placeholder: pointer to current position in memory to write dynamic values to.
110     :param datamem_start: position where the whole datemem section starts.
111     """
112 
113     if isinstance(typ, BaseType):
114         if isinstance(arg, LLLnode):
115             value = unwrap_location(arg)
116         else:
117             value = Expr(arg, context).lll_node
118             value = base_type_conversion(value, value.typ, typ, pos)
119         holder.append(LLLnode.from_list(["mstore", placeholder, value], typ=typ, location="memory"))
120     elif isinstance(typ, ByteArrayLike):
121 
122         if isinstance(arg, LLLnode):  # Is prealloacted variable.
123             source_lll = arg
124         else:
125             source_lll = Expr(arg, context).lll_node
126 
127         # Set static offset, in arg slot.
128         holder.append(LLLnode.from_list(["mstore", placeholder, ["mload", dynamic_offset_counter]]))
129         # Get the biginning to write the ByteArray to.
130         dest_placeholder = LLLnode.from_list(
131             ["add", datamem_start, ["mload", dynamic_offset_counter]],
132             typ=typ,
133             location="memory",
134             annotation="pack_args_by_32:dest_placeholder",
135         )
136         copier = make_byte_array_copier(dest_placeholder, source_lll, pos=pos)
137         holder.append(copier)
138         # Add zero padding.
139         holder.append(zero_pad(dest_placeholder))
140 
141         # Increment offset counter.
142         increment_counter = LLLnode.from_list(
143             [
144                 "mstore",
145                 dynamic_offset_counter,
146                 [
147                     "add",
148                     [
149                         "add",
150                         ["mload", dynamic_offset_counter],
151                         ["ceil32", ["mload", dest_placeholder]],
152                     ],
153                     32,
154                 ],
155             ],
156             annotation="Increment dynamic offset counter",
157         )
158         holder.append(increment_counter)
159     elif isinstance(typ, ListType):
160         maxlen += (typ.count - 1) * 32
161         typ = typ.subtype
162 
163         def check_list_type_match(provided):  # Check list types match.
164             if provided != typ:
165                 raise TypeMismatch(
166                     f"Log list type '{provided}' does not match provided, expected '{typ}'"
167                 )
168 
169         # NOTE: Below code could be refactored into iterators/getter functions for each type of
170         #       repetitive loop. But seeing how each one is a unique for loop, and in which way
171         #       the sub value makes the difference in each type of list clearer.
172 
173         # List from storage
174         if isinstance(arg, vy_ast.Attribute) and arg.value.id == "self":
175             stor_list = context.globals[arg.attr]
176             check_list_type_match(stor_list.typ.subtype)
177             size = stor_list.typ.count
178             mem_offset = 0
179             for i in range(0, size):
180                 storage_offset = i
181                 arg2 = LLLnode.from_list(
182                     ["sload", ["add", ["sha3_32", Expr(arg, context).lll_node], storage_offset]],
183                     typ=typ,
184                 )
185                 holder, maxlen = pack_args_by_32(
186                     holder, maxlen, arg2, typ, context, placeholder + mem_offset, pos=pos,
187                 )
188                 mem_offset += get_size_of_type(typ) * 32
189 
190         # List from variable.
191         elif isinstance(arg, vy_ast.Name):
192             size = context.vars[arg.id].size
193             pos = context.vars[arg.id].pos
194             check_list_type_match(context.vars[arg.id].typ.subtype)
195             mem_offset = 0
196             for _ in range(0, size):
197                 arg2 = LLLnode.from_list(
198                     pos + mem_offset, typ=typ, location=context.vars[arg.id].location
199                 )
200                 holder, maxlen = pack_args_by_32(
201                     holder, maxlen, arg2, typ, context, placeholder + mem_offset, pos=pos,
202                 )
203                 mem_offset += get_size_of_type(typ) * 32
204 
205         # List from list literal.
206         else:
207             mem_offset = 0
208             for arg2 in arg.elements:
209                 holder, maxlen = pack_args_by_32(
210                     holder, maxlen, arg2, typ, context, placeholder + mem_offset, pos=pos,
211                 )
212                 mem_offset += get_size_of_type(typ) * 32
213     return holder, maxlen
214 
215 
216 # Pack logging data arguments
217 def pack_logging_data(expected_data, args, context, pos):
218     # Checks to see if there's any data
219     if not args:
220         return ["seq"], 0, None, 0
221     holder = ["seq"]
222     maxlen = len(args) * 32  # total size of all packed args (upper limit)
223 
224     # Unroll any function calls, to temp variables.
225     prealloacted = {}
226     for idx, (arg, _expected_arg) in enumerate(zip(args, expected_data)):
227 
228         if isinstance(arg, (vy_ast.Str, vy_ast.Call)):
229             expr = Expr(arg, context)
230             source_lll = expr.lll_node
231             typ = source_lll.typ
232 
233             if isinstance(arg, vy_ast.Str):
234                 if len(arg.s) > typ.maxlen:
235                     raise TypeMismatch(f"Data input bytes are to big: {len(arg.s)} {typ}", pos)
236 
237             tmp_variable = context.new_internal_variable(source_lll.typ)
238             tmp_variable_node = LLLnode.from_list(
239                 tmp_variable,
240                 typ=source_lll.typ,
241                 pos=getpos(arg),
242                 location="memory",
243                 annotation=f"log_prealloacted {source_lll.typ}",
244             )
245             # Store len.
246             # holder.append(['mstore', len_placeholder, ['mload', unwrap_location(source_lll)]])
247             # Copy bytes.
248 
249             holder.append(
250                 make_setter(tmp_variable_node, source_lll, pos=getpos(arg), location="memory")
251             )
252             prealloacted[idx] = tmp_variable_node
253 
254     # Create internal variables for for dynamic and static args.
255     static_types = []
256     for data in expected_data:
257         static_types.append(data.typ if not isinstance(data.typ, ByteArrayLike) else BaseType(32))
258 
259     requires_dynamic_offset = any(isinstance(data.typ, ByteArrayLike) for data in expected_data)
260 
261     dynamic_offset_counter = None
262     if requires_dynamic_offset:
263         dynamic_offset_counter = context.new_internal_variable(BaseType(32))
264         dynamic_placeholder = context.new_internal_variable(BaseType(32))
265 
266     static_vars = [context.new_internal_variable(i) for i in static_types]
267 
268     # Populate static placeholders.
269     for i, (arg, data) in enumerate(zip(args, expected_data)):
270         typ = data.typ
271         placeholder = static_vars[i]
272         if not isinstance(typ, ByteArrayLike):
273             holder, maxlen = pack_args_by_32(
274                 holder, maxlen, prealloacted.get(i, arg), typ, context, placeholder, pos=pos,
275             )
276 
277     # Dynamic position starts right after the static args.
278     if requires_dynamic_offset:
279         holder.append(LLLnode.from_list(["mstore", dynamic_offset_counter, maxlen]))
280 
281     # Calculate maximum dynamic offset placeholders, used for gas estimation.
282     for _arg, data in zip(args, expected_data):
283         typ = data.typ
284         if isinstance(typ, ByteArrayLike):
285             maxlen += 32 + ceil32(typ.maxlen)
286 
287     if requires_dynamic_offset:
288         datamem_start = dynamic_placeholder + 32
289     else:
290         datamem_start = static_vars[0]
291 
292     # Copy necessary data into allocated dynamic section.
293     for i, (arg, data) in enumerate(zip(args, expected_data)):
294         typ = data.typ
295         if isinstance(typ, ByteArrayLike):
296             pack_args_by_32(
297                 holder=holder,
298                 maxlen=maxlen,
299                 arg=prealloacted.get(i, arg),
300                 typ=typ,
301                 context=context,
302                 placeholder=static_vars[i],
303                 datamem_start=datamem_start,
304                 dynamic_offset_counter=dynamic_offset_counter,
305                 pos=pos,
306             )
307 
308     return holder, maxlen, dynamic_offset_counter, datamem_start
309
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/vyper/parser/events.py b/vyper/parser/events.py
--- a/vyper/parser/events.py
+++ b/vyper/parser/events.py
@@ -1,5 +1,5 @@
 from vyper import ast as vy_ast
-from vyper.exceptions import TypeMismatch
+from vyper.exceptions import StructureException, TypeMismatch
 from vyper.parser.expr import Expr
 from vyper.parser.lll_node import LLLnode
 from vyper.parser.parser_utils import (
@@ -7,6 +7,7 @@
     getpos,
     make_byte_array_copier,
     make_setter,
+    mzero,
     unwrap_location,
     zero_pad,
 )
@@ -157,6 +158,13 @@
         )
         holder.append(increment_counter)
     elif isinstance(typ, ListType):
+
+        if isinstance(arg, vy_ast.Call) and arg.func.get("id") == "empty":
+            # special case for `empty()` with a static-sized array
+            holder.append(mzero(placeholder, get_size_of_type(typ) * 32))
+            maxlen += (get_size_of_type(typ) - 1) * 32
+            return holder, maxlen
+
         maxlen += (typ.count - 1) * 32
         typ = typ.subtype
 
@@ -225,7 +233,7 @@
     prealloacted = {}
     for idx, (arg, _expected_arg) in enumerate(zip(args, expected_data)):
 
-        if isinstance(arg, (vy_ast.Str, vy_ast.Call)):
+        if isinstance(arg, (vy_ast.Str, vy_ast.Call)) and arg.get("func.id") != "empty":
             expr = Expr(arg, context)
             source_lll = expr.lll_node
             typ = source_lll.typ
@@ -293,6 +301,11 @@
     for i, (arg, data) in enumerate(zip(args, expected_data)):
         typ = data.typ
         if isinstance(typ, ByteArrayLike):
+            if isinstance(arg, vy_ast.Call) and arg.func.get("id") == "empty":
+                # TODO add support for this
+                raise StructureException(
+                    "Cannot use `empty` on Bytes or String types within an event log", arg
+                )
             pack_args_by_32(
                 holder=holder,
                 maxlen=maxlen,

{"golden_diff": "diff --git a/vyper/parser/events.py b/vyper/parser/events.py\n--- a/vyper/parser/events.py\n+++ b/vyper/parser/events.py\n@@ -1,5 +1,5 @@\n from vyper import ast as vy_ast\n-from vyper.exceptions import TypeMismatch\n+from vyper.exceptions import StructureException, TypeMismatch\n from vyper.parser.expr import Expr\n from vyper.parser.lll_node import LLLnode\n from vyper.parser.parser_utils import (\n@@ -7,6 +7,7 @@\n     getpos,\n     make_byte_array_copier,\n     make_setter,\n+    mzero,\n     unwrap_location,\n     zero_pad,\n )\n@@ -157,6 +158,13 @@\n         )\n         holder.append(increment_counter)\n     elif isinstance(typ, ListType):\n+\n+        if isinstance(arg, vy_ast.Call) and arg.func.get(\"id\") == \"empty\":\n+            # special case for `empty()` with a static-sized array\n+            holder.append(mzero(placeholder, get_size_of_type(typ) * 32))\n+            maxlen += (get_size_of_type(typ) - 1) * 32\n+            return holder, maxlen\n+\n         maxlen += (typ.count - 1) * 32\n         typ = typ.subtype\n \n@@ -225,7 +233,7 @@\n     prealloacted = {}\n     for idx, (arg, _expected_arg) in enumerate(zip(args, expected_data)):\n \n-        if isinstance(arg, (vy_ast.Str, vy_ast.Call)):\n+        if isinstance(arg, (vy_ast.Str, vy_ast.Call)) and arg.get(\"func.id\") != \"empty\":\n             expr = Expr(arg, context)\n             source_lll = expr.lll_node\n             typ = source_lll.typ\n@@ -293,6 +301,11 @@\n     for i, (arg, data) in enumerate(zip(args, expected_data)):\n         typ = data.typ\n         if isinstance(typ, ByteArrayLike):\n+            if isinstance(arg, vy_ast.Call) and arg.func.get(\"id\") == \"empty\":\n+                # TODO add support for this\n+                raise StructureException(\n+                    \"Cannot use `empty` on Bytes or String types within an event log\", arg\n+                )\n             pack_args_by_32(\n                 holder=holder,\n                 maxlen=maxlen,\n", "issue": "Cannot use empty for an array inside an event log\n### What's your issue about?\r\n\r\nThe following code:\r\n\r\n```python\r\nevent Foo:\r\n    a: bytes32[2]\r\n\r\n@external\r\ndef test():\r\n    log Foo(empty(bytes32[2]))\r\n```\r\n\r\nProduces the following error:\r\n\r\n```python\r\nFile \"/home/computer/code/python/vyper/vyper/parser/events.py\", line 208, in pack_args_by_32\r\n    for arg2 in arg.elements:\r\nAttributeError: 'LLLnode' object has no attribute 'elements'\r\n```\r\n\r\nThe issue happens with any array type.\r\n\r\n### How can it be fixed?\r\nI think that this code should compile, so we need to look at what's happening in parser that prevents it.\r\n\n", "before_files": [{"content": "from vyper import ast as vy_ast\nfrom vyper.exceptions import TypeMismatch\nfrom vyper.parser.expr import Expr\nfrom vyper.parser.lll_node import LLLnode\nfrom vyper.parser.parser_utils import (\n    base_type_conversion,\n    getpos,\n    make_byte_array_copier,\n    make_setter,\n    unwrap_location,\n    zero_pad,\n)\nfrom vyper.types.types import (\n    BaseType,\n    ByteArrayLike,\n    ListType,\n    get_size_of_type,\n)\nfrom vyper.utils import bytes_to_int, ceil32, keccak256\n\n\ndef pack_logging_topics(event_id, args, expected_topics, context, pos):\n    topics = [event_id]\n    code_pos = pos\n    for pos, expected_topic in enumerate(expected_topics):\n        expected_type = expected_topic.typ\n        arg = args[pos]\n        value = Expr(arg, context).lll_node\n        arg_type = value.typ\n\n        if isinstance(arg_type, ByteArrayLike) and isinstance(expected_type, ByteArrayLike):\n            if arg_type.maxlen > expected_type.maxlen:\n                raise TypeMismatch(\n                    f\"Topic input bytes are too big: {arg_type} {expected_type}\", code_pos\n                )\n\n            if isinstance(arg, (vy_ast.Str, vy_ast.Bytes)):\n                # for literals, generate the topic at compile time\n                value = arg.value\n                if isinstance(value, str):\n                    value = value.encode()\n                topics.append(bytes_to_int(keccak256(value)))\n\n            elif value.location == \"memory\":\n                topics.append([\"sha3\", [\"add\", value, 32], [\"mload\", value]])\n\n            else:\n                # storage or calldata\n                placeholder = context.new_internal_variable(value.typ)\n                placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location=\"memory\")\n                copier = make_byte_array_copier(\n                    placeholder_node,\n                    LLLnode.from_list(\"_sub\", typ=value.typ, location=value.location),\n                )\n                lll_node = [\n                    \"with\",\n                    \"_sub\",\n                    value,\n                    [\"seq\", copier, [\"sha3\", [\"add\", placeholder, 32], [\"mload\", placeholder]]],\n                ]\n                topics.append(lll_node)\n\n        elif isinstance(arg_type, ListType) and isinstance(expected_type, ListType):\n            size = get_size_of_type(value.typ) * 32\n            if value.location == \"memory\":\n                topics.append([\"sha3\", value, size])\n\n            else:\n                # storage or calldata\n                placeholder = context.new_internal_variable(value.typ)\n                placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location=\"memory\")\n                setter = make_setter(placeholder_node, value, \"memory\", value.pos)\n                lll_node = [\"seq\", setter, [\"sha3\", placeholder, size]]\n                topics.append(lll_node)\n\n        else:\n            if arg_type != expected_type:\n                raise TypeMismatch(\n                    f\"Invalid type for logging topic, got {arg_type} expected {expected_type}\",\n                    value.pos,\n                )\n            value = unwrap_location(value)\n            value = base_type_conversion(value, arg_type, expected_type, pos=code_pos)\n            topics.append(value)\n\n    return topics\n\n\ndef pack_args_by_32(\n    holder,\n    maxlen,\n    arg,\n    typ,\n    context,\n    placeholder,\n    dynamic_offset_counter=None,\n    datamem_start=None,\n    pos=None,\n):\n    \"\"\"\n    Copy necessary variables to pre-allocated memory section.\n\n    :param holder: Complete holder for all args\n    :param maxlen: Total length in bytes of the full arg section (static + dynamic).\n    :param arg: Current arg to pack\n    :param context: Context of arg\n    :param placeholder: Static placeholder for static argument part.\n    :param dynamic_offset_counter: position counter stored in static args.\n    :param dynamic_placeholder: pointer to current position in memory to write dynamic values to.\n    :param datamem_start: position where the whole datemem section starts.\n    \"\"\"\n\n    if isinstance(typ, BaseType):\n        if isinstance(arg, LLLnode):\n            value = unwrap_location(arg)\n        else:\n            value = Expr(arg, context).lll_node\n            value = base_type_conversion(value, value.typ, typ, pos)\n        holder.append(LLLnode.from_list([\"mstore\", placeholder, value], typ=typ, location=\"memory\"))\n    elif isinstance(typ, ByteArrayLike):\n\n        if isinstance(arg, LLLnode):  # Is prealloacted variable.\n            source_lll = arg\n        else:\n            source_lll = Expr(arg, context).lll_node\n\n        # Set static offset, in arg slot.\n        holder.append(LLLnode.from_list([\"mstore\", placeholder, [\"mload\", dynamic_offset_counter]]))\n        # Get the biginning to write the ByteArray to.\n        dest_placeholder = LLLnode.from_list(\n            [\"add\", datamem_start, [\"mload\", dynamic_offset_counter]],\n            typ=typ,\n            location=\"memory\",\n            annotation=\"pack_args_by_32:dest_placeholder\",\n        )\n        copier = make_byte_array_copier(dest_placeholder, source_lll, pos=pos)\n        holder.append(copier)\n        # Add zero padding.\n        holder.append(zero_pad(dest_placeholder))\n\n        # Increment offset counter.\n        increment_counter = LLLnode.from_list(\n            [\n                \"mstore\",\n                dynamic_offset_counter,\n                [\n                    \"add\",\n                    [\n                        \"add\",\n                        [\"mload\", dynamic_offset_counter],\n                        [\"ceil32\", [\"mload\", dest_placeholder]],\n                    ],\n                    32,\n                ],\n            ],\n            annotation=\"Increment dynamic offset counter\",\n        )\n        holder.append(increment_counter)\n    elif isinstance(typ, ListType):\n        maxlen += (typ.count - 1) * 32\n        typ = typ.subtype\n\n        def check_list_type_match(provided):  # Check list types match.\n            if provided != typ:\n                raise TypeMismatch(\n                    f\"Log list type '{provided}' does not match provided, expected '{typ}'\"\n                )\n\n        # NOTE: Below code could be refactored into iterators/getter functions for each type of\n        #       repetitive loop. But seeing how each one is a unique for loop, and in which way\n        #       the sub value makes the difference in each type of list clearer.\n\n        # List from storage\n        if isinstance(arg, vy_ast.Attribute) and arg.value.id == \"self\":\n            stor_list = context.globals[arg.attr]\n            check_list_type_match(stor_list.typ.subtype)\n            size = stor_list.typ.count\n            mem_offset = 0\n            for i in range(0, size):\n                storage_offset = i\n                arg2 = LLLnode.from_list(\n                    [\"sload\", [\"add\", [\"sha3_32\", Expr(arg, context).lll_node], storage_offset]],\n                    typ=typ,\n                )\n                holder, maxlen = pack_args_by_32(\n                    holder, maxlen, arg2, typ, context, placeholder + mem_offset, pos=pos,\n                )\n                mem_offset += get_size_of_type(typ) * 32\n\n        # List from variable.\n        elif isinstance(arg, vy_ast.Name):\n            size = context.vars[arg.id].size\n            pos = context.vars[arg.id].pos\n            check_list_type_match(context.vars[arg.id].typ.subtype)\n            mem_offset = 0\n            for _ in range(0, size):\n                arg2 = LLLnode.from_list(\n                    pos + mem_offset, typ=typ, location=context.vars[arg.id].location\n                )\n                holder, maxlen = pack_args_by_32(\n                    holder, maxlen, arg2, typ, context, placeholder + mem_offset, pos=pos,\n                )\n                mem_offset += get_size_of_type(typ) * 32\n\n        # List from list literal.\n        else:\n            mem_offset = 0\n            for arg2 in arg.elements:\n                holder, maxlen = pack_args_by_32(\n                    holder, maxlen, arg2, typ, context, placeholder + mem_offset, pos=pos,\n                )\n                mem_offset += get_size_of_type(typ) * 32\n    return holder, maxlen\n\n\n# Pack logging data arguments\ndef pack_logging_data(expected_data, args, context, pos):\n    # Checks to see if there's any data\n    if not args:\n        return [\"seq\"], 0, None, 0\n    holder = [\"seq\"]\n    maxlen = len(args) * 32  # total size of all packed args (upper limit)\n\n    # Unroll any function calls, to temp variables.\n    prealloacted = {}\n    for idx, (arg, _expected_arg) in enumerate(zip(args, expected_data)):\n\n        if isinstance(arg, (vy_ast.Str, vy_ast.Call)):\n            expr = Expr(arg, context)\n            source_lll = expr.lll_node\n            typ = source_lll.typ\n\n            if isinstance(arg, vy_ast.Str):\n                if len(arg.s) > typ.maxlen:\n                    raise TypeMismatch(f\"Data input bytes are to big: {len(arg.s)} {typ}\", pos)\n\n            tmp_variable = context.new_internal_variable(source_lll.typ)\n            tmp_variable_node = LLLnode.from_list(\n                tmp_variable,\n                typ=source_lll.typ,\n                pos=getpos(arg),\n                location=\"memory\",\n                annotation=f\"log_prealloacted {source_lll.typ}\",\n            )\n            # Store len.\n            # holder.append(['mstore', len_placeholder, ['mload', unwrap_location(source_lll)]])\n            # Copy bytes.\n\n            holder.append(\n                make_setter(tmp_variable_node, source_lll, pos=getpos(arg), location=\"memory\")\n            )\n            prealloacted[idx] = tmp_variable_node\n\n    # Create internal variables for for dynamic and static args.\n    static_types = []\n    for data in expected_data:\n        static_types.append(data.typ if not isinstance(data.typ, ByteArrayLike) else BaseType(32))\n\n    requires_dynamic_offset = any(isinstance(data.typ, ByteArrayLike) for data in expected_data)\n\n    dynamic_offset_counter = None\n    if requires_dynamic_offset:\n        dynamic_offset_counter = context.new_internal_variable(BaseType(32))\n        dynamic_placeholder = context.new_internal_variable(BaseType(32))\n\n    static_vars = [context.new_internal_variable(i) for i in static_types]\n\n    # Populate static placeholders.\n    for i, (arg, data) in enumerate(zip(args, expected_data)):\n        typ = data.typ\n        placeholder = static_vars[i]\n        if not isinstance(typ, ByteArrayLike):\n            holder, maxlen = pack_args_by_32(\n                holder, maxlen, prealloacted.get(i, arg), typ, context, placeholder, pos=pos,\n            )\n\n    # Dynamic position starts right after the static args.\n    if requires_dynamic_offset:\n        holder.append(LLLnode.from_list([\"mstore\", dynamic_offset_counter, maxlen]))\n\n    # Calculate maximum dynamic offset placeholders, used for gas estimation.\n    for _arg, data in zip(args, expected_data):\n        typ = data.typ\n        if isinstance(typ, ByteArrayLike):\n            maxlen += 32 + ceil32(typ.maxlen)\n\n    if requires_dynamic_offset:\n        datamem_start = dynamic_placeholder + 32\n    else:\n        datamem_start = static_vars[0]\n\n    # Copy necessary data into allocated dynamic section.\n    for i, (arg, data) in enumerate(zip(args, expected_data)):\n        typ = data.typ\n        if isinstance(typ, ByteArrayLike):\n            pack_args_by_32(\n                holder=holder,\n                maxlen=maxlen,\n                arg=prealloacted.get(i, arg),\n                typ=typ,\n                context=context,\n                placeholder=static_vars[i],\n                datamem_start=datamem_start,\n                dynamic_offset_counter=dynamic_offset_counter,\n                pos=pos,\n            )\n\n    return holder, maxlen, dynamic_offset_counter, datamem_start\n", "path": "vyper/parser/events.py"}], "after_files": [{"content": "from vyper import ast as vy_ast\nfrom vyper.exceptions import StructureException, TypeMismatch\nfrom vyper.parser.expr import Expr\nfrom vyper.parser.lll_node import LLLnode\nfrom vyper.parser.parser_utils import (\n    base_type_conversion,\n    getpos,\n    make_byte_array_copier,\n    make_setter,\n    mzero,\n    unwrap_location,\n    zero_pad,\n)\nfrom vyper.types.types import (\n    BaseType,\n    ByteArrayLike,\n    ListType,\n    get_size_of_type,\n)\nfrom vyper.utils import bytes_to_int, ceil32, keccak256\n\n\ndef pack_logging_topics(event_id, args, expected_topics, context, pos):\n    topics = [event_id]\n    code_pos = pos\n    for pos, expected_topic in enumerate(expected_topics):\n        expected_type = expected_topic.typ\n        arg = args[pos]\n        value = Expr(arg, context).lll_node\n        arg_type = value.typ\n\n        if isinstance(arg_type, ByteArrayLike) and isinstance(expected_type, ByteArrayLike):\n            if arg_type.maxlen > expected_type.maxlen:\n                raise TypeMismatch(\n                    f\"Topic input bytes are too big: {arg_type} {expected_type}\", code_pos\n                )\n\n            if isinstance(arg, (vy_ast.Str, vy_ast.Bytes)):\n                # for literals, generate the topic at compile time\n                value = arg.value\n                if isinstance(value, str):\n                    value = value.encode()\n                topics.append(bytes_to_int(keccak256(value)))\n\n            elif value.location == \"memory\":\n                topics.append([\"sha3\", [\"add\", value, 32], [\"mload\", value]])\n\n            else:\n                # storage or calldata\n                placeholder = context.new_internal_variable(value.typ)\n                placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location=\"memory\")\n                copier = make_byte_array_copier(\n                    placeholder_node,\n                    LLLnode.from_list(\"_sub\", typ=value.typ, location=value.location),\n                )\n                lll_node = [\n                    \"with\",\n                    \"_sub\",\n                    value,\n                    [\"seq\", copier, [\"sha3\", [\"add\", placeholder, 32], [\"mload\", placeholder]]],\n                ]\n                topics.append(lll_node)\n\n        elif isinstance(arg_type, ListType) and isinstance(expected_type, ListType):\n            size = get_size_of_type(value.typ) * 32\n            if value.location == \"memory\":\n                topics.append([\"sha3\", value, size])\n\n            else:\n                # storage or calldata\n                placeholder = context.new_internal_variable(value.typ)\n                placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location=\"memory\")\n                setter = make_setter(placeholder_node, value, \"memory\", value.pos)\n                lll_node = [\"seq\", setter, [\"sha3\", placeholder, size]]\n                topics.append(lll_node)\n\n        else:\n            if arg_type != expected_type:\n                raise TypeMismatch(\n                    f\"Invalid type for logging topic, got {arg_type} expected {expected_type}\",\n                    value.pos,\n                )\n            value = unwrap_location(value)\n            value = base_type_conversion(value, arg_type, expected_type, pos=code_pos)\n            topics.append(value)\n\n    return topics\n\n\ndef pack_args_by_32(\n    holder,\n    maxlen,\n    arg,\n    typ,\n    context,\n    placeholder,\n    dynamic_offset_counter=None,\n    datamem_start=None,\n    pos=None,\n):\n    \"\"\"\n    Copy necessary variables to pre-allocated memory section.\n\n    :param holder: Complete holder for all args\n    :param maxlen: Total length in bytes of the full arg section (static + dynamic).\n    :param arg: Current arg to pack\n    :param context: Context of arg\n    :param placeholder: Static placeholder for static argument part.\n    :param dynamic_offset_counter: position counter stored in static args.\n    :param dynamic_placeholder: pointer to current position in memory to write dynamic values to.\n    :param datamem_start: position where the whole datemem section starts.\n    \"\"\"\n\n    if isinstance(typ, BaseType):\n        if isinstance(arg, LLLnode):\n            value = unwrap_location(arg)\n        else:\n            value = Expr(arg, context).lll_node\n            value = base_type_conversion(value, value.typ, typ, pos)\n        holder.append(LLLnode.from_list([\"mstore\", placeholder, value], typ=typ, location=\"memory\"))\n    elif isinstance(typ, ByteArrayLike):\n\n        if isinstance(arg, LLLnode):  # Is prealloacted variable.\n            source_lll = arg\n        else:\n            source_lll = Expr(arg, context).lll_node\n\n        # Set static offset, in arg slot.\n        holder.append(LLLnode.from_list([\"mstore\", placeholder, [\"mload\", dynamic_offset_counter]]))\n        # Get the biginning to write the ByteArray to.\n        dest_placeholder = LLLnode.from_list(\n            [\"add\", datamem_start, [\"mload\", dynamic_offset_counter]],\n            typ=typ,\n            location=\"memory\",\n            annotation=\"pack_args_by_32:dest_placeholder\",\n        )\n        copier = make_byte_array_copier(dest_placeholder, source_lll, pos=pos)\n        holder.append(copier)\n        # Add zero padding.\n        holder.append(zero_pad(dest_placeholder))\n\n        # Increment offset counter.\n        increment_counter = LLLnode.from_list(\n            [\n                \"mstore\",\n                dynamic_offset_counter,\n                [\n                    \"add\",\n                    [\n                        \"add\",\n                        [\"mload\", dynamic_offset_counter],\n                        [\"ceil32\", [\"mload\", dest_placeholder]],\n                    ],\n                    32,\n                ],\n            ],\n            annotation=\"Increment dynamic offset counter\",\n        )\n        holder.append(increment_counter)\n    elif isinstance(typ, ListType):\n\n        if isinstance(arg, vy_ast.Call) and arg.func.get(\"id\") == \"empty\":\n            # special case for `empty()` with a static-sized array\n            holder.append(mzero(placeholder, get_size_of_type(typ) * 32))\n            maxlen += (get_size_of_type(typ) - 1) * 32\n            return holder, maxlen\n\n        maxlen += (typ.count - 1) * 32\n        typ = typ.subtype\n\n        def check_list_type_match(provided):  # Check list types match.\n            if provided != typ:\n                raise TypeMismatch(\n                    f\"Log list type '{provided}' does not match provided, expected '{typ}'\"\n                )\n\n        # NOTE: Below code could be refactored into iterators/getter functions for each type of\n        #       repetitive loop. But seeing how each one is a unique for loop, and in which way\n        #       the sub value makes the difference in each type of list clearer.\n\n        # List from storage\n        if isinstance(arg, vy_ast.Attribute) and arg.value.id == \"self\":\n            stor_list = context.globals[arg.attr]\n            check_list_type_match(stor_list.typ.subtype)\n            size = stor_list.typ.count\n            mem_offset = 0\n            for i in range(0, size):\n                storage_offset = i\n                arg2 = LLLnode.from_list(\n                    [\"sload\", [\"add\", [\"sha3_32\", Expr(arg, context).lll_node], storage_offset]],\n                    typ=typ,\n                )\n                holder, maxlen = pack_args_by_32(\n                    holder, maxlen, arg2, typ, context, placeholder + mem_offset, pos=pos,\n                )\n                mem_offset += get_size_of_type(typ) * 32\n\n        # List from variable.\n        elif isinstance(arg, vy_ast.Name):\n            size = context.vars[arg.id].size\n            pos = context.vars[arg.id].pos\n            check_list_type_match(context.vars[arg.id].typ.subtype)\n            mem_offset = 0\n            for _ in range(0, size):\n                arg2 = LLLnode.from_list(\n                    pos + mem_offset, typ=typ, location=context.vars[arg.id].location\n                )\n                holder, maxlen = pack_args_by_32(\n                    holder, maxlen, arg2, typ, context, placeholder + mem_offset, pos=pos,\n                )\n                mem_offset += get_size_of_type(typ) * 32\n\n        # List from list literal.\n        else:\n            mem_offset = 0\n            for arg2 in arg.elements:\n                holder, maxlen = pack_args_by_32(\n                    holder, maxlen, arg2, typ, context, placeholder + mem_offset, pos=pos,\n                )\n                mem_offset += get_size_of_type(typ) * 32\n    return holder, maxlen\n\n\n# Pack logging data arguments\ndef pack_logging_data(expected_data, args, context, pos):\n    # Checks to see if there's any data\n    if not args:\n        return [\"seq\"], 0, None, 0\n    holder = [\"seq\"]\n    maxlen = len(args) * 32  # total size of all packed args (upper limit)\n\n    # Unroll any function calls, to temp variables.\n    prealloacted = {}\n    for idx, (arg, _expected_arg) in enumerate(zip(args, expected_data)):\n\n        if isinstance(arg, (vy_ast.Str, vy_ast.Call)) and arg.get(\"func.id\") != \"empty\":\n            expr = Expr(arg, context)\n            source_lll = expr.lll_node\n            typ = source_lll.typ\n\n            if isinstance(arg, vy_ast.Str):\n                if len(arg.s) > typ.maxlen:\n                    raise TypeMismatch(f\"Data input bytes are to big: {len(arg.s)} {typ}\", pos)\n\n            tmp_variable = context.new_internal_variable(source_lll.typ)\n            tmp_variable_node = LLLnode.from_list(\n                tmp_variable,\n                typ=source_lll.typ,\n                pos=getpos(arg),\n                location=\"memory\",\n                annotation=f\"log_prealloacted {source_lll.typ}\",\n            )\n            # Store len.\n            # holder.append(['mstore', len_placeholder, ['mload', unwrap_location(source_lll)]])\n            # Copy bytes.\n\n            holder.append(\n                make_setter(tmp_variable_node, source_lll, pos=getpos(arg), location=\"memory\")\n            )\n            prealloacted[idx] = tmp_variable_node\n\n    # Create internal variables for for dynamic and static args.\n    static_types = []\n    for data in expected_data:\n        static_types.append(data.typ if not isinstance(data.typ, ByteArrayLike) else BaseType(32))\n\n    requires_dynamic_offset = any(isinstance(data.typ, ByteArrayLike) for data in expected_data)\n\n    dynamic_offset_counter = None\n    if requires_dynamic_offset:\n        dynamic_offset_counter = context.new_internal_variable(BaseType(32))\n        dynamic_placeholder = context.new_internal_variable(BaseType(32))\n\n    static_vars = [context.new_internal_variable(i) for i in static_types]\n\n    # Populate static placeholders.\n    for i, (arg, data) in enumerate(zip(args, expected_data)):\n        typ = data.typ\n        placeholder = static_vars[i]\n        if not isinstance(typ, ByteArrayLike):\n            holder, maxlen = pack_args_by_32(\n                holder, maxlen, prealloacted.get(i, arg), typ, context, placeholder, pos=pos,\n            )\n\n    # Dynamic position starts right after the static args.\n    if requires_dynamic_offset:\n        holder.append(LLLnode.from_list([\"mstore\", dynamic_offset_counter, maxlen]))\n\n    # Calculate maximum dynamic offset placeholders, used for gas estimation.\n    for _arg, data in zip(args, expected_data):\n        typ = data.typ\n        if isinstance(typ, ByteArrayLike):\n            maxlen += 32 + ceil32(typ.maxlen)\n\n    if requires_dynamic_offset:\n        datamem_start = dynamic_placeholder + 32\n    else:\n        datamem_start = static_vars[0]\n\n    # Copy necessary data into allocated dynamic section.\n    for i, (arg, data) in enumerate(zip(args, expected_data)):\n        typ = data.typ\n        if isinstance(typ, ByteArrayLike):\n            if isinstance(arg, vy_ast.Call) and arg.func.get(\"id\") == \"empty\":\n                # TODO add support for this\n                raise StructureException(\n                    \"Cannot use `empty` on Bytes or String types within an event log\", arg\n                )\n            pack_args_by_32(\n                holder=holder,\n                maxlen=maxlen,\n                arg=prealloacted.get(i, arg),\n                typ=typ,\n                context=context,\n                placeholder=static_vars[i],\n                datamem_start=datamem_start,\n                dynamic_offset_counter=dynamic_offset_counter,\n                pos=pos,\n            )\n\n    return holder, maxlen, dynamic_offset_counter, datamem_start\n", "path": "vyper/parser/events.py"}]}