f05360d4a2aa1443e2627ab3e7645c8481f0ceba
[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
27 // === CODE ===
28 /**
29  * \brief Dereference a created object
30  */
31 void SpiderScript_DereferenceValue(tSpiderValue *Object)
32 {
33         if(!Object || Object == ERRPTR) return ;
34         Object->ReferenceCount --;
35         if( Object->ReferenceCount == 0 )
36         {
37                 switch( (enum eSpiderScript_DataTypes) Object->Type )
38                 {
39                 case SS_DATATYPE_OBJECT:
40                         Object->Object->Type->Destructor( Object->Object );
41                         break;
42                 case SS_DATATYPE_OPAQUE:
43                         Object->Opaque.Destroy( Object->Opaque.Data );
44                         break;
45                 default:
46                         break;
47                 }
48                 free(Object);
49         }
50 }
51
52 /**
53  * \brief Reference a value
54  */
55 void SpiderScript_ReferenceValue(tSpiderValue *Object)
56 {
57         if(!Object || Object == ERRPTR) return ;
58         Object->ReferenceCount ++;
59 }
60
61 /**
62  * \brief Allocate and initialise a SpiderScript object
63  */
64 tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes)
65 {
66          int    size = sizeof(tSpiderObject) + Class->NAttributes * sizeof(tSpiderValue*) + ExtraBytes;
67         tSpiderObject   *ret = malloc(size);
68         
69         ret->Type = Class;
70         ret->ReferenceCount = 1;
71         ret->OpaqueData = &ret->Attributes[ Class->NAttributes ];
72         memset( ret->Attributes, 0, Class->NAttributes * sizeof(tSpiderValue*) );
73         
74         return ret;
75 }
76
77 /**
78  * \brief Create an integer object
79  */
80 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
81 {
82         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
83         ret->Type = SS_DATATYPE_INTEGER;
84         ret->ReferenceCount = 1;
85         ret->Integer = Value;
86         return ret;
87 }
88
89 /**
90  * \brief Create an real number object
91  */
92 tSpiderValue *SpiderScript_CreateReal(double Value)
93 {
94         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
95         ret->Type = SS_DATATYPE_REAL;
96         ret->ReferenceCount = 1;
97         ret->Real = Value;
98         return ret;
99 }
100
101 /**
102  * \brief Create an string object
103  */
104 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
105 {
106         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
107         ret->Type = SS_DATATYPE_STRING;
108         ret->ReferenceCount = 1;
109         ret->String.Length = Length;
110         if( Data )
111                 memcpy(ret->String.Data, Data, Length);
112         else
113                 memset(ret->String.Data, 0, Length);
114         ret->String.Data[Length] = '\0';
115         return ret;
116 }
117
118 /**
119  * \brief Concatenate two strings
120  */
121 tSpiderValue *SpiderScript_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2)
122 {
123          int    newLen = 0;
124         tSpiderValue    *ret;
125         
126         if( Str1 && Str1->Type != SS_DATATYPE_STRING)
127                 return NULL;
128         if( Str2 && Str2->Type != SS_DATATYPE_STRING)
129                 return NULL;
130         
131         if(Str1)        newLen += Str1->String.Length;
132         if(Str2)        newLen += Str2->String.Length;
133         ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
134         ret->Type = SS_DATATYPE_STRING;
135         ret->ReferenceCount = 1;
136         ret->String.Length = newLen;
137         if(Str1)
138                 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
139         if(Str2) {
140                 if(Str1)
141                         memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
142                 else
143                         memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
144         }
145         ret->String.Data[ newLen ] = '\0';
146         return ret;
147 }
148
149 /**
150  * \brief Cast one object to another
151  * \brief Type  Destination type
152  * \brief Source        Input data
153  */
154 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
155 {
156         tSpiderValue    *ret = ERRPTR;
157          int    len = 0;
158
159         if( !Source )
160         {
161                 switch(Type)
162                 {
163                 case SS_DATATYPE_INTEGER:       return SpiderScript_CreateInteger(0);
164                 case SS_DATATYPE_REAL:  return SpiderScript_CreateReal(0);
165                 case SS_DATATYPE_STRING:        return SpiderScript_CreateString(4, "null");
166                 }
167                 return NULL;
168         }
169         
170         // Check if anything needs to be done
171         if( Source->Type == Type ) {
172                 SpiderScript_DereferenceValue(Source);
173                 return Source;
174         }
175         
176         // Debug
177         #if 0
178         {
179                 printf("Casting %i ", Source->Type);
180                 switch(Source->Type)
181                 {
182                 case SS_DATATYPE_INTEGER:       printf("0x%lx", Source->Integer);       break;
183                 case SS_DATATYPE_STRING:        printf("\"%s\"", Source->String.Data);  break;
184                 case SS_DATATYPE_REAL:  printf("%f", Source->Real);     break;
185                 default:        break;
186                 }
187                 printf(" to %i\n", Type);
188         }
189         #endif
190         
191         // Object casts
192         #if 0
193         if( Source->Type == SS_DATATYPE_OBJECT )
194         {
195                 const char      *name = NULL;
196                 switch(Type)
197                 {
198                 case SS_DATATYPE_INTEGER:       name = "cast Integer";  break;
199                 case SS_DATATYPE_REAL:          name = "cast Real";     break;
200                 case SS_DATATYPE_STRING:        name = "cast String";   break;
201                 case SS_DATATYPE_ARRAY:         name = "cast Array";    break;
202                 default:
203                         AST_RuntimeError(NULL, "Invalid cast to %i from Object", Type);
204                         return ERRPTR;
205                 }
206                 if( fcnname )
207                 {
208                         ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
209                         if( ret != ERRPTR )
210                                 return ret;
211                         // Fall through and try casting (which will usually fail)
212                 }
213         }
214         #endif
215         
216         switch( (enum eSpiderScript_DataTypes)Type )
217         {
218         case SS_DATATYPE_UNDEF:
219         case SS_DATATYPE_ARRAY:
220         case SS_DATATYPE_OPAQUE:
221                 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
222                 return ERRPTR;
223         case SS_DATATYPE_OBJECT:
224                 // TODO: 
225                 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
226                 return ERRPTR;
227         
228         case SS_DATATYPE_INTEGER:
229                 ret = malloc(sizeof(tSpiderValue));
230                 ret->Type = SS_DATATYPE_INTEGER;
231                 ret->ReferenceCount = 1;
232                 switch(Source->Type)
233                 {
234                 case SS_DATATYPE_INTEGER:       break;  // Handled above
235                 case SS_DATATYPE_STRING:        ret->Integer = atoi(Source->String.Data);       break;
236                 case SS_DATATYPE_REAL:  ret->Integer = Source->Real;    break;
237                 default:
238                         AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
239                         free(ret);
240                         ret = ERRPTR;
241                         break;
242                 }
243                 break;
244         
245         case SS_DATATYPE_REAL:
246                 ret = malloc(sizeof(tSpiderValue));
247                 ret->Type = SS_DATATYPE_REAL;
248                 ret->ReferenceCount = 1;
249                 switch(Source->Type)
250                 {
251                 case SS_DATATYPE_STRING:        ret->Real = atof(Source->String.Data);  break;
252                 case SS_DATATYPE_INTEGER:       ret->Real = Source->Integer;    break;
253                 default:
254                         AST_RuntimeError(NULL, "Invalid cast from %i to Real", Source->Type);
255                         free(ret);
256                         ret = ERRPTR;
257                         break;
258                 }
259                 break;
260         
261         case SS_DATATYPE_STRING:
262                 switch(Source->Type)
263                 {
264                 case SS_DATATYPE_INTEGER:       len = snprintf(NULL, 0, "%li", Source->Integer);        break;
265                 case SS_DATATYPE_REAL:  len = snprintf(NULL, 0, "%g", Source->Real);    break;
266                 default:        break;
267                 }
268                 ret = malloc(sizeof(tSpiderValue) + len + 1);
269                 ret->Type = SS_DATATYPE_STRING;
270                 ret->ReferenceCount = 1;
271                 ret->String.Length = len;
272                 switch(Source->Type)
273                 {
274                 case SS_DATATYPE_INTEGER:       sprintf(ret->String.Data, "%li", Source->Integer);      break;
275                 case SS_DATATYPE_REAL:
276                         sprintf(ret->String.Data, "%g", Source->Real);  break;
277                 default:
278                         AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
279                         free(ret);
280                         ret = ERRPTR;
281                         break;
282                 }
283                 break;
284         
285         default:
286                 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target %i", Type);
287                 ret = ERRPTR;
288                 break;
289         }
290         
291         return ret;
292 }
293
294 /**
295  * \brief Condenses a value down to a boolean
296  */
297 int SpiderScript_IsValueTrue(tSpiderValue *Value)
298 {
299         if( Value == ERRPTR )   return 0;
300         if( Value == NULL )     return 0;
301         
302         switch( (enum eSpiderScript_DataTypes)Value->Type )
303         {
304         case SS_DATATYPE_UNDEF:
305                 return 0;
306         
307         case SS_DATATYPE_INTEGER:
308                 return !!Value->Integer;
309         
310         case SS_DATATYPE_REAL:
311                 return (-.5f < Value->Real && Value->Real < 0.5f);
312         
313         case SS_DATATYPE_STRING:
314                 return Value->String.Length > 0;
315         
316         case SS_DATATYPE_OBJECT:
317                 return Value->Object != NULL;
318         
319         case SS_DATATYPE_OPAQUE:
320                 return Value->Opaque.Data != NULL;
321         
322         case SS_DATATYPE_ARRAY:
323                 return Value->Array.Length > 0;
324         default:
325                 AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
326                 return 0;
327         }
328         return 0;
329 }
330
331 /**
332  * \brief Free a value
333  * \note Just calls Object_Dereference
334  */
335 void SpiderScript_FreeValue(tSpiderValue *Value)
336 {
337         SpiderScript_DereferenceValue(Value);
338 }
339
340 /**
341  * \brief Dump a value into a string
342  * \return Heap string
343  */
344 char *SpiderScript_DumpValue(tSpiderValue *Value)
345 {
346         char    *ret;
347         if( Value == ERRPTR )
348                 return strdup("ERRPTR");
349         if( Value == NULL )
350                 return strdup("null");
351         
352         switch( (enum eSpiderScript_DataTypes)Value->Type )
353         {
354         case SS_DATATYPE_UNDEF: return strdup("undefined");
355         
356         case SS_DATATYPE_INTEGER:
357                 ret = malloc( sizeof(Value->Integer)*2 + 3 );
358                 sprintf(ret, "0x%lx", Value->Integer);
359                 return ret;
360         
361         case SS_DATATYPE_REAL:
362                 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
363                 sprintf(ret, "%f", Value->Real);
364                 return ret;
365         
366         case SS_DATATYPE_STRING:
367                 ret = malloc( Value->String.Length + 3 );
368                 ret[0] = '"';
369                 strcpy(ret+1, Value->String.Data);
370                 ret[Value->String.Length+1] = '"';
371                 ret[Value->String.Length+2] = '\0';
372                 return ret;
373         
374         case SS_DATATYPE_OBJECT:
375                 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
376                 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
377                 return ret;
378         
379         case SS_DATATYPE_OPAQUE:
380                 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
381                 sprintf(ret, "*%p", Value->Opaque.Data);
382                 return ret;
383         
384         case SS_DATATYPE_ARRAY:
385                 return strdup("Array");
386         
387         default:
388                 AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
389                 return NULL;
390         }
391         
392 }
393
394

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