We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
2-clause if statement must have a zerovalent body error
### Version Information

* vyper Version: 0.1.0b5
* OS: win
* Python Version (python --version): 3.7.0
* Environment (output of `pip freeze`):

```
attrdict==2.0.0
base58==1.0.2
certifi==2018.11.29
chardet==3.0.4
codecov==2.0.15
coverage==4.5.2
cytoolz==0.9.0.1
ecdsa==0.13
eth-abi==1.3.0
eth-account==0.3.0
eth-hash==0.2.0
eth-keyfile==0.5.1
eth-keys==0.2.0b3
eth-rlp==0.1.2
eth-typing==2.0.0
eth-utils==1.4.0
hexbytes==0.1.0
idna==2.7
numpy==1.15.4
pandas==0.23.4
parsimonious==0.8.1
pycryptodome==3.7.2
python-dateutil==2.7.5
pytz==2018.7
requests==2.20.1
rlp==1.0.3
setuptools-scm==3.1.0
six==1.11.0
toolz==0.9.0
tronapi==3.0.2
urllib3==1.24.1
vyper==0.1.0b5
```

### What's your issue about?

Script returns cryptic "zerovalent" error when there is a function call after an if statement. Adding a pass statement after the function call makes it go away. Likewise, replacing the function call with the body of the function call makes it go away.

Stripped down example:
```
@private
def foo():
    pass

@public
def start():
    if True:
        self.foo()
        # pass  # uncomment to successfully compile
```

Error output:
```
Error compiling:  error_reproduce.vy
Exception: 2-clause if statement must have a zerovalent body: [seq,
  /* Internal Call: foo */
  [seq_unchecked,
    [add, pc, 6],
    [goto, priv_3264763256],
    jumpdest,
    0]]
```

Compiled using `vyper error_reproduce.vy`


