3 * by John Hodge (thePowersGang)
6 * - Generate a bytecode file
15 #define BC_NS_SEPARATOR '@'
18 extern tSpiderFunction *gpExports_First;
19 extern tSpiderNamespace gExportNamespaceRoot;
20 extern tSpiderValue *AST_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Arguments);
21 extern tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args);
24 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
25 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
28 void *SpiderScript_int_GetNamespace(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
29 const char *BasePath, const char *ItemPath,
38 tSpiderNamespace *lastns, *ns;
40 // Prepend the base namespace
51 lastns = RootNamespace;
53 end = strchr(name, BC_NS_SEPARATOR);
64 // Check for this level
65 for( ns = lastns->FirstChild; ns; ns = ns->Next )
67 printf("%p %.*s == %s\n", lastns, len, name, ns->Name);
68 if( strncmp(name, ns->Name, len) == 0 && ns->Name[len] == 0 )
74 if(!end && !bTriedBase) {
75 end = ItemPath - 1; // -1 to counter (name = end + 1)
88 tSpiderFunction *SpiderScript_int_GetNativeFunction(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
89 const char *BasePath, const char *FunctionPath)
95 ns = SpiderScript_int_GetNamespace(Script, RootNamespace, BasePath, FunctionPath, &name);
98 for( fcn = ns->Functions; fcn; fcn = fcn->Next )
100 if( strcmp(name, fcn->Name) == 0 )
107 tSpiderObjectDef *SpiderScript_int_GetNativeClass(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
108 const char *BasePath, const char *ClassPath
111 tSpiderNamespace *ns;
113 tSpiderObjectDef *class;
115 ns = SpiderScript_int_GetNamespace(Script, RootNamespace, BasePath, ClassPath, &name);
118 for( class = ns->Classes; class; class = class->Next )
120 if( strcmp(name, class->Name) == 0 )
128 * \brief Execute a script function
129 * \param Script Script context to execute in
130 * \param Namespace Namespace to search for the function
131 * \param Function Function name to execute
132 * \param NArguments Number of arguments to pass
133 * \param Arguments Arguments passed
135 tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
136 const char *Function,
137 const char *DefaultNamespaces[],
138 int NArguments, tSpiderValue **Arguments,
142 tSpiderValue *ret = ERRPTR;
143 tSpiderFunction *fcn = NULL;
146 // Scan list, Last item should always be NULL, so abuse that to check non-prefixed
147 for( i = 0; i == 0 || (DefaultNamespaces && DefaultNamespaces[i-1]); i ++ )
149 const char *ns = DefaultNamespaces ? DefaultNamespaces[i] : NULL;
150 fcn = SpiderScript_int_GetNativeFunction(Script, &Script->Variant->RootNamespace, ns, Function);
153 fcn = SpiderScript_int_GetNativeFunction(Script, &gExportNamespaceRoot, ns, Function);
156 // TODO: Script namespacing
159 // Search the variant's global exports
162 for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
164 if( strcmp( fcn->Name, Function ) == 0 )
169 // Fourth: Search language exports
172 for( fcn = gpExports_First; fcn; fcn = fcn->Next )
174 if( strcmp( fcn->Name, Function ) == 0 )
179 // Find the function in the script?
180 // TODO: Script namespacing
181 if( !fcn && strchr(Function, BC_NS_SEPARATOR) == NULL )
183 tScript_Function *sfcn;
184 for( sfcn = Script->Functions; sfcn; sfcn = sfcn->Next )
186 if( strcmp(sfcn->Name, Function) == 0 )
193 ret = Bytecode_ExecuteFunction(Script, sfcn, NArguments, Arguments);
195 ret = AST_ExecuteFunction(Script, sfcn, NArguments, Arguments);
197 if( FunctionIdent ) {
198 *FunctionIdent = sfcn;
199 // Abuses alignment requirements on almost all platforms
200 *(intptr_t*)FunctionIdent |= 1;
210 // TODO: Type Checking
211 ret = fcn->Handler( Script, NArguments, Arguments );
214 *FunctionIdent = fcn;
220 fprintf(stderr, "Undefined reference to function '%s'\n", Function);
226 * \brief Execute an object method function
227 * \param Script Script context to execute in
228 * \param Object Object in which to find the method
229 * \param MethodName Name of method to call
230 * \param NArguments Number of arguments to pass
231 * \param Arguments Arguments passed
233 tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
234 tSpiderObject *Object, const char *MethodName,
235 int NArguments, tSpiderValue **Arguments)
237 tSpiderFunction *fcn;
239 tSpiderValue *newargs[NArguments+1];
242 // TODO: Support program defined objects
244 // Search for the function
245 for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
247 if( strcmp(fcn->Name, MethodName) == 0 )
253 AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
254 Object->Type->Name, MethodName);
258 // Create the "this" argument
259 this.Type = SS_DATATYPE_OBJECT;
260 this.ReferenceCount = 1;
261 this.Object = Object;
263 memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
265 // Check the type of the arguments
266 for( i = 0; fcn->ArgTypes[i]; i ++ )
268 if( i >= NArguments ) {
269 for( ; fcn->ArgTypes[i]; i ++ ) ;
270 AST_RuntimeError(NULL, "Argument count mismatch (%i passed, %i expected)",
274 if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
276 AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
277 Arguments[i]->Type, fcn->ArgTypes[i]);
283 return fcn->Handler(Script, NArguments+1, newargs);
287 * \brief Execute a script function
288 * \param Script Script context to execute in
289 * \param Function Function name to execute
290 * \param NArguments Number of arguments to pass
291 * \param Arguments Arguments passed
293 tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
294 const char *ClassPath, const char *DefaultNamespaces[],
295 int NArguments, tSpiderValue **Arguments)
297 tSpiderValue *ret = ERRPTR;
298 tSpiderObjectDef *class;
301 // Scan list, Last item should always be NULL, so abuse that to check non-prefixed
302 for( i = 0; i == 0 || DefaultNamespaces[i-1]; i ++ )
304 const char *ns = DefaultNamespaces[i];
305 class = SpiderScript_int_GetNativeClass(Script, &Script->Variant->RootNamespace, ns, ClassPath);
308 class = SpiderScript_int_GetNativeClass(Script, &gExportNamespaceRoot, ns, ClassPath);
311 // TODO: Language defined classes
314 // First: Find the function in the script
315 // TODO: Implement script-defined classes
318 tAST_Function *astClass;
319 for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
321 if( strcmp(astClass->Name, ClassName) == 0 )
331 // Build a block State
335 bs.BaseNamespace = &Script->Variant->RootNamespace;
336 bs.CurNamespace = NULL;
338 bs.Ident = giNextBlockIdent ++;
340 for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
342 if( i >= NArguments ) break; // TODO: Return gracefully
345 arg->DefVar.DataType, arg->DefVar.Name,
350 ret = AST_ExecuteNode(&bs, astFcn->Code);
353 SpiderScript_DereferenceValue(ret); // Dereference output of last block statement
354 ret = bs.RetVal; // Set to return value of block
360 tAST_Variable *nextVar = bs.FirstVar->Next;
361 Variable_Destroy( bs.FirstVar );
362 bs.FirstVar = nextVar;
372 // TODO: Type Checking
375 obj = class->Constructor( NArguments, Arguments );
376 if( obj == NULL || obj == ERRPTR )
379 // Creatue return object
380 ret = malloc( sizeof(tSpiderValue) );
381 ret->Type = SS_DATATYPE_OBJECT;
382 ret->ReferenceCount = 1;
389 fprintf(stderr, "Undefined reference to class '%s'\n", ClassPath);
394 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
399 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
401 fprintf(stderr, "%s: ", Type);
402 va_start(args, Format);
403 vfprintf(stderr, Format, args);
405 fprintf(stderr, "\n");
407 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
412 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
414 fprintf(stderr, "error: ");
415 va_start(args, Format);
416 vfprintf(stderr, Format, args);
418 fprintf(stderr, "\n");