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;
144 tScript_Function *sfcn;
147 if( FunctionIdent && *FunctionIdent ) {
148 if( *(intptr_t*)FunctionIdent & 1 ) {
149 sfcn = (void*)( *(intptr_t*)FunctionIdent & ~1 );
153 fcn = *FunctionIdent;
158 // Scan list, Last item should always be NULL, so abuse that to check non-prefixed
159 for( i = 0; i == 0 || (DefaultNamespaces && DefaultNamespaces[i-1]); i ++ )
161 const char *ns = DefaultNamespaces ? DefaultNamespaces[i] : NULL;
162 fcn = SpiderScript_int_GetNativeFunction(Script, &Script->Variant->RootNamespace, ns, Function);
165 fcn = SpiderScript_int_GetNativeFunction(Script, &gExportNamespaceRoot, ns, Function);
168 // TODO: Script namespacing
171 // Search the variant's global exports
174 for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
176 if( strcmp( fcn->Name, Function ) == 0 )
181 // Fourth: Search language exports
184 for( fcn = gpExports_First; fcn; fcn = fcn->Next )
186 if( strcmp( fcn->Name, Function ) == 0 )
191 // Find the function in the script?
192 // TODO: Script namespacing
193 if( !fcn && strchr(Function, BC_NS_SEPARATOR) == NULL )
195 for( sfcn = Script->Functions; sfcn; sfcn = sfcn->Next )
197 if( strcmp(sfcn->Name, Function) == 0 )
205 ret = Bytecode_ExecuteFunction(Script, sfcn, NArguments, Arguments);
207 ret = AST_ExecuteFunction(Script, sfcn, NArguments, Arguments);
209 if( FunctionIdent ) {
210 *FunctionIdent = sfcn;
211 // Abuses alignment requirements on almost all platforms
212 *(intptr_t*)FunctionIdent |= 1;
223 // TODO: Type Checking
224 ret = fcn->Handler( Script, NArguments, Arguments );
227 *FunctionIdent = fcn;
233 fprintf(stderr, "Undefined reference to function '%s'\n", Function);
239 * \brief Execute an object method function
240 * \param Script Script context to execute in
241 * \param Object Object in which to find the method
242 * \param MethodName Name of method to call
243 * \param NArguments Number of arguments to pass
244 * \param Arguments Arguments passed
246 tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
247 tSpiderObject *Object, const char *MethodName,
248 int NArguments, tSpiderValue **Arguments)
250 tSpiderFunction *fcn;
252 tSpiderValue *newargs[NArguments+1];
255 // TODO: Support program defined objects
257 // Search for the function
258 for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
260 if( strcmp(fcn->Name, MethodName) == 0 )
266 AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
267 Object->Type->Name, MethodName);
271 // Create the "this" argument
272 this.Type = SS_DATATYPE_OBJECT;
273 this.ReferenceCount = 1;
274 this.Object = Object;
276 memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
278 // Check the type of the arguments
279 for( i = 0; fcn->ArgTypes[i]; i ++ )
281 if( i >= NArguments ) {
282 for( ; fcn->ArgTypes[i]; i ++ ) ;
283 AST_RuntimeError(NULL, "Argument count mismatch (%i passed, %i expected)",
287 if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
289 AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
290 Arguments[i]->Type, fcn->ArgTypes[i]);
296 return fcn->Handler(Script, NArguments+1, newargs);
300 * \brief Execute a script function
301 * \param Script Script context to execute in
302 * \param Function Function name to execute
303 * \param NArguments Number of arguments to pass
304 * \param Arguments Arguments passed
306 tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
307 const char *ClassPath, const char *DefaultNamespaces[],
308 int NArguments, tSpiderValue **Arguments)
310 tSpiderValue *ret = ERRPTR;
311 tSpiderObjectDef *class;
314 // Scan list, Last item should always be NULL, so abuse that to check non-prefixed
315 for( i = 0; i == 0 || DefaultNamespaces[i-1]; i ++ )
317 const char *ns = DefaultNamespaces[i];
318 class = SpiderScript_int_GetNativeClass(Script, &Script->Variant->RootNamespace, ns, ClassPath);
321 class = SpiderScript_int_GetNativeClass(Script, &gExportNamespaceRoot, ns, ClassPath);
324 // TODO: Language defined classes
327 // First: Find the function in the script
328 // TODO: Implement script-defined classes
331 tAST_Function *astClass;
332 for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
334 if( strcmp(astClass->Name, ClassName) == 0 )
344 // Build a block State
348 bs.BaseNamespace = &Script->Variant->RootNamespace;
349 bs.CurNamespace = NULL;
351 bs.Ident = giNextBlockIdent ++;
353 for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
355 if( i >= NArguments ) break; // TODO: Return gracefully
358 arg->DefVar.DataType, arg->DefVar.Name,
363 ret = AST_ExecuteNode(&bs, astFcn->Code);
366 SpiderScript_DereferenceValue(ret); // Dereference output of last block statement
367 ret = bs.RetVal; // Set to return value of block
373 tAST_Variable *nextVar = bs.FirstVar->Next;
374 Variable_Destroy( bs.FirstVar );
375 bs.FirstVar = nextVar;
385 // TODO: Type Checking
388 obj = class->Constructor( NArguments, Arguments );
389 if( obj == NULL || obj == ERRPTR )
392 // Creatue return object
393 ret = malloc( sizeof(tSpiderValue) );
394 ret->Type = SS_DATATYPE_OBJECT;
395 ret->ReferenceCount = 1;
402 fprintf(stderr, "Undefined reference to class '%s'\n", ClassPath);
407 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
412 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
414 fprintf(stderr, "%s: ", Type);
415 va_start(args, Format);
416 vfprintf(stderr, Format, args);
418 fprintf(stderr, "\n");
420 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
425 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
427 fprintf(stderr, "error: ");
428 va_start(args, Format);
429 vfprintf(stderr, Format, args);
431 fprintf(stderr, "\n");