10 void Object_Dereference(tSpiderValue *Object);
11 void Object_Reference(tSpiderValue *Object);
12 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value);
13 tSpiderValue *SpiderScript_CreateReal(double Value);
14 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data);
15 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
16 int SpiderScript_IsValueTrue(tSpiderValue *Value);
17 void SpiderScript_FreeValue(tSpiderValue *Value);
18 char *SpiderScript_DumpValue(tSpiderValue *Value);
20 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
21 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, int Operation, tSpiderValue *Left, tSpiderValue *Right);
23 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
24 int Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value);
25 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name);
26 void Variable_Destroy(tAST_Variable *Variable);
28 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
32 * \brief Dereference a created object
34 void Object_Dereference(tSpiderValue *Object)
37 if(Object == ERRPTR) return ;
38 Object->ReferenceCount --;
39 // printf("%p Dereferenced (%i)\n", Object, Object->ReferenceCount);
40 if( Object->ReferenceCount == 0 ) {
41 switch( (enum eSpiderScript_DataTypes) Object->Type )
43 case SS_DATATYPE_OBJECT:
44 Object->Object->Type->Destructor( Object->Object );
46 case SS_DATATYPE_OPAQUE:
47 Object->Opaque.Destroy( Object->Opaque.Data );
56 void Object_Reference(tSpiderValue *Object)
59 Object->ReferenceCount ++;
60 // printf("%p Referenced (%i)\n", Object, Object->ReferenceCount);
64 * \brief Create an integer object
66 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
68 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
69 ret->Type = SS_DATATYPE_INTEGER;
70 ret->ReferenceCount = 1;
76 * \brief Create an real number object
78 tSpiderValue *SpiderScript_CreateReal(double Value)
80 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
81 ret->Type = SS_DATATYPE_REAL;
82 ret->ReferenceCount = 1;
88 * \brief Create an string object
90 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
92 tSpiderValue *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
93 ret->Type = SS_DATATYPE_STRING;
94 ret->ReferenceCount = 1;
95 ret->String.Length = Length;
96 memcpy(ret->String.Data, Data, Length);
97 ret->String.Data[Length] = '\0';
102 * \brief Concatenate two strings
104 tSpiderValue *Object_StringConcat(tSpiderValue *Str1, tSpiderValue *Str2)
108 if(Str1) newLen += Str1->String.Length;
109 if(Str2) newLen += Str2->String.Length;
110 ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
111 ret->Type = SS_DATATYPE_STRING;
112 ret->ReferenceCount = 1;
113 ret->String.Length = newLen;
115 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
118 memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
120 memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
122 ret->String.Data[ newLen ] = '\0';
127 * \brief Cast one object to another
128 * \brief Type Destination type
129 * \brief Source Input data
131 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
133 tSpiderValue *ret = ERRPTR;
136 if( !Source ) return NULL;
138 // Check if anything needs to be done
139 if( Source->Type == Type ) {
140 Object_Reference(Source);
144 switch( (enum eSpiderScript_DataTypes)Type )
146 case SS_DATATYPE_UNDEF:
147 case SS_DATATYPE_ARRAY:
148 case SS_DATATYPE_OPAQUE:
149 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
152 case SS_DATATYPE_INTEGER:
153 ret = malloc(sizeof(tSpiderValue));
154 ret->Type = SS_DATATYPE_INTEGER;
155 ret->ReferenceCount = 1;
158 case SS_DATATYPE_INTEGER: break; // Handled above
159 case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
160 case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
162 AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
169 case SS_DATATYPE_STRING:
172 case SS_DATATYPE_INTEGER: len = snprintf(NULL, 0, "%li", Source->Integer); break;
173 case SS_DATATYPE_REAL: snprintf(NULL, 0, "%f", Source->Real); break;
176 ret = malloc(sizeof(tSpiderValue) + len + 1);
177 ret->Type = SS_DATATYPE_STRING;
178 ret->ReferenceCount = 1;
179 ret->String.Length = len;
182 case SS_DATATYPE_INTEGER: sprintf(ret->String.Data, "%li", Source->Integer); break;
183 case SS_DATATYPE_REAL: sprintf(ret->String.Data, "%f", Source->Real); break;
185 AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
193 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target");
201 * \brief Condenses a value down to a boolean
203 int SpiderScript_IsValueTrue(tSpiderValue *Value)
205 if( Value == ERRPTR ) return 0;
206 if( Value == NULL ) return 0;
208 switch( (enum eSpiderScript_DataTypes)Value->Type )
210 case SS_DATATYPE_UNDEF:
213 case SS_DATATYPE_INTEGER:
214 return !!Value->Integer;
216 case SS_DATATYPE_REAL:
217 return (-.5f < Value->Real && Value->Real < 0.5f);
219 case SS_DATATYPE_STRING:
220 return Value->String.Length > 0;
222 case SS_DATATYPE_OBJECT:
223 return Value->Object != NULL;
225 case SS_DATATYPE_OPAQUE:
226 return Value->Opaque.Data != NULL;
228 case SS_DATATYPE_ARRAY:
229 return Value->Array.Length > 0;
231 AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
238 * \brief Free a value
239 * \note Just calls Object_Dereference
241 void SpiderScript_FreeValue(tSpiderValue *Value)
243 Object_Dereference(Value);
247 * \brief Dump a value into a string
248 * \return Heap string
250 char *SpiderScript_DumpValue(tSpiderValue *Value)
253 if( Value == ERRPTR )
254 return strdup("ERRPTR");
256 return strdup("null");
258 switch( (enum eSpiderScript_DataTypes)Value->Type )
260 case SS_DATATYPE_UNDEF: return strdup("undefined");
262 case SS_DATATYPE_INTEGER:
263 ret = malloc( sizeof(Value->Integer)*2 + 3 );
264 sprintf(ret, "0x%lx", Value->Integer);
267 case SS_DATATYPE_REAL:
268 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
269 sprintf(ret, "%f", Value->Real);
272 case SS_DATATYPE_STRING:
273 ret = malloc( Value->String.Length + 3 );
275 strcpy(ret+1, Value->String.Data);
276 ret[Value->String.Length+1] = '"';
277 ret[Value->String.Length+2] = '\0';
280 case SS_DATATYPE_OBJECT:
281 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
282 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
285 case SS_DATATYPE_OPAQUE:
286 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
287 sprintf(ret, "*%p", Value->Opaque.Data);
290 case SS_DATATYPE_ARRAY:
291 return strdup("Array");
294 AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
301 * \brief Execute an AST node and return its value
303 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
306 tSpiderValue *ret = NULL, *tmpobj;
307 tSpiderValue *op1, *op2; // Binary operations
308 int cmp; // Used in comparisons
313 case NODETYPE_NOP: ret = NULL; break;
318 tAST_BlockState blockInfo;
319 blockInfo.FirstVar = NULL;
320 blockInfo.RetVal = NULL;
321 blockInfo.Parent = Block;
322 blockInfo.Script = Block->Script;
324 for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
326 tmpobj = AST_ExecuteNode(&blockInfo, node);
327 if(tmpobj == ERRPTR) { // Error check
331 if(tmpobj) Object_Dereference(tmpobj); // Free unused value
334 // Clean up variables
335 while(blockInfo.FirstVar)
337 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
338 Variable_Destroy( blockInfo.FirstVar );
339 blockInfo.FirstVar = nextVar;
342 if( blockInfo.RetVal )
343 Block->RetVal = blockInfo.RetVal;
349 case NODETYPE_ASSIGN:
350 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
351 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
354 ret = AST_ExecuteNode(Block, Node->Assign.Value);
358 if( Node->Assign.Operation != NODETYPE_NOP )
360 tSpiderValue *varVal = Variable_GetValue(Block, Node->Assign.Dest->Variable.Name);
362 value = AST_ExecuteNode_BinOp(Block, Node->Assign.Operation, varVal, ret);
363 if( value == ERRPTR )
365 if(ret) Object_Dereference(ret);
366 Object_Dereference(varVal);
370 if( Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret ) ) {
371 Object_Dereference( ret );
377 case NODETYPE_FUNCTIONCALL:
380 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
383 // Logical block (used to allocate `params`)
385 tSpiderValue *params[nParams];
387 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
388 params[i] = AST_ExecuteNode(Block, node);
389 if( params[i] == ERRPTR ) {
390 while(i--) Object_Dereference(params[i]);
397 // Call the function (SpiderScript_ExecuteMethod does the
398 // required namespace handling)
399 ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
401 // Dereference parameters
402 while(i--) Object_Dereference(params[i]);
411 ret = AST_ExecuteNode(Block, Node->If.Condition);
412 if( SpiderScript_IsValueTrue(ret) ) {
413 Object_Dereference(AST_ExecuteNode(Block, Node->If.True));
416 Object_Dereference(AST_ExecuteNode(Block, Node->If.False));
418 Object_Dereference(ret);
424 ret = AST_ExecuteNode(Block, Node->For.Init);
425 if( Node->For.bCheckAfter )
428 Object_Dereference(ret);
429 ret = AST_ExecuteNode(Block, Node->For.Code);
430 Object_Dereference(ret);
431 ret = AST_ExecuteNode(Block, Node->For.Increment);
432 Object_Dereference(ret);
433 ret = AST_ExecuteNode(Block, Node->For.Condition);
434 } while( SpiderScript_IsValueTrue(ret) );
438 Object_Dereference(ret);
439 ret = AST_ExecuteNode(Block, Node->For.Condition);
440 while( SpiderScript_IsValueTrue(ret) ) {
441 Object_Dereference(ret);
442 ret = AST_ExecuteNode(Block, Node->For.Code);
443 Object_Dereference(ret);
444 ret = AST_ExecuteNode(Block, Node->For.Increment);
445 Object_Dereference(ret);
446 ret = AST_ExecuteNode(Block, Node->For.Condition);
449 Object_Dereference(ret);
454 case NODETYPE_RETURN:
455 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
456 Block->RetVal = ret; // Return value set
457 //Object_Reference(ret); // Make sure it exists after return
458 ret = NULL; // the `return` statement does not return a value
462 case NODETYPE_DEFVAR:
464 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
469 case NODETYPE_VARIABLE:
470 ret = Variable_GetValue( Block, Node->Variable.Name );
473 // Cast a value to another
476 tSpiderValue *tmp = AST_ExecuteNode(Block, Node->Cast.Value);
477 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmp );
478 Object_Dereference(tmp);
482 // Index into an array
484 AST_RuntimeError(Node, "TODO - Array Indexing");
488 // TODO: Implement runtime constants
489 case NODETYPE_CONSTANT:
490 AST_RuntimeError(Node, "TODO - Runtime Constants");
494 case NODETYPE_STRING: ret = SpiderScript_CreateString( Node->String.Length, Node->String.Data ); break;
495 case NODETYPE_INTEGER: ret = SpiderScript_CreateInteger( Node->Integer ); break;
496 case NODETYPE_REAL: ret = SpiderScript_CreateReal( Node->Real ); break;
498 // --- Operations ---
499 // Boolean Operations
500 case NODETYPE_LOGICALAND: // Logical AND (&&)
501 case NODETYPE_LOGICALOR: // Logical OR (||)
502 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
503 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
504 if(op1 == ERRPTR) return ERRPTR;
505 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
507 Object_Dereference(op1);
513 case NODETYPE_LOGICALAND:
514 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
516 case NODETYPE_LOGICALOR:
517 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
519 case NODETYPE_LOGICALXOR:
520 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
525 // Free intermediate objects
526 Object_Dereference(op1);
527 Object_Dereference(op2);
531 case NODETYPE_EQUALS:
532 case NODETYPE_LESSTHAN:
533 case NODETYPE_GREATERTHAN:
534 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
535 if(op1 == ERRPTR) return ERRPTR;
536 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
538 Object_Dereference(op1);
543 if( op1->Type != op2->Type ) {
544 // If dynamically typed, convert op2 to op1's type
545 if(Block->Script->Variant->bDyamicTyped)
548 op2 = SpiderScript_CastValueTo(op1->Type, op2);
549 Object_Dereference(tmpobj);
551 Object_Dereference(op1);
555 // If statically typed, this should never happen, but catch it anyway
557 AST_RuntimeError(Node, "Statically typed implicit cast");
565 // - String Compare (does a strcmp, well memcmp)
566 case SS_DATATYPE_STRING:
567 // Call memcmp to do most of the work
569 op1->String.Data, op2->String.Data,
570 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
572 // Handle reaching the end of the string
574 if( op1->String.Length == op2->String.Length )
576 else if( op1->String.Length < op2->String.Length )
583 // - Integer Comparisons
584 case SS_DATATYPE_INTEGER:
585 if( op1->Integer == op2->Integer )
587 else if( op1->Integer < op2->Integer )
593 AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type);
598 // Free intermediate objects
599 Object_Dereference(op1);
600 Object_Dereference(op2);
609 case NODETYPE_EQUALS: ret = SpiderScript_CreateInteger(cmp == 0); break;
610 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0); break;
611 case NODETYPE_GREATERTHAN: ret = SpiderScript_CreateInteger(cmp > 0); break;
613 AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type);
619 // General Binary Operations
621 case NODETYPE_SUBTRACT:
622 case NODETYPE_MULTIPLY:
623 case NODETYPE_DIVIDE:
624 case NODETYPE_MODULO:
628 case NODETYPE_BITSHIFTLEFT:
629 case NODETYPE_BITSHIFTRIGHT:
630 case NODETYPE_BITROTATELEFT:
632 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
633 if(op1 == ERRPTR) return ERRPTR;
634 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
636 Object_Dereference(op1);
640 ret = AST_ExecuteNode_BinOp(Block, Node->Type, op1, op2);
642 // Free intermediate objects
643 Object_Dereference(op1);
644 Object_Dereference(op2);
649 // AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
656 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, int Operation, tSpiderValue *Left, tSpiderValue *Right)
658 tSpiderValue *preCastValue = Right;
662 if( Left && Right && Left->Type != Right->Type )
666 // - Operator overload functions
667 if( Left->Type == SS_DATATYPE_OBJECT )
672 case NODETYPE_ADD: fcnname = "+"; break;
673 case NODETYPE_SUBTRACT: fcnname = "-"; break;
674 case NODETYPE_MULTIPLY: fcnname = "*"; break;
675 case NODETYPE_DIVIDE: fcnname = "/"; break;
676 case NODETYPE_MODULO: fcnname = "%"; break;
677 case NODETYPE_BWAND: fcnname = "&"; break;
678 case NODETYPE_BWOR: fcnname = "|"; break;
679 case NODETYPE_BWXOR: fcnname = "^"; break;
680 case NODETYPE_BITSHIFTLEFT: fcnname = "<<"; break;
681 case NODETYPE_BITSHIFTRIGHT:fcnname = ">>"; break;
682 case NODETYPE_BITROTATELEFT:fcnname = "<<<"; break;
683 default: fcnname = NULL; break;
688 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
691 // Fall through and try casting (which will usually fail)
696 // If implicit casts are allowed, convert Right to Left's type
697 if(Block->Script->Variant->bImplicitCasts)
699 Right = SpiderScript_CastValueTo(Left->Type, Right);
703 // If statically typed, this should never happen, but catch it anyway
705 AST_RuntimeError(NULL, "Implicit cast not allowed (from %i to %i)\n", Right->Type, Left->Type);
711 if( Left == NULL || Right == NULL ) {
712 if(Right && Right != preCastValue) free(Right);
719 // String Concatenation
720 case SS_DATATYPE_STRING:
723 case NODETYPE_ADD: // Concatenate
724 ret = Object_StringConcat(Left, Right);
727 AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
732 // Integer Operations
733 case SS_DATATYPE_INTEGER:
736 case NODETYPE_ADD: ret = SpiderScript_CreateInteger( Left->Integer + Right->Integer ); break;
737 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( Left->Integer - Right->Integer ); break;
738 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( Left->Integer * Right->Integer ); break;
739 case NODETYPE_DIVIDE: ret = SpiderScript_CreateInteger( Left->Integer / Right->Integer ); break;
740 case NODETYPE_MODULO: ret = SpiderScript_CreateInteger( Left->Integer % Right->Integer ); break;
741 case NODETYPE_BWAND: ret = SpiderScript_CreateInteger( Left->Integer & Right->Integer ); break;
742 case NODETYPE_BWOR: ret = SpiderScript_CreateInteger( Left->Integer | Right->Integer ); break;
743 case NODETYPE_BWXOR: ret = SpiderScript_CreateInteger( Left->Integer ^ Right->Integer ); break;
744 case NODETYPE_BITSHIFTLEFT: ret = SpiderScript_CreateInteger( Left->Integer << Right->Integer ); break;
745 case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( Left->Integer >> Right->Integer ); break;
746 case NODETYPE_BITROTATELEFT:
747 ret = SpiderScript_CreateInteger( (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer)) );
750 AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Operation);
757 case SS_DATATYPE_REAL:
761 AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
768 AST_RuntimeError(NULL, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
773 if(Right && Right != preCastValue) free(Right);
779 * \brief Define a variable
780 * \param Block Current block state
781 * \param Type Type of the variable
782 * \param Name Name of the variable
783 * \return Boolean Failure
785 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
787 tAST_Variable *var, *prev = NULL;
789 for( var = Block->FirstVar; var; prev = var, var = var->Next )
791 if( strcmp(var->Name, Name) == 0 ) {
792 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
797 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
801 strcpy(var->Name, Name);
803 if(prev) prev->Next = var;
804 else Block->FirstVar = var;
806 //printf("Defined variable %s (%i)\n", Name, Type);
812 * \brief Set the value of a variable
813 * \return Boolean Failure
815 int Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value)
820 for( bs = Block; bs; bs = bs->Parent )
822 for( var = bs->FirstVar; var; var = var->Next )
824 if( strcmp(var->Name, Name) == 0 )
826 if( !Block->Script->Variant->bDyamicTyped
827 && (Value && var->Type != Value->Type) )
829 AST_RuntimeError(NULL, "Type mismatch assigning to '%s'", Name);
832 // printf("Assign %p to '%s'\n", Value, var->Name);
833 Object_Reference(Value);
834 Object_Dereference(var->Object);
841 if( Block->Script->Variant->bDyamicTyped )
844 var = Variable_Define(Block, Value->Type, Name);
845 Object_Reference(Value);
851 AST_RuntimeError(NULL, "Variable '%s' set while undefined", Name);
857 * \brief Get the value of a variable
859 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name)
864 for( bs = Block; bs; bs = bs->Parent )
866 for( var = bs->FirstVar; var; var = var->Next )
868 if( strcmp(var->Name, Name) == 0 ) {
869 Object_Reference(var->Object);
876 AST_RuntimeError(NULL, "Variable '%s' used undefined", Name);
882 * \brief Destorys a variable
884 void Variable_Destroy(tAST_Variable *Variable)
886 // printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
887 Object_Dereference(Variable->Object);
891 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
895 fprintf(stderr, "ERROR: ");
896 va_start(args, Format);
897 vfprintf(stderr, Format, args);
899 fprintf(stderr, "\n");
903 fprintf(stderr, " at %s:%i\n", Node->File, Node->Line);