-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathZimbuFile.zu
276 lines (239 loc) · 8.03 KB
/
ZimbuFile.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
#
# The Zimbu compiler written in Zimbu
#
# ZimbuFile class: A Zimbu file that can be (or has been) parsed.
# Does not contain info about where it was imported, see
# UsedFile for that.
#
# 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 "Builtin.zu"
IMPORT "Config.zu"
IMPORT "Declaration.zu"
IMPORT "FileScope.zu"
IMPORT "MethodScope.zu"
IMPORT "Output.zu"
IMPORT "Parse.zu"
IMPORT "Resolve.zu"
IMPORT "UsedFile.zu"
IMPORT "ZuiDeclarationExt.zu"
IMPORT "ZuiFile.zu"
CLASS ZimbuFile @items=public # TODO: restrict visibility
string $filename # file name relative to build directory
string $fullname # file name with full path
string $rootName # |filename| with directory and ".zu"/".zwt" removed
string $dirName # directory relative to build directory
string $outDir # where to write the output
string $initFunc # name of function that inits global vars
int $startedPass # pass number that started (and may have ended)
bool $didInitFunc # set when generated call to initFunc
bool $isMainFile # TRUE for main file; should contain Main()
bool $topZwtFile # was used in IMPORT.ZWT
bool $usedAsZwt # was used in IMPORT.ZWT or imported through it
bool $usedAsZimbu # was used in IMPORT
bool $isProto # converted from a .proto file
# Scope for the file level, contains the list of statements.
FileScope $fileScope
# Scope used for the initialization function. Stores temp variables used in
# initialization expressions.
MethodScope $initScope
Declaration $item # The one item that this file exports.
# NIL when there is not exactly one item.
# Keep track of which Token.Type.id keywords have been used in this file.
# Set just after parsing.
# This is for loading a built-in library only when it is used.
set<string> $usedIdKeywords
CodeSpecific $c # C specific values
CodeSpecific $js # JS specific values
# When the ZimbuFile was loaded from a .zui file then $zuiFile contains the
# relevant information. When not then it will be filled after resolving.
ZuiFile $zuiFile
bool $didReadZuiFile # TRUE if zuiFile was read OK
NEW(string filename, bool isMainFile)
$filename = filename
IF $filename.startsWith("./")
$filename = $filename.slice(2)
}
$fullname = IO.fullPath(filename)
$isMainFile = isMainFile
IF $filename.slice(-3) == ".zu"
$rootName = $filename.slice(0, -4) # without ".zu"
ELSE
LOG.error("File not ending in .zu: \($filename)")
}
int slash = $rootName.findLast('/')
IF slash >= 0
$dirName = $rootName.slice(0, slash - 1)
$rootName = $rootName.slice(slash + 1)
ELSE
$dirName = ""
}
# Set the directory to store the produced files.
IF $dirName != ""
$outDir = $dirName .. "/" .. Config.zudirName
IF $outDir.startsWith("./")
$outDir = $outDir.slice(2)
}
ELSE
$outDir = Config.zudirName
}
# TODO: use varString?
string root = "INC_"
# Include directory name, replace every "/" with "__"
int idx
WHILE idx < $dirName.Size()
slash = $dirName.find('/', idx)
IF slash < 0
root ..= $dirName.slice(idx) .. "__"
BREAK
}
IF slash == 0
root ..= "__"
ELSE
# TODO: including ".." as "dd__" causes trouble when compiling
# different binaries that use the proto plugin.
string s = $dirName.slice(idx, slash - 1)
IF s != ".."
root ..= s .. "__"
}
}
idx = slash + 1
}
root ..= $rootName
# Identifiers start with "I", use "J" to be unique.
$initFunc = "J" .. $rootName
$startedPass = -1 # didn't start any pass yet (parsing is 0)
$c = NEW()
$js = NEW()
}
#= Return the name of the .zui file.
FUNC $zuiName() string
RETURN $outDir .. "/" .. $rootName .. ".zui"
}
# Parse the file, unless done already.
# Return FAIL if the file could not be read.
FUNC $parse(string indent, UsedFile usedFile) status
IF $startedPass == -1
$zuiFile = NEW($filename, $outDir, $zuiName())
IF writeZuiFlag.get()
# Attempt reading the .zui file for this .zu file.
# This only works when it exists and the header has information
# matching the .zu file.
$didReadZuiFile = $zuiFile.read(indent) == OK
# TODO: If reading worked then return here, no need to parse.
# Do need to add object references.
}
$startedPass = 0
$fileScope = FileScope.parseFile($filename, indent, usedFile)
}
RETURN $fileScope == NIL ? FAIL : OK
}
# Write the .zui file for this ZimbuFile, if appropriate.
PROC $writeZui()
IF $zuiFile != NIL
IF !$didReadZuiFile
# Add the list of builtin modules to the ZuiFile.
FOR key IN $usedIdKeywords.keys()
IF Builtin.isBuiltin(key)
$zuiFile.contents.addBuiltin(key)
}
}
$zuiFile.write()
ELSE
LOG.info(".zui file was read: \($zuiName())")
}
}
}
# Return the name of the top module in this file.
# If not found returns NIL.
FUNC $getModuleName() string
Zui.Statement stmt = $getModuleStatement()
IF stmt == NIL
RETURN NIL
}
RETURN stmt.getDeclaration().getName()
}
# Find the node in this file that is the top module.
# If not found gives an error and returns NIL.
FUNC $getModuleStatement() Zui.Statement
RETURN $getDeclarationStatement(TRUE)
}
# Find the node in this file that is the top module or class.
# If not found gives an error and returns NIL.
FUNC $getDeclarationStatement(bool moduleOnly) Zui.Statement
# Find the module after IMPORT statements.
FOR stmt IN $fileScope.statements ?: []
IF stmt.getType() == Zui.StatementType.eMODULE_DECL
|| (!moduleOnly && stmt.getType() == Zui.StatementType.eCLASS_DECL)
RETURN stmt
}
}
LOG.error("No Module found in import")
RETURN NIL
}
FUNC $hasUsedItem(Resolve gen, string indent) bool
bool typeUsed
FOR stmt IN $fileScope.statements ?: []
IF stmt.getType() == Zui.StatementType.eMODULE_DECL
|| stmt.getType() == Zui.StatementType.eCLASS_DECL
|| stmt.getType() == Zui.StatementType.eBITS_DECL
|| stmt.getType() == Zui.StatementType.eENUM_DECL
|| stmt.getType() == Zui.StatementType.eMETHOD_DECL
Zui.Declaration zuiDecl = stmt.getDeclaration()
VAR declExt = ZuiDeclarationExt.get(zuiDecl)
# A PIECE does not have a declaration, since it's copied to where it
# is used.
IF declExt.decl != NIL
IF gen.isDeclUsed(declExt.decl)
RETURN TRUE
}
IF declExt.decl.typeUsed
typeUsed = TRUE
}
}
}
}
IF typeUsed
LOG.info("\(indent)\($filename): Only type is used")
ELSE
LOG.info("\(indent)\($filename): No used items")
}
# When the type was used do go into the item anyway.
RETURN typeUsed
}
SHARED
ARG.Bool writeZuiFlag = NEW(NIL, "zui", FALSE, "Write .zui files")
CLASS CodeSpecific @directory @items=directory
string $startedWrite # name of code that writing has started for
Output.Group $outputs
NEW()
$clear()
}
PROC $clear()
$outputs = NEW()
}
}
# The languages to produce code in.
# For a zwt file we always produce JS, for a zimbu file it can be both C
# and JS.
BITS WriteLang
bool $c
bool $js
}
# Find |name| in |importList|.
FUNC find(list<ZimbuFile> importList, string name) ZimbuFile
IF importList != NIL
string fullname = IO.fullPath(name)
FOR import IN importList
IF import.fullname == fullname
RETURN import
}
}
}
RETURN NIL
}
}
}