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

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