-
Notifications
You must be signed in to change notification settings - Fork 7
/
option.py
188 lines (155 loc) · 6.9 KB
/
option.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# flake8: noqa: E501
from __future__ import absolute_import
import os
from aheui._argparse import ArgumentParser, ParserError
from aheui._compat import bigint, PY3
from aheui.version import VERSION
from aheui.warning import CommandLineArgumentWarning, warnings
from aheui import compile
parser = ArgumentParser(prog='aheui')
parser.add_argument('--opt', '-O', default='1', choices='0,1,2', description='Set optimization level.', full_description="""\t0: No optimization.
\t1: Quickly resolve deadcode by rough stacksize emulation and merge constant operations.
\t2: Perfectly resolve deadcode by stacksize emulation, reserialize code chunks and merge constant operations.
""")
parser.add_argument('--source', '-S', default='auto', choices='auto,bytecode,asm,text', description='Set source filetype.', full_description="""\t- `auto`: Guess the source type. `bytecode` if `.aheuic` or `End of bytecode` pattern in source. `asm` is `.aheuis`. `text` if `.aheui`. `text` is default.
\t- `bytecode`: Aheui bytecode. (Bytecode representation of `ahsembly`.
\t- `asm`: See `ahsembly`.
\t- `asm+comment`: Same as `asm` with comments.
\t- usage: `--source=asm`, `-Sbytecode` or `-S text`
""")
parser.add_argument('--target', '-T', default='run', choices='run,bytecode,asm,asm+comment', description='Set target filetype.', full_description="""\t- `run`: Run given code.
\t- `bytecode`: Aheui bytecode. (Bytecode representation of `ahsembly`.
\t- `asm`: See `ahsembly`.
\t- usage: `--target=asm`, `-Tbytecode` or `-T run`
""")
parser.add_argument('--output', '-o', default='', description='Output file. Default is ``. See details for each target. If the value is `-`, it is standard output.', full_description="""\t- `run` target: This option is not availble and ignored.
\t- `bytecode` target: Default value is `.aheuic`
\t- `asm` target: Default value is `.aheuis`
""")
parser.add_argument('--cmd', '-c', default='', description='Program passed in as string')
parser.add_argument('--no-c', '--no-c', narg='0', default='no', description='Do not generate `.aheuic` file automatically.', full_description='\tWhat is .aheuic? https://github.com/aheui/snippets/commit/cbb5a12e7cd2db771538ab28dfbc9ad1ada86f35\n')
parser.add_argument('--warning-limit', '--warning-limit', default='', description='Set repetitive warning limit. '' fallbacks to environment variable `RPAHEUI_WARNING_LIMIT`. 0 means no warning. -1 means no limit. Default is 3.')
parser.add_argument('--trace-limit', '--trace-limit', default='', description='Set JIT trace limit. '' fallbacks to environment variable `RPAHEUI_TRACE_LIMIT`.')
parser.add_argument('--version', '-v', narg='-1', default='no', description='Show program version', message=('%s %s' % (VERSION, bigint.NAME)).encode('utf-8'))
parser.add_argument('--help', '-h', narg='-1', default='no', description='Show this help text')
class OptionError(Exception):
pass
class ParsingError(OptionError):
def __init__(self, msg):
self.args = (msg,)
def message(self):
return self.args[0]
class IntOptionParsingError(OptionError):
def __init__(self, key, value):
self.args = (key, value)
def message(self):
return 'The value of %s="%s" is not a valid integer' % self.args
class SourceError(OptionError):
pass
class NoInputError(SourceError):
def message(self):
return "no input files"
class CommandConflictInputFileError(SourceError):
def message(self):
return "--cmd,-c and input file cannot be used together"
def kwarg_or_environ(kwargs, environ, arg_key, env_key):
if arg_key in kwargs and kwargs[arg_key] != '':
return (1, kwargs[arg_key])
try:
return (2, environ[env_key])
except KeyError:
return (0, '')
def kwarg_or_environ_int(kwargs, environ, arg_key, env_key, default):
source, arg = kwarg_or_environ(kwargs, environ, arg_key, env_key)
if source == 0:
return default
try:
value = int(arg)
except ValueError:
if source == 1:
raise IntOptionParsingError('--' + arg_key, arg)
elif source == 2:
raise IntOptionParsingError(env_key, arg)
else:
assert False
return value
def open_input(filename):
return os.open(filename, os.O_RDONLY, 0o777)
def process_options(argv, environ):
try:
kwargs, args = parser.parse_args(argv)
except ParserError as e:
raise ParsingError(e.message())
cmd = kwargs['cmd']
if cmd == '':
if len(args) != 2:
raise NoInputError()
filename = args[1]
if filename == '-':
fp = 0
contents = compile.read(fp)
else:
fp = open_input(filename)
contents = compile.read(fp)
os.close(fp)
else:
if len(args) != 1:
raise CommandConflictInputFileError
if PY3:
cmd = cmd.encode('utf-8')
contents = cmd
filename = '-'
source = kwargs['source']
if source == 'auto':
if filename.endswith('.aheui'):
source = 'text'
elif filename.endswith('.aheuic'):
source = 'bytecode'
elif filename.endswith('.aheuis'):
source = 'asm'
elif b'\xff\xff\xff\xff' in contents:
source = 'bytecode'
else:
source = 'text'
opt_level = kwargs['opt']
target = kwargs['target']
need_aheuic = target == 'run' and kwargs['no-c'] == 'no'\
and filename != '-' and not filename.endswith('.aheuic')
if need_aheuic:
aheuic_output = filename
if filename.endswith('.aheui'):
aheuic_output = filename + 'c'
elif filename.endswith('.aheuis'):
aheuic_output = filename[:-1] + 'c'
else:
aheuic_output = filename + '.aheuic'
else:
aheuic_output = None
output = kwargs['output']
comment_aheuis = False
if output == '':
if target == 'bytecode':
output = filename
if output.endswith('.aheui'):
output += 'c'
else:
output += '.aheuic'
elif target in ['asm', 'asm+comment']:
output = filename
if output != '-':
if output.endswith('.aheui'):
output += 's'
else:
output += '.aheuis'
comment_aheuis = target == 'asm+comment'
elif target == 'run':
output = '-'
else:
assert False # must be handled by argparse
raise SystemExit()
else:
if target == 'run':
warnings.warn(CommandLineArgumentWarning, b'--target=run always ignores --output')
warning_limit = kwarg_or_environ_int(kwargs, environ, 'warning-limit', 'RPAHEUI_WARNING_LIMIT', 3)
trace_limit = kwarg_or_environ_int(kwargs, environ, 'trace-limit', 'RPAHEUI_TRACE_LIMIT', -1)
return cmd, source, contents, opt_level, target, aheuic_output, comment_aheuis, output, warning_limit, trace_limit