SpiderScript - Bugfixing, most bytecode runs now
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / ast_to_bytecode.c
1 /*
2  * SpiderScript Library
3  *
4  * AST to Bytecode Conversion
5  */
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <string.h>
10 #include "common.h"
11 #include "ast.h"
12 #include "bytecode_gen.h"
13 #include "bytecode_ops.h"
14
15 #define TRACE_VAR_LOOKUPS       0
16 #define TRACE_NODE_RETURNS      0
17 #define MAX_NAMESPACE_DEPTH     10
18
19 // === IMPORTS ===
20 extern tSpiderFunction  *gpExports_First;
21
22 // === TYPES ===
23 typedef struct sAST_BlockInfo
24 {
25         struct sAST_BlockInfo   *Parent;
26         void    *Handle;
27         const char      *Tag;
28
29          int    BreakTarget;
30          int    ContinueTarget;
31         
32         const char      *CurNamespaceStack[MAX_NAMESPACE_DEPTH];
33 } tAST_BlockInfo;
34
35 // === PROTOTYPES ===
36 // Node Traversal
37  int    AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue);
38 // Variables
39  int    BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name);
40  int    BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
41  int    BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
42 // - Errors
43 void    AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
44 void    AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
45
46 // === GLOBALS ===
47 // int  giNextBlockIdent = 1;
48
49 // === CODE ===
50 int SpiderScript_BytecodeScript(tSpiderScript *Script)
51 {
52         tScript_Function        *fcn;
53         for(fcn = Script->Functions; fcn; fcn = fcn->Next)
54         {
55                 if( Bytecode_ConvertFunction(fcn) == 0 )
56                         return -1;
57         }
58         return 0;
59 }
60
61 /**
62  * \brief Convert a function into bytecode
63  */
64 tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
65 {
66         tBC_Function    *ret;
67         tAST_BlockInfo bi = {0};
68
69         // TODO: Return BCFcn instead?
70         if(Fcn->BCFcn)  return Fcn->BCFcn;
71         
72         ret = Bytecode_CreateFunction(Fcn);
73         if(!ret)        return NULL;
74         
75         bi.Handle = ret;
76         if( AST_ConvertNode(&bi, Fcn->ASTFcn, 0) )
77         {
78                 Bytecode_DeleteFunction(ret);
79                 return NULL;
80         }
81
82         Fcn->BCFcn = ret;
83
84         return ret;
85 }
86
87 /**
88  * \brief Convert a node into bytecode
89  * \param Block Execution context
90  * \param Node  Node to execute
91  */
92 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
93 {
94         tAST_Node       *node;
95          int    ret = 0;
96          int    i, op = 0;
97          int    bAddedValue = 1;
98         
99         switch(Node->Type)
100         {
101         // No Operation
102         case NODETYPE_NOP:
103                 bAddedValue = 0;
104                 break;
105         
106         // Code block
107         case NODETYPE_BLOCK:
108                 Bytecode_AppendEnterContext(Block->Handle);     // Create a new block
109                 {
110                         tAST_BlockInfo  blockInfo = {0};
111                         blockInfo.Parent = Block;
112                         blockInfo.Handle = Block->Handle;
113                         // Loop over all nodes, or until the return value is set
114                         for(node = Node->Block.FirstChild;
115                                 node;
116                                 node = node->NextSibling )
117                         {
118                                 AST_ConvertNode(Block, node, 0);
119                         }
120                 }
121                 Bytecode_AppendLeaveContext(Block->Handle);     // Leave this context
122                 bAddedValue = 0;
123                 break;
124         
125         // Assignment
126         case NODETYPE_ASSIGN:
127                 // TODO: Support assigning to object attributes
128                 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
129                         AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
130                         return -1;
131                 }
132                 
133                 // Perform assignment operation
134                 if( Node->Assign.Operation != NODETYPE_NOP )
135                 {
136                         
137                         ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
138                         if(ret) return ret;
139                         ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
140                         if(ret) return ret;
141                         switch(Node->Assign.Operation)
142                         {
143                         // General Binary Operations
144                         case NODETYPE_ADD:      op = BC_OP_ADD; break;
145                         case NODETYPE_SUBTRACT: op = BC_OP_SUBTRACT;    break;
146                         case NODETYPE_MULTIPLY: op = BC_OP_MULTIPLY;    break;
147                         case NODETYPE_DIVIDE:   op = BC_OP_DIVIDE;      break;
148                         case NODETYPE_MODULO:   op = BC_OP_MODULO;      break;
149                         case NODETYPE_BWAND:    op = BC_OP_BITAND;      break;
150                         case NODETYPE_BWOR:     op = BC_OP_BITOR;       break;
151                         case NODETYPE_BWXOR:    op = BC_OP_BITXOR;      break;
152                         case NODETYPE_BITSHIFTLEFT:     op = BC_OP_BITSHIFTLEFT;        break;
153                         case NODETYPE_BITSHIFTRIGHT:    op = BC_OP_BITSHIFTRIGHT;       break;
154                         case NODETYPE_BITROTATELEFT:    op = BC_OP_BITROTATELEFT;       break;
155
156                         default:
157                                 AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
158                                 break;
159                         }
160                         printf("assign, op = %i\n", op);
161                         Bytecode_AppendBinOp(Block->Handle, op);
162                 }
163                 else
164                 {
165                         ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
166                         if(ret) return ret;
167                 }
168                 
169                 if( bKeepValue )
170                         Bytecode_AppendDuplicate(Block->Handle);
171                 // Set the variable value
172                 ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
173                 bAddedValue = 0;
174                 break;
175         
176         // Post increment/decrement
177         case NODETYPE_POSTINC:
178         case NODETYPE_POSTDEC:
179                 Bytecode_AppendConstInt(Block->Handle, 1);
180                 
181                 // TODO: Support assigning to object attributes
182                 if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
183                         AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
184                         return -1;
185                 }
186
187                 ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
188                 if(ret) return ret;
189
190                 if( Node->Type == NODETYPE_POSTDEC )
191                         Bytecode_AppendBinOp(Block->Handle, BC_OP_SUBTRACT);
192                 else
193                         Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
194                 if(ret) return ret;
195
196                 ret = BC_Variable_SetValue(Block, Node->UniOp.Value);
197                 if(ret) return ret;
198                 break;
199         
200         // Function Call
201         case NODETYPE_METHODCALL:
202         case NODETYPE_FUNCTIONCALL:
203         case NODETYPE_CREATEOBJECT: {
204                  int    nargs = 0;
205                 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
206                 {
207                         ret = AST_ConvertNode(Block, node, 1);
208                         if(ret) return ret;
209                         nargs ++;
210                 }
211                 
212                 // Call the function
213                 if( Node->Type == NODETYPE_METHODCALL )
214                 {
215                         // TODO: Sanity check stack top
216                         ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
217                         if(ret) return ret;
218                         Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
219                 }
220                 else
221                 {
222                          int    newnamelen = 0;
223                         char    *manglename;
224                         for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ )
225                                 newnamelen = strlen(Block->CurNamespaceStack[i]) + 1;
226                         newnamelen += strlen(Node->FunctionCall.Name) + 1;
227                         manglename = alloca(newnamelen);
228                         manglename[0] = 0;
229                         for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ ) {
230                                  int    pos;
231                                 strcat(manglename, Block->CurNamespaceStack[i]);
232                                 pos = strlen(manglename);
233                                 manglename[pos] = BC_NS_SEPARATOR;
234                                 manglename[pos+1] = '\0';
235                         }
236                         strcat(manglename, Node->FunctionCall.Name);
237                                 
238                         if( Node->Type == NODETYPE_CREATEOBJECT )
239                         {
240                                 // TODO: Sanity check stack top
241                                 Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
242                         }
243                         else
244                         {
245                                 Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
246                         }
247                 }
248                 } break;
249         
250         // Conditional
251         case NODETYPE_IF: {
252                  int    if_end;
253                 ret = AST_ConvertNode(Block, Node->If.Condition, 1);
254                 if(ret) return ret;
255                 
256                 if_end = Bytecode_AllocateLabel(Block->Handle);
257
258                 if( Node->If.False->Type != NODETYPE_NOP )
259                 {
260                          int    if_true = Bytecode_AllocateLabel(Block->Handle);
261                         
262                         Bytecode_AppendCondJump(Block->Handle, if_true);
263         
264                         // False
265                         ret = AST_ConvertNode(Block, Node->If.False, 0);
266                         if(ret) return ret;
267                         Bytecode_AppendJump(Block->Handle, if_end);
268                         Bytecode_SetLabel(Block->Handle, if_true);
269                 }
270                 else
271                 {
272                         Bytecode_AppendCondJumpNot(Block->Handle, if_end);
273                 }
274                 
275                 // True
276                 ret = AST_ConvertNode(Block, Node->If.True, 0);
277                 if(ret) return ret;
278
279                 // End
280                 Bytecode_SetLabel(Block->Handle, if_end);
281                 bAddedValue = 0;
282                 } break;
283         
284         // Loop
285         case NODETYPE_LOOP: {
286                  int    loop_start, loop_end;
287                  int    saved_break, saved_continue;
288                 const char      *saved_tag;
289
290                 // Initialise
291                 ret = AST_ConvertNode(Block, Node->For.Init, 0);
292                 if(ret) return ret;
293                 
294                 loop_start = Bytecode_AllocateLabel(Block->Handle);
295                 loop_end = Bytecode_AllocateLabel(Block->Handle);
296
297                 saved_break = Block->BreakTarget;
298                 saved_continue = Block->ContinueTarget;
299                 saved_tag = Block->Tag;
300                 Block->BreakTarget = loop_end;
301                 Block->ContinueTarget = loop_end;
302                 Block->Tag = Node->For.Tag;
303
304                 Bytecode_SetLabel(Block->Handle, loop_start);
305
306                 // Check initial condition
307                 if( !Node->For.bCheckAfter )
308                 {
309                         ret = AST_ConvertNode(Block, Node->For.Condition, 1);
310                         if(ret) return ret;
311                         Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
312                         Bytecode_AppendCondJump(Block->Handle, loop_end);
313                 }
314         
315                 // Code
316                 ret = AST_ConvertNode(Block, Node->For.Code, 0);
317                 if(ret) return ret;
318                 
319                 // Increment
320                 ret = AST_ConvertNode(Block, Node->For.Increment, 0);
321                 if(ret) return ret;
322
323                 // Tail check
324                 if( Node->For.bCheckAfter )
325                 {
326                         ret = AST_ConvertNode(Block, Node->For.Condition, 1);
327                         if(ret) return ret;
328                         Bytecode_AppendCondJump(Block->Handle, loop_start);
329                 }
330                 else
331                 {
332                         Bytecode_AppendJump(Block->Handle, loop_start);
333                 }
334
335                 Bytecode_SetLabel(Block->Handle, loop_end);
336
337                 Block->BreakTarget = saved_break;
338                 Block->ContinueTarget = saved_continue;
339                 Block->Tag = saved_tag;
340                 bAddedValue = 0;
341                 } break;
342         
343         // Return
344         case NODETYPE_RETURN:
345                 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
346                 if(ret) return ret;
347                 Bytecode_AppendReturn(Block->Handle);
348                 bAddedValue = 0;
349                 break;
350         
351         case NODETYPE_BREAK:
352         case NODETYPE_CONTINUE: {
353                 tAST_BlockInfo  *bi = Block;
354                 if( Node->Variable.Name[0] ) {
355                         while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0)  bi = bi->Parent;
356                 }
357                 if( !bi )       return 1;
358                 // TODO: Check if BreakTarget/ContinueTarget are valid
359                 if( Node->Type == NODETYPE_BREAK )
360                         Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
361                 else
362                         Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
363                 bAddedValue = 0;
364                 } break;
365         
366         // Define a variable
367         case NODETYPE_DEFVAR:
368                 ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
369                 if(ret) return ret;
370                 
371                 if( Node->DefVar.InitialValue )
372                 {
373                         ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
374                         if(ret) return ret;
375                         Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
376                 }
377                 bAddedValue = 0;
378                 break;
379         
380         // Scope
381         case NODETYPE_SCOPE:
382                 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ );
383                 if( i == MAX_NAMESPACE_DEPTH ) {
384                         AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", i);
385                         return 2;
386                 }
387                 Block->CurNamespaceStack[i] = Node->Scope.Name;
388                 ret = AST_ConvertNode(Block, Node->Scope.Element, 2);
389                 Block->CurNamespaceStack[i] = NULL;
390                 break;
391         
392         // Variable
393         case NODETYPE_VARIABLE:
394                 ret = BC_Variable_GetValue( Block, Node );
395                 break;
396         
397         // Element of an Object
398         case NODETYPE_ELEMENT:
399                 ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
400                 if(ret) return ret;
401
402                 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
403                 break;
404
405         // Cast a value to another
406         case NODETYPE_CAST:
407                 ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
408                 if(ret) return ret;
409                 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
410                 break;
411
412         // Index into an array
413         case NODETYPE_INDEX:
414                 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);      // Array
415                 if(ret) return ret;
416                 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);     // Offset
417                 if(ret) return ret;
418                 
419                 Bytecode_AppendIndex(Block->Handle);
420                 break;
421
422         // TODO: Implement runtime constants
423         case NODETYPE_CONSTANT:
424                 // TODO: Scan namespace for constant name
425                 AST_RuntimeError(Node, "TODO - Runtime Constants");
426                 ret = -1;
427                 break;
428         
429         // Constant Values
430         case NODETYPE_STRING:
431                 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
432                 break;
433         case NODETYPE_INTEGER:
434                 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
435                 break;
436         case NODETYPE_REAL:
437                 Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
438                 break;
439         
440         // --- Operations ---
441         // Boolean Operations
442         case NODETYPE_LOGICALNOT:       // Logical NOT (!)
443                 if(!op) op = BC_OP_LOGICNOT;
444         case NODETYPE_BWNOT:    // Bitwise NOT (~)
445                 if(!op) op = BC_OP_BITNOT;
446         case NODETYPE_NEGATE:   // Negation (-)
447                 if(!op) op = BC_OP_NEG;
448                 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
449                 if(ret) return ret;
450                 Bytecode_AppendUniOp(Block->Handle, op);
451                 break;
452
453         // Logic
454         case NODETYPE_LOGICALAND:       if(!op) op = BC_OP_LOGICAND;
455         case NODETYPE_LOGICALOR:        if(!op) op = BC_OP_LOGICOR;
456         case NODETYPE_LOGICALXOR:       if(!op) op = BC_OP_LOGICXOR;
457         // Comparisons
458         case NODETYPE_EQUALS:   if(!op) op = BC_OP_EQUALS;
459         case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN;
460         case NODETYPE_GREATERTHAN:      if(!op) op = BC_OP_GREATERTHAN;
461         case NODETYPE_LESSTHANEQUAL:    if(!op) op = BC_OP_LESSTHANOREQUAL;
462         case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
463         // General Binary Operations
464         case NODETYPE_ADD:      if(!op) op = BC_OP_ADD;
465         case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
466         case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
467         case NODETYPE_DIVIDE:   if(!op) op = BC_OP_DIVIDE;
468         case NODETYPE_MODULO:   if(!op) op = BC_OP_MODULO;
469         case NODETYPE_BWAND:    if(!op) op = BC_OP_BITAND;
470         case NODETYPE_BWOR:     if(!op) op = BC_OP_BITOR;
471         case NODETYPE_BWXOR:    if(!op) op = BC_OP_BITXOR;
472         case NODETYPE_BITSHIFTLEFT:     if(!op) op = BC_OP_BITSHIFTLEFT;
473         case NODETYPE_BITSHIFTRIGHT:    if(!op) op = BC_OP_BITSHIFTRIGHT;
474         case NODETYPE_BITROTATELEFT:    if(!op) op = BC_OP_BITROTATELEFT;
475                 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
476                 if(ret) return ret;
477                 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
478                 if(ret) return ret;
479         
480                 Bytecode_AppendBinOp(Block->Handle, op);
481                 break;
482         
483         default:
484                 ret = -1;
485                 AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
486                 break;
487         }
488
489         #if TRACE_NODE_RETURNS
490         if(ret && ret != ERRPTR) {
491                 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
492         }
493         else {
494                 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
495         }
496         #endif
497
498         if( !bKeepValue && bAddedValue )
499                 Bytecode_AppendDelete(Block->Handle);
500
501         return ret;
502 }
503
504 /**
505  * \brief Define a variable
506  * \param Block Current block state
507  * \param Type  Type of the variable
508  * \param Name  Name of the variable
509  * \return Boolean Failure
510  */
511 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
512 {
513         #if 0
514         tAST_Variable   *var, *prev = NULL;
515         
516         for( var = Block->FirstVar; var; prev = var, var = var->Next )
517         {
518                 if( strcmp(var->Name, Name) == 0 ) {
519                         AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
520                         return ERRPTR;
521                 }
522         }
523         
524         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
525         var->Next = NULL;
526         var->Type = Type;
527         strcpy(var->Name, Name);
528         
529         if(prev)        prev->Next = var;
530         else    Block->FirstVar = var;
531         
532         return var;
533         #else
534         Bytecode_AppendDefineVar(Block->Handle, Name, Type);
535         return 0;
536         #endif
537 }
538
539 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
540 {
541         #if 0
542         tAST_Variable   *var = NULL;
543         
544         // Speed hack
545         if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
546                 var = VarNode->ValueCache;
547                 #if TRACE_VAR_LOOKUPS
548                 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
549                         VarNode->Variable.Name, var,
550                         VarNode->BlockState, VarNode->BlockIdent
551                         );
552                 #endif
553         }
554         else
555         {
556                 tAST_BlockInfo  *bs;
557                 for( bs = Block; bs; bs = bs->Parent )
558                 {
559                         for( var = bs->FirstVar; var; var = var->Next )
560                         {
561                                 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
562                                         break;
563                         }
564                         if(var) break;
565                 }
566                 
567                 if( !var )
568                 {
569                         if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
570                                 // Define variable
571                                 var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
572                         }
573                         else
574                         {
575                                 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
576                                 return NULL;
577                         }
578                 }
579                 
580                 #if TRACE_VAR_LOOKUPS
581                 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
582                         VarNode->Variable.Name, var,
583                         Block, Block->Ident);
584                 #endif
585                 
586                 VarNode->ValueCache = var;
587                 VarNode->BlockState = Block;
588                 VarNode->BlockIdent = Block->Ident;
589         }
590         
591         return var;
592         #else
593         return (void*)1;
594         #endif
595 }
596
597 /**
598  * \brief Set the value of a variable
599  * \return Boolean Failure
600  */
601 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
602 {
603         tAST_Variable   *var;
604         
605         var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
606         if(!var)        return -1;
607
608         // TODO: Check types
609
610         Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
611         return 0;
612 }
613
614 /**
615  * \brief Get the value of a variable
616  */
617 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
618 {
619         tAST_Variable   *var;
620
621         var = BC_Variable_Lookup(Block, VarNode, 0);    
622         if(!var)        return -1;
623         
624         Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
625         return 0;
626 }
627
628 #if 0
629 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
630 {
631         va_list args;
632         
633         if(Node) {
634                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
635         }
636         fprintf(stderr, "%s: ", Type);
637         va_start(args, Format);
638         vfprintf(stderr, Format, args);
639         va_end(args);
640         fprintf(stderr, "\n");
641 }
642 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
643 {
644         va_list args;
645         
646         if(Node) {
647                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
648         }
649         fprintf(stderr, "error: ");
650         va_start(args, Format);
651         vfprintf(stderr, Format, args);
652         va_end(args);
653         fprintf(stderr, "\n");
654 }
655 #endif

UCC git Repository :: git.ucc.asn.au