]> git.lizzy.rs Git - rust.git/blob - src/etc/2014-06-rewrite-bytes-macros.py
cleanup: s/impl Copy/#[derive(Copy)]/g
[rust.git] / src / etc / 2014-06-rewrite-bytes-macros.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2014 The Rust Project Developers. See the COPYRIGHT
4 # file at the top-level directory of this distribution and at
5 # http://rust-lang.org/COPYRIGHT.
6 #
7 # Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
8 # http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
9 # <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
10 # option. This file may not be copied, modified, or distributed
11 # except according to those terms.
12
13 import sys
14 import subprocess
15 import re
16
17
18 def main():
19     if len(sys.argv) <= 1:
20         print('Usage: %s [ --apply ] filename1.rs filename2.rs ...'
21               % sys.argv[0])
22     elif sys.argv[1] == '--apply':
23         for filename in sys.argv[2:]:
24             patch(filename)
25     else:
26         for filename in sys.argv[1:]:
27             diff(filename)
28
29
30 def patch(filename):
31     source = read(filename)
32     rewritten = rewrite_bytes_macros(source)
33     if rewritten is not None and rewritten != source:
34         write(filename, rewritten)
35
36
37 def diff(filename):
38     rewritten = rewrite_bytes_macros(read(filename))
39     if rewritten is not None:
40         p = subprocess.Popen(['diff', '-u', filename, '-'],
41                              stdin=subprocess.PIPE)
42         p.stdin.write(rewritten)
43         p.stdin.close()
44         p.wait()
45
46
47 def read(filename):
48     with open(filename, 'rb') as f:
49         return f.read()
50
51
52 def write(filename, content):
53     with open(filename, 'wb') as f:
54         f.write(content)
55
56
57 def rewrite_bytes_macros(source):
58     rewritten, num_occurrences = BYTES_MACRO_RE.subn(rewrite_one_macro, source)
59     if num_occurrences > 0:
60         return rewritten
61
62
63 BYTES_MACRO_RE = re.compile(br'bytes!\(  (?P<args>  [^)]*  )  \)', re.VERBOSE)
64
65
66 def rewrite_one_macro(match):
67     try:
68         bytes = parse_bytes(split_args(match.group('args')))
69         return b'b"' + b''.join(map(escape, bytes)) + b'"'
70     except SkipThisRewrite:
71         print('Skipped: %s' % match.group(0).decode('utf8', 'replace'))
72         return match.group(0)
73
74
75 class SkipThisRewrite(Exception):
76     pass
77
78
79 def split_args(args):
80     previous = b''
81     for arg in args.split(b','):
82         if previous:
83             arg = previous + b',' + arg
84         if arg.count(b'"') % 2 == 0:
85             yield arg
86             previous = b''
87         else:
88             previous = arg
89     if previous:
90         yield previous
91
92
93 def parse_bytes(args):
94     for arg in args:
95         arg = arg.strip()
96         if (arg.startswith(b'"') and arg.endswith(b'"')) or (
97                 arg.startswith(b"'") and arg.endswith(b"'")):
98             # Escaped newline means something different in Rust and Python.
99             if b'\\\n' in arg:
100                 raise SkipThisRewrite
101             for byte in eval(b'u' + arg).encode('utf8'):
102                 yield ord(byte)
103         else:
104             if arg.endswith(b'u8'):
105                 arg = arg[:-2]
106             # Assume that all Rust integer literals
107             # are valid Python integer literals
108             value = int(eval(arg))
109             assert value <= 0xFF
110             yield value
111
112
113 def escape(byte):
114     c = chr(byte)
115     escaped = {
116         b'\0': br'\0',
117         b'\t': br'\t',
118         b'\n': br'\n',
119         b'\r': br'\r',
120         b'\'': b'\\\'',
121         b'\\': br'\\',
122     }.get(c)
123     if escaped is not None:
124         return escaped
125     elif b' ' <= c <= b'~':
126         return chr(byte)
127     else:
128         return ('\\x%02X' % byte).encode('ascii')
129
130
131 if str is not bytes:
132     # Python 3.x
133     ord = lambda x: x
134     chr = lambda x: bytes([x])
135
136
137 if __name__ == '__main__':
138     main()