--- 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/self_call.py`
Content:
```
1 from vyper.exceptions import (
2     ConstancyViolationException
3 )
4 from vyper.parser.lll_node import (
5     LLLnode
6 )
7 from vyper.parser.parser_utils import (
8     pack_arguments,
9     getpos
10 )
11 from vyper.signatures.function_signature import (
12     FunctionSignature
13 )
14 from vyper.types import (
15     BaseType,
16     ByteArrayType,
17     ListType,
18     TupleType,
19     ceil32,
20     get_size_of_type,
21 )
22 
23 
24 def call_lookup_specs(stmt_expr, context):
25     from vyper.parser.expr import Expr
26     method_name = stmt_expr.func.attr
27     expr_args = [Expr(arg, context).lll_node for arg in stmt_expr.args]
28     sig = FunctionSignature.lookup_sig(context.sigs, method_name, expr_args, stmt_expr, context)
29     return method_name, expr_args, sig
30 
31 
32 def make_call(stmt_expr, context):
33     method_name, _, sig = call_lookup_specs(stmt_expr, context)
34 
35     if context.is_constant and not sig.const:
36         raise ConstancyViolationException(
37             "May not call non-constant function '%s' within a constant function." % (method_name),
38             getpos(stmt_expr)
39         )
40 
41     if sig.private:
42         return call_self_private(stmt_expr, context, sig)
43     else:
44         return call_self_public(stmt_expr, context, sig)
45 
46 
47 def call_make_placeholder(stmt_expr, context, sig):
48     if sig.output_type is None:
49         return 0, 0, 0
50 
51     output_placeholder = context.new_placeholder(typ=sig.output_type)
52     out_size = get_size_of_type(sig.output_type) * 32
53     returner = output_placeholder
54 
55     if not sig.private and isinstance(sig.output_type, ByteArrayType):
56             returner = output_placeholder + 32
57 
58     return output_placeholder, returner, out_size
59 
60 
61 def call_self_private(stmt_expr, context, sig):
62     # ** Private Call **
63     # Steps:
64     # (x) push current local variables
65     # (x) push arguments
66     # (x) push jumpdest (callback ptr)
67     # (x) jump to label
68     # (x) pop return values
69     # (x) pop local variables
70 
71     method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)
72     pre_init = []
73     pop_local_vars = []
74     push_local_vars = []
75     pop_return_values = []
76     push_args = []
77 
78     # Push local variables.
79     if context.vars:
80         var_slots = [(v.pos, v.size) for name, v in context.vars.items()]
81         var_slots.sort(key=lambda x: x[0])
82         mem_from, mem_to = var_slots[0][0], var_slots[-1][0] + var_slots[-1][1] * 32
83         push_local_vars = [
84             ['mload', pos] for pos in range(mem_from, mem_to, 32)
85         ]
86         pop_local_vars = [
87             ['mstore', pos, 'pass'] for pos in reversed(range(mem_from, mem_to, 32))
88         ]
89 
90     # Push Arguments
91     if expr_args:
92         inargs, inargsize, arg_pos = pack_arguments(sig, expr_args, context, return_placeholder=False, pos=getpos(stmt_expr))
93         push_args += [inargs]  # copy arguments first, to not mess up the push/pop sequencing.
94         static_arg_count = len(expr_args) * 32
95         static_pos = arg_pos + static_arg_count
96         total_arg_size = ceil32(inargsize - 4)
97 
98         if len(expr_args) * 32 != total_arg_size:  # requires dynamic section.
99             ident = 'push_args_%d_%d_%d' % (sig.method_id, stmt_expr.lineno, stmt_expr.col_offset)
100             start_label = ident + '_start'
101             end_label = ident + '_end'
102             i_placeholder = context.new_placeholder(BaseType('uint256'))
103             push_args += [
104                 ['mstore', i_placeholder, arg_pos + total_arg_size],
105                 ['label', start_label],
106                 ['if', ['lt', ['mload', i_placeholder], static_pos], ['goto', end_label]],
107                 ['if_unchecked', ['ne', ['mload', ['mload', i_placeholder]], 0], ['mload', ['mload', i_placeholder]]],
108                 ['mstore', i_placeholder, ['sub', ['mload', i_placeholder], 32]],  # decrease i
109                 ['goto', start_label],
110                 ['label', end_label]
111             ]
112 
113         # push static section
114         push_args += [
115             ['mload', pos] for pos in reversed(range(arg_pos, static_pos, 32))
116         ]
117 
118     # Jump to function label.
119     jump_to_func = [
120         ['add', ['pc'], 6],  # set callback pointer.
121         ['goto', 'priv_{}'.format(sig.method_id)],
122         ['jumpdest'],
123     ]
124 
125     # Pop return values.
126     returner = [0]
127     if sig.output_type:
128         output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)
129         if output_size > 0:
130             dynamic_offsets = []
131             if isinstance(sig.output_type, (BaseType, ListType)):
132                 pop_return_values = [
133                     ['mstore', ['add', output_placeholder, pos], 'pass'] for pos in range(0, output_size, 32)
134                 ]
135             elif isinstance(sig.output_type, ByteArrayType):
136                 dynamic_offsets = [(0, sig.output_type)]
137                 pop_return_values = [
138                     ['pop', 'pass'],
139                 ]
140             elif isinstance(sig.output_type, TupleType):
141                 static_offset = 0
142                 pop_return_values = []
143                 for out_type in sig.output_type.members:
144                     if isinstance(out_type, ByteArrayType):
145                         pop_return_values.append(['mstore', ['add', output_placeholder, static_offset], 'pass'])
146                         dynamic_offsets.append((['mload', ['add', output_placeholder, static_offset]], out_type))
147                     else:
148                         pop_return_values.append(['mstore', ['add', output_placeholder, static_offset], 'pass'])
149                     static_offset += 32
150 
151             # append dynamic unpacker.
152             dyn_idx = 0
153             for in_memory_offset, out_type in dynamic_offsets:
154                 ident = "%d_%d_arg_%d" % (stmt_expr.lineno, stmt_expr.col_offset, dyn_idx)
155                 dyn_idx += 1
156                 start_label = 'dyn_unpack_start_' + ident
157                 end_label = 'dyn_unpack_end_' + ident
158                 i_placeholder = context.new_placeholder(typ=BaseType('uint256'))
159                 begin_pos = ['add', output_placeholder, in_memory_offset]
160                 # loop until length.
161                 o = LLLnode.from_list(
162                     ['seq_unchecked',
163                         ['mstore', begin_pos, 'pass'],  # get len
164                         ['mstore', i_placeholder, 0],
165                         ['label', start_label],
166                         ['if', ['ge', ['mload', i_placeholder], ['ceil32', ['mload', begin_pos]]], ['goto', end_label]],  # break
167                         ['mstore', ['add', ['add', begin_pos, 32], ['mload', i_placeholder]], 'pass'],  # pop into correct memory slot.
168                         ['mstore', i_placeholder, ['add', 32, ['mload', i_placeholder]]],  # increment i
169                         ['goto', start_label],
170                         ['label', end_label]],
171                     typ=None, annotation='dynamic unpacker', pos=getpos(stmt_expr))
172                 pop_return_values.append(o)
173 
174     o = LLLnode.from_list(
175         ['seq_unchecked'] + pre_init + push_local_vars + push_args + jump_to_func + pop_return_values + pop_local_vars + [returner],
176         typ=sig.output_type, location='memory', pos=getpos(stmt_expr), annotation='Internal Call: %s' % method_name,
177         add_gas_estimate=sig.gas
178     )
179     o.gas += sig.gas
180     return o
181 
182 
183 def call_self_public(stmt_expr, context, sig):
184     # self.* style call to a public function.
185     method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)
186     add_gas = sig.gas  # gas of call
187     inargs, inargsize, _ = pack_arguments(sig, expr_args, context, pos=getpos(stmt_expr))
188     output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)
189     assert_call = [
190         'assert', ['call', ['gas'], ['address'], 0, inargs, inargsize, output_placeholder, output_size]
191     ]
192     if output_size > 0:
193         assert_call = ['seq', assert_call, returner]
194     o = LLLnode.from_list(
195         assert_call,
196         typ=sig.output_type, location='memory',
197         pos=getpos(stmt_expr), add_gas_estimate=add_gas, annotation='Internal Call: %s' % method_name)
198     o.gas += sig.gas
199     return o
200
```
--- 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/self_call.py b/vyper/parser/self_call.py
--- a/vyper/parser/self_call.py
+++ b/vyper/parser/self_call.py
@@ -171,8 +171,21 @@
                     typ=None, annotation='dynamic unpacker', pos=getpos(stmt_expr))
                 pop_return_values.append(o)
 
+    call_body = (
+        ['seq_unchecked'] +
+        pre_init +
+        push_local_vars +
+        push_args +
+        jump_to_func +
+        pop_return_values +
+        pop_local_vars +
+        [returner]
+    )
+    # If we have no return, we need to pop off
+    pop_returner_call_body = ['pop', call_body] if sig.output_type is None else call_body
+
     o = LLLnode.from_list(
-        ['seq_unchecked'] + pre_init + push_local_vars + push_args + jump_to_func + pop_return_values + pop_local_vars + [returner],
+        pop_returner_call_body,
         typ=sig.output_type, location='memory', pos=getpos(stmt_expr), annotation='Internal Call: %s' % method_name,
         add_gas_estimate=sig.gas
     )

{"golden_diff": "diff --git a/vyper/parser/self_call.py b/vyper/parser/self_call.py\n--- a/vyper/parser/self_call.py\n+++ b/vyper/parser/self_call.py\n@@ -171,8 +171,21 @@\n                     typ=None, annotation='dynamic unpacker', pos=getpos(stmt_expr))\n                 pop_return_values.append(o)\n \n+    call_body = (\n+        ['seq_unchecked'] +\n+        pre_init +\n+        push_local_vars +\n+        push_args +\n+        jump_to_func +\n+        pop_return_values +\n+        pop_local_vars +\n+        [returner]\n+    )\n+    # If we have no return, we need to pop off\n+    pop_returner_call_body = ['pop', call_body] if sig.output_type is None else call_body\n+\n     o = LLLnode.from_list(\n-        ['seq_unchecked'] + pre_init + push_local_vars + push_args + jump_to_func + pop_return_values + pop_local_vars + [returner],\n+        pop_returner_call_body,\n         typ=sig.output_type, location='memory', pos=getpos(stmt_expr), annotation='Internal Call: %s' % method_name,\n         add_gas_estimate=sig.gas\n     )\n", "issue": "2-clause if statement must have a zerovalent body error\n### Version Information\r\n\r\n* vyper Version: 0.1.0b5\r\n* OS: win\r\n* Python Version (python --version): 3.7.0\r\n* Environment (output of `pip freeze`):\r\n\r\n```\r\nattrdict==2.0.0\r\nbase58==1.0.2\r\ncertifi==2018.11.29\r\nchardet==3.0.4\r\ncodecov==2.0.15\r\ncoverage==4.5.2\r\ncytoolz==0.9.0.1\r\necdsa==0.13\r\neth-abi==1.3.0\r\neth-account==0.3.0\r\neth-hash==0.2.0\r\neth-keyfile==0.5.1\r\neth-keys==0.2.0b3\r\neth-rlp==0.1.2\r\neth-typing==2.0.0\r\neth-utils==1.4.0\r\nhexbytes==0.1.0\r\nidna==2.7\r\nnumpy==1.15.4\r\npandas==0.23.4\r\nparsimonious==0.8.1\r\npycryptodome==3.7.2\r\npython-dateutil==2.7.5\r\npytz==2018.7\r\nrequests==2.20.1\r\nrlp==1.0.3\r\nsetuptools-scm==3.1.0\r\nsix==1.11.0\r\ntoolz==0.9.0\r\ntronapi==3.0.2\r\nurllib3==1.24.1\r\nvyper==0.1.0b5\r\n```\r\n\r\n### What's your issue about?\r\n\r\nScript returns cryptic \"zerovalent\" error when there is a function call after an if statement. Adding a pass statement after the function call makes it go away. Likewise, replacing the function call with the body of the function call makes it go away.\r\n\r\nStripped down example:\r\n```\r\n@private\r\ndef foo():\r\n    pass\r\n\r\n@public\r\ndef start():\r\n    if True:\r\n        self.foo()\r\n        # pass  # uncomment to successfully compile\r\n```\r\n\r\nError output:\r\n```\r\nError compiling:  error_reproduce.vy\r\nException: 2-clause if statement must have a zerovalent body: [seq,\r\n  /* Internal Call: foo */\r\n  [seq_unchecked,\r\n    [add, pc, 6],\r\n    [goto, priv_3264763256],\r\n    jumpdest,\r\n    0]]\r\n```\r\n\r\nCompiled using `vyper error_reproduce.vy`\r\n\n", "before_files": [{"content": "from vyper.exceptions import (\n    ConstancyViolationException\n)\nfrom vyper.parser.lll_node import (\n    LLLnode\n)\nfrom vyper.parser.parser_utils import (\n    pack_arguments,\n    getpos\n)\nfrom vyper.signatures.function_signature import (\n    FunctionSignature\n)\nfrom vyper.types import (\n    BaseType,\n    ByteArrayType,\n    ListType,\n    TupleType,\n    ceil32,\n    get_size_of_type,\n)\n\n\ndef call_lookup_specs(stmt_expr, context):\n    from vyper.parser.expr import Expr\n    method_name = stmt_expr.func.attr\n    expr_args = [Expr(arg, context).lll_node for arg in stmt_expr.args]\n    sig = FunctionSignature.lookup_sig(context.sigs, method_name, expr_args, stmt_expr, context)\n    return method_name, expr_args, sig\n\n\ndef make_call(stmt_expr, context):\n    method_name, _, sig = call_lookup_specs(stmt_expr, context)\n\n    if context.is_constant and not sig.const:\n        raise ConstancyViolationException(\n            \"May not call non-constant function '%s' within a constant function.\" % (method_name),\n            getpos(stmt_expr)\n        )\n\n    if sig.private:\n        return call_self_private(stmt_expr, context, sig)\n    else:\n        return call_self_public(stmt_expr, context, sig)\n\n\ndef call_make_placeholder(stmt_expr, context, sig):\n    if sig.output_type is None:\n        return 0, 0, 0\n\n    output_placeholder = context.new_placeholder(typ=sig.output_type)\n    out_size = get_size_of_type(sig.output_type) * 32\n    returner = output_placeholder\n\n    if not sig.private and isinstance(sig.output_type, ByteArrayType):\n            returner = output_placeholder + 32\n\n    return output_placeholder, returner, out_size\n\n\ndef call_self_private(stmt_expr, context, sig):\n    # ** Private Call **\n    # Steps:\n    # (x) push current local variables\n    # (x) push arguments\n    # (x) push jumpdest (callback ptr)\n    # (x) jump to label\n    # (x) pop return values\n    # (x) pop local variables\n\n    method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)\n    pre_init = []\n    pop_local_vars = []\n    push_local_vars = []\n    pop_return_values = []\n    push_args = []\n\n    # Push local variables.\n    if context.vars:\n        var_slots = [(v.pos, v.size) for name, v in context.vars.items()]\n        var_slots.sort(key=lambda x: x[0])\n        mem_from, mem_to = var_slots[0][0], var_slots[-1][0] + var_slots[-1][1] * 32\n        push_local_vars = [\n            ['mload', pos] for pos in range(mem_from, mem_to, 32)\n        ]\n        pop_local_vars = [\n            ['mstore', pos, 'pass'] for pos in reversed(range(mem_from, mem_to, 32))\n        ]\n\n    # Push Arguments\n    if expr_args:\n        inargs, inargsize, arg_pos = pack_arguments(sig, expr_args, context, return_placeholder=False, pos=getpos(stmt_expr))\n        push_args += [inargs]  # copy arguments first, to not mess up the push/pop sequencing.\n        static_arg_count = len(expr_args) * 32\n        static_pos = arg_pos + static_arg_count\n        total_arg_size = ceil32(inargsize - 4)\n\n        if len(expr_args) * 32 != total_arg_size:  # requires dynamic section.\n            ident = 'push_args_%d_%d_%d' % (sig.method_id, stmt_expr.lineno, stmt_expr.col_offset)\n            start_label = ident + '_start'\n            end_label = ident + '_end'\n            i_placeholder = context.new_placeholder(BaseType('uint256'))\n            push_args += [\n                ['mstore', i_placeholder, arg_pos + total_arg_size],\n                ['label', start_label],\n                ['if', ['lt', ['mload', i_placeholder], static_pos], ['goto', end_label]],\n                ['if_unchecked', ['ne', ['mload', ['mload', i_placeholder]], 0], ['mload', ['mload', i_placeholder]]],\n                ['mstore', i_placeholder, ['sub', ['mload', i_placeholder], 32]],  # decrease i\n                ['goto', start_label],\n                ['label', end_label]\n            ]\n\n        # push static section\n        push_args += [\n            ['mload', pos] for pos in reversed(range(arg_pos, static_pos, 32))\n        ]\n\n    # Jump to function label.\n    jump_to_func = [\n        ['add', ['pc'], 6],  # set callback pointer.\n        ['goto', 'priv_{}'.format(sig.method_id)],\n        ['jumpdest'],\n    ]\n\n    # Pop return values.\n    returner = [0]\n    if sig.output_type:\n        output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)\n        if output_size > 0:\n            dynamic_offsets = []\n            if isinstance(sig.output_type, (BaseType, ListType)):\n                pop_return_values = [\n                    ['mstore', ['add', output_placeholder, pos], 'pass'] for pos in range(0, output_size, 32)\n                ]\n            elif isinstance(sig.output_type, ByteArrayType):\n                dynamic_offsets = [(0, sig.output_type)]\n                pop_return_values = [\n                    ['pop', 'pass'],\n                ]\n            elif isinstance(sig.output_type, TupleType):\n                static_offset = 0\n                pop_return_values = []\n                for out_type in sig.output_type.members:\n                    if isinstance(out_type, ByteArrayType):\n                        pop_return_values.append(['mstore', ['add', output_placeholder, static_offset], 'pass'])\n                        dynamic_offsets.append((['mload', ['add', output_placeholder, static_offset]], out_type))\n                    else:\n                        pop_return_values.append(['mstore', ['add', output_placeholder, static_offset], 'pass'])\n                    static_offset += 32\n\n            # append dynamic unpacker.\n            dyn_idx = 0\n            for in_memory_offset, out_type in dynamic_offsets:\n                ident = \"%d_%d_arg_%d\" % (stmt_expr.lineno, stmt_expr.col_offset, dyn_idx)\n                dyn_idx += 1\n                start_label = 'dyn_unpack_start_' + ident\n                end_label = 'dyn_unpack_end_' + ident\n                i_placeholder = context.new_placeholder(typ=BaseType('uint256'))\n                begin_pos = ['add', output_placeholder, in_memory_offset]\n                # loop until length.\n                o = LLLnode.from_list(\n                    ['seq_unchecked',\n                        ['mstore', begin_pos, 'pass'],  # get len\n                        ['mstore', i_placeholder, 0],\n                        ['label', start_label],\n                        ['if', ['ge', ['mload', i_placeholder], ['ceil32', ['mload', begin_pos]]], ['goto', end_label]],  # break\n                        ['mstore', ['add', ['add', begin_pos, 32], ['mload', i_placeholder]], 'pass'],  # pop into correct memory slot.\n                        ['mstore', i_placeholder, ['add', 32, ['mload', i_placeholder]]],  # increment i\n                        ['goto', start_label],\n                        ['label', end_label]],\n                    typ=None, annotation='dynamic unpacker', pos=getpos(stmt_expr))\n                pop_return_values.append(o)\n\n    o = LLLnode.from_list(\n        ['seq_unchecked'] + pre_init + push_local_vars + push_args + jump_to_func + pop_return_values + pop_local_vars + [returner],\n        typ=sig.output_type, location='memory', pos=getpos(stmt_expr), annotation='Internal Call: %s' % method_name,\n        add_gas_estimate=sig.gas\n    )\n    o.gas += sig.gas\n    return o\n\n\ndef call_self_public(stmt_expr, context, sig):\n    # self.* style call to a public function.\n    method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)\n    add_gas = sig.gas  # gas of call\n    inargs, inargsize, _ = pack_arguments(sig, expr_args, context, pos=getpos(stmt_expr))\n    output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)\n    assert_call = [\n        'assert', ['call', ['gas'], ['address'], 0, inargs, inargsize, output_placeholder, output_size]\n    ]\n    if output_size > 0:\n        assert_call = ['seq', assert_call, returner]\n    o = LLLnode.from_list(\n        assert_call,\n        typ=sig.output_type, location='memory',\n        pos=getpos(stmt_expr), add_gas_estimate=add_gas, annotation='Internal Call: %s' % method_name)\n    o.gas += sig.gas\n    return o\n", "path": "vyper/parser/self_call.py"}], "after_files": [{"content": "from vyper.exceptions import (\n    ConstancyViolationException\n)\nfrom vyper.parser.lll_node import (\n    LLLnode\n)\nfrom vyper.parser.parser_utils import (\n    pack_arguments,\n    getpos\n)\nfrom vyper.signatures.function_signature import (\n    FunctionSignature\n)\nfrom vyper.types import (\n    BaseType,\n    ByteArrayType,\n    ListType,\n    TupleType,\n    ceil32,\n    get_size_of_type,\n)\n\n\ndef call_lookup_specs(stmt_expr, context):\n    from vyper.parser.expr import Expr\n    method_name = stmt_expr.func.attr\n    expr_args = [Expr(arg, context).lll_node for arg in stmt_expr.args]\n    sig = FunctionSignature.lookup_sig(context.sigs, method_name, expr_args, stmt_expr, context)\n    return method_name, expr_args, sig\n\n\ndef make_call(stmt_expr, context):\n    method_name, _, sig = call_lookup_specs(stmt_expr, context)\n\n    if context.is_constant and not sig.const:\n        raise ConstancyViolationException(\n            \"May not call non-constant function '%s' within a constant function.\" % (method_name),\n            getpos(stmt_expr)\n        )\n\n    if sig.private:\n        return call_self_private(stmt_expr, context, sig)\n    else:\n        return call_self_public(stmt_expr, context, sig)\n\n\ndef call_make_placeholder(stmt_expr, context, sig):\n    if sig.output_type is None:\n        return 0, 0, 0\n\n    output_placeholder = context.new_placeholder(typ=sig.output_type)\n    out_size = get_size_of_type(sig.output_type) * 32\n    returner = output_placeholder\n\n    if not sig.private and isinstance(sig.output_type, ByteArrayType):\n            returner = output_placeholder + 32\n\n    return output_placeholder, returner, out_size\n\n\ndef call_self_private(stmt_expr, context, sig):\n    # ** Private Call **\n    # Steps:\n    # (x) push current local variables\n    # (x) push arguments\n    # (x) push jumpdest (callback ptr)\n    # (x) jump to label\n    # (x) pop return values\n    # (x) pop local variables\n\n    method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)\n    pre_init = []\n    pop_local_vars = []\n    push_local_vars = []\n    pop_return_values = []\n    push_args = []\n\n    # Push local variables.\n    if context.vars:\n        var_slots = [(v.pos, v.size) for name, v in context.vars.items()]\n        var_slots.sort(key=lambda x: x[0])\n        mem_from, mem_to = var_slots[0][0], var_slots[-1][0] + var_slots[-1][1] * 32\n        push_local_vars = [\n            ['mload', pos] for pos in range(mem_from, mem_to, 32)\n        ]\n        pop_local_vars = [\n            ['mstore', pos, 'pass'] for pos in reversed(range(mem_from, mem_to, 32))\n        ]\n\n    # Push Arguments\n    if expr_args:\n        inargs, inargsize, arg_pos = pack_arguments(sig, expr_args, context, return_placeholder=False, pos=getpos(stmt_expr))\n        push_args += [inargs]  # copy arguments first, to not mess up the push/pop sequencing.\n        static_arg_count = len(expr_args) * 32\n        static_pos = arg_pos + static_arg_count\n        total_arg_size = ceil32(inargsize - 4)\n\n        if len(expr_args) * 32 != total_arg_size:  # requires dynamic section.\n            ident = 'push_args_%d_%d_%d' % (sig.method_id, stmt_expr.lineno, stmt_expr.col_offset)\n            start_label = ident + '_start'\n            end_label = ident + '_end'\n            i_placeholder = context.new_placeholder(BaseType('uint256'))\n            push_args += [\n                ['mstore', i_placeholder, arg_pos + total_arg_size],\n                ['label', start_label],\n                ['if', ['lt', ['mload', i_placeholder], static_pos], ['goto', end_label]],\n                ['if_unchecked', ['ne', ['mload', ['mload', i_placeholder]], 0], ['mload', ['mload', i_placeholder]]],\n                ['mstore', i_placeholder, ['sub', ['mload', i_placeholder], 32]],  # decrease i\n                ['goto', start_label],\n                ['label', end_label]\n            ]\n\n        # push static section\n        push_args += [\n            ['mload', pos] for pos in reversed(range(arg_pos, static_pos, 32))\n        ]\n\n    # Jump to function label.\n    jump_to_func = [\n        ['add', ['pc'], 6],  # set callback pointer.\n        ['goto', 'priv_{}'.format(sig.method_id)],\n        ['jumpdest'],\n    ]\n\n    # Pop return values.\n    returner = [0]\n    if sig.output_type:\n        output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)\n        if output_size > 0:\n            dynamic_offsets = []\n            if isinstance(sig.output_type, (BaseType, ListType)):\n                pop_return_values = [\n                    ['mstore', ['add', output_placeholder, pos], 'pass'] for pos in range(0, output_size, 32)\n                ]\n            elif isinstance(sig.output_type, ByteArrayType):\n                dynamic_offsets = [(0, sig.output_type)]\n                pop_return_values = [\n                    ['pop', 'pass'],\n                ]\n            elif isinstance(sig.output_type, TupleType):\n                static_offset = 0\n                pop_return_values = []\n                for out_type in sig.output_type.members:\n                    if isinstance(out_type, ByteArrayType):\n                        pop_return_values.append(['mstore', ['add', output_placeholder, static_offset], 'pass'])\n                        dynamic_offsets.append((['mload', ['add', output_placeholder, static_offset]], out_type))\n                    else:\n                        pop_return_values.append(['mstore', ['add', output_placeholder, static_offset], 'pass'])\n                    static_offset += 32\n\n            # append dynamic unpacker.\n            dyn_idx = 0\n            for in_memory_offset, out_type in dynamic_offsets:\n                ident = \"%d_%d_arg_%d\" % (stmt_expr.lineno, stmt_expr.col_offset, dyn_idx)\n                dyn_idx += 1\n                start_label = 'dyn_unpack_start_' + ident\n                end_label = 'dyn_unpack_end_' + ident\n                i_placeholder = context.new_placeholder(typ=BaseType('uint256'))\n                begin_pos = ['add', output_placeholder, in_memory_offset]\n                # loop until length.\n                o = LLLnode.from_list(\n                    ['seq_unchecked',\n                        ['mstore', begin_pos, 'pass'],  # get len\n                        ['mstore', i_placeholder, 0],\n                        ['label', start_label],\n                        ['if', ['ge', ['mload', i_placeholder], ['ceil32', ['mload', begin_pos]]], ['goto', end_label]],  # break\n                        ['mstore', ['add', ['add', begin_pos, 32], ['mload', i_placeholder]], 'pass'],  # pop into correct memory slot.\n                        ['mstore', i_placeholder, ['add', 32, ['mload', i_placeholder]]],  # increment i\n                        ['goto', start_label],\n                        ['label', end_label]],\n                    typ=None, annotation='dynamic unpacker', pos=getpos(stmt_expr))\n                pop_return_values.append(o)\n\n    call_body = (\n        ['seq_unchecked'] +\n        pre_init +\n        push_local_vars +\n        push_args +\n        jump_to_func +\n        pop_return_values +\n        pop_local_vars +\n        [returner]\n    )\n    # If we have no return, we need to pop off\n    pop_returner_call_body = ['pop', call_body] if sig.output_type is None else call_body\n\n    o = LLLnode.from_list(\n        pop_returner_call_body,\n        typ=sig.output_type, location='memory', pos=getpos(stmt_expr), annotation='Internal Call: %s' % method_name,\n        add_gas_estimate=sig.gas\n    )\n    o.gas += sig.gas\n    return o\n\n\ndef call_self_public(stmt_expr, context, sig):\n    # self.* style call to a public function.\n    method_name, expr_args, sig = call_lookup_specs(stmt_expr, context)\n    add_gas = sig.gas  # gas of call\n    inargs, inargsize, _ = pack_arguments(sig, expr_args, context, pos=getpos(stmt_expr))\n    output_placeholder, returner, output_size = call_make_placeholder(stmt_expr, context, sig)\n    assert_call = [\n        'assert', ['call', ['gas'], ['address'], 0, inargs, inargsize, output_placeholder, output_size]\n    ]\n    if output_size > 0:\n        assert_call = ['seq', assert_call, returner]\n    o = LLLnode.from_list(\n        assert_call,\n        typ=sig.output_type, location='memory',\n        pos=getpos(stmt_expr), add_gas_estimate=add_gas, annotation='Internal Call: %s' % method_name)\n    o.gas += sig.gas\n    return o\n", "path": "vyper/parser/self_call.py"}]}