-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgmlc.py
executable file
·153 lines (116 loc) · 4.83 KB
/
gmlc.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
#!/usr/bin/python
import sys
import argparse
import glob
import os
import shutil
from gmlc_compiler import Compiler, CHAR_SYMBOLS
from gmlc_sbltranslator import SblTranslator
from gmlc_utils import *
class BColors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
class AlertType:
ERR = 1
WARN = 2
def main():
# Parse input
parser = argparse.ArgumentParser()
parser.add_argument("files", nargs="+", help="File/s to compile. Globs allowed.")
parser.add_argument("-o", "--output", type=str, help="Output file path, not including extension.", default="out")
parser.add_argument("-se", "--script-export", help="Allow parsing of exported scripts from Game Maker.", action="store_true")
parser.add_argument("-r", "--release", help="Minify GML code. Runtime errors will be illegible.", action="store_true")
parser.add_argument("-el", "--errorlim", type=int, help="Maximum number of errors before aborting.", default=10)
parser.add_argument("-dne", "--dbg-no-encrypt", help="Will break the executable but share code output.", action="store_true")
parser.add_argument("-minstr", "--minify-strings", help="Will minify strings that consist solely of a name.", action="store_true")
args = parser.parse_args()
# Find files to compile
compile_files = []
for glob_path in args.files:
matches = glob.glob(glob_path)
compile_files.extend(matches)
# Temporary file for compiling
tmppath = ".tmpcomp"
exepath = "run.exe"
compiler = Compiler(args.script_export)
alerts = []
error_num = 0
# Compile files
with open(tmppath, "w") as f_out:
# Helper to process feed result
def process_feed_results(results, alerts):
(out, warn, err) = results
map(lambda warning : alerts.append((AlertType.WARN, source, line, col, warning)), warn)
map(lambda error : alerts.append((AlertType.ERR, source, line, col, error)), err)
if out:
# Add transpiled code to executable
f_out.write(out)
return error_num + len(err)
for source in compile_files:
print "Compiling", source + "..."
with open(source,"r") as f_in:
line = 1
ml_comment = False
for linestr in f_in:
symbols, ml_comment = line_to_symbols(linestr, CHAR_SYMBOLS, ml_comment)
for symbol, idx in symbols:
col = idx + 1
# Generate compiled code, warnings, errors
results = compiler.feed(symbol)
error_num = process_feed_results(results, alerts)
if error_num > args.errorlim: break
line += 1
if error_num > args.errorlim: break
if error_num > args.errorlim: break
# Finalize file
#final_results = compiler.feed_final
# Finalize compilation
final_results = compiler.feed_final()
error_num = process_feed_results(final_results, alerts)
# Simple warnings
if args.dbg_no_encrypt:
alerts.append((AlertType.WARN, None, None, None, "Encryption is disabled. Executable is not runnable."))
# Notify the user of results
map(lambda alert: print_alert(alert), alerts)
if error_num != 0:
# Delete output file
os.remove(tmppath)
# Alert
print "Compilation failed due to errors."
return 1
# Create the executable by copying
outpath = args.output + ".exe" if args.output[-4:] != ".exe" else args.output
shutil.copy(exepath, outpath)
# Translate to the executable
resource_names = compiler.get_resource_names()
script_names = compiler.get_script_names()
exe_size = os.path.getsize(exepath)
translator = SblTranslator(resource_names, script_names, exe_size, args.release, not args.dbg_no_encrypt)
with open(outpath, "a") as f_out, open(tmppath, "r") as f_in:
for compiled_line in f_in:
symbols = explode_preserve(compiled_line, None)
for symbol in symbols:
f_out.write(translator.feed(symbol))
# Delete temporary file
os.remove(tmppath)
print "Compilation passed. Output file:", outpath, "generated."
# Prints an alert
def print_alert(alert):
(typ, source, line, col, string) = alert
# Print type
if typ == AlertType.ERR:
print BColors.FAIL + "ERROR" + BColors.ENDC,
elif typ == AlertType.WARN:
print BColors.WARNING + "WARNING" + BColors.ENDC,
# Print location
if source: print "in file", source + ", line", line, "col", col
# Print string
print string
if __name__ == "__main__":
main()