-
Notifications
You must be signed in to change notification settings - Fork 0
/
webcc.monkey
458 lines (344 loc) · 9.05 KB
/
webcc.monkey
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
#Rem
'jstool' application: "WebCC" - Driver program for the Monkey transpiler.
Based heavily on 'TransCC': Original software placed into the public domain. (02/24/2011)
No warranty implied; use at your own risk.
#End
'Strict
Public
' Preprocessor related:
#WEBCC_EXTENSION_REGAL_MODULES = True
' Tell 'jstool' that we'll be starting this natively. (Button, function call, etc)
#JSTOOL_STANDALONE = True
' Imports:
' JavaScript:
Import "native/wcc_support.js"
' Monkey:
Import trans
Import builders
' Constant variable(s):
Const VERSION:String = "1.0.1 {1.86}"
' External bindings:
Extern
' Global variable(s):
' This is externally defined so we can bypass 'bbInit' at the target/translator level.
Global __Monkey_DirectoryLoaded:Bool="__monkey_DirectoryLoaded"
Public
' Functions:
Function Main:Int()
' Local variable(s):
Local CC:= New WebCC()
If (Not __Monkey_DirectoryLoaded) Then
__OS_AddFileSystem(__OS_ToRemotePath(RealPath("data/webcc_filesystem.txt")))
#If WEBCC_EXTENSION_REGAL_MODULES
__OS_AddFileSystem(__OS_ToRemotePath(RealPath("data/modules/regal/regal_filesystem.txt")))
#End
__Monkey_DirectoryLoaded = True
Endif
CC.Run(AppArgs())
' Return the default response.
Return 0
End
Function Die:Int(Message:String, ExitCode:Int=-1)
Print("WEBCC (TRANS) FAILED: " + Message)
ExitApp(ExitCode)
Return ExitCode
End
Function StripQuotes:String(Str:String)
If (Str.Length >= 2 And Str.StartsWith("~q") And Str.EndsWith("~q")) Then
Return Str[1..-1]
Endif
Return Str
End
Function ReplaceEnv:String(Str:String)
Local Bits:= New StringStack()
Repeat
Local i:= Str.Find("${")
If (i = -1) Then Exit
Local e:= Str.Find("}", i+2)
If (e = -1) Then Exit
If (i >= 2 And Str[i-2..i] = "//") Then
Bits.Push(Str[..e+1])
Str = Str[e+1..]
Continue
Endif
Local t:= Str[i+2..e]
Local v:= GetConfigVar(t)
If (Not v) Then v = GetEnv(t)
Bits.Push(Str[..i])
Bits.Push(v)
Str = Str[e+1..]
Forever
If (Bits.IsEmpty()) Then
Return Str
Endif
Bits.Push(Str)
Return Bits.Join("")
End
Function ReplaceBlock:String(text:String, tag:String, repText:String, mark:String="~n//")
' Find the beginning tag.
Local beginTag:= mark + "${" + tag + "_BEGIN}"
Local i:= text.Find(beginTag)
If (i = -1) Then
Die("Error updating target project - can't find block begin tag '" + tag + "'. You may need to delete target .build directory.")
Endif
i += beginTag.Length
While (i < text.Length And text[i-1] <> 10)
i += 1
Wend
' Find the ending tag.
Local endTag:= mark + "${" + tag + "_END}"
Local i2:= text.Find(endTag, i-1)
If (i2 = -1) Then
Die("Error updating target project - can't find block end tag '" + tag + "'.")
Endif
If (Not repText Or repText[repText.Length-1] = 10) Then
i2 += 1
Endif
Return text[..i] + repText + text[i2..]
End
Function MatchPathAlt:Bool(text:String, alt:String)
If (Not alt.Contains( "*" )) Then
Return (alt = text)
Endif
Local Bits:= alt.Split( "*" )
If (Not text.StartsWith(Bits[0])) Then
Return False
Endif
Local n:= (Bits.Length - 1)
Local i:= Bits[0].Length
For Local j:= 1 Until n
Local bit:= Bits[j]
i = text.Find(bit, i)
If (i = -1) Then
Return False
Endif
i += bit.Length
Next
Return text[i..].EndsWith(Bits[n])
End
Function MatchPath:Bool(text:String, pattern:String)
text = "/" + text
Local alts:= pattern.Split("|")
Local match:= False
For Local alt:= Eachin alts
If (Not alt) Then
Continue
Endif
If (alt.StartsWith("!")) Then
If (MatchPathAlt(text, alt[1..])) Then
Return False
Endif
Else
If (MatchPathAlt(text, alt)) Then
match = True
Endif
Endif
Next
Return match
End
' Classes:
Class Target
' Fields:
Field dir:String
Field name:String
Field system:String
Field builder:Builder
' Constructor(s):
Method New(dir:String, name:String, system:String, builder:Builder)
Self.dir = dir
Self.name = name
Self.system = system
Self.builder = builder
End
End
Class WebCC
' Constant variable(s):
' This value must be enclosed in quotes, and be the same in the execution environment.
Const EXEC_PREFIX:String = "~q||MNKYEXECUTE||~q"
' Fields (Public):
' Command-line options:
Field opt_safe:Bool
Field opt_clean:Bool
Field opt_check:Bool
Field opt_update:Bool
Field opt_build:Bool
Field opt_run:Bool
Field opt_srcpath:String
Field opt_cfgfile:String
Field opt_output:String
Field opt_config:String
Field opt_casedcfg:String
Field opt_target:String
Field opt_modpath:String
Field opt_builddir:String
' Meta:
Field args:String[]
Field monkeydir:String
Field target:Target
' Fields (Private):
Private
Field _builders:= New StringMap<Builder>
Field _targets:= New StringMap<Target>
Public
' Methods:
Method Run:Void(args:String[])
Self.args = args
Print("WebCC Monkey compiler V" + VERSION)
Local APath:= AppPath()
Local EDir:= ExtractDir(APath)
monkeydir=RealPath( EDir +"/.." )
SetEnv "MONKEYDIR",monkeydir
SetEnv "TRANSDIR",monkeydir+"/bin"
ParseArgs
LoadConfig
EnumBuilders
EnumTargets "targets"
If args.Length<2
Local valid:=""
For Local it:=Eachin _targets
valid+=" "+it.Key.Replace( " ","_" )
Next
Print "TRANS Usage: WebCC [-update] [-build] [-run] [-clean] [-config=...] [-target=...] [-cfgfile=...] [-modpath=...] <main_monkey_source_file>"
Print "Valid targets:"+valid
Print "Valid configs: debug release"
ExitApp 0
Endif
target=_targets.Get( opt_target.Replace( "_"," " ) )
If Not target Die "Invalid target"
target.builder.Make
End
Method GetReleaseVersion:String()
Local f:=LoadString( monkeydir+"/VERSIONS.TXT" )
For Local t:=Eachin f.Split( "~n" )
t=t.Trim()
If t.StartsWith( "***** v" ) And t.EndsWith( " *****" ) Return t[6..-6]
Next
Return ""
End
Method EnumBuilders:Void()
For Local it:=Eachin Builders( Self )
If it.Value.IsValid() _builders.Set it.Key,it.Value
Next
End
Method EnumTargets:Void( dir:String )
Local p:=monkeydir+"/"+dir
For Local f:=Eachin LoadDir( p )
Local t:=p+"/"+f+"/TARGET.MONKEY"
If FileType(t)<>FILETYPE_FILE Continue
PushConfigScope
PreProcess t
Local name:=GetConfigVar( "TARGET_NAME" )
If name
Local system:=GetConfigVar( "TARGET_SYSTEM" )
If system
Local builder:=_builders.Get( GetConfigVar( "TARGET_BUILDER" ) )
If builder
Local host:=GetConfigVar( "TARGET_HOST" )
If Not host Or host=HostOS
_targets.Set name,New Target( f,name,system,builder )
Endif
Endif
Endif
Endif
PopConfigScope
Next
End
Method ParseArgs:Void()
If args.Length>1 opt_srcpath=StripQuotes( args[args.Length-1].Trim() )
For Local i:=1 Until args.Length-1
Local arg:=args[i].Trim(),rhs:=""
Local j:=arg.Find( "=" )
If j<>-1
rhs=StripQuotes( arg[j+1..] )
arg=arg[..j]
Endif
If (j = -1) Then
Select arg.ToLower()
Case "-safe"
opt_safe = True
Case "-clean"
opt_clean = True
Case "-check"
opt_check = True
Case "-update"
opt_check = True
opt_update = True
Case "-build"
opt_check = True
opt_update = True
opt_build = True
Case "-run"
opt_check = True
opt_update = True
opt_build = True
opt_run = True
Default
Die("Unrecognized command-line option: " + arg)
End Select
Elseif (arg.StartsWith("-")) Then
Select arg.ToLower()
Case "-cfgfile"
opt_cfgfile=rhs
Case "-output"
opt_output=rhs
Case "-config"
opt_config=rhs.ToLower()
Case "-target"
opt_target=rhs
Case "-modpath"
opt_modpath=rhs
Case "-builddir"
opt_builddir=rhs
Default
Die "Unrecognized command line option: "+arg
End
Elseif (arg.StartsWith("+")) Then
SetConfigVar(arg[1..], rhs)
Else
Die("Command-line parser error: " + arg)
End
Next
End
Method LoadConfig:Void()
Local cfgpath:=monkeydir+"/bin/"
If opt_cfgfile
cfgpath+=opt_cfgfile
Else
cfgpath+="config."+HostOS+".txt"
Endif
If FileType( cfgpath )<>FILETYPE_FILE Die "Failed to open config file"
Local cfg:= LoadString(cfgpath)
For Local line:=Eachin cfg.Split( "~n" )
line=line.Trim()
If Not line Or line.StartsWith( "'" ) Continue
Local i:= line.Find( "=" )
If i=-1 Die "Error in config file, line="+line
Local lhs:=line[..i].Trim()
Local rhs:=line[i+1..].Trim()
rhs=ReplaceEnv( rhs )
Local path:=StripQuotes( rhs )
While path.EndsWith( "/" ) Or path.EndsWith( "\" )
path=path[..-1]
Wend
Select lhs
Case "MODPATH"
If (Not opt_modpath) Then
opt_modpath = path
Endif
Default
Print("WebCC: Ignoring unrecognized config variable: " + lhs)
End Select
Next
End
Method Execute:Bool(CommandLine:String, FailHard:Bool=True)
Local ResponseCode:= os.Execute(CommandLine)
If (Not ResponseCode) Then
Return True
Endif
If (FailHard) Then
Die("Error executing '" + CommandLine + "', return code: " + ResponseCode)
Endif
' Return the default response.
Return False
End
End