-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMainFile.zu
332 lines (274 loc) · 10 KB
/
MainFile.zu
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
#
# The Zimbu compiler written in Zimbu
#
# MainFile class: values for the main file.
#
# Copyright 2009 Bram Moolenaar All Rights Reserved.
# Licensed under the Apache License, Version 2.0. See the LICENSE file or
# obtain a copy at: http://www.apache.org/licenses/LICENSE-2.0
#
IMPORT.PROTO "zui.proto"
IMPORT "Annotator.zu"
IMPORT "Builtin.zu"
IMPORT "ClassType.zu"
IMPORT "Declaration.zu"
IMPORT "DeclStore.zu"
IMPORT "Generate.zu"
IMPORT "Output.zu"
IMPORT "Resolve.zu"
IMPORT "SContext.zu"
IMPORT "TopScope.zu"
IMPORT "Type.zu"
IMPORT "UsedFile.zu"
IMPORT "ZimbuFile.zu"
IMPORT "ZuiDeclarationExt.zu"
IMPORT "genC/ZuiWriteC.zu"
IMPORT "genC/WriteC.zu"
IMPORT "genJS/WriteJS.zu"
CLASS MainFile @items=public # TODO: restrict visibility
UsedFile $usedFile # The file contents, and imports recursively.
TopScope $topScope # What is used globally.
NEW(string fileName)
$topScope = NEW()
$usedFile = NEW(fileName, isMainFile + isTopFile)
}
# Parse the main file.
FUNC $parse() status
RETURN $usedFile.parse($topScope, "")
}
# Return TRUE if there is a Main() method in this file.
FUNC $hasMain() bool
RETURN $usedFile.hasMain()
}
# Recursively parse imported files.
# Doing all the parsing first quickly finds syntax errors and locates used
# builtin modules.
PROC $parseImports()
$usedFile.parseImports("", $getSContext())
}
# Recursively resolve symbols.
# Return TRUE if another pass is needed.
FUNC $resolve() bool
++$topScope.pass
bool r = Generate.resolve($usedFile, $getSContext())
# Run the garbage collector after finishing every other pass.
IF ($topScope.pass & 1) == 0
GENERATE_IF Z.have("portable")
GC.run()
GENERATE_ELSE
# Run the garbage collector in another thread, so that this one can
# continue after the mark phase.
IF %gcThread == NIL
%gcPipe = NEW()
%gcThread = NEW()
%gcThread.start()
}
%gcPipe.write(TRUE)
}
}
RETURN r
}
FUNC $getSContext() SContext
Resolve gen = NEW()
Output.Group dummy = NEW()
RETURN NEW($topScope, $usedFile.scope(), gen, dummy)
}
# Recursively write all the files imported by this UsedFile.
# Only to be used for the main file.
PROC $writeZuiFiles()
FOR builtin IN $topScope.usedBuiltins
IF builtin != NIL && builtin.usedFile != NIL
builtin.usedFile.zimbuFile.writeZui()
}
}
FOR zimbuFile IN $topScope.usedImports
zimbuFile.writeZui()
}
}
# Write C code to |outFile| from .zui files.
PROC $writeZuiC(IO.File outFile)
ZuiWriteC.write($usedFile, $topScope, outFile)
}
# Generate C code and write it to |outFile|.
PROC $generateC(string inFileName, IO.File outFile)
WriteC gen = NEW()
# Mark all symbols used directly or indirectly from Main() as used.
$usedFile.markMainUsed(gen, $topScope)
# Mark dependencies in Builtin modules as used.
Builtin.markUsed(gen, $topScope)
# Let the language add dependencies for used symbols.
# Must come last before write().
gen.markUsed()
# Now it's no longer permitted to mark items as used that are defined
# in the program or libraries.
gen.didMarkUsed = TRUE
# Add annotations to the code. Used to decide if temp vars are needed and
# protect unsafe calls.
Annotator.annotate($usedFile, $topScope, gen)
# First do it with undefinedNonZero FALSE so that errors in generated code
# will be given.
bool undefinedNonZero = Generate.undefinedNonZero
Generate.undefinedNonZero = FALSE
$generateCinner(inFileName, gen, outFile)
IF undefinedNonZero && LOG.errorCount == 0
# We have undefined symbols but no errors were reported. Do it again
# while producing unused code as well, so that errors in not generated
# code are given.
IO.print("Making another pass to find errors")
$topScope.clearStartedWrite()
Generate.undefinedNonZero = TRUE
Generate.continueAfterError = TRUE
$generateCinner(inFileName, gen, outFile)
}
IF undefinedNonZero && LOG.errorCount == 0
LOG.error("Last pass had undefined symbols, "
.. "yet no errors were reported when generating code")
Generate.reportUndef = TRUE
Generate.skip_zero_undefined = FALSE
$resolve()
}
}
PROC $generateCinner(string inFileName, WriteC gen, IO.File outFile)
# Write the C code into |outputs|.
Output.Group outputs = NEW()
outputs.startWriting()
SContext ctx = NEW($topScope, $usedFile.scope(), gen, outputs)
# Write global declarations to |outputs|.
gen.writeGlobals(ctx)
# Write code to |outputs|.
Generate.write($usedFile, ctx, outputs)
IF LOG.errorCount == 0
# Write the collected C code from |outputs| into the output file.
outFile.write("/*\n")
outFile.write(" * Generated from Zimbu file " .. inFileName .. "\n")
outFile.write(" */\n")
gen.writeFile($usedFile, ctx, outputs, outFile)
}
}
# If there are any ZUT modules, write the Javascript.
PROC $generateJS()
IF $topScope.javascriptImports == NIL
RETURN
}
LOG.info("Generating Javascript code...")
WriteJS jsGen = createJsGen()
Output.Group jsOutputs = NEW()
jsOutputs.startWriting()
FOR zimbuFile IN $topScope.javascriptImports.values()
Zui.Statement stmt = zimbuFile.getDeclarationStatement(FALSE)
IF stmt != NIL
Declaration topDecl =
ZuiDeclarationExt.get(stmt.getDeclaration()).decl
# Mark used items.
jsGen.setDeclUsed(topDecl)
Type type = topDecl.type.getEffType()
IF type ISA ClassType
# Register the controller constructor.
jsOutputs.bodyOut.write("zut.controllers['\(type.name)'] = \(type.pName);\n")
}
}
}
# Mark the action methods that were registered from C as used.
IF $topScope.registeredActions != NIL
FOR method IN $topScope.registeredActions
jsGen.setDeclUsed(method)
}
}
# Used in writeZutFooter()
Declaration newContextDecl = DeclStore.getDecl("MZUTModule__CContext",
"MNEW__1")
jsGen.setDeclUsed(newContextDecl)
Declaration newConfigDecl = DeclStore.getDecl("MZUTModule__CEventConfig",
"MNEW")
jsGen.setDeclUsed(newConfigDecl)
Declaration clickMethodDecl = DeclStore.getDecl("MZUTModule__CEvent__X",
"FnewClickEvent")
jsGen.setDeclUsed(clickMethodDecl)
Declaration overMethodDecl = DeclStore.getDecl("MZUTModule__CEvent__X",
"FnewMouseOverEvent")
jsGen.setDeclUsed(overMethodDecl)
Declaration outMethodDecl = DeclStore.getDecl("MZUTModule__CEvent__X",
"FnewMouseOutEvent")
jsGen.setDeclUsed(outMethodDecl)
string outDir
bool first = TRUE
# Produce the imports marked with @javascript.
FOR zimbuFile IN $topScope.javascriptImports.values()
UsedFile usedFile = NEW(zimbuFile, FALSE)
SContext newCtx = NEW($topScope, usedFile.scope(), jsGen, jsOutputs)
IF first
first = FALSE
# Generate used parts of builtin modules.
Builtin.generateBuiltins(FALSE, TRUE, newCtx)
}
jsOutputs.structOut.write("// \(zimbuFile.filename) structs\n")
jsOutputs.declOut.write("// \(zimbuFile.filename) declarations\n")
jsOutputs.bodyOut.write("// \(zimbuFile.filename) bodies\n")
Generate.write(usedFile, newCtx, jsOutputs, " ")
# TODO: use the output directory of the binary.
outDir = zimbuFile.outDir
}
# Write JSoutputs to ZUDIR/main.js
jsGen.writeJavascript(outDir, "main.js", jsOutputs)
}
SHARED
PROC generateJSFile(UsedFile usedFile, SContext ctx)
Zui.Statement stmt = usedFile.zimbuFile.getModuleStatement()
IF stmt == NIL
RETURN
}
Declaration moduleDecl = ZuiDeclarationExt.get(stmt.getDeclaration()).decl
WriteJS jsGen = createJsGen()
# Delete older versions of the produced files.
string fname = jsGen.zwtFilename(usedFile.zimbuFile)
IO.print("Deleting \(fname)")
IO.delete(fname)
# Mark used items.
jsGen.setDeclUsed(moduleDecl)
string moduleName = usedFile.zimbuFile.getModuleName()
Declaration initDecl = DeclStore.getDecl("M" .. moduleName, "Finit")
IF initDecl == NIL
LOG.internal("no init() in \(moduleName)")
ELSE
# This recursively marks everything used from the init() method as used.
jsGen.setDeclUsed(initDecl)
}
# Produce the JS file.
Output.Group jsOutputs = NEW()
SContext newCtx = NEW(ctx.topScope, usedFile.scope(), jsGen, jsOutputs)
Generate.write(usedFile, newCtx, jsOutputs,
ctx.scope.importIndent .. " ")
# Write JSoutputs to ZUDIR/ModuleName.html
jsGen.writeZwtImport(usedFile.zimbuFile, jsOutputs)
}
FUNC createJsGen() WriteJS
WriteJS jsGen = NEW()
# Dependencies may have been added to Declarations used in
# addDependsOnCond() while the declaration was not used. We do not want
# to use them here.
Declaration.abstractClass.clearDependsOn()
Declaration.inheritMethod.clearDependsOn()
# We do want to write a declaration for abstract classes.
jsGen.setDeclUsed(Declaration.abstractClass)
# A method is written in the parent class, not the child.
jsGen.setDeclUsed(Declaration.inheritMethod)
RETURN jsGen
}
GENERATE_IF !Z.have("portable")
pipe<bool> %gcPipe
GcThread %gcThread
CLASS GcThread EXTENDS thread
PROC $body() @replace
WHILE TRUE
status st
bool doIt = %gcPipe.read(&st)
IF st == FAIL
BREAK
}
GC.run()
}
}
}
}
}
}