SpiderScript - Moved header to directory, ready to remove from tree
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / values.c
1 /*
2  * SpiderScript Library
3  * by John Hodge (thePowersGang)
4  * 
5  * values.c
6  * - Manage tSpiderValue objects
7  */
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include "spiderscript.h"
12
13 // === IMPORTS ===
14 extern void     AST_RuntimeError(void *Node, const char *Format, ...);
15
16 // === PROTOTYPES ===
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);
26 // --- Operations
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);
31
32
33 // === CODE ===
34 /**
35  * \brief Dereference a created object
36  */
37 void SpiderScript_DereferenceValue(tSpiderValue *Object)
38 {
39         if(!Object || Object == ERRPTR) return ;
40         Object->ReferenceCount --;
41         if( Object->ReferenceCount == 0 )
42         {
43                  int    i;
44
45                 if( Object->Type == SS_DATATYPE_ARRAY || SS_GETARRAYDEPTH(Object->Type) )
46                 {
47                         for( i = 0; i < Object->Array.Length; i ++ )
48                         {
49                                 if( Object->Array.Items[i] ) {
50                                         SpiderScript_DereferenceValue(Object->Array.Items[i]);
51                                 }
52                                 Object->Array.Items[i] = NULL;
53                         }
54                 }
55                 else
56                 {               
57                         switch( (enum eSpiderScript_DataTypes) Object->Type )
58                         {
59                         case SS_DATATYPE_OBJECT:
60                                 Object->Object->ReferenceCount --;
61                                 if(Object->Object->ReferenceCount == 0) {
62                                                 Object->Object->Type->Destructor( Object->Object );
63                                 }
64                                 Object->Object = NULL;
65                                 break;
66         
67                         case SS_DATATYPE_OPAQUE:
68                                 Object->Opaque.Destroy( Object->Opaque.Data );
69                                 break;
70                         default:
71                                 break;
72                         }
73                 }
74                 free(Object);
75         }
76 }
77
78 /**
79  * \brief Reference a value
80  */
81 void SpiderScript_ReferenceValue(tSpiderValue *Object)
82 {
83         if(!Object || Object == ERRPTR) return ;
84         Object->ReferenceCount ++;
85 }
86
87 /**
88  * \brief Allocate and initialise a SpiderScript object
89  */
90 tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes)
91 {
92          int    size = sizeof(tSpiderObject) + Class->NAttributes * sizeof(tSpiderValue*) + ExtraBytes;
93         tSpiderObject   *ret = malloc(size);
94         
95         ret->Type = Class;
96         ret->ReferenceCount = 1;
97         ret->OpaqueData = &ret->Attributes[ Class->NAttributes ];
98         memset( ret->Attributes, 0, Class->NAttributes * sizeof(tSpiderValue*) );
99         
100         return ret;
101 }
102
103 /**
104  * \brief Create an integer object
105  */
106 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
107 {
108         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
109         ret->Type = SS_DATATYPE_INTEGER;
110         ret->ReferenceCount = 1;
111         ret->Integer = Value;
112         return ret;
113 }
114
115 /**
116  * \brief Create an real number object
117  */
118 tSpiderValue *SpiderScript_CreateReal(double Value)
119 {
120         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
121         ret->Type = SS_DATATYPE_REAL;
122         ret->ReferenceCount = 1;
123         ret->Real = Value;
124         return ret;
125 }
126
127 /**
128  * \brief Create an string object
129  */
130 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
131 {
132         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
133         ret->Type = SS_DATATYPE_STRING;
134         ret->ReferenceCount = 1;
135         ret->String.Length = Length;
136         if( Data )
137                 memcpy(ret->String.Data, Data, Length);
138         else
139                 memset(ret->String.Data, 0, Length);
140         ret->String.Data[Length] = '\0';
141         return ret;
142 }
143
144 tSpiderValue *SpiderScript_CreateArray(int InnerType, int ItemCount)
145 {
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*));
151         return ret;
152 }
153
154 /**
155  * \brief Concatenate two strings
156  */
157 tSpiderValue *SpiderScript_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2)
158 {
159          int    newLen = 0;
160         tSpiderValue    *ret;
161         
162         if( Str1 && Str1->Type != SS_DATATYPE_STRING)
163                 return NULL;
164         if( Str2 && Str2->Type != SS_DATATYPE_STRING)
165                 return NULL;
166         
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;
173         if(Str1)
174                 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
175         if(Str2) {
176                 if(Str1)
177                         memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
178                 else
179                         memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
180         }
181         ret->String.Data[ newLen ] = '\0';
182         return ret;
183 }
184
185 /**
186  * \brief Cast one object to another
187  * \brief Type  Destination type
188  * \brief Source        Input data
189  */
190 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
191 {
192         tSpiderValue    *ret = ERRPTR;
193          int    len = 0;
194
195         if( !Source )
196         {
197                 switch(Type)
198                 {
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");
202                 }
203                 return NULL;
204         }
205         
206         // Check if anything needs to be done
207         if( Source->Type == Type ) {
208                 SpiderScript_ReferenceValue(Source);
209                 return Source;
210         }
211         
212         // Debug
213         #if 0
214         {
215                 printf("Casting %i ", Source->Type);
216                 switch(Source->Type)
217                 {
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;
221                 default:        break;
222                 }
223                 printf(" to %i\n", Type);
224         }
225         #endif
226         
227         // Object casts
228         #if 0
229         if( Source->Type == SS_DATATYPE_OBJECT )
230         {
231                 const char      *name = NULL;
232                 switch(Type)
233                 {
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;
238                 default:
239                         AST_RuntimeError(NULL, "Invalid cast to %i from Object", Type);
240                         return ERRPTR;
241                 }
242                 if( fcnname )
243                 {
244                         ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
245                         if( ret != ERRPTR )
246                                 return ret;
247                         // Fall through and try casting (which will usually fail)
248                 }
249         }
250         #endif
251         
252         switch( (enum eSpiderScript_DataTypes)Type )
253         {
254         case SS_DATATYPE_UNDEF:
255         case SS_DATATYPE_ARRAY:
256         case SS_DATATYPE_OPAQUE:
257                 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
258                 return ERRPTR;
259         case SS_DATATYPE_OBJECT:
260                 // TODO: 
261                 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
262                 return ERRPTR;
263         
264         case SS_DATATYPE_INTEGER:
265                 ret = malloc(sizeof(tSpiderValue));
266                 ret->Type = SS_DATATYPE_INTEGER;
267                 ret->ReferenceCount = 1;
268                 switch(Source->Type)
269                 {
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;
273                 default:
274                         AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
275                         free(ret);
276                         ret = ERRPTR;
277                         break;
278                 }
279                 break;
280         
281         case SS_DATATYPE_REAL:
282                 ret = malloc(sizeof(tSpiderValue));
283                 ret->Type = SS_DATATYPE_REAL;
284                 ret->ReferenceCount = 1;
285                 switch(Source->Type)
286                 {
287                 case SS_DATATYPE_STRING:        ret->Real = atof(Source->String.Data);  break;
288                 case SS_DATATYPE_INTEGER:       ret->Real = Source->Integer;    break;
289                 default:
290                         AST_RuntimeError(NULL, "Invalid cast from %i to Real", Source->Type);
291                         free(ret);
292                         ret = ERRPTR;
293                         break;
294                 }
295                 break;
296         
297         case SS_DATATYPE_STRING:
298                 switch(Source->Type)
299                 {
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;
302                 default:        break;
303                 }
304                 ret = malloc(sizeof(tSpiderValue) + len + 1);
305                 ret->Type = SS_DATATYPE_STRING;
306                 ret->ReferenceCount = 1;
307                 ret->String.Length = len;
308                 switch(Source->Type)
309                 {
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;
313                 default:
314                         AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
315                         free(ret);
316                         ret = ERRPTR;
317                         break;
318                 }
319                 break;
320         
321         default:
322                 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target %i", Type);
323                 ret = ERRPTR;
324                 break;
325         }
326         
327         return ret;
328 }
329
330 /**
331  * \brief Condenses a value down to a boolean
332  */
333 int SpiderScript_IsValueTrue(tSpiderValue *Value)
334 {
335         if( Value == ERRPTR )   return 0;
336         if( Value == NULL )     return 0;
337         
338         switch( (enum eSpiderScript_DataTypes)Value->Type )
339         {
340         case SS_DATATYPE_UNDEF:
341                 return 0;
342         
343         case SS_DATATYPE_INTEGER:
344                 return !!Value->Integer;
345         
346         case SS_DATATYPE_REAL:
347                 return (-.5f < Value->Real && Value->Real < 0.5f);
348         
349         case SS_DATATYPE_STRING:
350                 return Value->String.Length > 0;
351         
352         case SS_DATATYPE_OBJECT:
353                 return Value->Object != NULL;
354         
355         case SS_DATATYPE_OPAQUE:
356                 return Value->Opaque.Data != NULL;
357         
358         case SS_DATATYPE_ARRAY:
359                 return Value->Array.Length > 0;
360         default:
361                 AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
362                 return 0;
363         }
364         return 0;
365 }
366
367 /**
368  * \brief Free a value
369  * \note Just calls Object_Dereference
370  */
371 void SpiderScript_FreeValue(tSpiderValue *Value)
372 {
373         SpiderScript_DereferenceValue(Value);
374 }
375
376 /**
377  * \brief Dump a value into a string
378  * \return Heap string
379  */
380 char *SpiderScript_DumpValue(tSpiderValue *Value)
381 {
382         char    *ret;
383         if( Value == ERRPTR )
384                 return strdup("ERRPTR");
385         if( Value == NULL )
386                 return strdup("null");
387         
388         switch( (enum eSpiderScript_DataTypes)Value->Type )
389         {
390         case SS_DATATYPE_UNDEF: return strdup("undefined");
391         
392         case SS_DATATYPE_INTEGER:
393                 ret = malloc( sizeof(Value->Integer)*2 + 3 );
394                 sprintf(ret, "0x%lx", Value->Integer);
395                 return ret;
396         
397         case SS_DATATYPE_REAL:
398                 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
399                 sprintf(ret, "%f", Value->Real);
400                 return ret;
401         
402         case SS_DATATYPE_STRING:
403                 ret = malloc( Value->String.Length + 3 );
404                 ret[0] = '"';
405                 strcpy(ret+1, Value->String.Data);
406                 ret[Value->String.Length+1] = '"';
407                 ret[Value->String.Length+2] = '\0';
408                 return ret;
409         
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);
413                 return ret;
414         
415         case SS_DATATYPE_OPAQUE:
416                 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
417                 sprintf(ret, "*%p", Value->Opaque.Data);
418                 return ret;
419         
420         case SS_DATATYPE_ARRAY:
421                 return strdup("Array");
422         
423         default:
424                 AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
425                 return NULL;
426         }
427         
428 }
429
430 // ---
431 tSpiderValue *SpiderScript_DoOp(tSpiderValue *Left, enum eSpiderValueOps Operation, int bCanCast, tSpiderValue *Right)
432 {
433         switch(Left->Type)
434         {
435         case SS_DATATYPE_INTEGER:
436                 return SpiderScript_int_DoOpInt(Left, Operation, bCanCast, Right);
437         default:
438                 return NULL;
439         }
440         return NULL;
441 }
442
443 tSpiderValue *SpiderScript_int_DoOpInt(tSpiderValue *Left, enum eSpiderValueOps Operation, int bCanCast, tSpiderValue *Right)
444 {
445         tSpiderValue    *oldright = Right;
446         tSpiderValue    *ret = NULL;
447          int64_t        rv = 0;
448
449         // Casting
450         if(Right && Right->Type != SS_DATATYPE_INTEGER) {
451                 if(!bCanCast)   return ERRPTR;
452                 Right = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, Right);
453         }
454
455         // Do the operation
456         switch(Operation)
457         {
458         case SS_VALUEOP_NEGATE:
459                 if(Right)       ret = ERRPTR;
460                 else    rv = -Left->Integer;
461                 break;
462         case SS_VALUEOP_ADD:
463                 if(!Right)      ret = ERRPTR;
464                 else    rv = Left->Integer + Right->Integer;
465                 break;
466         case SS_VALUEOP_SUBTRACT:
467                 if(!Right)      ret = ERRPTR;
468                 else    rv = Left->Integer - Right->Integer;
469                 break;
470         default:
471                 ret = ERRPTR;
472                 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented integer operation %i", Operation);
473                 break;
474         }
475
476         // Delete temporary value
477         if( Right != oldright )
478                 SpiderScript_DereferenceValue(Right);
479
480         // Return error if signaled
481         if(ret == ERRPTR)
482                 return ERRPTR;
483
484         // Reuse `Left` if possible, to reduce mallocs  
485         if(Left->ReferenceCount == 1) {
486                 SpiderScript_ReferenceValue(Left);
487                 Left->Integer = rv;
488                 return Left;
489         }
490         else {
491                 return SpiderScript_CreateInteger(rv);
492         }
493 }
494

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