aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/LuaSL/LuaSL_compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/LuaSL/LuaSL_compile.c')
-rw-r--r--src/LuaSL/LuaSL_compile.c2345
1 files changed, 2345 insertions, 0 deletions
diff --git a/src/LuaSL/LuaSL_compile.c b/src/LuaSL/LuaSL_compile.c
new file mode 100644
index 0000000..771888e
--- /dev/null
+++ b/src/LuaSL/LuaSL_compile.c
@@ -0,0 +1,2345 @@
1
2#include "LuaSL.h"
3
4/* TODO - problem de jour
5*/
6
7
8static void outputBitOp(FILE *file, outputMode mode, LSL_Leaf *leaf);
9static void outputBlockToken(FILE *file, outputMode mode, LSL_Leaf *content);
10static void outputCrementsToken(FILE *file, outputMode mode, LSL_Leaf *content);
11static void outputFloatToken(FILE *file, outputMode mode, LSL_Leaf *content);
12static void outputFunctionToken(FILE *file, outputMode mode, LSL_Leaf *content);
13static void outputFunctionCallToken(FILE *file, outputMode mode, LSL_Leaf *content);
14static void outputIntegerToken(FILE *file, outputMode mode, LSL_Leaf *content);
15static void outputIdentifierToken(FILE *file, outputMode mode, LSL_Leaf *content);
16static void outputListToken(FILE *file, outputMode mode, LSL_Leaf *content);
17static void outputParameterListToken(FILE *file, outputMode mode, LSL_Leaf *content);
18static void outputParenthesisToken(FILE *file, outputMode mode, LSL_Leaf *content);
19static void outputStateToken(FILE *file, outputMode mode, LSL_Leaf *content);
20static void outputStatementToken(FILE *file, outputMode mode, LSL_Leaf *content);
21static void outputStringToken(FILE *file, outputMode mode, LSL_Leaf *content);
22
23LSL_Token LSL_Tokens[] =
24{
25 // Various forms of "space".
26 {LSL_COMMENT, ST_NONE, "/*", LSL_NONE, NULL},
27 {LSL_COMMENT_LINE, ST_NONE, "//", LSL_NONE, NULL},
28 {LSL_SPACE, ST_NONE, " ", LSL_NONE, NULL},
29
30 // Operators, in order of precedence, low to high
31 // Left to right, unless otherwise stated.
32 // According to http://wiki.secondlife.com/wiki/Category:LSL_Operators, which was obsoleted by http://wiki.secondlife.com/wiki/LSL_Operators but that has less info.
33
34 {LSL_ASSIGNMENT_CONCATENATE,ST_CONCATENATION, "+=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL},
35 {LSL_ASSIGNMENT_ADD, ST_CONCATENATION, "+=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL},
36 {LSL_ASSIGNMENT_SUBTRACT, ST_ASSIGNMENT, "-=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL},
37 {LSL_ASSIGNMENT_MULTIPLY, ST_ASSIGNMENT, "*=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL},
38 {LSL_ASSIGNMENT_MODULO, ST_MODULO, "%=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL},
39 {LSL_ASSIGNMENT_DIVIDE, ST_ASSIGNMENT, "/=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL},
40 {LSL_ASSIGNMENT_PLAIN, ST_CONCATENATION, "=", LSL_RIGHT2LEFT | LSL_ASSIGNMENT, NULL},
41
42 {LSL_BOOL_AND, ST_BOOLEAN, "&&", LSL_RIGHT2LEFT, NULL},
43// QUIRK - Seems to be some disagreement about BOOL_AND/BOOL_OR precedence. Either they are equal, or OR is higher.
44// QUIRK - No boolean short circuiting.
45// LUA - Short circiuts boolean operations, and goes left to right.
46// LUA - "and" returns its first argument if it is false, otherwise, it returns its second argument. "or" returns its first argument if it is not false, otherwise it returns its second argument.
47// Note that the above means that "and/or" can return any type.
48 {LSL_BOOL_OR, ST_BOOLEAN, "||", LSL_RIGHT2LEFT, NULL},
49 {LSL_BIT_OR, ST_BITWISE, "|", LSL_LEFT2RIGHT, outputBitOp},
50 {LSL_BIT_XOR, ST_BITWISE, "^", LSL_LEFT2RIGHT, outputBitOp},
51 {LSL_BIT_AND, ST_BITWISE, "&", LSL_LEFT2RIGHT, outputBitOp},
52// QUIRK - Booleans and conditionals are executed right to left. Or maybe not, depending on who you believe.
53 {LSL_NOT_EQUAL, ST_EQUALITY, "!=", LSL_RIGHT2LEFT, NULL},
54 {LSL_EQUAL, ST_EQUALITY, "==", LSL_RIGHT2LEFT, NULL},
55 {LSL_GREATER_EQUAL, ST_COMPARISON, ">=", LSL_RIGHT2LEFT, NULL},
56 {LSL_LESS_EQUAL, ST_COMPARISON, "<=", LSL_RIGHT2LEFT, NULL},
57 {LSL_GREATER_THAN, ST_COMPARISON, ">", LSL_RIGHT2LEFT, NULL},
58 {LSL_LESS_THAN, ST_COMPARISON, "<", LSL_RIGHT2LEFT, NULL},
59// LUA - comparisons are always false if they are different types. Tables, userdata, and functions are compared by reference. Strings compare in alphabetical order, depending on current locale.
60// LUA - really only has three conditionals, as it translates a ~= b to not (a == b), a > b to b < a, and a >= b to b <= a.
61 {LSL_RIGHT_SHIFT, ST_BITWISE, ">>", LSL_LEFT2RIGHT, outputBitOp},
62 {LSL_LEFT_SHIFT, ST_BITWISE, "<<", LSL_LEFT2RIGHT, outputBitOp},
63 {LSL_CONCATENATE, ST_ADD, "+", LSL_LEFT2RIGHT, NULL},
64 {LSL_ADD, ST_ADD, "+", LSL_LEFT2RIGHT, NULL},
65 {LSL_SUBTRACT, ST_SUBTRACT, "-", LSL_LEFT2RIGHT, NULL},
66 {LSL_CROSS_PRODUCT, ST_NONE, "%", LSL_LEFT2RIGHT, NULL},
67 {LSL_DOT_PRODUCT, ST_NONE, "*", LSL_LEFT2RIGHT, NULL},
68 {LSL_MULTIPLY, ST_MULTIPLY, "*", LSL_LEFT2RIGHT, NULL},
69 {LSL_MODULO, ST_MODULO, "%", LSL_LEFT2RIGHT, NULL},
70 {LSL_DIVIDE, ST_MULTIPLY, "/", LSL_LEFT2RIGHT, NULL},
71 {LSL_NEGATION, ST_NEGATE, "-", LSL_RIGHT2LEFT | LSL_UNARY, NULL},
72 {LSL_BOOL_NOT, ST_BOOL_NOT, "!", LSL_RIGHT2LEFT | LSL_UNARY, NULL},
73 {LSL_BIT_NOT, ST_BIT_NOT, "~", LSL_RIGHT2LEFT | LSL_UNARY, outputBitOp},
74
75// LUA precedence - (it has no bit operators, at least not until 5.2, but LuaJIT has them as table functions.)
76// or
77// and
78// < > <= >= ~= ==
79// ..
80// + -
81// * /
82// not negate
83// exponentiation (^)
84
85 {LSL_TYPECAST_CLOSE, ST_NONE, ")", LSL_RIGHT2LEFT | LSL_UNARY, NULL},
86 {LSL_TYPECAST_OPEN, ST_NONE, "(", LSL_RIGHT2LEFT | LSL_UNARY, outputParenthesisToken},
87 {LSL_ANGLE_CLOSE, ST_NONE, ">", LSL_LEFT2RIGHT | LSL_CREATION, NULL},
88 {LSL_ANGLE_OPEN, ST_NONE, "<", LSL_LEFT2RIGHT | LSL_CREATION, NULL},
89 {LSL_BRACKET_CLOSE, ST_NONE, "]", LSL_INNER2OUTER | LSL_CREATION, NULL},
90 {LSL_BRACKET_OPEN, ST_NONE, "[", LSL_INNER2OUTER | LSL_CREATION, NULL},
91 {LSL_PARENTHESIS_CLOSE, ST_NONE, ")", LSL_INNER2OUTER, NULL},
92 {LSL_PARENTHESIS_OPEN, ST_NONE, "(", LSL_INNER2OUTER, outputParenthesisToken},
93 {LSL_DOT, ST_NONE, ".", LSL_RIGHT2LEFT, NULL},
94 {LSL_DECREMENT_POST, ST_NONE, "--", LSL_RIGHT2LEFT | LSL_UNARY, outputCrementsToken},
95 {LSL_DECREMENT_PRE, ST_NONE, "--", LSL_RIGHT2LEFT | LSL_UNARY, outputCrementsToken},
96 {LSL_INCREMENT_POST, ST_NONE, "++", LSL_RIGHT2LEFT | LSL_UNARY, outputCrementsToken},
97 {LSL_INCREMENT_PRE, ST_NONE, "++", LSL_RIGHT2LEFT | LSL_UNARY, outputCrementsToken},
98 {LSL_COMMA, ST_NONE, ",", LSL_LEFT2RIGHT, NULL},
99
100 {LSL_EXPRESSION, ST_NONE, "expression", LSL_NONE , NULL},
101
102 // Types.
103 {LSL_FLOAT, ST_NONE, "float", LSL_NONE, outputFloatToken},
104 {LSL_INTEGER, ST_NONE, "integer", LSL_NONE, outputIntegerToken},
105 {LSL_KEY, ST_NONE, "key", LSL_NONE, outputStringToken},
106 {LSL_LIST, ST_NONE, "list", LSL_NONE, outputListToken},
107 {LSL_ROTATION, ST_NONE, "rotation", LSL_NONE, outputListToken},
108 {LSL_STRING, ST_NONE, "string", LSL_NONE, outputStringToken},
109 {LSL_VECTOR, ST_NONE, "vector", LSL_NONE, outputListToken},
110
111 // Types names.
112 {LSL_TYPE_FLOAT, ST_NONE, "float", LSL_TYPE, NULL},
113 {LSL_TYPE_INTEGER, ST_NONE, "integer", LSL_TYPE, NULL},
114 {LSL_TYPE_KEY, ST_NONE, "key", LSL_TYPE, NULL},
115 {LSL_TYPE_LIST, ST_NONE, "list", LSL_TYPE, NULL},
116 {LSL_TYPE_ROTATION, ST_NONE, "rotation", LSL_TYPE, NULL},
117 {LSL_TYPE_STRING, ST_NONE, "string", LSL_TYPE, NULL},
118 {LSL_TYPE_VECTOR, ST_NONE, "vector", LSL_TYPE, NULL},
119
120 // Then the rest of the syntax tokens.
121 {LSL_FUNCTION_CALL, ST_NONE, "funccall", LSL_NONE, outputFunctionCallToken},
122 {LSL_IDENTIFIER, ST_NONE, "identifier", LSL_NONE, outputIdentifierToken},
123 {LSL_VARIABLE, ST_NONE, "variable", LSL_NONE, outputIdentifierToken},
124
125 {LSL_LABEL, ST_NONE, "@", LSL_NONE, NULL},
126
127 {LSL_DO, ST_NONE, "do", LSL_NONE, NULL},
128 {LSL_FOR, ST_NONE, "for", LSL_NONE, NULL},
129 {LSL_ELSE, ST_NONE, "else", LSL_NONE, NULL},
130 {LSL_ELSEIF, ST_NONE, "elseif", LSL_NONE, NULL},
131 {LSL_IF, ST_NONE, "if", LSL_NONE, NULL},
132 {LSL_JUMP, ST_NONE, "jump", LSL_NONE, NULL},
133 {LSL_RETURN, ST_NONE, "return", LSL_NONE, NULL},
134 {LSL_STATE_CHANGE, ST_NONE, "state", LSL_NONE, NULL},
135 {LSL_WHILE, ST_NONE, "while", LSL_NONE, NULL},
136 {LSL_STATEMENT, ST_NONE, ";", LSL_NOIGNORE, outputStatementToken},
137
138 {LSL_BLOCK_CLOSE, ST_NONE, "}", LSL_NONE, NULL},
139 {LSL_BLOCK_OPEN, ST_NONE, "{", LSL_NONE, outputBlockToken},
140 {LSL_PARAMETER, ST_NONE, "parameter", LSL_NONE, outputIdentifierToken},
141 {LSL_PARAMETER_LIST, ST_NONE, "plist", LSL_NONE, outputParameterListToken},
142 {LSL_FUNCTION, ST_NONE, "function", LSL_NONE, outputFunctionToken},
143 {LSL_DEFAULT, ST_NONE, "default", LSL_NONE, outputStateToken},
144 {LSL_STATE, ST_NONE, "state", LSL_NONE, outputStateToken},
145 {LSL_SCRIPT, ST_NONE, "", LSL_NONE, NULL},
146
147 {LSL_UNKNOWN, ST_NONE, "unknown", LSL_NONE, NULL},
148
149 // A sentinal.
150 {999999, ST_NONE, NULL, LSL_NONE, NULL}
151};
152
153// VERY IMPORTANT to keep this in sync with enum opType from LuaSL_LSL_tree.h!
154allowedTypes allowed[] =
155{
156 {OT_nothing, "nothing", (ST_NONE)}, //
157
158 {OT_bool, "boolean", (ST_BOOL_NOT)}, // bool !
159 {OT_integer, "integer", (ST_BOOL_NOT | ST_BIT_NOT | ST_NEGATE)}, // int ! - ~
160 {OT_float, "float", (ST_BOOL_NOT | ST_NEGATE)}, // float ! -
161 {OT_key, "key", (ST_BOOL_NOT)}, // key !
162 {OT_list, "list", (ST_NONE)}, //
163 {OT_rotation, "rotation", (ST_NONE)}, //
164 {OT_string, "string", (ST_BOOL_NOT)}, // string !
165 {OT_vector, "vector", (ST_NONE)}, //
166 {OT_other, "other", (ST_NONE)}, //
167
168 {OT_bool, "boolean", (ST_BOOLEAN | ST_EQUALITY)}, // bool bool == != = && ||
169
170 {OT_integer, "integer", (ST_MULTIPLY | ST_ADD | ST_SUBTRACT | ST_EQUALITY | ST_COMPARISON | ST_CONCATENATION | ST_ASSIGNMENT | ST_MODULO | ST_BITWISE)}, // int boolean * / + - % == != < > <= >= = += -= *= /= %= & | ^ << >>
171 {OT_integer, "integer", (ST_MULTIPLY | ST_ADD | ST_SUBTRACT | ST_EQUALITY | ST_COMPARISON | ST_CONCATENATION | ST_ASSIGNMENT | ST_MODULO | ST_BITWISE)}, // int int * / + - % == != < > <= >= = += -= *= /= %= & | ^ << >>
172 {OT_float, "float", (ST_MULTIPLY | ST_ADD | ST_SUBTRACT | ST_EQUALITY | ST_COMPARISON | ST_CONCATENATION | ST_ASSIGNMENT)}, // int float cast to float float
173 {OT_float, "float", (ST_MULTIPLY | ST_ADD | ST_SUBTRACT | ST_EQUALITY | ST_COMPARISON | ST_CONCATENATION | ST_ASSIGNMENT)}, // float int cast to float float
174 {OT_float, "float", (ST_MULTIPLY | ST_ADD | ST_SUBTRACT | ST_EQUALITY | ST_COMPARISON | ST_CONCATENATION | ST_ASSIGNMENT)}, // float float * / + - == != < > <= >= = += -= *= /=
175
176 {OT_string, "string", (ST_ADD | ST_EQUALITY | ST_CONCATENATION)}, // key key cast to string string
177 {OT_string, "string", (ST_ADD | ST_EQUALITY | ST_CONCATENATION)}, // key string cast to string string
178 {OT_string, "string", (ST_ADD | ST_EQUALITY | ST_CONCATENATION)}, // string key cast to string string
179 {OT_string, "string", (ST_ADD | ST_EQUALITY | ST_CONCATENATION)}, // string string + == != = +=
180
181 {OT_list, "list", (ST_ADD | ST_EQUALITY | ST_CONCATENATION | ST_ASSIGNMENT )}, // list list + == != = +=
182 {OT_list, "list", (ST_ADD | ST_COMPARISON | ST_CONCATENATION | ST_ASSIGNMENT )}, // list boolean + < > <= >= = +=
183 {OT_list, "list", (ST_ADD | ST_COMPARISON | ST_CONCATENATION | ST_ASSIGNMENT )}, // list integer + < > <= >= = +=
184 {OT_list, "list", (ST_ADD | ST_COMPARISON | ST_CONCATENATION | ST_ASSIGNMENT )}, // list float + < > <= >= = +=
185 {OT_list, "list", (ST_ADD | ST_COMPARISON | ST_CONCATENATION | ST_ASSIGNMENT )}, // list string + < > <= >= = +=
186 {OT_integer, "integer", (ST_ADD | ST_COMPARISON)}, // integer list + < > <= >=
187 {OT_float, "float", (ST_ADD | ST_COMPARISON)}, // float list + < > <= >=
188 {OT_list, "list", (ST_ADD | ST_CONCATENATION)}, // list other + = +=
189
190 {OT_vector, "vector", (ST_MULTIPLY | ST_ADD | ST_SUBTRACT | ST_EQUALITY | ST_CONCATENATION | ST_ASSIGNMENT | ST_MODULO)}, // vector vector * / + - % == != = += -= *= /= %=
191 {OT_vector, "vector", (ST_MULTIPLY | ST_ASSIGNMENT)}, // vector float * / *= /=
192 {OT_vector, "vector", (ST_MULTIPLY)}, // vector rotation * /
193
194 {OT_rotation, "rotation", (ST_MULTIPLY | ST_ADD | ST_SUBTRACT | ST_EQUALITY | ST_CONCATENATION | ST_ASSIGNMENT)}, // rotation rotation * / + - == != = += -= *= /=
195
196 {OT_other, "other", (ST_NONE)}, //
197 {OT_undeclared, "undeclared", (ST_NONE)}, //
198 {OT_invalid, "invalid", (ST_NONE)} //
199};
200
201opType opExpr[][10] =
202{
203 {OT_nothing, OT_bool, OT_integer, OT_float, OT_key, OT_list, OT_rotation, OT_string, OT_vector, OT_other},
204 {OT_bool, OT_boolBool, OT_invalid, OT_invalid, OT_invalid, OT_invalid, OT_invalid, OT_invalid, OT_invalid, OT_invalid},
205 {OT_integer, OT_intBool, OT_intInt, OT_intFloat, OT_invalid, OT_intList, OT_invalid, OT_invalid, OT_invalid, OT_invalid},
206 {OT_float, OT_invalid, OT_floatInt, OT_floatFloat, OT_invalid, OT_floatList, OT_invalid, OT_invalid, OT_invalid, OT_invalid},
207 {OT_key, OT_invalid, OT_invalid, OT_invalid, OT_keyKey, OT_invalid, OT_invalid, OT_keyString, OT_invalid, OT_invalid},
208 {OT_list, OT_listBool, OT_listInt, OT_listFloat, OT_invalid, OT_listList, OT_invalid, OT_listString, OT_invalid, OT_listOther},
209 {OT_rotation, OT_invalid, OT_invalid, OT_invalid, OT_invalid, OT_invalid, OT_rotationRotation, OT_invalid, OT_invalid, OT_invalid},
210 {OT_string, OT_invalid, OT_invalid, OT_invalid, OT_stringKey, OT_invalid, OT_invalid, OT_stringString, OT_invalid, OT_invalid},
211 {OT_vector, OT_invalid, OT_invalid, OT_vectorFloat, OT_invalid, OT_invalid, OT_vectorRotation, OT_invalid, OT_vectorVector, OT_invalid},
212 {OT_other, OT_invalid, OT_invalid, OT_invalid, OT_invalid, OT_invalid, OT_invalid, OT_invalid, OT_invalid, OT_otherOther}
213};
214
215
216LSL_Token **tokens = NULL;
217LSL_Script constants;
218int lowestToken = 999999;
219
220
221static LSL_Leaf *newLeaf(LSL_Type type, LSL_Leaf *left, LSL_Leaf *right)
222{
223 LSL_Leaf *leaf = calloc(1, sizeof(LSL_Leaf));
224
225 if (leaf)
226 {
227 leaf->left = left;
228 leaf->right = right;
229 leaf->toKen = tokens[type - lowestToken];
230 }
231
232 return leaf;
233}
234
235void burnLeaf(void *data)
236{
237 LSL_Leaf *leaf = data;
238
239 if (leaf)
240 {
241// TODO - the problem here is that lemon wants to free these after a reduce, but we might want to keep them around. Should ref count them or something.
242// burnLeaf(leaf->left);
243// burnLeaf(leaf->right);
244 // TODO - Should free up the value to.
245//#if LUASL_DIFF_CHECK
246// eina_strbuf_free(leaf->ignorable);
247//#endif
248// free(leaf);
249 }
250}
251
252static LSL_Leaf *findFunction(LuaSL_compiler *compiler, const char *name)
253{
254 LSL_Leaf *func = NULL;
255
256 if (name)
257 {
258 if (NULL == func)
259 func = eina_hash_find(constants.functions, name);
260 if (NULL != func)
261 {
262 func->flags |= MF_LSLCONST;
263 func->value.functionValue->flags |= MF_LSLCONST;
264 }
265 else
266 func = eina_hash_find(compiler->script.functions, name);
267
268 }
269
270 return func;
271}
272
273static LSL_Leaf *findVariable(LuaSL_compiler *compiler, const char *name)
274{
275 LSL_Leaf *var = NULL;
276
277 if (name)
278 {
279 LSL_Block *block = compiler->currentBlock;
280
281 while ((block) && (NULL == var))
282 {
283 if (block->function)
284 {
285 LSL_Leaf *param = NULL;
286 EINA_INARRAY_FOREACH((&(block->function->vars)), param)
287 {
288 if ((param) && (LSL_PARAMETER == param->toKen->type))
289 {
290// if (name == param->value.identifierValue->name.text) // Assuming they are stringshares.
291 if (0 == strcmp(name, param->value.identifierValue->name.text)) // Not assuming they are stringeshares. They should be.
292 var = param;
293 }
294 }
295 }
296 if ((NULL == var) && block->variables)
297 var = eina_hash_find(block->variables, name);
298 block = block->outerBlock;
299 }
300
301 if (NULL == var)
302 {
303 var = eina_hash_find(constants.variables, name);
304 if (var)
305 {
306 var->flags |= MF_LSLCONST;
307 var->value.identifierValue->flags |= MF_LSLCONST;
308 }
309 }
310 if (NULL == var)
311 var = eina_hash_find(compiler->script.variables, name);
312 }
313
314 return var;
315}
316
317LSL_Leaf *checkVariable(LuaSL_compiler *compiler, LSL_Leaf *identifier, LSL_Leaf *dot, LSL_Leaf *sub)
318{
319 gameGlobals *ourGlobals = compiler->game;
320 const char *search;
321
322 if (dot)
323 search = identifier->value.identifierValue->name.text;
324 else
325 search = identifier->value.stringValue;
326
327 if (identifier)
328 {
329 LSL_Leaf *var = findVariable(compiler, search);
330
331 if (var)
332 {
333 if (LUASL_DEBUG)
334 PI("Found %s!", identifier->value.stringValue);
335 identifier->value.identifierValue = var->value.identifierValue;
336 identifier->basicType = var->basicType;
337 if ((dot) && (sub))
338 {
339 LSL_Identifier *id = calloc(1, sizeof(LSL_Identifier));
340
341 if (id)
342 {
343 memcpy(id, var->value.identifierValue, sizeof(LSL_Identifier));
344 identifier->value.identifierValue = id;
345 if (LSL_ROTATION == var->toKen->type)
346 {
347 // TODO - check if it's one of x, y, z, or s.
348 }
349 if (LSL_VECTOR == var->toKen->type)
350 {
351 // TODO - check if it's one of x, y, or z.
352 }
353 identifier->value.identifierValue->sub = sub->value.stringValue;
354 identifier->basicType = OT_float;
355 }
356 }
357 }
358 else
359 {
360 compiler->script.bugCount++;
361 sendBack(ourGlobals, compiler->client, compiler->SID, "compilerError(%d,%d,NOT found %s)", identifier->line, identifier->column, identifier->value.stringValue);
362 }
363 }
364
365 return identifier;
366}
367
368LSL_Leaf *addOperation(LuaSL_compiler *compiler, LSL_Leaf *left, LSL_Leaf *lval, LSL_Leaf *right)
369{
370 gameGlobals *ourGlobals = compiler->game;
371
372 if (lval)
373 {
374 opType lType, rType;
375
376 lval->left = left;
377 lval->right = right;
378
379 // Convert subtract to negate if needed.
380 if ((NULL == left) && (LSL_SUBTRACT == lval->toKen->type))
381 lval->toKen = tokens[LSL_NEGATION - lowestToken];
382
383 // Try to figure out what type of operation this is.
384 if (NULL == left)
385 lType = OT_nothing;
386 else
387 {
388 if ((left->toKen) && (LSL_IDENTIFIER == left->toKen->type) && (left->value.identifierValue))
389 {
390 LSL_Leaf *var = findVariable(compiler, left->value.identifierValue->name.text);
391
392 if (var)
393 lType = var->basicType;
394 if (left->value.identifierValue->sub)
395 {
396 // TODO - keep an eye on this, but I think all the sub types are floats.
397 lType = OT_float;
398 }
399 }
400 else
401 lType = left->basicType;
402 if (OT_undeclared == lType)
403 {
404 compiler->script.warningCount++;
405 sendBack(ourGlobals, compiler->client, compiler->SID, "compilerWarning(%d,%d,Undeclared identifier issue, deferring this until the second pass)", lval->line, lval->column);
406 lval->basicType = OT_undeclared;
407 return lval;
408 }
409 if (OT_vector < lType)
410 lType = allowed[lType].result;
411 }
412 if (NULL == right)
413 rType = OT_nothing;
414 else
415 {
416 if ((right->toKen) && (LSL_IDENTIFIER == right->toKen->type) && (right->value.identifierValue))
417 {
418 LSL_Leaf *var = findVariable(compiler, right->value.identifierValue->name.text);
419
420 if (var)
421 rType = var->basicType;
422 if (right->value.identifierValue->sub)
423 {
424 // TODO - keep an eye on this, but I think all the sub types are floats.
425 rType = OT_float;
426 }
427 }
428 else
429 rType = right->basicType;
430 if (OT_undeclared == rType)
431 {
432 compiler->script.warningCount++;
433 sendBack(ourGlobals, compiler->client, compiler->SID, "compilerWarning(%d,%d,Undeclared identifier issue, deferring this until the second pass)", lval->line, lval->column);
434 lval->basicType = OT_undeclared;
435 return lval;
436 }
437 if (OT_vector < rType)
438 rType = allowed[rType].result;
439 }
440
441 // Convert add to concatenate if needed.
442 if ((LSL_ADD == lval->toKen->type) && (OT_string == lType) && (OT_string == rType))
443 lval->toKen = tokens[LSL_CONCATENATE - lowestToken];
444
445 switch (lval->toKen->subType)
446 {
447 case ST_BOOLEAN :
448 case ST_COMPARISON :
449 case ST_EQUALITY :
450 lval->basicType = OT_bool;
451 break;
452 default :
453 // The basic lookup.
454 lval->basicType = opExpr[lType][rType];
455 if (OT_invalid != lval->basicType)
456 {
457 // Check if it's an allowed operation.
458 if (0 == (lval->toKen->subType & allowed[lval->basicType].subTypes))
459 lval->basicType = OT_invalid;
460 else
461 {
462 // Double check the corner cases.
463 switch (lval->toKen->subType)
464 {
465 case ST_MULTIPLY :
466 if (OT_vectorVector == lval->basicType)
467 {
468 if (LSL_MULTIPLY == lval->toKen->type)
469 {
470 lval->basicType = OT_float;
471 lval->toKen = tokens[LSL_DOT_PRODUCT - lowestToken];
472 }
473 else
474 lval->basicType = OT_vector;
475 }
476 break;
477 default :
478 break;
479 }
480 }
481 }
482 break;
483 }
484
485 /* Flag assignments for the "assignments are statements, which can't happen inside expressions" test.
486 *
487 * Assignments in the middle of expressions are legal in LSL, but not in Lua.
488 * The big complication is that they often happen in the conditionals of flow control statements. That's a big bitch.
489 *
490 * So things like -
491 *
492 * while ((x = doSomething()) == foo)
493 * {
494 * buggerAround();
495 * }
496 *
497 * Turns into -
498 *
499 * x = doSomething();
500 * while (x == foo)
501 * {
502 * buggerAround();
503 * x = doSomething();
504 * }
505 *
506 * http://lua-users.org/wiki/StatementsInExpressions was helpful. Which suggests something like this -
507 *
508 * while ( (function() x = doSomething(); return x; end)() == foo)
509 * {
510 * buggerAround();
511 * }
512 *
513 * The remaining problem is when to recognise the need to do that.
514 * That's what this code and the matching code in addParenthesis() does.
515 */
516 // TODO - Only got one of these in my test scripts, so leave all this debugging shit in until it's been tested more.
517 if (left)
518 {
519 if (left->flags & MF_ASSIGNEXP)
520 {
521//if ((left) && (right))
522// printf("%s %s %s\n", left->toKen->toKen, lval->toKen->toKen, right->toKen->toKen);
523//else if (left)
524// printf("%s %s NORIGHT\n", left->toKen->toKen, lval->toKen->toKen);
525//else if (right)
526// printf("NOLEFT %s %s\n", lval->toKen->toKen, right->toKen->toKen);
527//else
528// printf("NOLEFT %s NORIGHT\n", lval->toKen->toKen);
529// printf("############################################################################## left\n");
530 left->flags |= MF_WRAPFUNC;
531 if (LSL_PARENTHESIS_OPEN == left->toKen->type)
532 left->value.parenthesis->flags |= MF_WRAPFUNC;
533 }
534 }
535 if (lval)
536 {
537// if (lval->flags & MF_ASSIGNEXP)
538// printf("############################################################################## lval %s %s\n", left->toKen->toKen, right->toKen->toKen);
539 if (LSL_ASSIGNMENT & lval->toKen->flags)
540 {
541 lval->flags |= MF_ASSIGNEXP;
542//// printf("******************* lval %s %s\n", left->toKen->toKen, right->toKen->toKen);
543 if (LSL_IDENTIFIER == left->toKen->type) // It always should be.
544 {
545 left->flags |= MF_ASSIGNEXP;
546//// printf("$$$$$$$$$$$$$$$$$ lval\n");
547 }
548 }
549 }
550 // TODO - Don't think I have to do this on the right.
551 if (right)
552 {
553 if (right->flags & MF_ASSIGNEXP)
554 {
555if ((left) && (right))
556 printf("%s %s %s\n", left->toKen->toKen, lval->toKen->toKen, right->toKen->toKen);
557else if (left)
558 printf("%s %s NORIGHT\n", left->toKen->toKen, lval->toKen->toKen);
559else if (right)
560 printf("NOLEFT %s %s\n", lval->toKen->toKen, right->toKen->toKen);
561else
562 printf("NOLEFT %s NORIGHT\n", lval->toKen->toKen);
563 printf("############################################################################## right\n");
564 right->flags |= MF_WRAPFUNC;
565 }
566 }
567
568 if (OT_invalid == lval->basicType)
569 {
570 const char *leftType = "", *rightType = "", *leftToken = "", *rightToken = "";
571
572 if (left)
573 {
574 if (left->toKen)
575 leftToken = left->toKen->toKen;
576 else
577 PE("BROKEN LEFT TOKEN!!!!!!!!!!!!!!!!!!");
578 leftType = allowed[left->basicType].name;
579 }
580 if (right)
581 {
582 if (right->toKen)
583 rightToken = right->toKen->toKen;
584 else
585 PE("BROKEN RIGHT TOKEN!!!!!!!!!!!!!!!!!!");
586 rightType = allowed[right->basicType].name;
587 }
588
589 compiler->script.bugCount++;
590 sendBack(ourGlobals, compiler->client, compiler->SID, "compilerError(%d,%d,Invalid operation [%s(%s) %s %s(%s)])", lval->line, lval->column, leftType, leftToken, lval->toKen->toKen, rightType, rightToken);
591 }
592 }
593
594 return lval;
595}
596
597LSL_Leaf *addBlock(LuaSL_compiler *compiler, LSL_Leaf *left, LSL_Leaf *lval, LSL_Leaf *right)
598{
599 // Damn, look ahead. The } symbol is getting read (and thus endBlock called) before the last statement in the block is reduced (which actually calls the add*() functions).
600 compiler->currentBlock = compiler->currentBlock->outerBlock;
601#if LUASL_DIFF_CHECK
602 if ((left) && (right))
603 {
604 left->value.blockValue->closeIgnorable = right->ignorable;
605 right->ignorable = NULL;
606 }
607#endif
608 return lval;
609}
610
611LSL_Leaf *addCrement(LuaSL_compiler *compiler, LSL_Leaf *variable, LSL_Leaf *crement, LSL_Type type)
612{
613 if ((variable) && (crement))
614 {
615 crement->value.identifierValue = variable->value.identifierValue;
616#if LUASL_DIFF_CHECK
617 crement->value.identifierValue->ignorable = variable->ignorable;
618 variable->ignorable = NULL;
619#endif
620 crement->basicType = variable->basicType;
621 crement->toKen = tokens[type - lowestToken];
622 switch (crement->toKen->type)
623 {
624 case LSL_DECREMENT_PRE : variable->value.identifierValue->flags |= MF_PREDEC; break;
625 case LSL_INCREMENT_PRE : variable->value.identifierValue->flags |= MF_PREINC; break;
626 case LSL_DECREMENT_POST : variable->value.identifierValue->flags |= MF_POSTDEC; break;
627 case LSL_INCREMENT_POST : variable->value.identifierValue->flags |= MF_POSTINC; break;
628 }
629 variable->value.identifierValue->definition->flags = variable->value.identifierValue->flags;
630 }
631
632 return crement;
633}
634
635LSL_Leaf *addParameter(LuaSL_compiler *compiler, LSL_Leaf *type, LSL_Leaf *identifier)
636{
637 LSL_Identifier *result = calloc(1, sizeof(LSL_Identifier));
638
639 if ( (identifier) && (result))
640 {
641 result->name.text = identifier->value.stringValue;
642#if LUASL_DIFF_CHECK
643 result->name.ignorable = identifier->ignorable;
644 identifier->ignorable = NULL;
645#endif
646 result->value.toKen = tokens[LSL_UNKNOWN - lowestToken];
647 identifier->value.identifierValue = result;
648 identifier->toKen = tokens[LSL_PARAMETER - lowestToken];
649 identifier->left = type;
650 if (type)
651 {
652 identifier->basicType = type->basicType;
653 result->value.basicType = type->basicType;
654 result->value.toKen = type->toKen; // This is the LSL_TYPE_* toKen instead of the LSL_* toKen. Not sure if that's a problem.
655 }
656 }
657 return identifier;
658}
659
660LSL_Leaf *collectParameters(LuaSL_compiler *compiler, LSL_Leaf *list, LSL_Leaf *comma, LSL_Leaf *newParam)
661{
662 LSL_Function *func = NULL;
663
664 if (NULL == list)
665 list = newLeaf(LSL_FUNCTION, NULL, NULL);
666
667 if (list)
668 {
669 func = list->value.functionValue;
670 if (NULL == func)
671 {
672 func = calloc(1, sizeof(LSL_Function));
673 if (func)
674 {
675 list->value.functionValue = func;
676 eina_inarray_step_set(&(func->vars), sizeof(Eina_Inarray), sizeof(LSL_Leaf), 3);
677 }
678 }
679
680 if (func)
681 {
682 if (newParam)
683 {
684 if (LUASL_DIFF_CHECK)
685 {
686 // Stash the comma for diff later.
687 if (comma)
688 eina_inarray_push(&(func->vars), comma);
689 }
690 eina_inarray_push(&(func->vars), newParam);
691 // At this point, pointers to newParams are not pointing to the one in func->vars, AND newParam is no longer needed.
692 }
693 }
694 }
695 return list;
696}
697
698LSL_Leaf *addFunction(LuaSL_compiler *compiler, LSL_Leaf *type, LSL_Leaf *identifier, LSL_Leaf *open, LSL_Leaf *params, LSL_Leaf *close)
699{
700 LSL_Function *func = NULL;
701
702 if (params)
703 {
704 func = params->value.functionValue;
705 // At this point, params is no longer needed, except if we are doing diff.
706 // open and close are not needed either if we are not doing diff.
707 if (func)
708 {
709 if (identifier)
710 {
711 func->name.text = identifier->value.stringValue;
712#if LUASL_DIFF_CHECK
713 func->name.ignorable = identifier->ignorable;
714 identifier->ignorable = NULL;
715#endif
716 identifier->toKen = tokens[LSL_FUNCTION - lowestToken];
717 identifier->value.functionValue = func;
718 if (type)
719 {
720 func->type.text = type->toKen->toKen;
721#if LUASL_DIFF_CHECK
722 func->type.ignorable = type->ignorable;
723 type->ignorable = NULL;
724#endif
725 identifier->basicType = type->basicType;
726 }
727 else
728 identifier->basicType = OT_nothing;
729 if (compiler->inState)
730 eina_hash_add(compiler->state.handlers, func->name.text, func);
731 else
732 eina_hash_add(compiler->script.functions, func->name.text, identifier);
733#if LUASL_DIFF_CHECK
734// func->params = addParenthesis(open, params, LSL_PARAMETER_LIST, close);
735#endif
736 }
737 compiler->currentFunction = func;
738 }
739 }
740
741 return identifier;
742}
743
744LSL_Leaf *addFunctionBody(LuaSL_compiler *compiler, LSL_Leaf *function, LSL_Leaf *block)
745{
746 LSL_Leaf *statement = NULL;
747
748 if (function)
749 {
750 function->value.functionValue->block = block->value.blockValue;
751 statement = addStatement(compiler, NULL, function, NULL, function, NULL, NULL, NULL);
752 }
753
754 return statement;
755}
756
757LSL_Leaf *collectArguments(LuaSL_compiler *compiler, LSL_Leaf *list, LSL_Leaf *comma, LSL_Leaf *arg)
758{
759 LSL_FunctionCall *call = NULL;
760
761 if (NULL == list)
762 list = newLeaf(LSL_FUNCTION_CALL, NULL, NULL);
763
764 if (list)
765 {
766 call = list->value.functionCallValue;
767 if (NULL == call)
768 {
769 call = calloc(1, sizeof(LSL_FunctionCall));
770 if (call)
771 {
772 list->value.functionCallValue = call;
773 eina_inarray_step_set(&(call->params), sizeof(Eina_Inarray), sizeof(LSL_Leaf), 3);
774 }
775 }
776
777 if (call)
778 {
779 if (arg)
780 {
781 if (LUASL_DIFF_CHECK)
782 {
783 // Stash the comma for diff later.
784 if (comma)
785 eina_inarray_push(&(call->params), comma);
786 }
787 eina_inarray_push(&(call->params), arg);
788 // At this point, pointers to arg are not pointing to the one in call->params, AND arg is no longer needed.
789 }
790 }
791 }
792 return list;
793}
794
795LSL_Leaf *addFunctionCall(LuaSL_compiler *compiler, LSL_Leaf *identifier, LSL_Leaf *open, LSL_Leaf *params, LSL_Leaf *close)
796{
797 LSL_Leaf *func = findFunction(compiler, identifier->value.stringValue);
798 LSL_FunctionCall *call = NULL;
799
800 if (params)
801 {
802 call = params->value.functionCallValue;
803 }
804 else
805 call = calloc(1, sizeof(LSL_FunctionCall));
806
807 if (func)
808 {
809 if (call)
810 {
811 call->function = func->value.functionValue;
812 eina_clist_element_init(&(call->dangler));
813 }
814 identifier->value.functionCallValue = call;
815 identifier->toKen = tokens[LSL_FUNCTION_CALL - lowestToken];
816 identifier->basicType = func->basicType;
817 }
818 else
819 {
820 // It may be declared later, so store it and check later.
821 if (call)
822 {
823 eina_clist_add_tail(&(compiler->danglingCalls), &(call->dangler));
824 call->call = identifier;
825 }
826 // Here the identifier stringValue needs to be kept for later searching.
827 identifier->toKen = tokens[LSL_UNKNOWN - lowestToken];
828 identifier->basicType = OT_undeclared;
829 compiler->undeclared = TRUE;
830 }
831
832 return identifier;
833}
834
835LSL_Leaf *addList(LSL_Leaf *left, LSL_Leaf *list, LSL_Leaf *right)
836{
837 left = addParenthesis(left, list, LSL_LIST, right);
838 left->toKen = tokens[LSL_LIST - lowestToken];
839 left->basicType = OT_list;
840 return left;
841}
842
843LSL_Leaf *addRotVec(LSL_Leaf *left, LSL_Leaf *list, LSL_Leaf *right)
844{
845 LSL_Type type = LSL_ROTATION;
846 opType otype = OT_rotation;
847
848 // TODO - count the members of list to see if it's a vector.
849 left = addParenthesis(left, list, type, right);
850 left->toKen = tokens[type - lowestToken];
851 left->basicType = otype;
852 return left;
853}
854
855LSL_Leaf *addNumby(LSL_Leaf *numby)
856{
857 LSL_Numby *num = calloc(1, sizeof(LSL_Numby));
858
859 if ((numby) && (num))
860 {
861 num->text.text = numby->value.stringValue;
862#if LUASL_DIFF_CHECK
863 num->text.ignorable = numby->ignorable;
864 numby->ignorable = NULL;
865#endif
866 switch (numby->toKen->type)
867 {
868 case LSL_FLOAT :
869 {
870 num->value.floatValue = atof(num->text.text);
871 numby->basicType = OT_float;
872 break;
873 }
874 case LSL_INTEGER :
875 {
876 num->value.integerValue = atoi(num->text.text);
877 numby->basicType = OT_integer;
878 break;
879 }
880 default:
881 break;
882 }
883 numby->value.numbyValue = num;
884 num->type = numby->basicType;
885 }
886 return numby;
887}
888
889LSL_Leaf *addParenthesis(LSL_Leaf *lval, LSL_Leaf *expr, LSL_Type type, LSL_Leaf *rval)
890{
891 LSL_Parenthesis *parens = calloc(1, sizeof(LSL_Parenthesis));
892
893 if (parens)
894 {
895 parens->contents = expr;
896 parens->type = type;
897#if LUASL_DIFF_CHECK
898 parens->rightIgnorable = rval->ignorable;
899 // Actualy, at this point, rval is no longer needed.
900 rval->ignorable = NULL;
901#endif
902 if (lval)
903 {
904 lval->value.parenthesis = parens;
905 if (expr)
906 {
907 lval->basicType = expr->basicType;
908 // Propagate these flags inwards and outwards.
909 if (MF_ASSIGNEXP & expr->flags)
910 lval->flags |= MF_ASSIGNEXP;
911 if (MF_WRAPFUNC & expr->flags)
912 parens->flags |= MF_WRAPFUNC;
913 }
914 }
915 }
916 return lval;
917}
918
919LSL_Leaf *addState(LuaSL_compiler *compiler, LSL_Leaf *state, LSL_Leaf *identifier, LSL_Leaf *block)
920{
921 LSL_State *result = calloc(1, sizeof(LSL_State));
922
923 if ((identifier) && (result))
924 {
925 Eina_Iterator *handlers;
926 LSL_Function *func;
927
928 memcpy(result, &(compiler->state), sizeof(LSL_State));
929 compiler->state.block = NULL;
930 compiler->state.handlers = NULL;
931 result->name.text = identifier->value.stringValue;
932#if LUASL_DIFF_CHECK
933 result->name.ignorable = identifier->ignorable;
934 identifier->ignorable = NULL;
935#endif
936 handlers = eina_hash_iterator_data_new(result->handlers);
937 while(eina_iterator_next(handlers, (void **) &func))
938 {
939 func->state = result->name.text;
940 }
941 result->block = block->value.blockValue;
942 if (state)
943 {
944 result->state.text = state->toKen->toKen;
945#if LUASL_DIFF_CHECK
946 result->state.ignorable = state->ignorable;
947 state->ignorable = NULL;
948#endif
949 }
950 identifier->value.stateValue = result;
951 identifier->toKen = tokens[LSL_STATE - lowestToken];
952 eina_hash_add(compiler->script.states, result->name.text, identifier);
953 compiler->inState = FALSE;
954 }
955
956 return identifier;
957}
958
959LSL_Leaf *addIfElse(LuaSL_compiler *compiler, LSL_Leaf *ifBlock, LSL_Leaf *elseBlock)
960{
961 if (ifBlock->value.statementValue->elseBlock)
962 {
963 LSL_Statement *oldElseIf = ifBlock->value.statementValue->elseBlock;
964
965 while (oldElseIf->elseBlock)
966 oldElseIf = oldElseIf->elseBlock;
967
968 oldElseIf->elseBlock = elseBlock->value.statementValue;
969 }
970 else
971 ifBlock->value.statementValue->elseBlock = elseBlock->value.statementValue;
972 return ifBlock;
973}
974
975LSL_Leaf *addFor(LuaSL_compiler *compiler, LSL_Leaf *lval, LSL_Leaf *flow, LSL_Leaf *left, LSL_Leaf *expr0, LSL_Leaf *stat0, LSL_Leaf *expr1, LSL_Leaf *stat1, LSL_Leaf *expr2, LSL_Leaf *right, LSL_Leaf *block)
976{
977 LSL_Leaf **exprs = calloc(5, sizeof(LSL_Leaf *));
978
979 if (exprs)
980 {
981 lval = addStatement(compiler, lval, flow, left, expr0, right, block, NULL);
982 exprs[0] = expr0;
983 exprs[1] = stat0;
984 exprs[2] = expr1;
985 exprs[3] = stat1;
986 exprs[4] = expr2;
987 lval->value.statementValue->expressions = (LSL_Leaf *) exprs;
988 }
989 return lval;
990}
991
992LSL_Leaf *addStatement(LuaSL_compiler *compiler, LSL_Leaf *lval, LSL_Leaf *flow, LSL_Leaf *left, LSL_Leaf *expr, LSL_Leaf *right, LSL_Leaf *block, LSL_Leaf *identifier)
993{
994 gameGlobals *ourGlobals = compiler->game;
995 LSL_Statement *stat = calloc(1, sizeof(LSL_Statement));
996 boolean justOne = FALSE;
997
998 if (NULL == lval)
999 lval = newLeaf(LSL_STATEMENT, NULL, NULL);
1000
1001 if (stat)
1002 {
1003 stat->type = flow->toKen->type;
1004 stat->expressions = expr;
1005 if (block)
1006 {
1007 if (LSL_BLOCK_OPEN == block->toKen->type)
1008 stat->block = block->value.blockValue;
1009 else
1010 stat->single = block->value.statementValue;
1011 }
1012 eina_clist_element_init(&(stat->statement));
1013 if (identifier)
1014 {
1015 stat->identifier.text = identifier->value.stringValue;
1016#if LUASL_DIFF_CHECK
1017 stat->identifier.ignorable = identifier->ignorable;
1018 identifier->ignorable = NULL;
1019#endif
1020 }
1021 if (left)
1022 {
1023 LSL_Leaf *parens = addParenthesis(left, expr, LSL_EXPRESSION, right);
1024
1025 if (parens)
1026 stat->parenthesis = parens->value.parenthesis;
1027 }
1028
1029 switch (stat->type)
1030 {
1031 case LSL_EXPRESSION :
1032 {
1033 break;
1034 }
1035 case LSL_FUNCTION :
1036 {
1037 break;
1038 }
1039 case LSL_DO :
1040 {
1041 break;
1042 }
1043 case LSL_FOR :
1044 {
1045 justOne = TRUE;
1046 break;
1047 }
1048 case LSL_IF :
1049 {
1050 justOne = TRUE;
1051 break;
1052 }
1053 case LSL_ELSE :
1054 {
1055 justOne = TRUE;
1056 break;
1057 }
1058 case LSL_ELSEIF :
1059 {
1060 justOne = TRUE;
1061 break;
1062 }
1063 case LSL_JUMP :
1064 {
1065 justOne = TRUE;
1066 break;
1067 }
1068 case LSL_LABEL :
1069 {
1070 justOne = TRUE;
1071 break;
1072 }
1073 case LSL_RETURN :
1074 {
1075 justOne = TRUE;
1076 break;
1077 }
1078 case LSL_STATE_CHANGE :
1079 {
1080 justOne = TRUE;
1081 break;
1082 }
1083 case LSL_STATEMENT :
1084 {
1085 break;
1086 }
1087 case LSL_WHILE :
1088 {
1089 stat->identifier.text = NULL;
1090 justOne = TRUE;
1091 break;
1092 }
1093 case LSL_IDENTIFIER :
1094 {
1095 break;
1096 }
1097 case LSL_VARIABLE :
1098 {
1099 if (identifier)
1100 {
1101 stat->identifier.text = identifier->value.identifierValue->name.text;
1102 identifier->value.identifierValue->definition = stat;
1103 stat->flags = identifier->value.identifierValue->flags;
1104 }
1105 break;
1106 }
1107 default :
1108 {
1109 compiler->script.bugCount++;
1110 PE("Should not be here %d.", stat->type);
1111 break;
1112 }
1113 }
1114
1115#if LUASL_DIFF_CHECK
1116 if (justOne && (flow))
1117 {
1118 stat->ignorable = calloc(2, sizeof(Eina_Strbuf *));
1119 if (stat->ignorable)
1120 {
1121 stat->ignorable[1] = flow->ignorable;
1122 flow->ignorable = NULL;
1123 }
1124 }
1125#endif
1126
1127 if (lval)
1128 {
1129#if LUASL_DIFF_CHECK
1130 if (NULL == stat->ignorable)
1131 stat->ignorable = calloc(1, sizeof(Eina_Strbuf *));
1132 if (stat->ignorable)
1133 {
1134 stat->ignorable[0] = lval->ignorable;
1135 lval->ignorable = NULL;
1136 }
1137#endif
1138 lval->value.statementValue = stat;
1139 }
1140
1141#if LUASL_DIFF_CHECK
1142 if (left)
1143 {
1144 if (NULL == stat->ignorable)
1145 stat->ignorable = calloc(3, sizeof(Eina_Strbuf *));
1146 else
1147 stat->ignorable = realloc(stat->ignorable, 3 * sizeof(Eina_Strbuf *));
1148 if (stat->ignorable)
1149 {
1150 stat->ignorable[2] = left->ignorable;
1151 left->ignorable = NULL;
1152 }
1153 }
1154#endif
1155 }
1156
1157 return lval;
1158}
1159
1160LSL_Leaf *collectStatements(LuaSL_compiler *compiler, LSL_Leaf *list, LSL_Leaf *statement)
1161{
1162// Guess this is not needed after all, and seemed to cause the "states with only one function get dropped" bug.
1163// boolean wasNull = FALSE;
1164
1165 if (NULL == list)
1166 {
1167 list = newLeaf(LSL_BLOCK_OPEN, NULL, NULL);
1168// wasNull = TRUE;
1169 }
1170
1171 if (list)
1172 {
1173 if (statement)
1174 {
1175// if (!wasNull)
1176 list->value.blockValue = compiler->currentBlock; // Maybe NULL.
1177
1178 if ((compiler->inState) && (LSL_FUNCTION == statement->value.statementValue->type))
1179 {
1180 eina_clist_add_tail(&(compiler->state.block->statements), &(statement->value.statementValue->statement));
1181 }
1182 else if (list->value.blockValue)
1183 {
1184 eina_clist_add_tail(&(list->value.blockValue->statements), &(statement->value.statementValue->statement));
1185 }
1186 }
1187 }
1188
1189 return list;
1190}
1191
1192/* Typecasting
1193
1194LSL is statically typed, so stored values are not converted, only the values used in expressions are.
1195Lua is dynamically typed, so stored values are changed (sometimes I think).
1196
1197LSL implicitly typecasts - There is a shitload of QUIRKs about this. Apparently some don't work anyway.
1198 integer -> float (Says in lslwiki that precision is never lost, which is bullshit, since they are both 32 bit. Would be true if the float is 64 bit. Lua suggest to use 64 bit floats to emulate 32 bit integers.)
1199 string -> key
1200 Some functions need help with this or the other way around.
1201 string -> vector (Maybe, should test that.)
1202 vector -> string (Maybe, should test that.)
1203 Also happens when getting stuff from lists.
1204
1205Explicit type casting -
1206 string -> integer
1207 Leading spaces are ignored, as are any characters after the run of digits.
1208 All other strings convert to 0.
1209 Which means "" and " " convert to 0.
1210 Strings in hexadecimal format will work, same in Lua (though Lua can't handle "0x", but "0x0" is fine).
1211 keys <-> string
1212 No other typecasting can be done with keys.
1213 float -> string
1214 You get a bunch of trailing 0s.
1215
1216QUIRK - I have seen cases where a double explicit typecast was needed in SL, but was considered to be invalid syntax in OS.
1217
1218Any binary operation involving a float and an integer implicitly casts the integer to float.
1219
1220A boolean operation deals with TRUE (1) and FALSE (0). Any non zero value is a TRUE (generally sigh).
1221On the other hand, in Lua, only false and nil are false, everything else is true. 0 is true. sigh
1222Bitwise operations only apply to integers. Right shifts are arithmetic, not logical.
1223
1224integer = integer0 % integer1; // Apparently only applies to integers, but works fine on floats in OS.
1225string = string0 + string1; // Concatenation.
1226list = list0 + list1; // Concatenation. Also works if either is not a list, it's promoted to a list first.
1227list = (list=[]) + list + ["new_item"]; // Voodoo needed for old LSL, works in Mono but not needed, does not work in OS. Works for strings to.
1228bool = list == != int // Only compares the lengths, probably applies to the other conditionals to.
1229vector = vector0 + vector1; // Add elements together.
1230vector = vector0 - vector1; // Subtract elements of vector1 from elements of vector0.
1231float = vector0 * vector1; // A dot product of the vectors.
1232vector = vector0 % vector1; // A cross product of the vectors.
1233vector = vector * float; // Scale the vector, works the other way around I think. Works for integer to, but it will end up being cast to float.
1234vector = vector / float; // Scale the vector, works the other way around I think. Works for integer to, but it will end up being cast to float.
1235vector = vector * rotation; // Rotate the vector by the rotation. Other way around wont compile.
1236vector = vector / rotation; // Rotate the vector by the rotation, in the opposite direction. Other way around wont compile.
1237rotation = llGetRot() * rotation; // Rotate an object around the global axis.
1238rotation = rotation * llGetLocalRot(); // Rotate an object around the local axis.
1239rotation = rotation0 * rotation1; // Add two rotations, so the result is as if you applied each rotation one after the other.
1240 // Division rotates in the opposite direction.
1241rotation = rotation0 + rotation1; // Similar to vector, but it's a meaningless thing as far as rotations go.
1242rotation = rotation0 - rotation1; // Similar to vector, but it's a meaningless thing as far as rotations go.
1243
1244A boolean operator results in a boolean value. (any types)
1245A comparison operator results in a boolean value. (any types)
1246A bitwise operator results in an integer value. (intInt or int)
1247A dot product operator results in a float value. (vector * vector)
1248A vectorFloat results in a vector value.
1249
1250*/
1251
1252LSL_Leaf *addTypecast(LSL_Leaf *lval, LSL_Leaf *type, LSL_Leaf *rval, LSL_Leaf *expr)
1253{
1254 addParenthesis(lval, expr, LSL_TYPECAST_OPEN, rval);
1255 if (lval)
1256 {
1257 if (type)
1258 {
1259 lval->basicType = type->basicType;
1260 if ((expr) && (OT_integer == type->basicType)) // TODO - Should be from string, but I guess I'm not propagating basic types up from function calls and parenthesis?
1261 lval->value.parenthesis->flags |= MF_TYPECAST;
1262 }
1263 // Actualy, at this point, type is no longer needed.
1264 lval->toKen = tokens[LSL_TYPECAST_OPEN - lowestToken];
1265 }
1266// if (rval)
1267// rval->toKen = tokens[LSL_TYPECAST_CLOSE - lowestToken];
1268
1269 return lval;
1270}
1271
1272LSL_Leaf *addVariable(LuaSL_compiler *compiler, LSL_Leaf *type, LSL_Leaf *identifier, LSL_Leaf *assignment, LSL_Leaf *expr)
1273{
1274 LSL_Identifier *result = calloc(1, sizeof(LSL_Identifier));
1275
1276 if ( (identifier) && (result))
1277 {
1278 result->name.text = identifier->value.stringValue;
1279#if LUASL_DIFF_CHECK
1280 result->name.ignorable = identifier->ignorable;
1281 identifier->ignorable = NULL;
1282#endif
1283 result->value.toKen = tokens[LSL_UNKNOWN - lowestToken];
1284 identifier->value.identifierValue = result;
1285 identifier->toKen = tokens[LSL_VARIABLE - lowestToken];
1286 identifier->left = type;
1287 identifier->right = assignment;
1288 if (assignment)
1289 assignment->right = expr;
1290 else
1291 identifier->flags |= MF_NOASSIGN;
1292 if (type)
1293 {
1294 if (compiler->currentBlock)
1295 {
1296 identifier->flags |= MF_LOCAL;
1297 result->flags |= MF_LOCAL;
1298 type->flags |= MF_LOCAL;
1299 }
1300 identifier->basicType = type->basicType;
1301 result->value.basicType = type->basicType;
1302 result->value.toKen = type->toKen; // This is the LSL_TYPE_* toKen instead of the LSL_* toKen. Not sure if that's a problem.
1303 }
1304 if (compiler->currentBlock)
1305 eina_hash_add(compiler->currentBlock->variables, result->name.text, identifier);
1306 else
1307 eina_hash_add(compiler->script.variables, result->name.text, identifier);
1308 }
1309
1310 return identifier;
1311}
1312
1313LSL_Leaf *beginBlock(LuaSL_compiler *compiler, LSL_Leaf *block)
1314{
1315 LSL_Block *blok = calloc(1, sizeof(LSL_Block));
1316
1317 if (blok)
1318 {
1319 eina_clist_init(&(blok->statements));
1320 blok->variables = eina_hash_stringshared_new(burnLeaf);
1321 block->value.blockValue = blok;
1322 if ((NULL == compiler->currentBlock) && (NULL == compiler->currentFunction))
1323 {
1324 compiler->inState = TRUE;
1325 compiler->state.block=blok;
1326 compiler->state.handlers = eina_hash_stringshared_new(free);
1327 }
1328 blok->outerBlock = compiler->currentBlock;
1329 compiler->currentBlock = blok;
1330 blok->function = compiler->currentFunction;
1331 compiler->currentFunction = NULL;
1332#if LUASL_DIFF_CHECK
1333 blok->openIgnorable = block->ignorable;
1334 block->ignorable = NULL;
1335#endif
1336 }
1337 return block;
1338}
1339
1340static void secondPass(LuaSL_compiler *compiler, LSL_Leaf *leaf)
1341{
1342 if (leaf)
1343 {
1344 secondPass(compiler, leaf->left);
1345 if (OT_undeclared == leaf->basicType)
1346 leaf = addOperation(compiler, leaf->left, leaf, leaf->right);
1347 secondPass(compiler, leaf->right);
1348 }
1349}
1350
1351static void outputLeaf(FILE *file, outputMode mode, LSL_Leaf *leaf)
1352{
1353 if (leaf)
1354 {
1355 if ((OM_LUA == mode) &&(ST_BITWISE != leaf->toKen->subType))
1356 outputLeaf(file, mode, leaf->left);
1357#if LUASL_DIFF_CHECK
1358 if ((!(LSL_NOIGNORE & leaf->toKen->flags)) && (leaf->ignorable))
1359 fwrite(eina_strbuf_string_get(leaf->ignorable), 1, eina_strbuf_length_get(leaf->ignorable), file);
1360#endif
1361 if (leaf->toKen->output)
1362 leaf->toKen->output(file, mode, leaf);
1363 else
1364 {
1365 if (OM_LUA == mode)
1366 {
1367 if (MF_WRAPFUNC & leaf->flags)
1368 {
1369// TODO - Leaving this here in case we trip over one.
1370if ((leaf->left) && (leaf->right))
1371 printf("%s %s %s\n", leaf->left->toKen->toKen, leaf->toKen->toKen, leaf->right->toKen->toKen);
1372else if (leaf->left)
1373 printf("%s %s NORIGHT\n", leaf->left->toKen->toKen, leaf->toKen->toKen);
1374else if (leaf->right)
1375 printf("NOLEFT %s %s\n", leaf->toKen->toKen, leaf->right->toKen->toKen);
1376else
1377 printf("NOLEFT %s NORIGHT\n", leaf->toKen->toKen);
1378 }
1379 if ((LSL_ASSIGNMENT & leaf->toKen->flags) && (LSL_ASSIGNMENT_PLAIN != leaf->toKen->type))
1380 {
1381 if (leaf->left->value.identifierValue->sub)
1382 fprintf(file, " --[[%s]] = %s.%s %.1s ", leaf->toKen->toKen, leaf->left->value.identifierValue->name.text, leaf->left->value.identifierValue->sub, leaf->toKen->toKen);
1383 else
1384 fprintf(file, " --[[%s]] = %s %.1s ", leaf->toKen->toKen, leaf->left->value.identifierValue->name.text, leaf->toKen->toKen);
1385 }
1386 else if (LSL_TYPE & leaf->toKen->flags)
1387 {
1388 if (MF_LOCAL & leaf->flags)
1389 fprintf(file, " local ");
1390 fprintf(file, " --[[%s]] ", leaf->toKen->toKen);
1391 }
1392 else if (LSL_BOOL_AND == leaf->toKen->type)
1393 fprintf(file, " and ");
1394 else if (LSL_BOOL_OR == leaf->toKen->type)
1395 fprintf(file, " or ");
1396 else if (LSL_BOOL_NOT == leaf->toKen->type)
1397 fprintf(file, " not ");
1398 else if (LSL_CONCATENATE == leaf->toKen->type)
1399 fprintf(file, " .. ");
1400 else if (LSL_NOT_EQUAL == leaf->toKen->type)
1401 fprintf(file, " ~= ");
1402 else
1403 fprintf(file, "%s", leaf->toKen->toKen);
1404 }
1405 else
1406 fprintf(file, "%s", leaf->toKen->toKen);
1407 }
1408 if ((OM_LUA == mode) &&(ST_BITWISE != leaf->toKen->subType))
1409 outputLeaf(file, mode, leaf->right);
1410 }
1411}
1412
1413// Circular references, so declare this one first.
1414static void outputRawStatement(FILE *file, outputMode mode, LSL_Statement *statement);
1415
1416static void outputRawBlock(FILE *file, outputMode mode, LSL_Block *block, boolean doEnd)
1417{
1418 if (block)
1419 {
1420 LSL_Statement *stat = NULL;
1421
1422#if LUASL_DIFF_CHECK
1423 if (block->openIgnorable)
1424 fwrite(eina_strbuf_string_get(block->openIgnorable), 1, eina_strbuf_length_get(block->openIgnorable), file);
1425 if (OM_LSL == mode)
1426 fprintf(file, "{");
1427#else
1428 if (OM_LSL == mode)
1429 fprintf(file, "\n{\n");
1430 else if (doEnd && (OM_LUA == mode))
1431 fprintf(file, "\n");
1432#endif
1433 EINA_CLIST_FOR_EACH_ENTRY(stat, &(block->statements), LSL_Statement, statement)
1434 {
1435 outputRawStatement(file, mode, stat);
1436 }
1437#if LUASL_DIFF_CHECK
1438 if (block->closeIgnorable)
1439 fwrite(eina_strbuf_string_get(block->closeIgnorable), 1, eina_strbuf_length_get(block->closeIgnorable), file);
1440#endif
1441 if (OM_LSL == mode)
1442 fprintf(file, "}");
1443 else if (doEnd && (OM_LUA == mode))
1444 fprintf(file, "end ");
1445 }
1446}
1447
1448// TODO - should clean this up by refactoring the bits in the switch outside.
1449static void outputRawParenthesisToken(FILE *file, outputMode mode, LSL_Parenthesis *parenthesis, const char *typeName)
1450{
1451 if ((OM_LUA == mode) && (LSL_TYPECAST_OPEN == parenthesis->type))
1452 {
1453 if (MF_TYPECAST & parenthesis->flags)
1454 fprintf(file, " _LSL.%sTypecast(", typeName);
1455 else
1456 fprintf(file, " --[[%s]] ", typeName);
1457 outputLeaf(file, mode, parenthesis->contents);
1458 if (MF_TYPECAST & parenthesis->flags)
1459 fprintf(file, ") ");
1460 return;
1461 }
1462
1463 if ((OM_LUA == mode) && (MF_WRAPFUNC & parenthesis->flags))
1464 fprintf(file, " (function() ");
1465 else
1466 fprintf(file, "(");
1467 if (LSL_TYPECAST_OPEN == parenthesis->type)
1468 fprintf(file, "%s", typeName); // TODO - We are missing the type ignorable text here.
1469 else
1470 outputLeaf(file, mode, parenthesis->contents);
1471 if ((OM_LUA == mode) && (MF_WRAPFUNC & parenthesis->flags))
1472 fprintf(file, "; return x; end)() ");
1473 else
1474 {
1475#if LUASL_DIFF_CHECK
1476 fprintf(file, "%s)", eina_strbuf_string_get(parenthesis->rightIgnorable));
1477#else
1478 fprintf(file, ")");
1479#endif
1480 }
1481
1482 if (LSL_TYPECAST_OPEN == parenthesis->type)
1483 outputLeaf(file, mode, parenthesis->contents);
1484}
1485
1486static void outputText(FILE *file, LSL_Text *text, boolean ignore)
1487{
1488 if (text->text)
1489 {
1490#if LUASL_DIFF_CHECK
1491 if (ignore && (text->ignorable))
1492 fwrite(eina_strbuf_string_get(text->ignorable), 1, eina_strbuf_length_get(text->ignorable), file);
1493#endif
1494 fprintf(file, "%s", text->text);
1495 }
1496}
1497
1498static void outputRawStatement(FILE *file, outputMode mode, LSL_Statement *statement)
1499{
1500 boolean isBlock = FALSE;
1501
1502 if (statement)
1503 {
1504 switch (statement->type)
1505 {
1506 case LSL_EXPRESSION :
1507 {
1508 break;
1509 }
1510 case LSL_FUNCTION :
1511 {
1512 isBlock = TRUE;
1513 break;
1514 }
1515 case LSL_DO :
1516 {
1517 fprintf(file, "%s", tokens[statement->type - lowestToken]->toKen);
1518 break;
1519 }
1520 case LSL_FOR :
1521 {
1522#if LUASL_DIFF_CHECK
1523 if ((statement->ignorable) && (statement->ignorable[1]))
1524 fwrite(eina_strbuf_string_get(statement->ignorable[1]), 1, eina_strbuf_length_get(statement->ignorable[1]), file);
1525#endif
1526 if (OM_LSL == mode)
1527 {
1528 isBlock = TRUE;
1529 fprintf(file, "%s", tokens[statement->type - lowestToken]->toKen);
1530 }
1531 else if (OM_LUA == mode)
1532 {
1533 LSL_Leaf **exprs = (LSL_Leaf **) statement->expressions;
1534
1535 outputLeaf(file, mode, exprs[0]);
1536 fprintf(file, ";\nwhile (");
1537 outputLeaf(file, mode, exprs[2]);
1538#if LUASL_DIFF_CHECK
1539 fprintf(file, "%s)\n", eina_strbuf_string_get(statement->parenthesis->rightIgnorable));
1540#else
1541 fprintf(file, ") do\n");
1542#endif
1543 if (statement->block)
1544 outputRawBlock(file, mode, statement->block, FALSE);
1545 if (statement->single)
1546 outputRawStatement(file, mode, statement->single);
1547 fprintf(file, "\n");
1548 outputLeaf(file, mode, exprs[4]);
1549 fprintf(file, ";\nend\n");
1550 return;
1551 }
1552 break;
1553 }
1554 case LSL_IF :
1555 case LSL_ELSE :
1556 case LSL_ELSEIF :
1557 {
1558 isBlock = TRUE;
1559#if LUASL_DIFF_CHECK
1560 if ((statement->ignorable) && (statement->ignorable[1]))
1561 fwrite(eina_strbuf_string_get(statement->ignorable[1]), 1, eina_strbuf_length_get(statement->ignorable[1]), file);
1562#endif
1563 fprintf(file, "%s", tokens[statement->type - lowestToken]->toKen);
1564 if (OM_LUA == mode)
1565 {
1566 fprintf(file, " ");
1567 if (LSL_ELSE != statement->type)
1568 {
1569 if (statement->parenthesis)
1570 outputRawParenthesisToken(file, mode, statement->parenthesis, "");
1571 else
1572 outputLeaf(file, mode, statement->expressions);
1573 fprintf(file, " then\n");
1574 }
1575 if (statement->block)
1576 outputRawBlock(file, mode, statement->block, FALSE);
1577 if (statement->single)
1578 outputRawStatement(file, mode, statement->single);
1579 if (statement->elseBlock)
1580 outputRawStatement(file, mode, statement->elseBlock);
1581 if (LSL_IF == statement->type)
1582 {
1583#if 1
1584 fprintf(file, " end\n");
1585#else
1586 fprintf(file, " end --[[");
1587 if (statement->parenthesis)
1588 outputRawParenthesisToken(file, mode, statement->parenthesis, "");
1589 else
1590 outputLeaf(file, mode, statement->expressions);
1591 fprintf(file, "]]\n");
1592#endif
1593 }
1594 return;
1595 }
1596 break;
1597 }
1598 case LSL_JUMP :
1599 {
1600#if LUASL_DIFF_CHECK
1601 if ((statement->ignorable) && (statement->ignorable[1]))
1602 fwrite(eina_strbuf_string_get(statement->ignorable[1]), 1, eina_strbuf_length_get(statement->ignorable[1]), file);
1603#endif
1604 fprintf(file, "%s", tokens[statement->type - lowestToken]->toKen);
1605 break;
1606 }
1607 case LSL_LABEL :
1608 {
1609#if LUASL_DIFF_CHECK
1610 if ((statement->ignorable) && (statement->ignorable[1]))
1611 fwrite(eina_strbuf_string_get(statement->ignorable[1]), 1, eina_strbuf_length_get(statement->ignorable[1]), file);
1612#endif
1613 fprintf(file, "%s", tokens[statement->type - lowestToken]->toKen);
1614 break;
1615 }
1616 case LSL_RETURN :
1617 {
1618#if LUASL_DIFF_CHECK
1619 if ((statement->ignorable) && (statement->ignorable[1]))
1620 fwrite(eina_strbuf_string_get(statement->ignorable[1]), 1, eina_strbuf_length_get(statement->ignorable[1]), file);
1621#endif
1622 fprintf(file, "%s", tokens[statement->type - lowestToken]->toKen);
1623 break;
1624 }
1625 case LSL_STATE_CHANGE :
1626 {
1627#if LUASL_DIFF_CHECK
1628 if ((statement->ignorable) && (statement->ignorable[1]))
1629 fwrite(eina_strbuf_string_get(statement->ignorable[1]), 1, eina_strbuf_length_get(statement->ignorable[1]), file);
1630#endif
1631 if (OM_LSL == mode)
1632 {
1633 fprintf(file, "%s", tokens[statement->type - lowestToken]->toKen);
1634 if (statement->identifier.text)
1635 outputText(file, &(statement->identifier), TRUE);
1636 }
1637 else if (OM_LUA == mode)
1638 {
1639 fprintf(file, "return _LSL.stateChange(_");
1640 if (statement->identifier.text)
1641 outputText(file, &(statement->identifier), TRUE);
1642 fprintf(file, "State)");
1643 }
1644 break;
1645 }
1646 case LSL_STATEMENT :
1647 {
1648 break;
1649 }
1650 case LSL_WHILE :
1651 {
1652 isBlock = TRUE;
1653#if LUASL_DIFF_CHECK
1654 if ((statement->ignorable) && (statement->ignorable[1]))
1655 fwrite(eina_strbuf_string_get(statement->ignorable[1]), 1, eina_strbuf_length_get(statement->ignorable[1]), file);
1656#else
1657 if (OM_LUA == mode)
1658 fprintf(file, "\n");
1659#endif
1660 fprintf(file, "%s", tokens[statement->type - lowestToken]->toKen);
1661 if (OM_LUA == mode)
1662 {
1663 if (statement->parenthesis)
1664 outputRawParenthesisToken(file, mode, statement->parenthesis, "");
1665 fprintf(file, " do ");
1666 if (statement->block)
1667 outputRawBlock(file, mode, statement->block, TRUE);
1668 if (statement->single)
1669 outputRawStatement(file, mode, statement->single);
1670 fprintf(file, "\n");
1671 return;
1672 }
1673 break;
1674 }
1675 case LSL_IDENTIFIER :
1676 {
1677 break;
1678 }
1679 case LSL_VARIABLE :
1680 {
1681 break;
1682 }
1683 default :
1684 {
1685 fprintf(file, "@@Should not be here %s.@@", tokens[statement->type - lowestToken]->toKen);
1686 break;
1687 }
1688 }
1689
1690#if LUASL_DIFF_CHECK
1691 if ((statement->ignorable) && (statement->ignorable[2]))
1692 fwrite(eina_strbuf_string_get(statement->ignorable[2]), 1, eina_strbuf_length_get(statement->ignorable[2]), file);
1693#else
1694 if (OM_LUA == mode)
1695 fprintf(file, " ");
1696#endif
1697 if (LSL_FOR == statement->type)
1698 {
1699 LSL_Leaf **exprs = (LSL_Leaf **) statement->expressions;
1700 int i;
1701
1702 fprintf(file, "(");
1703 for (i = 0; i < 5; i++)
1704 {
1705 outputLeaf(file, mode, exprs[i]);
1706 if (i % 2)
1707 fprintf(file, ";");
1708 }
1709#if LUASL_DIFF_CHECK
1710 fprintf(file, "%s)", eina_strbuf_string_get(statement->parenthesis->rightIgnorable));
1711#else
1712 fprintf(file, ")");
1713#endif
1714 }
1715 else if (statement->parenthesis)
1716 outputRawParenthesisToken(file, mode, statement->parenthesis, "");
1717 else
1718 outputLeaf(file, mode, statement->expressions);
1719
1720 if (statement->block)
1721 outputRawBlock(file, mode, statement->block, TRUE);
1722 if (statement->single)
1723 outputRawStatement(file, mode, statement->single);
1724
1725#if LUASL_DIFF_CHECK
1726 if ((statement->ignorable) && (statement->ignorable[0]))
1727 fwrite(eina_strbuf_string_get(statement->ignorable[0]), 1, eina_strbuf_length_get(statement->ignorable[0]), file);
1728#endif
1729
1730 if (!isBlock)
1731 {
1732 fprintf(file, ";");
1733 if (!LUASL_DIFF_CHECK)
1734 fprintf(file, "\n");
1735 }
1736
1737 if ((LSL_VARIABLE == statement->type) && (OM_LUA == mode) && (MF_LOCAL & statement->flags))
1738 {
1739 const char *name = statement->identifier.text;
1740
1741// if ((MF_PREDEC | MF_PREINC | MF_POSTDEC | MF_POSTINC) & statement->flags)
1742// fprintf(file, "\n");
1743 if (MF_PREDEC & statement->flags) fprintf(file, "local function _preDecrement_%s() %s = %s - 1; return %s; end\n", name, name, name, name);
1744 if (MF_PREINC & statement->flags) fprintf(file, "local function _preIncrement_%s() %s = %s + 1; return %s; end\n", name, name, name, name);
1745 if (MF_POSTDEC & statement->flags) fprintf(file, "local function _postDecrement_%s() local _temp = %s; %s = %s - 1; return _temp; end\n", name, name, name, name);
1746 if (MF_POSTINC & statement->flags) fprintf(file, "local function _postDecrement_%s() local _temp = %s; %s = %s + 1; return _temp; end\n", name, name, name, name);
1747 }
1748
1749 if (statement->elseBlock)
1750 outputRawStatement(file, mode, statement->elseBlock);
1751 }
1752}
1753
1754static void outputBitOp(FILE *file, outputMode mode, LSL_Leaf *leaf)
1755{
1756 if (OM_LSL == mode)
1757 outputLeaf(file, mode, leaf);
1758 else if (OM_LUA == mode)
1759 {
1760 switch (leaf->toKen->type)
1761 {
1762 case LSL_BIT_AND : fprintf(file, " _bit.band("); break;
1763 case LSL_BIT_OR : fprintf(file, " _bit.bor("); break;
1764 case LSL_BIT_XOR : fprintf(file, " _bit.xor("); break;
1765 case LSL_BIT_NOT : fprintf(file, " _bit.bnot("); break;
1766 case LSL_LEFT_SHIFT : fprintf(file, " _bit.lshift("); break;
1767 case LSL_RIGHT_SHIFT : fprintf(file, " _bit.arshift("); break;
1768 default : break;
1769 }
1770 outputLeaf(file, mode, leaf->left);
1771 if (LSL_BIT_NOT != leaf->toKen->type)
1772 {
1773 fprintf(file, ", ");
1774 outputLeaf(file, mode, leaf->right);
1775 }
1776 fprintf(file, ") ");
1777 }
1778}
1779
1780static void outputBlockToken(FILE *file, outputMode mode, LSL_Leaf *content)
1781{
1782 if (content)
1783 outputRawBlock(file, mode, content->value.blockValue, TRUE);
1784}
1785
1786static void outputCrementsToken(FILE *file, outputMode mode, LSL_Leaf *content)
1787{
1788 if (content)
1789 {
1790 if (OM_LSL == mode)
1791 {
1792 switch (content->toKen->type)
1793 {
1794 case LSL_DECREMENT_PRE :
1795 case LSL_INCREMENT_PRE :
1796 {
1797 fprintf(file, "%s", content->toKen->toKen);
1798#if LUASL_DIFF_CHECK
1799 if (content->value.identifierValue->ignorable)
1800 fwrite(eina_strbuf_string_get(content->value.identifierValue->ignorable), 1, eina_strbuf_length_get(content->value.identifierValue->ignorable), file);
1801#endif
1802 outputText(file, &(content->value.identifierValue->name), FALSE);
1803 break;
1804 }
1805 case LSL_DECREMENT_POST :
1806 case LSL_INCREMENT_POST :
1807 {
1808#if LUASL_DIFF_CHECK
1809 if (content->value.identifierValue->ignorable)
1810 fwrite(eina_strbuf_string_get(content->value.identifierValue->ignorable), 1, eina_strbuf_length_get(content->value.identifierValue->ignorable), file);
1811#endif
1812 outputText(file, &(content->value.identifierValue->name), FALSE);
1813 fprintf(file, "%s", content->toKen->toKen);
1814 break;
1815 }
1816 default :
1817 break;
1818 }
1819 }
1820 else if (OM_LUA == mode)
1821 {
1822 if (MF_LOCAL & content->value.identifierValue->flags)
1823 fprintf(file, " _");
1824 else
1825 fprintf(file, " _LSL.");
1826 switch (content->toKen->type)
1827 {
1828 case LSL_DECREMENT_PRE : fprintf(file, "preDecrement"); break;
1829 case LSL_INCREMENT_PRE : fprintf(file, "preIncrement"); break;
1830 case LSL_DECREMENT_POST : fprintf(file, "postDecrement"); break;
1831 case LSL_INCREMENT_POST : fprintf(file, "postIncrement"); break;
1832 default :
1833 break;
1834 }
1835 if (MF_LOCAL & content->value.identifierValue->flags)
1836 fprintf(file, "_");
1837 else
1838 fprintf(file, "(\"");
1839#if LUASL_DIFF_CHECK
1840 if (content->value.identifierValue->ignorable)
1841 fwrite(eina_strbuf_string_get(content->value.identifierValue->ignorable), 1, eina_strbuf_length_get(content->value.identifierValue->ignorable), file);
1842#endif
1843 outputText(file, &(content->value.identifierValue->name), FALSE);
1844 if (MF_LOCAL & content->value.identifierValue->flags)
1845 fprintf(file, "()");
1846 else
1847 fprintf(file, "\")");
1848 }
1849 }
1850}
1851
1852static void outputFloatToken(FILE *file, outputMode mode, LSL_Leaf *content)
1853{
1854 if (content)
1855 outputText(file, &(content->value.numbyValue->text), !(LSL_NOIGNORE & content->toKen->flags));
1856}
1857
1858static void outputFunctionToken(FILE *file, outputMode mode, LSL_Leaf *content)
1859{
1860 if (content)
1861 {
1862 LSL_Function *func = content->value.functionValue;
1863 LSL_Leaf *param = NULL;
1864 int first = TRUE;
1865
1866 if (OM_LSL == mode)
1867 {
1868 outputText(file, &(func->type), !(LSL_NOIGNORE & content->toKen->flags));
1869 outputText(file, &(func->name), !(LSL_NOIGNORE & content->toKen->flags));
1870 // TODO - should print comma and parenthesis ignorables.
1871 fprintf(file, "(");
1872 EINA_INARRAY_FOREACH((&(func->vars)), param)
1873 {
1874 if (!LUASL_DIFF_CHECK)
1875 {
1876 if (!first)
1877 fprintf(file, ", ");
1878 }
1879 outputLeaf(file, mode, param);
1880 first = FALSE;
1881 }
1882 fprintf(file, ")");
1883 outputRawBlock(file, mode, func->block, TRUE);
1884 if (!LUASL_DIFF_CHECK)
1885 fprintf(file, "\n");
1886 }
1887 else if (OM_LUA == mode)
1888 {
1889 if (func->state)
1890 fprintf(file, "\n\n_%sState.%s = function(", func->state, func->name.text);
1891 else
1892 {
1893 fprintf(file, "\n\nfunction ");
1894 if (func->type.text)
1895 fprintf(file, " --[[%s]] ", func->type.text);
1896 fprintf(file, "%s(", func->name.text);
1897 }
1898 EINA_INARRAY_FOREACH((&(func->vars)), param)
1899 {
1900 // Commenting out the types is done in outputLeaf() which outputs all the types.
1901 if (!LUASL_DIFF_CHECK)
1902 {
1903 if (!first)
1904 fprintf(file, ", ");
1905 }
1906 outputLeaf(file, mode, param);
1907 first = FALSE;
1908 }
1909 fprintf(file, ")");
1910 outputRawBlock(file, mode, func->block, TRUE);
1911 }
1912 }
1913}
1914
1915static void outputFunctionCallToken(FILE *file, outputMode mode, LSL_Leaf *content)
1916{
1917 if (content)
1918 {
1919 LSL_FunctionCall *call = content->value.functionCallValue;
1920 LSL_Leaf *param = NULL;
1921 boolean first = TRUE;
1922
1923 // TODO - should output it's own ignorable here.
1924 if ((OM_LUA == mode) && (MF_LSLCONST & call->function->flags))
1925 fprintf(file, "_LSL.");
1926 outputText(file, &(call->function->name), FALSE); // Don't output the function definitions ignorable.
1927 fprintf(file, "(");
1928 EINA_INARRAY_FOREACH((&(call->params)), param)
1929 {
1930 if ((OM_LUA == mode) && (!first))
1931 fprintf(file, ", ");
1932 outputLeaf(file, mode, param);
1933 first = FALSE;
1934 }
1935 fprintf(file, ")");
1936 }
1937}
1938
1939static void outputIntegerToken(FILE *file, outputMode mode, LSL_Leaf *content)
1940{
1941 if (content)
1942 outputText(file, &(content->value.numbyValue->text), !(LSL_NOIGNORE & content->toKen->flags));
1943}
1944
1945static void outputIdentifierToken(FILE *file, outputMode mode, LSL_Leaf *content)
1946{
1947 if (content)
1948 {
1949 if (LSL_IDENTIFIER == content->toKen->type)
1950 {
1951 if ((OM_LUA == mode) && (MF_LSLCONST & content->value.identifierValue->flags))
1952 fprintf(file, "_LSL.");
1953 outputText(file, &(content->value.identifierValue->name), FALSE);
1954 if (content->value.identifierValue->sub)
1955 fprintf(file, ".%s", content->value.identifierValue->sub);
1956 }
1957 else
1958 if ((LSL_VARIABLE == content->toKen->type) && (MF_NOASSIGN & content->flags))
1959 {
1960 outputText(file, &(content->value.identifierValue->name), !(LSL_NOIGNORE & content->toKen->flags));
1961 if (OM_LUA == mode)
1962 {
1963 switch (content->basicType)
1964 {
1965 case OT_bool : fprintf(file, " = false"); break;
1966 case OT_integer : fprintf(file, " = 0"); break;
1967 case OT_float : fprintf(file, " = 0.0"); break;
1968 case OT_key : fprintf(file, " = _LSL.NULL_KEY"); break;
1969 case OT_list : fprintf(file, " = {}"); break;
1970 case OT_rotation : fprintf(file, " = _LSL.ZERO_ROTATION"); break;
1971 case OT_string : fprintf(file, " = \"\""); break;
1972 case OT_vector : fprintf(file, " = _LSL.ZERO_VECTOR"); break;
1973 default : fprintf(file, " = nil"); break;
1974 }
1975 }
1976 }
1977 else
1978 outputText(file, &(content->value.identifierValue->name), !(LSL_NOIGNORE & content->toKen->flags));
1979 }
1980}
1981
1982static void outputListToken(FILE *file, outputMode mode, LSL_Leaf *content)
1983{
1984 if (content)
1985 {
1986 LSL_Parenthesis *parens = content->value.parenthesis;
1987
1988 if (parens->contents)
1989 {
1990 LSL_FunctionCall *call = parens->contents->value.functionCallValue;
1991 LSL_Leaf *param = NULL;
1992 const char *ig = "";
1993
1994 // TODO - should output it's own ignorable here.
1995 if (OM_LSL == mode)
1996 {
1997 switch (parens->type)
1998 {
1999 case LSL_LIST : fprintf(file, "["); break;
2000 case LSL_ROTATION :
2001 case LSL_VECTOR : fprintf(file, "<");
2002 default : break;
2003 }
2004 }
2005 else if (OM_LUA == mode)
2006 {
2007 switch (parens->type)
2008 {
2009 case LSL_LIST : fprintf(file, "{"); break;
2010 case LSL_ROTATION :
2011 case LSL_VECTOR : fprintf(file, "{");
2012 default : break;
2013 }
2014 }
2015 EINA_INARRAY_FOREACH((&(call->params)), param)
2016 {
2017 outputLeaf(file, mode, param);
2018 if (OM_LUA == mode)
2019 fprintf(file, ", ");
2020 }
2021#if LUASL_DIFF_CHECK
2022 ig = eina_strbuf_string_get(parens->rightIgnorable);
2023#endif
2024 if (OM_LSL == mode)
2025 {
2026 switch (parens->type)
2027 {
2028 case LSL_LIST : fprintf(file, "%s]", ig); break;
2029 case LSL_ROTATION :
2030 case LSL_VECTOR : fprintf(file, "%s>", ig);
2031 default : break;
2032 }
2033 }
2034 else if (OM_LUA == mode)
2035 {
2036 switch (parens->type)
2037 {
2038 case LSL_LIST : fprintf(file, "%s}", ig); break;
2039 case LSL_ROTATION :
2040 case LSL_VECTOR : fprintf(file, "%s}", ig);
2041 default : break;
2042 }
2043 }
2044 }
2045 }
2046}
2047
2048static void outputParameterListToken(FILE *file, outputMode mode, LSL_Leaf *content)
2049{
2050 if (content)
2051 outputLeaf(file, mode, content->value.listValue);
2052 // TODO - Should go through the list, and output any crements functions we need at the top of the block.
2053}
2054
2055static void outputParenthesisToken(FILE *file, outputMode mode, LSL_Leaf *content)
2056{
2057 if (content)
2058 outputRawParenthesisToken(file, mode, content->value.parenthesis, allowed[content->basicType].name);
2059}
2060
2061static void outputStateToken(FILE *file, outputMode mode, LSL_Leaf *content)
2062{
2063 if (content)
2064 {
2065 LSL_State *state = content->value.stateValue;
2066
2067 if (state)
2068 {
2069 if (OM_LSL == mode)
2070 {
2071 outputText(file, &(state->state), !(LSL_NOIGNORE & content->toKen->flags));
2072 outputText(file, &(state->name), !(LSL_NOIGNORE & content->toKen->flags));
2073 outputRawBlock(file, mode, state->block, TRUE);
2074 }
2075 else if (OM_LUA == mode)
2076 {
2077 fprintf(file, "\n\n--[[state]] _");
2078 outputText(file, &(state->name), !(LSL_NOIGNORE & content->toKen->flags));
2079 fprintf(file, "State = {};");
2080 outputRawBlock(file, mode, state->block, FALSE);
2081 }
2082 }
2083 }
2084}
2085
2086static void outputStatementToken(FILE *file, outputMode mode, LSL_Leaf *content)
2087{
2088 if (content)
2089 outputRawStatement(file, mode, content->value.statementValue);
2090}
2091
2092static void outputStringToken(FILE *file, outputMode mode, LSL_Leaf *content)
2093{
2094 if (content)
2095 fprintf(file, "%s", content->value.stringValue); // The quotes are part of the string value already.
2096}
2097
2098boolean compilerSetup(gameGlobals *ourGlobals)
2099{
2100 int i;
2101
2102 // Figure out what numbers lemon gave to our tokens.
2103 for (i = 0; LSL_Tokens[i].toKen != NULL; i++)
2104 {
2105 if (lowestToken > LSL_Tokens[i].type)
2106 lowestToken = LSL_Tokens[i].type;
2107 }
2108 tokens = calloc(i + 1, sizeof(LSL_Token *));
2109 if (tokens)
2110 {
2111 char buf[PATH_MAX];
2112
2113 // Sort the token table.
2114 for (i = 0; LSL_Tokens[i].toKen != NULL; i++)
2115 {
2116 int j = LSL_Tokens[i].type - lowestToken;
2117
2118 tokens[j] = &(LSL_Tokens[i]);
2119 }
2120
2121 // Compile the constants.
2122 snprintf(buf, sizeof(buf), "lua -e 'require(\"LSL\").gimmeLSL()' > %s/libraries/constants.lsl", PACKAGE_DATA_DIR);
2123 system(buf);
2124 snprintf(buf, sizeof(buf), "%s/libraries/constants.lsl", PACKAGE_DATA_DIR);
2125 compileLSL(ourGlobals, NULL, "FAKE_SID", buf, TRUE);
2126
2127 return TRUE;
2128 }
2129 else
2130 PC("No memory for tokens!");
2131
2132 return FALSE;
2133}
2134
2135static int luaWriter(lua_State *L, const void* p, size_t sz, void* ud)
2136{
2137 FILE *out = ud;
2138 int result = 0;
2139
2140 if (sz != fwrite(p, 1, sz, out))
2141 result = -1;
2142 return result;
2143}
2144
2145boolean compileLSL(gameGlobals *ourGlobals, Ecore_Con_Client *client, char *SID, char *script, boolean doConstants)
2146{
2147 boolean result = FALSE;
2148 LuaSL_compiler compiler;
2149 void *pParser = ParseAlloc(malloc);
2150 int yv;
2151
2152// Parse the LSL script, validating it and reporting errors.
2153// Just pass all LSL constants and ll*() )function names through to Lua, assume they are globals there.
2154
2155 memset(&compiler, 0, sizeof(LuaSL_compiler));
2156 compiler.game = ourGlobals;
2157 compiler.client = client;
2158 compiler.script.functions = eina_hash_stringshared_new(burnLeaf);
2159 compiler.script.states = eina_hash_stringshared_new(burnLeaf);
2160 compiler.script.variables = eina_hash_stringshared_new(burnLeaf);
2161 eina_clist_init(&(compiler.danglingCalls));
2162#if LUASL_DIFF_CHECK
2163 compiler.ignorable = eina_strbuf_new();
2164#endif
2165
2166 strncpy(compiler.SID, SID, 36);
2167 compiler.SID[36] = '\0';
2168 strncpy(compiler.fileName, script, PATH_MAX - 1);
2169 compiler.fileName[PATH_MAX - 1] = '\0';
2170 compiler.file = fopen(compiler.fileName, "r");
2171 if (NULL == compiler.file)
2172 {
2173 PE("Error opening file %s.", compiler.fileName);
2174 return FALSE;
2175 }
2176 compiler.ast = NULL;
2177 compiler.lval = newLeaf(LSL_UNKNOWN, NULL, NULL);
2178 // Text editors usually start counting at 1, even programmers editors. mcedit is an exception, but you can deal with that yourself.
2179 compiler.column = 1;
2180 compiler.line = 1;
2181
2182 if (yylex_init_extra(&compiler, &(compiler.scanner)))
2183 return result;
2184 if (LUASL_DEBUG)
2185 {
2186 yyset_debug(1, compiler.scanner);
2187 ParseTrace(stdout, "LSL_lemon ");
2188 }
2189 yyset_in(compiler.file, compiler.scanner);
2190 // on EOF yylex will return 0
2191 while((yv = yylex(compiler.lval, compiler.scanner)) != 0)
2192 {
2193 Parse(pParser, yv, compiler.lval, &compiler);
2194 if (LSL_SCRIPT == yv)
2195 break;
2196 compiler.lval = newLeaf(LSL_UNKNOWN, NULL, NULL);
2197 }
2198
2199 yylex_destroy(compiler.scanner);
2200 Parse (pParser, 0, compiler.lval, &compiler);
2201 ParseFree(pParser, free);
2202
2203 if (compiler.undeclared)
2204 {
2205// PW("A second pass is needed to check if functions where used before they where declared. To avoid this second pass, don't do that.");
2206 if (eina_clist_count(&(compiler.danglingCalls)))
2207 {
2208 LSL_FunctionCall *call = NULL;
2209
2210 EINA_CLIST_FOR_EACH_ENTRY(call, &(compiler.danglingCalls), LSL_FunctionCall, dangler)
2211 {
2212 LSL_Leaf *func = findFunction(&(compiler), call->call->value.stringValue);
2213
2214 if (func)
2215 {
2216 call->function = func->value.functionValue;
2217 // Coz the leaf still had the stringValue from before.
2218 call->call->value.functionCallValue = call;
2219 call->call->toKen = tokens[LSL_FUNCTION_CALL - lowestToken];
2220 call->call->basicType = func->basicType;
2221 }
2222 else
2223 sendBack(ourGlobals, compiler.client, compiler.SID, "compilerError(%d,%d,Undeclared function %s called)", call->call->line, call->call->column, call->call->value.stringValue);
2224 }
2225 }
2226 secondPass(&compiler, compiler.ast);
2227// PD("Second pass completed.");
2228 }
2229
2230 if (doConstants)
2231 {
2232 memcpy(&constants, &(compiler.script), sizeof(LSL_Script));
2233 result = TRUE;
2234 }
2235 else
2236 {
2237 result = FALSE;
2238
2239 if (compiler.ast)
2240 {
2241 FILE *out;
2242 char buffer[PATH_MAX];
2243 char outName[PATH_MAX];
2244 char luaName[PATH_MAX];
2245 int count;
2246
2247 if (LUASL_DIFF_CHECK)
2248 {
2249 strcpy(outName, compiler.fileName);
2250 strcat(outName, "2");
2251 out = fopen(outName, "w");
2252 if (out)
2253 {
2254 char diffName[PATH_MAX];
2255
2256 strcpy(diffName, compiler.fileName);
2257 strcat(diffName, ".diff");
2258 outputLeaf(out, OM_LSL, compiler.ast);
2259 fclose(out);
2260 sprintf(buffer, "diff -u \"%s\" \"%s\" > \"%s\"", compiler.fileName, outName, diffName);
2261 count = system(buffer);
2262 if (0 != count)
2263 PE("LSL output file is different - %s!", outName);
2264 else
2265 result = TRUE;
2266 }
2267 else
2268 PC("Unable to open file %s for writing!", outName);
2269 }
2270 strcpy(luaName, compiler.fileName);
2271 strcat(luaName, ".lua");
2272 out = fopen(luaName, "w");
2273 // Generate the Lua source code.
2274 if (out)
2275 {
2276 lua_State *L;
2277 int err;
2278 char *ext;
2279
2280 fprintf(out, "--// Generated code goes here.\n\n");
2281 fprintf(out, "local _bit = require(\"bit\")\n");
2282 fprintf(out, "local _LSL = require(\"LSL\")\n\n");
2283 fprintf(out, "local _SID = [=[%s]=]\n\n", compiler.SID);
2284 strcpy(buffer, basename(compiler.fileName));
2285 if ((ext = rindex(buffer, '.')))
2286 ext[0] = '\0';
2287 fprintf(out, "local _scriptName = [=[%s]=]\n\n", buffer);
2288 outputLeaf(out, OM_LUA, compiler.ast);
2289 fprintf(out, "\n\n_LSL.mainLoop(_SID, _scriptName, _defaultState)\n"); // This actually starts the script running.
2290 fprintf(out, "\n--// End of generated code.\n\n");
2291 fclose(out);
2292
2293 // Compile the Lua source code.
2294 L = luaL_newstate();
2295 luaL_openlibs(L);
2296 // This ends up pushing a function onto the stack. The function is the compiled code.
2297 err = luaL_loadfile(L, luaName);
2298 if (err)
2299 {
2300 compiler.script.bugCount++;
2301 if (LUA_ERRSYNTAX == err)
2302 PE("Lua syntax error in %s: %s", luaName, lua_tostring(L, -1));
2303 else if (LUA_ERRFILE == err)
2304 PE("Lua compile file error in %s: %s", luaName, lua_tostring(L, -1));
2305 else if (LUA_ERRMEM == err)
2306 PE("Lua compile memory allocation error in %s: %s", luaName, lua_tostring(L, -1));
2307 }
2308 else
2309 {
2310 // Write the compiled code to a file.
2311 strcat(luaName, ".out");
2312 out = fopen(luaName, "w");
2313 if (out)
2314 {
2315 err = lua_dump(L, luaWriter, out);
2316 if (err)
2317 {
2318 compiler.script.bugCount++;
2319 PE("Lua compile file error writing to %s", luaName);
2320 }
2321 fclose(out);
2322 }
2323 else
2324 PC("Unable to open file %s for writing!", luaName);
2325 }
2326 }
2327 else
2328 PC("Unable to open file %s for writing!", luaName);
2329 }
2330
2331 if (0 == compiler.script.bugCount)
2332 result = TRUE;
2333 }
2334
2335 if (NULL != compiler.file)
2336 {
2337 fclose(compiler.file);
2338 compiler.file = NULL;
2339 }
2340
2341 if (!doConstants)
2342 burnLeaf(compiler.ast);
2343
2344 return result;
2345}