SpiderScript - Light speedups, planning for smarter operation code
[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, 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);
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->Type == SS_DATATYPE_OBJECT) {
42         }
43         if( Object->ReferenceCount == 0 )
44         {
45                 switch( (enum eSpiderScript_DataTypes) Object->Type )
46                 {
47                 case SS_DATATYPE_OBJECT:
48                         Object->Object->ReferenceCount --;
49                         if(Object->Object->ReferenceCount == 0) {
50                                 Object->Object->Type->Destructor( Object->Object );
51                         }
52                         Object->Object = NULL;
53                         break;
54
55                 case SS_DATATYPE_OPAQUE:
56                         Object->Opaque.Destroy( Object->Opaque.Data );
57                         break;
58                 default:
59                         break;
60                 }
61                 free(Object);
62         }
63 }
64
65 /**
66  * \brief Reference a value
67  */
68 void SpiderScript_ReferenceValue(tSpiderValue *Object)
69 {
70         if(!Object || Object == ERRPTR) return ;
71         Object->ReferenceCount ++;
72 }
73
74 /**
75  * \brief Allocate and initialise a SpiderScript object
76  */
77 tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes)
78 {
79          int    size = sizeof(tSpiderObject) + Class->NAttributes * sizeof(tSpiderValue*) + ExtraBytes;
80         tSpiderObject   *ret = malloc(size);
81         
82         ret->Type = Class;
83         ret->ReferenceCount = 1;
84         ret->OpaqueData = &ret->Attributes[ Class->NAttributes ];
85         memset( ret->Attributes, 0, Class->NAttributes * sizeof(tSpiderValue*) );
86         
87         return ret;
88 }
89
90 /**
91  * \brief Create an integer object
92  */
93 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
94 {
95         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
96         ret->Type = SS_DATATYPE_INTEGER;
97         ret->ReferenceCount = 1;
98         ret->Integer = Value;
99         return ret;
100 }
101
102 /**
103  * \brief Create an real number object
104  */
105 tSpiderValue *SpiderScript_CreateReal(double Value)
106 {
107         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
108         ret->Type = SS_DATATYPE_REAL;
109         ret->ReferenceCount = 1;
110         ret->Real = Value;
111         return ret;
112 }
113
114 /**
115  * \brief Create an string object
116  */
117 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
118 {
119         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
120         ret->Type = SS_DATATYPE_STRING;
121         ret->ReferenceCount = 1;
122         ret->String.Length = Length;
123         if( Data )
124                 memcpy(ret->String.Data, Data, Length);
125         else
126                 memset(ret->String.Data, 0, Length);
127         ret->String.Data[Length] = '\0';
128         return ret;
129 }
130
131 /**
132  * \brief Concatenate two strings
133  */
134 tSpiderValue *SpiderScript_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2)
135 {
136          int    newLen = 0;
137         tSpiderValue    *ret;
138         
139         if( Str1 && Str1->Type != SS_DATATYPE_STRING)
140                 return NULL;
141         if( Str2 && Str2->Type != SS_DATATYPE_STRING)
142                 return NULL;
143         
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;
150         if(Str1)
151                 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
152         if(Str2) {
153                 if(Str1)
154                         memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
155                 else
156                         memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
157         }
158         ret->String.Data[ newLen ] = '\0';
159         return ret;
160 }
161
162 /**
163  * \brief Cast one object to another
164  * \brief Type  Destination type
165  * \brief Source        Input data
166  */
167 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
168 {
169         tSpiderValue    *ret = ERRPTR;
170          int    len = 0;
171
172         if( !Source )
173         {
174                 switch(Type)
175                 {
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");
179                 }
180                 return NULL;
181         }
182         
183         // Check if anything needs to be done
184         if( Source->Type == Type ) {
185                 SpiderScript_ReferenceValue(Source);
186                 return Source;
187         }
188         
189         // Debug
190         #if 0
191         {
192                 printf("Casting %i ", Source->Type);
193                 switch(Source->Type)
194                 {
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;
198                 default:        break;
199                 }
200                 printf(" to %i\n", Type);
201         }
202         #endif
203         
204         // Object casts
205         #if 0
206         if( Source->Type == SS_DATATYPE_OBJECT )
207         {
208                 const char      *name = NULL;
209                 switch(Type)
210                 {
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;
215                 default:
216                         AST_RuntimeError(NULL, "Invalid cast to %i from Object", Type);
217                         return ERRPTR;
218                 }
219                 if( fcnname )
220                 {
221                         ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
222                         if( ret != ERRPTR )
223                                 return ret;
224                         // Fall through and try casting (which will usually fail)
225                 }
226         }
227         #endif
228         
229         switch( (enum eSpiderScript_DataTypes)Type )
230         {
231         case SS_DATATYPE_UNDEF:
232         case SS_DATATYPE_ARRAY:
233         case SS_DATATYPE_OPAQUE:
234                 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
235                 return ERRPTR;
236         case SS_DATATYPE_OBJECT:
237                 // TODO: 
238                 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
239                 return ERRPTR;
240         
241         case SS_DATATYPE_INTEGER:
242                 ret = malloc(sizeof(tSpiderValue));
243                 ret->Type = SS_DATATYPE_INTEGER;
244                 ret->ReferenceCount = 1;
245                 switch(Source->Type)
246                 {
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;
250                 default:
251                         AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
252                         free(ret);
253                         ret = ERRPTR;
254                         break;
255                 }
256                 break;
257         
258         case SS_DATATYPE_REAL:
259                 ret = malloc(sizeof(tSpiderValue));
260                 ret->Type = SS_DATATYPE_REAL;
261                 ret->ReferenceCount = 1;
262                 switch(Source->Type)
263                 {
264                 case SS_DATATYPE_STRING:        ret->Real = atof(Source->String.Data);  break;
265                 case SS_DATATYPE_INTEGER:       ret->Real = Source->Integer;    break;
266                 default:
267                         AST_RuntimeError(NULL, "Invalid cast from %i to Real", Source->Type);
268                         free(ret);
269                         ret = ERRPTR;
270                         break;
271                 }
272                 break;
273         
274         case SS_DATATYPE_STRING:
275                 switch(Source->Type)
276                 {
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;
279                 default:        break;
280                 }
281                 ret = malloc(sizeof(tSpiderValue) + len + 1);
282                 ret->Type = SS_DATATYPE_STRING;
283                 ret->ReferenceCount = 1;
284                 ret->String.Length = len;
285                 switch(Source->Type)
286                 {
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;
290                 default:
291                         AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
292                         free(ret);
293                         ret = ERRPTR;
294                         break;
295                 }
296                 break;
297         
298         default:
299                 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target %i", Type);
300                 ret = ERRPTR;
301                 break;
302         }
303         
304         return ret;
305 }
306
307 /**
308  * \brief Condenses a value down to a boolean
309  */
310 int SpiderScript_IsValueTrue(tSpiderValue *Value)
311 {
312         if( Value == ERRPTR )   return 0;
313         if( Value == NULL )     return 0;
314         
315         switch( (enum eSpiderScript_DataTypes)Value->Type )
316         {
317         case SS_DATATYPE_UNDEF:
318                 return 0;
319         
320         case SS_DATATYPE_INTEGER:
321                 return !!Value->Integer;
322         
323         case SS_DATATYPE_REAL:
324                 return (-.5f < Value->Real && Value->Real < 0.5f);
325         
326         case SS_DATATYPE_STRING:
327                 return Value->String.Length > 0;
328         
329         case SS_DATATYPE_OBJECT:
330                 return Value->Object != NULL;
331         
332         case SS_DATATYPE_OPAQUE:
333                 return Value->Opaque.Data != NULL;
334         
335         case SS_DATATYPE_ARRAY:
336                 return Value->Array.Length > 0;
337         default:
338                 AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
339                 return 0;
340         }
341         return 0;
342 }
343
344 /**
345  * \brief Free a value
346  * \note Just calls Object_Dereference
347  */
348 void SpiderScript_FreeValue(tSpiderValue *Value)
349 {
350         SpiderScript_DereferenceValue(Value);
351 }
352
353 /**
354  * \brief Dump a value into a string
355  * \return Heap string
356  */
357 char *SpiderScript_DumpValue(tSpiderValue *Value)
358 {
359         char    *ret;
360         if( Value == ERRPTR )
361                 return strdup("ERRPTR");
362         if( Value == NULL )
363                 return strdup("null");
364         
365         switch( (enum eSpiderScript_DataTypes)Value->Type )
366         {
367         case SS_DATATYPE_UNDEF: return strdup("undefined");
368         
369         case SS_DATATYPE_INTEGER:
370                 ret = malloc( sizeof(Value->Integer)*2 + 3 );
371                 sprintf(ret, "0x%lx", Value->Integer);
372                 return ret;
373         
374         case SS_DATATYPE_REAL:
375                 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
376                 sprintf(ret, "%f", Value->Real);
377                 return ret;
378         
379         case SS_DATATYPE_STRING:
380                 ret = malloc( Value->String.Length + 3 );
381                 ret[0] = '"';
382                 strcpy(ret+1, Value->String.Data);
383                 ret[Value->String.Length+1] = '"';
384                 ret[Value->String.Length+2] = '\0';
385                 return ret;
386         
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);
390                 return ret;
391         
392         case SS_DATATYPE_OPAQUE:
393                 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
394                 sprintf(ret, "*%p", Value->Opaque.Data);
395                 return ret;
396         
397         case SS_DATATYPE_ARRAY:
398                 return strdup("Array");
399         
400         default:
401                 AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
402                 return NULL;
403         }
404         
405 }
406
407 // ---
408 tSpiderValue *SpiderScript_DoOp(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right)
409 {
410         switch(Left->Type)
411         {
412         case SS_DATATYPE_INTEGER:
413                 return SpiderScript_int_DoOpInt(Left, Operation, bCanCast, Right);
414         }
415         return NULL;
416 }
417
418 tSpiderValue *SpiderScript_int_DoOpInt(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right)
419 {
420         tSpiderValue    *oldright = Right;
421         tSpiderValue    *ret = NULL;
422          int64_t        rv;
423
424         // Casting
425         if(Right && Right->Type != SS_DATATYPE_INTEGER) {
426                 if(!bCanCast)   return ERRPTR;
427                 Right = SpiderScript_CastValueTo(Right, SS_DATATYPE_INTEGER);
428         }
429
430         // Do the operation
431         switch(Operation)
432         {
433         case SS_VALUEOP_NEGATE:
434                 if(Right)       ret = ERRPTR;
435                 else    rv = -Left->Integer;
436                 break;
437         case SS_VALUEOP_ADD:
438                 if(!Right)      ret = ERRPTR;
439                 else    rv = Left->Integer + Right->Integer;
440                 break;
441         }
442
443         // Delete temporary value
444         if( Right != oldright )
445                 SpiderScript_DereferenceValue(Right);
446
447         // Return error if signaled
448         if(ret == ERRPTR)
449                 return ERRPTR;
450
451         // Reuse `Left` if possible, to reduce mallocs  
452         if(Left->ReferenceCount == 1) {
453                 SpiderScript_ReferenceValue(Left);
454                 Left->Integer = rv;
455                 return Left;
456         }
457         else {
458                 return SpiderScript_CreateInteger(rv);
459         }
460 }
461

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