3 * by John Hodge (thePowersGang)
6 * - Manage tSpiderValue objects
11 #include "spiderscript.h"
14 extern void AST_RuntimeError(void *Node, const char *Format, ...);
17 void SpiderScript_DereferenceValue(tSpiderValue *Object);
18 void SpiderScript_ReferenceValue(tSpiderValue *Object);
19 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value);
20 tSpiderValue *SpiderScript_CreateReal(double Value);
21 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data);
22 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
23 int SpiderScript_IsValueTrue(tSpiderValue *Value);
24 void SpiderScript_FreeValue(tSpiderValue *Value);
25 char *SpiderScript_DumpValue(tSpiderValue *Value);
27 tSpiderValue *SpiderScript_DoOp(tSpiderValue *Left, enum eSpiderValueOps, int bCanCast, tSpiderValue *Right);
28 tSpiderValue *SpiderScript_int_DoOpInt(tSpiderValue *Left, enum eSpiderValueOps, int bCanCast, tSpiderValue *Right);
29 tSpiderValue *SpiderScript_int_DoOpReal(tSpiderValue *Left, enum eSpiderValueOps, int bCanCast, tSpiderValue *Right);
30 tSpiderValue *SpiderScript_int_DoOpString(tSpiderValue *Left, enum eSpiderValueOps, int bCanCast, tSpiderValue *Right);
35 * \brief Dereference a created object
37 void SpiderScript_DereferenceValue(tSpiderValue *Object)
39 if(!Object || Object == ERRPTR) return ;
40 Object->ReferenceCount --;
41 if( Object->ReferenceCount == 0 )
45 if( Object->Type == SS_DATATYPE_ARRAY || SS_GETARRAYDEPTH(Object->Type) )
47 for( i = 0; i < Object->Array.Length; i ++ )
49 if( Object->Array.Items[i] ) {
50 SpiderScript_DereferenceValue(Object->Array.Items[i]);
52 Object->Array.Items[i] = NULL;
57 switch( (enum eSpiderScript_DataTypes) Object->Type )
59 case SS_DATATYPE_OBJECT:
60 Object->Object->ReferenceCount --;
61 if(Object->Object->ReferenceCount == 0) {
62 Object->Object->Type->Destructor( Object->Object );
64 Object->Object = NULL;
67 case SS_DATATYPE_OPAQUE:
68 Object->Opaque.Destroy( Object->Opaque.Data );
79 * \brief Reference a value
81 void SpiderScript_ReferenceValue(tSpiderValue *Object)
83 if(!Object || Object == ERRPTR) return ;
84 Object->ReferenceCount ++;
88 * \brief Allocate and initialise a SpiderScript object
90 tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes)
92 int size = sizeof(tSpiderObject) + Class->NAttributes * sizeof(tSpiderValue*) + ExtraBytes;
93 tSpiderObject *ret = malloc(size);
96 ret->ReferenceCount = 1;
97 ret->OpaqueData = &ret->Attributes[ Class->NAttributes ];
98 memset( ret->Attributes, 0, Class->NAttributes * sizeof(tSpiderValue*) );
104 * \brief Create an integer object
106 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
108 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
109 ret->Type = SS_DATATYPE_INTEGER;
110 ret->ReferenceCount = 1;
111 ret->Integer = Value;
116 * \brief Create an real number object
118 tSpiderValue *SpiderScript_CreateReal(double Value)
120 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
121 ret->Type = SS_DATATYPE_REAL;
122 ret->ReferenceCount = 1;
128 * \brief Create an string object
130 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
132 tSpiderValue *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
133 ret->Type = SS_DATATYPE_STRING;
134 ret->ReferenceCount = 1;
135 ret->String.Length = Length;
137 memcpy(ret->String.Data, Data, Length);
139 memset(ret->String.Data, 0, Length);
140 ret->String.Data[Length] = '\0';
144 tSpiderValue *SpiderScript_CreateArray(int InnerType, int ItemCount)
146 tSpiderValue *ret = malloc( sizeof(tSpiderValue) + ItemCount*sizeof(tSpiderValue*) );
147 ret->Type = SS_MAKEARRAY(InnerType);
148 ret->ReferenceCount = 1;
149 ret->Array.Length = ItemCount;
150 memset(ret->Array.Items, 0, ItemCount*sizeof(tSpiderValue*));
155 * \brief Concatenate two strings
157 tSpiderValue *SpiderScript_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2)
162 if( Str1 && Str1->Type != SS_DATATYPE_STRING)
164 if( Str2 && Str2->Type != SS_DATATYPE_STRING)
167 if(Str1) newLen += Str1->String.Length;
168 if(Str2) newLen += Str2->String.Length;
169 ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
170 ret->Type = SS_DATATYPE_STRING;
171 ret->ReferenceCount = 1;
172 ret->String.Length = newLen;
174 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
177 memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
179 memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
181 ret->String.Data[ newLen ] = '\0';
186 * \brief Cast one object to another
187 * \brief Type Destination type
188 * \brief Source Input data
190 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
192 tSpiderValue *ret = ERRPTR;
199 case SS_DATATYPE_INTEGER: return SpiderScript_CreateInteger(0);
200 case SS_DATATYPE_REAL: return SpiderScript_CreateReal(0);
201 case SS_DATATYPE_STRING: return SpiderScript_CreateString(4, "null");
206 // Check if anything needs to be done
207 if( Source->Type == Type ) {
208 SpiderScript_ReferenceValue(Source);
215 printf("Casting %i ", Source->Type);
218 case SS_DATATYPE_INTEGER: printf("0x%lx", Source->Integer); break;
219 case SS_DATATYPE_STRING: printf("\"%s\"", Source->String.Data); break;
220 case SS_DATATYPE_REAL: printf("%f", Source->Real); break;
223 printf(" to %i\n", Type);
229 if( Source->Type == SS_DATATYPE_OBJECT )
231 const char *name = NULL;
234 case SS_DATATYPE_INTEGER: name = "cast Integer"; break;
235 case SS_DATATYPE_REAL: name = "cast Real"; break;
236 case SS_DATATYPE_STRING: name = "cast String"; break;
237 case SS_DATATYPE_ARRAY: name = "cast Array"; break;
239 AST_RuntimeError(NULL, "Invalid cast to %i from Object", Type);
244 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
247 // Fall through and try casting (which will usually fail)
252 switch( (enum eSpiderScript_DataTypes)Type )
254 case SS_DATATYPE_UNDEF:
255 case SS_DATATYPE_ARRAY:
256 case SS_DATATYPE_OPAQUE:
257 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
259 case SS_DATATYPE_OBJECT:
261 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
264 case SS_DATATYPE_INTEGER:
265 ret = malloc(sizeof(tSpiderValue));
266 ret->Type = SS_DATATYPE_INTEGER;
267 ret->ReferenceCount = 1;
270 case SS_DATATYPE_INTEGER: break; // Handled above
271 case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
272 case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
274 AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
281 case SS_DATATYPE_REAL:
282 ret = malloc(sizeof(tSpiderValue));
283 ret->Type = SS_DATATYPE_REAL;
284 ret->ReferenceCount = 1;
287 case SS_DATATYPE_STRING: ret->Real = atof(Source->String.Data); break;
288 case SS_DATATYPE_INTEGER: ret->Real = Source->Integer; break;
290 AST_RuntimeError(NULL, "Invalid cast from %i to Real", Source->Type);
297 case SS_DATATYPE_STRING:
300 case SS_DATATYPE_INTEGER: len = snprintf(NULL, 0, "%li", Source->Integer); break;
301 case SS_DATATYPE_REAL: len = snprintf(NULL, 0, "%g", Source->Real); break;
304 ret = malloc(sizeof(tSpiderValue) + len + 1);
305 ret->Type = SS_DATATYPE_STRING;
306 ret->ReferenceCount = 1;
307 ret->String.Length = len;
310 case SS_DATATYPE_INTEGER: sprintf(ret->String.Data, "%li", Source->Integer); break;
311 case SS_DATATYPE_REAL:
312 sprintf(ret->String.Data, "%g", Source->Real); break;
314 AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
322 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target %i", Type);
331 * \brief Condenses a value down to a boolean
333 int SpiderScript_IsValueTrue(tSpiderValue *Value)
335 if( Value == ERRPTR ) return 0;
336 if( Value == NULL ) return 0;
338 switch( (enum eSpiderScript_DataTypes)Value->Type )
340 case SS_DATATYPE_UNDEF:
343 case SS_DATATYPE_INTEGER:
344 return !!Value->Integer;
346 case SS_DATATYPE_REAL:
347 return (-.5f < Value->Real && Value->Real < 0.5f);
349 case SS_DATATYPE_STRING:
350 return Value->String.Length > 0;
352 case SS_DATATYPE_OBJECT:
353 return Value->Object != NULL;
355 case SS_DATATYPE_OPAQUE:
356 return Value->Opaque.Data != NULL;
358 case SS_DATATYPE_ARRAY:
359 return Value->Array.Length > 0;
361 AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
368 * \brief Free a value
369 * \note Just calls Object_Dereference
371 void SpiderScript_FreeValue(tSpiderValue *Value)
373 SpiderScript_DereferenceValue(Value);
377 * \brief Dump a value into a string
378 * \return Heap string
380 char *SpiderScript_DumpValue(tSpiderValue *Value)
383 if( Value == ERRPTR )
384 return strdup("ERRPTR");
386 return strdup("null");
388 switch( (enum eSpiderScript_DataTypes)Value->Type )
390 case SS_DATATYPE_UNDEF: return strdup("undefined");
392 case SS_DATATYPE_INTEGER:
393 ret = malloc( sizeof(Value->Integer)*2 + 3 );
394 sprintf(ret, "0x%lx", Value->Integer);
397 case SS_DATATYPE_REAL:
398 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
399 sprintf(ret, "%f", Value->Real);
402 case SS_DATATYPE_STRING:
403 ret = malloc( Value->String.Length + 3 );
405 strcpy(ret+1, Value->String.Data);
406 ret[Value->String.Length+1] = '"';
407 ret[Value->String.Length+2] = '\0';
410 case SS_DATATYPE_OBJECT:
411 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
412 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
415 case SS_DATATYPE_OPAQUE:
416 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
417 sprintf(ret, "*%p", Value->Opaque.Data);
420 case SS_DATATYPE_ARRAY:
421 return strdup("Array");
424 AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
431 tSpiderValue *SpiderScript_DoOp(tSpiderValue *Left, enum eSpiderValueOps Operation, int bCanCast, tSpiderValue *Right)
435 case SS_DATATYPE_INTEGER:
436 return SpiderScript_int_DoOpInt(Left, Operation, bCanCast, Right);
443 tSpiderValue *SpiderScript_int_DoOpInt(tSpiderValue *Left, enum eSpiderValueOps Operation, int bCanCast, tSpiderValue *Right)
445 tSpiderValue *oldright = Right;
446 tSpiderValue *ret = NULL;
450 if(Right && Right->Type != SS_DATATYPE_INTEGER) {
451 if(!bCanCast) return ERRPTR;
452 Right = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, Right);
458 case SS_VALUEOP_NEGATE:
459 if(Right) ret = ERRPTR;
460 else rv = -Left->Integer;
463 if(!Right) ret = ERRPTR;
464 else rv = Left->Integer + Right->Integer;
466 case SS_VALUEOP_SUBTRACT:
467 if(!Right) ret = ERRPTR;
468 else rv = Left->Integer - Right->Integer;
472 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented integer operation %i", Operation);
476 // Delete temporary value
477 if( Right != oldright )
478 SpiderScript_DereferenceValue(Right);
480 // Return error if signaled
484 // Reuse `Left` if possible, to reduce mallocs
485 if(Left->ReferenceCount == 1) {
486 SpiderScript_ReferenceValue(Left);
491 return SpiderScript_CreateInteger(rv);