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, int Operation, int bCanCast, tSpiderValue *Right);
28 tSpiderValue *SpiderScript_int_DoOpInt(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right);
29 tSpiderValue *SpiderScript_int_DoOpReal(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right);
30 tSpiderValue *SpiderScript_int_DoOpString(tSpiderValue *Left, int Operation, 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->Type == SS_DATATYPE_OBJECT) {
43 if( Object->ReferenceCount == 0 )
45 switch( (enum eSpiderScript_DataTypes) Object->Type )
47 case SS_DATATYPE_OBJECT:
48 Object->Object->ReferenceCount --;
49 if(Object->Object->ReferenceCount == 0) {
50 Object->Object->Type->Destructor( Object->Object );
52 Object->Object = NULL;
55 case SS_DATATYPE_OPAQUE:
56 Object->Opaque.Destroy( Object->Opaque.Data );
66 * \brief Reference a value
68 void SpiderScript_ReferenceValue(tSpiderValue *Object)
70 if(!Object || Object == ERRPTR) return ;
71 Object->ReferenceCount ++;
75 * \brief Allocate and initialise a SpiderScript object
77 tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes)
79 int size = sizeof(tSpiderObject) + Class->NAttributes * sizeof(tSpiderValue*) + ExtraBytes;
80 tSpiderObject *ret = malloc(size);
83 ret->ReferenceCount = 1;
84 ret->OpaqueData = &ret->Attributes[ Class->NAttributes ];
85 memset( ret->Attributes, 0, Class->NAttributes * sizeof(tSpiderValue*) );
91 * \brief Create an integer object
93 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
95 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
96 ret->Type = SS_DATATYPE_INTEGER;
97 ret->ReferenceCount = 1;
103 * \brief Create an real number object
105 tSpiderValue *SpiderScript_CreateReal(double Value)
107 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
108 ret->Type = SS_DATATYPE_REAL;
109 ret->ReferenceCount = 1;
115 * \brief Create an string object
117 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
119 tSpiderValue *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
120 ret->Type = SS_DATATYPE_STRING;
121 ret->ReferenceCount = 1;
122 ret->String.Length = Length;
124 memcpy(ret->String.Data, Data, Length);
126 memset(ret->String.Data, 0, Length);
127 ret->String.Data[Length] = '\0';
132 * \brief Concatenate two strings
134 tSpiderValue *SpiderScript_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2)
139 if( Str1 && Str1->Type != SS_DATATYPE_STRING)
141 if( Str2 && Str2->Type != SS_DATATYPE_STRING)
144 if(Str1) newLen += Str1->String.Length;
145 if(Str2) newLen += Str2->String.Length;
146 ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
147 ret->Type = SS_DATATYPE_STRING;
148 ret->ReferenceCount = 1;
149 ret->String.Length = newLen;
151 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
154 memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
156 memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
158 ret->String.Data[ newLen ] = '\0';
163 * \brief Cast one object to another
164 * \brief Type Destination type
165 * \brief Source Input data
167 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
169 tSpiderValue *ret = ERRPTR;
176 case SS_DATATYPE_INTEGER: return SpiderScript_CreateInteger(0);
177 case SS_DATATYPE_REAL: return SpiderScript_CreateReal(0);
178 case SS_DATATYPE_STRING: return SpiderScript_CreateString(4, "null");
183 // Check if anything needs to be done
184 if( Source->Type == Type ) {
185 SpiderScript_ReferenceValue(Source);
192 printf("Casting %i ", Source->Type);
195 case SS_DATATYPE_INTEGER: printf("0x%lx", Source->Integer); break;
196 case SS_DATATYPE_STRING: printf("\"%s\"", Source->String.Data); break;
197 case SS_DATATYPE_REAL: printf("%f", Source->Real); break;
200 printf(" to %i\n", Type);
206 if( Source->Type == SS_DATATYPE_OBJECT )
208 const char *name = NULL;
211 case SS_DATATYPE_INTEGER: name = "cast Integer"; break;
212 case SS_DATATYPE_REAL: name = "cast Real"; break;
213 case SS_DATATYPE_STRING: name = "cast String"; break;
214 case SS_DATATYPE_ARRAY: name = "cast Array"; break;
216 AST_RuntimeError(NULL, "Invalid cast to %i from Object", Type);
221 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
224 // Fall through and try casting (which will usually fail)
229 switch( (enum eSpiderScript_DataTypes)Type )
231 case SS_DATATYPE_UNDEF:
232 case SS_DATATYPE_ARRAY:
233 case SS_DATATYPE_OPAQUE:
234 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
236 case SS_DATATYPE_OBJECT:
238 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
241 case SS_DATATYPE_INTEGER:
242 ret = malloc(sizeof(tSpiderValue));
243 ret->Type = SS_DATATYPE_INTEGER;
244 ret->ReferenceCount = 1;
247 case SS_DATATYPE_INTEGER: break; // Handled above
248 case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
249 case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
251 AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
258 case SS_DATATYPE_REAL:
259 ret = malloc(sizeof(tSpiderValue));
260 ret->Type = SS_DATATYPE_REAL;
261 ret->ReferenceCount = 1;
264 case SS_DATATYPE_STRING: ret->Real = atof(Source->String.Data); break;
265 case SS_DATATYPE_INTEGER: ret->Real = Source->Integer; break;
267 AST_RuntimeError(NULL, "Invalid cast from %i to Real", Source->Type);
274 case SS_DATATYPE_STRING:
277 case SS_DATATYPE_INTEGER: len = snprintf(NULL, 0, "%li", Source->Integer); break;
278 case SS_DATATYPE_REAL: len = snprintf(NULL, 0, "%g", Source->Real); break;
281 ret = malloc(sizeof(tSpiderValue) + len + 1);
282 ret->Type = SS_DATATYPE_STRING;
283 ret->ReferenceCount = 1;
284 ret->String.Length = len;
287 case SS_DATATYPE_INTEGER: sprintf(ret->String.Data, "%li", Source->Integer); break;
288 case SS_DATATYPE_REAL:
289 sprintf(ret->String.Data, "%g", Source->Real); break;
291 AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
299 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target %i", Type);
308 * \brief Condenses a value down to a boolean
310 int SpiderScript_IsValueTrue(tSpiderValue *Value)
312 if( Value == ERRPTR ) return 0;
313 if( Value == NULL ) return 0;
315 switch( (enum eSpiderScript_DataTypes)Value->Type )
317 case SS_DATATYPE_UNDEF:
320 case SS_DATATYPE_INTEGER:
321 return !!Value->Integer;
323 case SS_DATATYPE_REAL:
324 return (-.5f < Value->Real && Value->Real < 0.5f);
326 case SS_DATATYPE_STRING:
327 return Value->String.Length > 0;
329 case SS_DATATYPE_OBJECT:
330 return Value->Object != NULL;
332 case SS_DATATYPE_OPAQUE:
333 return Value->Opaque.Data != NULL;
335 case SS_DATATYPE_ARRAY:
336 return Value->Array.Length > 0;
338 AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
345 * \brief Free a value
346 * \note Just calls Object_Dereference
348 void SpiderScript_FreeValue(tSpiderValue *Value)
350 SpiderScript_DereferenceValue(Value);
354 * \brief Dump a value into a string
355 * \return Heap string
357 char *SpiderScript_DumpValue(tSpiderValue *Value)
360 if( Value == ERRPTR )
361 return strdup("ERRPTR");
363 return strdup("null");
365 switch( (enum eSpiderScript_DataTypes)Value->Type )
367 case SS_DATATYPE_UNDEF: return strdup("undefined");
369 case SS_DATATYPE_INTEGER:
370 ret = malloc( sizeof(Value->Integer)*2 + 3 );
371 sprintf(ret, "0x%lx", Value->Integer);
374 case SS_DATATYPE_REAL:
375 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
376 sprintf(ret, "%f", Value->Real);
379 case SS_DATATYPE_STRING:
380 ret = malloc( Value->String.Length + 3 );
382 strcpy(ret+1, Value->String.Data);
383 ret[Value->String.Length+1] = '"';
384 ret[Value->String.Length+2] = '\0';
387 case SS_DATATYPE_OBJECT:
388 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
389 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
392 case SS_DATATYPE_OPAQUE:
393 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
394 sprintf(ret, "*%p", Value->Opaque.Data);
397 case SS_DATATYPE_ARRAY:
398 return strdup("Array");
401 AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
408 tSpiderValue *SpiderScript_DoOp(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right)
412 case SS_DATATYPE_INTEGER:
413 return SpiderScript_int_DoOpInt(Left, Operation, bCanCast, Right);
418 tSpiderValue *SpiderScript_int_DoOpInt(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right)
420 tSpiderValue *oldright = Right;
421 tSpiderValue *ret = NULL;
425 if(Right && Right->Type != SS_DATATYPE_INTEGER) {
426 if(!bCanCast) return ERRPTR;
427 Right = SpiderScript_CastValueTo(Right, SS_DATATYPE_INTEGER);
433 case SS_VALUEOP_NEGATE:
434 if(Right) ret = ERRPTR;
435 else rv = -Left->Integer;
438 if(!Right) ret = ERRPTR;
439 else rv = Left->Integer + Right->Integer;
443 // Delete temporary value
444 if( Right != oldright )
445 SpiderScript_DereferenceValue(Right);
447 // Return error if signaled
451 // Reuse `Left` if possible, to reduce mallocs
452 if(Left->ReferenceCount == 1) {
453 SpiderScript_ReferenceValue(Left);
458 return SpiderScript_CreateInteger(rv);