Skip to content

Commit 4d7759a

Browse files
authored
Merge pull request #103 from SerpentChris/master
Added script which translates imports to externs, more functionality …
2 parents 65dd688 + 65285dc commit 4d7759a

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed

load_contracts2.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#!/usr/bin/env python
2+
# Copyright (c) 2017 Christian Calderon
3+
4+
# Permission is hereby granted, free of charge, to any person obtaining a copy
5+
# of this software and associated documentation files (the "Software"), to deal
6+
# in the Software without restriction, including without limitation the rights
7+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
# copies of the Software, and to permit persons to whom the Software is
9+
# furnished to do so, subject to the following conditions:
10+
11+
# The above copyright notice and this permission notice shall be included in all
12+
# copies or substantial portions of the Software.
13+
14+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
# SOFTWARE.
21+
from __future__ import print_function
22+
import argparse
23+
import serpent
24+
import os
25+
import re
26+
import binascii
27+
import json
28+
import shutil
29+
import sys
30+
31+
if (3, 0) <= sys.version_info:
32+
_old_mk_signature = serpent.mk_signature
33+
def mk_signature(code):
34+
return _old_mk_signature(code).decode()
35+
serpent.mk_signature = mk_signature
36+
37+
PYNAME = '[A-Za-z_][A-Za-z0-9_]*'
38+
IMPORT = re.compile('import ({0}) as ({0})'.format(PYNAME))
39+
40+
DEFAULT_RPCADDR = 'http://localhost:8545'
41+
DEFAULT_SRCDIR = './src'
42+
DEFAULT_BUILDDIR = './build'
43+
44+
SERPENT_EXT = '.se'
45+
MACRO_EXT = '.sem'
46+
47+
parser = argparse.ArgumentParser(description='Compiles collections of serpent contracts.')
48+
parser.add_argument('-R', '--rpcaddr', help='Address of RPC server', default=DEFAULT_RPCADDR)
49+
parser.add_argument('-S', '--srcdir', help='Directory to search for Serpent code', default=DEFAULT_SRCDIR)
50+
parser.add_argument('-B', '--builddir', help='Directory to save translated code in.', default=DEFAULT_BUILDDIR)
51+
modes = parser.add_mutually_exclusive_group(required=True)
52+
modes.add_argument('-T', '--translate', help='Just translate imports and save in builddir', action='store_true', default=False)
53+
modes.add_argument('-U', '--update', help='Updates the externs in all the contracts.', action='store_true', default=False)
54+
55+
56+
def find_files(source_dir, extension):
57+
"""Makes a list of paths in the directory which end in the extenstion."""
58+
paths = []
59+
for entry in os.listdir(source_dir):
60+
entry = os.path.join(source_dir, entry)
61+
if os.path.isfile(entry) and entry.endswith(extension):
62+
paths.append(entry)
63+
elif os.path.isdir(entry):
64+
paths.extend(find_files(entry, extension))
65+
else:
66+
continue
67+
return paths
68+
69+
70+
def strip_dependencies(serpent_file):
71+
"""Separates dependency information from Serpent code in the file."""
72+
dependencies = []
73+
other_code = []
74+
crud = []
75+
done_with_crud = False
76+
with open(serpent_file) as code:
77+
for i, line in enumerate(code):
78+
line = line.rstrip()
79+
if line.startswith('#') and not done_with_crud:
80+
crud.append(line)
81+
continue
82+
done_with_crud = True
83+
84+
if line.startswith('import'):
85+
m = IMPORT.match(line)
86+
if m is None:
87+
print('SAD! weird import at line', i, 'in contract', path)
88+
sys.exit(1)
89+
dependencies.append((m.group(1), m.group(2)))
90+
else:
91+
other_code.append(line)
92+
93+
other_code.append('')
94+
crud.append('')
95+
96+
return dependencies, '\n'.join(other_code), '\n'.join(crud)
97+
98+
99+
def imports_to_externs(source_dir, new_dir):
100+
"""Translates code using import syntax to standard Serpent externs."""
101+
source_dir = os.path.abspath(source_dir)
102+
new_dir = os.path.abspath(new_dir)
103+
104+
shutil.copytree(source_dir, new_dir)
105+
106+
serpent_files = find_files(new_dir, SERPENT_EXT)
107+
108+
source_map = {}
109+
110+
for path in serpent_files:
111+
name = os.path.basename(path).replace(SERPENT_EXT, '')
112+
info = {}
113+
info['dependencies'], info['stripped_code'], info['crud'] = strip_dependencies(path)
114+
115+
with open(path, 'w') as temp:
116+
temp.write(info['stripped_code'])
117+
118+
extern_name = 'extern {}:'.format(name)
119+
signature = serpent.mk_signature(path)
120+
name_end = signature.find(':') + 1
121+
signature = extern_name + signature[name_end:]
122+
info['signature'] = signature
123+
info['path'] = path
124+
source_map[name] = info
125+
126+
lookup_fmt = '{} = Controller.lookup(\'{}\')'
127+
for name in source_map:
128+
info = source_map[name]
129+
signatures = ['macro Controller: 0xC001D00D', 'extern Controller: [lookup:[int256]:int256, checkWhitelist:[int256]:int256]']
130+
for oname, alias in info['dependencies']:
131+
signatures.append('')
132+
signatures.append(lookup_fmt.format(alias, oname))
133+
signatures.append(source_map[oname]['signature'])
134+
signatures.append('')
135+
new_code = '\n'.join([info['crud']] + signatures + [info['stripped_code']])
136+
path = info['path']
137+
138+
with open(path, 'w') as f:
139+
f.write(new_code)
140+
141+
142+
def update_externs(source_dir):
143+
pass
144+
145+
146+
def main():
147+
args = parser.parse_args()
148+
149+
if args.translate:
150+
imports_to_externs(args.srcdir, args.builddir)
151+
elif args.update:
152+
update_externs(args.srcdir)
153+
else:
154+
return 1
155+
156+
return 0
157+
158+
if __name__ == '__main__':
159+
sys.exit(main())

0 commit comments

Comments
 (0)