Fixed behavior of VTerm when driver is set at runtime
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / exec_ast.c
1 /*
2  */
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include "ast.h"
7
8 #define ERRPTR  ((void*)((intptr_t)0-1))
9
10 // === PROTOTYPES ===
11 void    Object_Dereference(tSpiderVariable *Object);
12 void    Object_Reference(tSpiderVariable *Object);
13 tSpiderVariable *Object_CreateInteger(uint64_t Value);
14 tSpiderVariable *Object_CreateReal(double Value);
15 tSpiderVariable *Object_CreateString(int Length, const char *Data);
16 tSpiderVariable *Object_CastTo(int Type, tSpiderVariable *Source);
17  int    Object_IsTrue(tSpiderVariable *Value);
18
19 void    Variable_SetValue(tSpiderScript *Script, const char *Name, tSpiderVariable *Value);
20 tSpiderVariable *Variable_GetValue(tSpiderScript *Script, const char *Name);
21
22 // === CODE ===
23 /**
24  * \brief Dereference a created object
25  */
26 void Object_Dereference(tSpiderVariable *Object)
27 {
28         Object->ReferenceCount --;
29         if( Object->ReferenceCount == 0 )       free(Object);
30 }
31
32 void Object_Reference(tSpiderVariable *Object)
33 {
34         Object->ReferenceCount ++;
35 }
36
37 /**
38  * \brief Create an integer object
39  */
40 tSpiderVariable *Object_CreateInteger(uint64_t Value)
41 {
42         tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) );
43         ret->Type = SS_DATATYPE_INTEGER;
44         ret->ReferenceCount = 1;
45         ret->Integer = Value;
46         return ret;
47 }
48
49 /**
50  * \brief Create an real number object
51  */
52 tSpiderVariable *Object_CreateReal(double Value)
53 {
54         tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) );
55         ret->Type = SS_DATATYPE_REAL;
56         ret->ReferenceCount = 1;
57         ret->Real = Value;
58         return ret;
59 }
60
61 /**
62  * \brief Create an string object
63  */
64 tSpiderVariable *Object_CreateString(int Length, const char *Data)
65 {
66         tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) + Length + 1 );
67         ret->Type = SS_DATATYPE_STRING;
68         ret->ReferenceCount = 1;
69         ret->String.Length = Length;
70         memcpy(ret->String.Data, Data, Length);
71         ret->String.Data[Length] = '\0';
72         return ret;
73 }
74
75 /**
76  */
77 tSpiderVariable *Object_CastTo(int Type, tSpiderVariable *Source)
78 {
79         tSpiderVariable *ret;
80         // Check if anything needs to be done
81         if( Source->Type == Type ) {
82                 Object_Reference(Source);
83                 return Source;
84         }
85         
86         switch(Type)
87         {
88         case SS_DATATYPE_UNDEF:
89         case SS_DATATYPE_NULL:
90         case SS_DATATYPE_ARRAY:
91                 fprintf(stderr, "Object_CastTo - Invalid cast to %i\n", Type);
92                 return ERRPTR;
93         
94         case SS_DATATYPE_INTEGER:
95                 ret = malloc(sizeof(tSpiderVariable));
96                 ret->Type = SS_DATATYPE_INTEGER;
97                 ret->ReferenceCount = 1;
98                 switch(Source->Type)
99                 {
100                 case SS_DATATYPE_INTEGER:       break;  // Handled above
101                 case SS_DATATYPE_STRING:        ret->Integer = atoi(Source->String.Data);       break;
102                 case SS_DATATYPE_REAL:  ret->Integer = Source->Real;    break;
103                 default:
104                         fprintf(stderr, "Object_CastTo - Invalid cast from %i\n", Source->Type);
105                         break;
106                 }
107                 break;
108         }
109         
110         return ret;
111 }
112
113 /**
114  * \brief Condenses a value down to a boolean
115  */
116 int Object_IsTrue(tSpiderVariable *Value)
117 {
118         switch(Value->Type)
119         {
120         case SS_DATATYPE_UNDEF:
121         case SS_DATATYPE_NULL:
122                 return 0;
123         
124         case SS_DATATYPE_INTEGER:
125                 return !!Value->Integer;
126         
127         case SS_DATATYPE_REAL:
128                 return (-.5f < Value->Real && Value->Real < 0.5f);
129         
130         case SS_DATATYPE_STRING:
131                 return Value->String.Length > 0;
132         
133         case SS_DATATYPE_OBJECT:
134                 return Value->Object != NULL;
135         
136         case SS_DATATYPE_ARRAY:
137                 return Value->Array.Length > 0;
138         }
139         return 0;
140 }
141
142 tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
143 {
144         tAST_Node       *node;
145         tSpiderVariable *ret, *tmpvar;
146         tSpiderVariable *op1, *op2;     // Binary operations
147          int    cmp;    // Used in comparisons
148         
149         switch(Node->Type)
150         {
151         // No Operation
152         case NODETYPE_NOP:      ret = NULL;     break ;
153         
154         // Code block
155         case NODETYPE_BLOCK:
156                 ret = NULL;
157                 for(node = Node->Block.FirstChild; node; node = node->NextSibling )
158                 {
159                         if(node->Type == NODETYPE_RETURN) {
160                                 ret = AST_ExecuteNode(Script, node);
161                                 break ;
162                         }
163                         else {
164                                 tmpvar = AST_ExecuteNode(Script, node);
165                                 if(tmpvar == ERRPTR)    return ERRPTR;  // Error check
166                                 if(tmpvar)      Object_Dereference(tmpvar);     // Free unused value
167                         }
168                 }
169                 break;
170         
171         // Assignment
172         case NODETYPE_ASSIGN:
173                 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
174                         fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
175                         return ERRPTR;
176                 }
177                 ret = AST_ExecuteNode(Script, Node->Assign.Value);
178                 // TODO: Apply operation
179                 Variable_SetValue( Script, Node->Assign.Dest->Variable.Name, ret );
180                 break;
181         
182         case NODETYPE_FUNCTIONCALL:
183                 // TODO: Find a function from the export list in variant
184                 //SpiderScript_ExecuteMethod(Script, Node->FunctionCall.Name
185                 ret = ERRPTR;
186                 fprintf(stderr, "TODO: Implement function calls\n");
187                 break;
188         
189         // Return's special handling happens elsewhere
190         case NODETYPE_RETURN:
191                 ret = AST_ExecuteNode(Script, Node->UniOp.Value);
192                 break;
193         
194         // Variable
195         case NODETYPE_VARIABLE: ret = Variable_GetValue( Script, Node->Variable.Name ); break;
196         
197         // TODO: Implement runtime constants
198         case NODETYPE_CONSTANT: ret = ERRPTR;   break;
199         // Constant Values
200         case NODETYPE_STRING:   ret = Object_CreateString( Node->String.Length, Node->String.Data );    break;
201         case NODETYPE_INTEGER:  ret = Object_CreateInteger( Node->Integer );    break;
202         case NODETYPE_REAL:     ret = Object_CreateReal( Node->Real );  break;
203         
204         // --- Operations ---
205         // Boolean Operations
206         case NODETYPE_LOGICALAND:       // Logical AND (&&)
207         case NODETYPE_LOGICALOR:        // Logical OR (||)
208         case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
209                 op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
210                 op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
211                 switch( Node->Type )
212                 {
213                 case NODETYPE_LOGICALAND:
214                         ret = Object_CreateInteger( Object_IsTrue(op1) && Object_IsTrue(op2) );
215                         break;
216                 case NODETYPE_LOGICALOR:
217                         ret = Object_CreateInteger( Object_IsTrue(op1) || Object_IsTrue(op2) );
218                         break;
219                 case NODETYPE_LOGICALXOR:
220                         ret = Object_CreateInteger( Object_IsTrue(op1) ^ Object_IsTrue(op2) );
221                         break;
222                 default:        break;
223                 }
224                 break;
225         
226         // Comparisons
227         case NODETYPE_EQUALS:
228         case NODETYPE_LESSTHAN:
229         case NODETYPE_GREATERTHAN:
230                 op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
231                 op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
232                 
233                 // No conversion done for NULL
234                 // TODO: Determine if this will ever be needed
235                 if( op1->Type == SS_DATATYPE_NULL )
236                 {
237                         // NULLs always typecheck
238                         ret = Object_CreateInteger(op2->Type == SS_DATATYPE_NULL);
239                         break;
240                 }
241                 
242                 // Convert types
243                 if( op1->Type != op2->Type ) {
244                         // If dynamically typed, convert op2 to op1's type
245                         if(Script->Variant->bDyamicTyped)
246                         {
247                                 tmpvar = op2;
248                                 op2 = Object_CastTo(op1->Type, op2);
249                                 Object_Dereference(tmpvar);
250                         }
251                         // If statically typed, this should never happen, but catch it anyway
252                         else {
253                                 ret = ERRPTR;
254                                 break;
255                         }
256                 }
257                 // Do operation
258                 switch(op1->Type)
259                 {
260                 // - NULL
261                 case SS_DATATYPE_NULL:  break;
262                 // - String Compare (does a strcmp, well memcmp)
263                 case SS_DATATYPE_STRING:
264                         // Call memcmp to do most of the work
265                         cmp = memcmp(
266                                 op1->String.Data, op2->String.Data,
267                                 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
268                                 );
269                         // Handle reaching the end of the string
270                         if( cmp == 0 ) {
271                                 if( op1->String.Length == op2->String.Length )
272                                         cmp = 0;
273                                 else if( op1->String.Length < op2->String.Length )
274                                         cmp = 1;
275                                 else
276                                         cmp = -1;
277                         }
278                         break;
279                 }
280                 
281                 // Free intermediate objects
282                 Object_Dereference(op1);
283                 Object_Dereference(op2);
284                 
285                 // Create return
286                 switch(Node->Type)
287                 {
288                 case NODETYPE_EQUALS:   ret = Object_CreateInteger(cmp == 0);   break;
289                 case NODETYPE_LESSTHAN: ret = Object_CreateInteger(cmp < 0);    break;
290                 case NODETYPE_GREATERTHAN:      ret = Object_CreateInteger(cmp > 0);    break;
291                 default:
292                         fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
293                         ret = ERRPTR;
294                         break;
295                 }
296                 break;
297         
298         // General Binary Operations
299         case NODETYPE_ADD:
300         case NODETYPE_SUBTRACT:
301         case NODETYPE_MULTIPLY:
302         case NODETYPE_DIVIDE:
303         case NODETYPE_MODULO:
304         case NODETYPE_BWAND:
305         case NODETYPE_BWOR:
306         case NODETYPE_BWXOR:
307         case NODETYPE_BITSHIFTLEFT:
308         case NODETYPE_BITSHIFTRIGHT:
309         case NODETYPE_BITROTATELEFT:
310                 // Get operands
311                 op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
312                 op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
313                 
314                 // Convert types
315                 if( op1->Type != op2->Type ) {
316                         // If dynamically typed, convert op2 to op1's type
317                         if(Script->Variant->bDyamicTyped)
318                         {
319                                 tmpvar = op2;
320                                 op2 = Object_CastTo(op1->Type, op2);
321                                 Object_Dereference(tmpvar);
322                         }
323                         // If statically typed, this should never happen, but catch it anyway
324                         else {
325                                 ret = ERRPTR;
326                                 break;
327                         }
328                 }
329                 
330                 // Do operation
331                 switch(op1->Type)
332                 {
333                 case SS_DATATYPE_NULL:  break;
334                 // String Concatenation
335                 case SS_DATATYPE_STRING:
336                         switch(Node->Type)
337                         {
338                         default:
339                                 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Node->Type);
340                                 ret = ERRPTR;
341                                 break;
342                         }
343                         break;
344                 case SS_DATATYPE_INTEGER:
345                         switch(Node->Type)
346                         {
347                         case NODETYPE_ADD:      ret = Object_CreateInteger( op1->Integer + op2->Integer );      break;
348                         case NODETYPE_SUBTRACT: ret = Object_CreateInteger( op1->Integer - op2->Integer );      break;
349                         case NODETYPE_MULTIPLY: ret = Object_CreateInteger( op1->Integer * op2->Integer );      break;
350                         case NODETYPE_DIVIDE:   ret = Object_CreateInteger( op1->Integer / op2->Integer );      break;
351                         case NODETYPE_MODULO:   ret = Object_CreateInteger( op1->Integer % op2->Integer );      break;
352                         case NODETYPE_BWAND:    ret = Object_CreateInteger( op1->Integer & op2->Integer );      break;
353                         case NODETYPE_BWOR:     ret = Object_CreateInteger( op1->Integer | op2->Integer );      break;
354                         case NODETYPE_BWXOR:    ret = Object_CreateInteger( op1->Integer ^ op2->Integer );      break;
355                         case NODETYPE_BITSHIFTLEFT:     ret = Object_CreateInteger( op1->Integer << op2->Integer );     break;
356                         case NODETYPE_BITSHIFTRIGHT:ret = Object_CreateInteger( op1->Integer >> op2->Integer ); break;
357                         case NODETYPE_BITROTATELEFT:
358                                 ret = Object_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) );
359                                 break;
360                         default:
361                                 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Node->Type);
362                                 ret = ERRPTR;
363                                 break;
364                         }
365                         break;
366                 }
367                 
368                 // Free intermediate objects
369                 Object_Dereference(op1);
370                 Object_Dereference(op2);
371                 break;
372         
373         //default:
374         //      ret = NULL;
375         //      fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
376         //      break;
377         }
378         return ret;
379 }

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