3 * by John Hodge (thePowersGang)
6 * - Generate a bytecode file
15 #define BC_NS_SEPARATOR '@'
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);
23 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
24 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
27 void *SpiderScript_int_GetNamespace(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
28 const char *BasePath, const char *ItemPath,
37 tSpiderNamespace *lastns, *ns;
39 // Prepend the base namespace
50 lastns = RootNamespace;
52 end = strchr(name, BC_NS_SEPARATOR);
63 // Check for this level
64 for( ns = lastns->FirstChild; ns; ns = ns->Next )
66 if( strncmp(name, ns->Name, len) == 0 && ns->Name[len] == 0 )
72 if(!end && !bTriedBase) {
73 end = ItemPath - 1; // -1 to counter (name = end + 1)
86 tSpiderFunction *SpiderScript_int_GetNativeFunction(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
87 const char *BasePath, const char *FunctionPath)
93 ns = SpiderScript_int_GetNamespace(Script, RootNamespace, BasePath, FunctionPath, &name);
96 for( fcn = ns->Functions; fcn; fcn = fcn->Next )
98 if( strcmp(name, fcn->Name) == 0 )
105 tSpiderObjectDef *SpiderScript_int_GetNativeClass(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
106 const char *BasePath, const char *ClassPath
109 tSpiderNamespace *ns;
111 tSpiderObjectDef *class;
113 ns = SpiderScript_int_GetNamespace(Script, RootNamespace, BasePath, ClassPath, &name);
116 for( class = ns->Classes; class; class = class->Next )
118 if( strcmp(name, class->Name) == 0 )
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
133 tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
134 const char *Function,
135 const char *DefaultNamespaces[],
136 int NArguments, tSpiderValue **Arguments,
140 tSpiderValue *ret = ERRPTR;
141 tSpiderFunction *fcn = NULL;
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 ++ )
147 const char *ns = DefaultNamespaces ? DefaultNamespaces[i] : NULL;
148 fcn = SpiderScript_int_GetNativeFunction(Script, &Script->Variant->RootNamespace,
152 // TODO: Script namespacing
155 // Search the variant's global exports
158 for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
160 if( strcmp( fcn->Name, Function ) == 0 )
165 // Fourth: Search language exports
168 for( fcn = gpExports_First; fcn; fcn = fcn->Next )
170 if( strcmp( fcn->Name, Function ) == 0 )
175 // Find the function in the script?
176 // TODO: Script namespacing
177 if( !fcn && strchr(Function, BC_NS_SEPARATOR) == NULL )
179 tScript_Function *sfcn;
180 for( sfcn = Script->Functions; sfcn; sfcn = sfcn->Next )
182 if( strcmp(sfcn->Name, Function) == 0 )
189 ret = Bytecode_ExecuteFunction(Script, sfcn, NArguments, Arguments);
191 ret = AST_ExecuteFunction(Script, sfcn, NArguments, Arguments);
193 if( FunctionIdent ) {
194 *FunctionIdent = sfcn;
195 // Abuses alignment requirements on almost all platforms
196 *(intptr_t*)FunctionIdent |= 1;
206 // TODO: Type Checking
207 ret = fcn->Handler( Script, NArguments, Arguments );
210 *FunctionIdent = fcn;
216 fprintf(stderr, "Undefined reference to function '%s'\n", Function);
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
229 tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
230 tSpiderObject *Object, const char *MethodName,
231 int NArguments, tSpiderValue **Arguments)
233 tSpiderFunction *fcn;
235 tSpiderValue *newargs[NArguments+1];
238 // TODO: Support program defined objects
240 // Search for the function
241 for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
243 if( strcmp(fcn->Name, MethodName) == 0 )
249 AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
250 Object->Type->Name, MethodName);
254 // Create the "this" argument
255 this.Type = SS_DATATYPE_OBJECT;
256 this.ReferenceCount = 1;
257 this.Object = Object;
259 memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
261 // Check the type of the arguments
262 for( i = 0; fcn->ArgTypes[i]; i ++ )
264 if( i >= NArguments ) {
265 for( ; fcn->ArgTypes[i]; i ++ ) ;
266 AST_RuntimeError(NULL, "Argument count mismatch (%i passed, %i expected)",
270 if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
272 AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
273 Arguments[i]->Type, fcn->ArgTypes[i]);
279 return fcn->Handler(Script, NArguments+1, newargs);
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
289 tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
290 const char *ClassPath, const char *DefaultNamespaces[],
291 int NArguments, tSpiderValue **Arguments)
293 tSpiderValue *ret = ERRPTR;
294 tSpiderObjectDef *class;
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 ++ )
300 class = SpiderScript_int_GetNativeClass(Script, &Script->Variant->RootNamespace,
301 DefaultNamespaces[i], ClassPath);
302 if( class != NULL ) break;
304 // TODO: Language defined classes
307 // First: Find the function in the script
308 // TODO: Implement script-defined classes
311 tAST_Function *astClass;
312 for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
314 if( strcmp(astClass->Name, ClassName) == 0 )
324 // Build a block State
328 bs.BaseNamespace = &Script->Variant->RootNamespace;
329 bs.CurNamespace = NULL;
331 bs.Ident = giNextBlockIdent ++;
333 for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
335 if( i >= NArguments ) break; // TODO: Return gracefully
338 arg->DefVar.DataType, arg->DefVar.Name,
343 ret = AST_ExecuteNode(&bs, astFcn->Code);
346 SpiderScript_DereferenceValue(ret); // Dereference output of last block statement
347 ret = bs.RetVal; // Set to return value of block
353 tAST_Variable *nextVar = bs.FirstVar->Next;
354 Variable_Destroy( bs.FirstVar );
355 bs.FirstVar = nextVar;
365 // TODO: Type Checking
368 obj = class->Constructor( NArguments, Arguments );
369 if( obj == NULL || obj == ERRPTR )
372 // Creatue return object
373 ret = malloc( sizeof(tSpiderValue) );
374 ret->Type = SS_DATATYPE_OBJECT;
375 ret->ReferenceCount = 1;
382 fprintf(stderr, "Undefined reference to class '%s'\n", ClassPath);
387 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
392 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
394 fprintf(stderr, "%s: ", Type);
395 va_start(args, Format);
396 vfprintf(stderr, Format, args);
398 fprintf(stderr, "\n");
400 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
405 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
407 fprintf(stderr, "error: ");
408 va_start(args, Format);
409 vfprintf(stderr, Format, args);
411 fprintf(stderr, "\n");