f0bc6975c0b8fe32e4ae98331c50b5ea890ddf61
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / exec.c
1 /*
2 * SpiderScript Library
3 * by John Hodge (thePowersGang)
4
5 * bytecode_makefile.c
6 * - Generate a bytecode file
7 */
8 #include <stdlib.h>
9 #include "common.h"
10 #include "ast.h"
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdarg.h>
14
15 #define BC_NS_SEPARATOR '@'
16
17 // === IMPORTS ===
18 extern tSpiderFunction  *gpExports_First;
19 extern tSpiderValue     *AST_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Arguments);
20 extern tSpiderValue     *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args);
21
22 // === PROTOTYPES ===
23 void    AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
24 void    AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
25
26 // === CODE ===
27 void *SpiderScript_int_GetNamespace(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
28         const char *BasePath, const char *ItemPath,
29         const char **ItemName
30         )
31 {
32          int    len;
33         const char      *name;
34         const char      *end;
35          int    bTriedBase;
36         
37         tSpiderNamespace        *lastns, *ns;
38
39         // Prepend the base namespace
40         if( BasePath ) {
41                 name = BasePath;
42                 bTriedBase = 0;
43         }
44         else {
45                 bTriedBase = 1;
46                 name = ItemPath;
47         }
48         
49         // Scan
50         lastns = RootNamespace;
51         do {
52                 end = strchr(name, BC_NS_SEPARATOR);
53                 if(!end) {
54                         if( !bTriedBase )
55                                 len = strlen(name);
56                         else
57                                 break;
58                 }
59                 else {
60                         len = end - name;
61                 }
62
63                 // Check for this level
64                 for( ns = lastns->FirstChild; ns; ns = ns->Next )
65                 {
66                         if( strncmp(name, ns->Name, len) == 0 && ns->Name[len] == 0 )
67                                 break ;
68                 }
69                 
70                 if(!ns) return NULL;            
71
72                 if(!end && !bTriedBase) {
73                         end = ItemPath - 1;     // -1 to counter (name = end + 1)
74                         bTriedBase = 1;
75                 }
76
77                 lastns = ns;
78                 name = end + 1;
79         } while( end );
80
81         *ItemName = name;
82
83         return lastns;
84 }
85
86 tSpiderFunction *SpiderScript_int_GetNativeFunction(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
87         const char *BasePath, const char *FunctionPath)
88 {
89         tSpiderNamespace *ns;
90         const char *name;
91         tSpiderFunction *fcn;
92
93         ns = SpiderScript_int_GetNamespace(Script, RootNamespace, BasePath, FunctionPath, &name);
94         if(!ns) return NULL;
95
96         for( fcn = ns->Functions; fcn; fcn = fcn->Next )
97         {
98                 if( strcmp(name, fcn->Name) == 0 )
99                         return fcn;
100         }
101         
102         return NULL;
103 }
104
105 tSpiderObjectDef *SpiderScript_int_GetNativeClass(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
106         const char *BasePath, const char *ClassPath
107         )
108 {
109         tSpiderNamespace *ns;
110         const char *name;
111         tSpiderObjectDef *class;
112
113         ns = SpiderScript_int_GetNamespace(Script, RootNamespace, BasePath, ClassPath, &name);
114         if(!ns) return NULL;
115         
116         for( class = ns->Classes; class; class = class->Next )
117         {
118                 if( strcmp(name, class->Name) == 0 )
119                         return class;
120         }
121
122         return NULL;
123 }
124
125 /**
126  * \brief Execute a script function
127  * \param Script        Script context to execute in
128  * \param Namespace     Namespace to search for the function
129  * \param Function      Function name to execute
130  * \param NArguments    Number of arguments to pass
131  * \param Arguments     Arguments passed
132  */
133 tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
134         const char *Function,
135         const char *DefaultNamespaces[],
136         int NArguments, tSpiderValue **Arguments,
137         void **FunctionIdent
138         )
139 {
140         tSpiderValue    *ret = ERRPTR;
141         tSpiderFunction *fcn = NULL;
142          int    i;
143
144         // Scan list, Last item should always be NULL, so abuse that to check non-prefixed      
145         for( i = 0; i == 0 || (DefaultNamespaces && DefaultNamespaces[i-1]); i ++ )
146         {
147                 const char *ns = DefaultNamespaces ? DefaultNamespaces[i] : NULL;
148                 fcn = SpiderScript_int_GetNativeFunction(Script, &Script->Variant->RootNamespace,
149                         ns, Function);
150                 if( fcn )       break;
151                 
152                 // TODO: Script namespacing
153         }
154
155         // Search the variant's global exports
156         if( !fcn )
157         {
158                 for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
159                 {
160                         if( strcmp( fcn->Name, Function ) == 0 )
161                                 break;
162                 }
163         }
164         
165         // Fourth: Search language exports
166         if( !fcn )
167         {
168                 for( fcn = gpExports_First; fcn; fcn = fcn->Next )
169                 {
170                         if( strcmp( fcn->Name, Function ) == 0 )
171                                 break;
172                 }
173         }
174         
175         // Find the function in the script?
176         // TODO: Script namespacing
177         if( !fcn && strchr(Function, BC_NS_SEPARATOR) == NULL )
178         {
179                 tScript_Function        *sfcn;
180                 for( sfcn = Script->Functions; sfcn; sfcn = sfcn->Next )
181                 {
182                         if( strcmp(sfcn->Name, Function) == 0 )
183                                 break;
184                 }
185                 // Execute!
186                 if(sfcn)
187                 {
188                         if( sfcn->BCFcn )
189                                 ret = Bytecode_ExecuteFunction(Script, sfcn, NArguments, Arguments);
190                         else
191                                 ret = AST_ExecuteFunction(Script, sfcn, NArguments, Arguments);
192
193                         if( FunctionIdent ) {
194                                 *FunctionIdent = sfcn;
195                                 // Abuses alignment requirements on almost all platforms
196                                 *(intptr_t*)FunctionIdent |= 1;
197                         }
198
199                         return ret;
200                 }
201         }
202         
203         if(fcn)
204         {
205                 // Execute!
206                 // TODO: Type Checking
207                 ret = fcn->Handler( Script, NArguments, Arguments );
208         
209                 if( FunctionIdent )
210                         *FunctionIdent = fcn;           
211
212                 return ret;
213         }
214         else
215         {
216                 fprintf(stderr, "Undefined reference to function '%s'\n", Function);
217                 return ERRPTR;
218         }
219 }
220
221 /**
222  * \brief Execute an object method function
223  * \param Script        Script context to execute in
224  * \param Object        Object in which to find the method
225  * \param MethodName    Name of method to call
226  * \param NArguments    Number of arguments to pass
227  * \param Arguments     Arguments passed
228  */
229 tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
230         tSpiderObject *Object, const char *MethodName,
231         int NArguments, tSpiderValue **Arguments)
232 {
233         tSpiderFunction *fcn;
234         tSpiderValue    this;
235         tSpiderValue    *newargs[NArguments+1];
236          int    i;
237         
238         // TODO: Support program defined objects
239         
240         // Search for the function
241         for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
242         {
243                 if( strcmp(fcn->Name, MethodName) == 0 )
244                         break;
245         }
246         // Error
247         if( !fcn )
248         {
249                 AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
250                         Object->Type->Name, MethodName);
251                 return ERRPTR;
252         }
253         
254         // Create the "this" argument
255         this.Type = SS_DATATYPE_OBJECT;
256         this.ReferenceCount = 1;
257         this.Object = Object;
258         newargs[0] = &this;
259         memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
260         
261         // Check the type of the arguments
262         for( i = 0; fcn->ArgTypes[i]; i ++ )
263         {
264                 if( i >= NArguments ) {
265                         for( ; fcn->ArgTypes[i]; i ++ ) ;
266                         AST_RuntimeError(NULL, "Argument count mismatch (%i passed, %i expected)",
267                                 NArguments, i);
268                         return ERRPTR;
269                 }
270                 if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
271                 {
272                         AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
273                                 Arguments[i]->Type, fcn->ArgTypes[i]);
274                         return ERRPTR;
275                 }
276         }
277         
278         // Call handler
279         return fcn->Handler(Script, NArguments+1, newargs);
280 }
281
282 /**
283  * \brief Execute a script function
284  * \param Script        Script context to execute in
285  * \param Function      Function name to execute
286  * \param NArguments    Number of arguments to pass
287  * \param Arguments     Arguments passed
288  */
289 tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
290         const char *ClassPath, const char *DefaultNamespaces[],
291         int NArguments, tSpiderValue **Arguments)
292 {
293         tSpiderValue    *ret = ERRPTR;
294         tSpiderObjectDef        *class;
295          int    i;      
296
297         // Scan list, Last item should always be NULL, so abuse that to check non-prefixed      
298         for( i = 0; i == 0 || DefaultNamespaces[i-1]; i ++ )
299         {
300                 class = SpiderScript_int_GetNativeClass(Script, &Script->Variant->RootNamespace,
301                         DefaultNamespaces[i], ClassPath);
302                 if( class != NULL )     break;
303                 
304                 // TODO: Language defined classes
305         }
306                 
307         // First: Find the function in the script
308         // TODO: Implement script-defined classes
309         #if 0
310         {
311                 tAST_Function   *astClass;
312                 for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
313                 {
314                         if( strcmp(astClass->Name, ClassName) == 0 )
315                                 break;
316                 }
317                 // Execute!
318                 if(astClass)
319                 {
320                         tAST_BlockState bs;
321                         tAST_Node       *arg;
322                          int    i = 0;
323                         
324                         // Build a block State
325                         bs.FirstVar = NULL;
326                         bs.RetVal = NULL;
327                         bs.Parent = NULL;
328                         bs.BaseNamespace = &Script->Variant->RootNamespace;
329                         bs.CurNamespace = NULL;
330                         bs.Script = Script;
331                         bs.Ident = giNextBlockIdent ++;
332                         
333                         for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
334                         {
335                                 if( i >= NArguments )   break;  // TODO: Return gracefully
336                                 // TODO: Type checks
337                                 Variable_Define(&bs,
338                                         arg->DefVar.DataType, arg->DefVar.Name,
339                                         Arguments[i]);
340                         }
341                         
342                         // Execute function
343                         ret = AST_ExecuteNode(&bs, astFcn->Code);
344                         if( ret != ERRPTR )
345                         {
346                                 SpiderScript_DereferenceValue(ret);     // Dereference output of last block statement
347                                 ret = bs.RetVal;        // Set to return value of block
348                         }
349                         bFound = 1;
350                         
351                         while(bs.FirstVar)
352                         {
353                                 tAST_Variable   *nextVar = bs.FirstVar->Next;
354                                 Variable_Destroy( bs.FirstVar );
355                                 bs.FirstVar = nextVar;
356                         }
357                 }
358         }
359         #endif
360         
361         // Execute!
362         if(class)
363         {
364                 tSpiderObject   *obj;
365                 // TODO: Type Checking
366                 
367                 // Call constructor
368                 obj = class->Constructor( NArguments, Arguments );
369                 if( obj == NULL || obj == ERRPTR )
370                         return (void *)obj;
371                 
372                 // Creatue return object
373                 ret = malloc( sizeof(tSpiderValue) );
374                 ret->Type = SS_DATATYPE_OBJECT;
375                 ret->ReferenceCount = 1;
376                 ret->Object = obj;
377                 
378                 return ret;
379         }
380         else    // Not found?
381         {
382                 fprintf(stderr, "Undefined reference to class '%s'\n", ClassPath);
383                 return ERRPTR;
384         }
385 }
386
387 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
388 {
389         va_list args;
390         
391         if(Node) {
392                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
393         }
394         fprintf(stderr, "%s: ", Type);
395         va_start(args, Format);
396         vfprintf(stderr, Format, args);
397         va_end(args);
398         fprintf(stderr, "\n");
399 }
400 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
401 {
402         va_list args;
403         
404         if(Node) {
405                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
406         }
407         fprintf(stderr, "error: ");
408         va_start(args, Format);
409         vfprintf(stderr, Format, args);
410         va_end(args);
411         fprintf(stderr, "\n");
412 }

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