X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FLibraries%2Flibspiderscript.so_src%2Fexec_ast.c;h=7a94dc426f0b33096186ff38c59497fd91665e59;hb=c43c05ef3234d6118ce601d299df60383d54ac7b;hp=d4c7995f14f5b7b23abf8265efbeb891ac4c6f1a;hpb=239f2374299c1471a40b1087725b32f3f163d9b3;p=tpg%2Facess2.git diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c index d4c7995f..7a94dc42 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c @@ -14,7 +14,6 @@ #define TRACE_NODE_RETURNS 0 // === IMPORTS === -extern tSpiderFunction *gpExports_First; // === PROTOTYPES === // - Node Execution @@ -76,296 +75,6 @@ tSpiderValue *AST_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, return ret; } -/** - * \brief Execute a script function - * \param Script Script context to execute in - * \param Namespace Namespace to search for the function - * \param Function Function name to execute - * \param NArguments Number of arguments to pass - * \param Arguments Arguments passed - */ -tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script, - tSpiderNamespace *Namespace, const char *Function, - int NArguments, tSpiderValue **Arguments) -{ - int bFound = 0; // Used to keep nesting levels down - tSpiderValue *ret = ERRPTR; - - // First: Find the function in the script - { - tScript_Function *fcn; - for( fcn = Script->Functions; fcn; fcn = fcn->Next ) - { - if( strcmp(fcn->Name, Function) == 0 ) - break; - } - // Execute! - if(fcn) - { - ret = AST_ExecuteFunction(Script, fcn, NArguments, Arguments); - bFound = 1; - } - } - - // Didn't find it in script? - if(!bFound) - { - tSpiderFunction *fcn; - fcn = NULL; // Just to allow the below code to be neat - - // Second: Scan current namespace - if( !fcn && Namespace ) - { - for( fcn = Namespace->Functions; fcn; fcn = fcn->Next ) - { - if( strcmp( fcn->Name, Function ) == 0 ) - break; - } - } - - // Third: Search the variant's global exports - if( !fcn ) - { - for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next ) - { - if( strcmp( fcn->Name, Function ) == 0 ) - break; - } - } - - // Fourth: Search language exports - if( !fcn ) - { - for( fcn = gpExports_First; fcn; fcn = fcn->Next ) - { - if( strcmp( fcn->Name, Function ) == 0 ) - break; - } - } - - // Execute! - if(fcn) - { - // TODO: Type Checking - ret = fcn->Handler( Script, NArguments, Arguments ); - bFound = 1; - } - } - - // Not found? - if(!bFound) - { - fprintf(stderr, "Undefined reference to function '%s' (ns='%s')\n", - Function, Namespace->Name); - return ERRPTR; - } - - return ret; -} - -/** - * \brief Execute an object method function - * \param Script Script context to execute in - * \param Object Object in which to find the method - * \param MethodName Name of method to call - * \param NArguments Number of arguments to pass - * \param Arguments Arguments passed - */ -tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script, - tSpiderObject *Object, const char *MethodName, - int NArguments, tSpiderValue **Arguments) -{ - tSpiderFunction *fcn; - tSpiderValue this; - tSpiderValue *newargs[NArguments+1]; - int i; - - // TODO: Support program defined objects - - // Search for the function - for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next ) - { - if( strcmp(fcn->Name, MethodName) == 0 ) - break; - } - // Error - if( !fcn ) - { - AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'", - Object->Type->Name, MethodName); - return ERRPTR; - } - - // Create the "this" argument - this.Type = SS_DATATYPE_OBJECT; - this.ReferenceCount = 1; - this.Object = Object; - newargs[0] = &this; - memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*)); - - // Check the type of the arguments - for( i = 0; fcn->ArgTypes[i]; i ++ ) - { - if( i >= NArguments ) { - for( ; fcn->ArgTypes[i]; i ++ ) ; - AST_RuntimeError(NULL, "Argument count mismatch (%i passed, %i expected)", - NArguments, i); - return ERRPTR; - } - if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] ) - { - AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)", - Arguments[i]->Type, fcn->ArgTypes[i]); - return ERRPTR; - } - } - - // Call handler - return fcn->Handler(Script, NArguments+1, newargs); -} - -/** - * \brief Execute a script function - * \param Script Script context to execute in - * \param Function Function name to execute - * \param NArguments Number of arguments to pass - * \param Arguments Arguments passed - */ -tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script, - tSpiderNamespace *Namespace, const char *ClassName, - int NArguments, tSpiderValue **Arguments) -{ - int bFound = 0; // Used to keep nesting levels down - tSpiderValue *ret = ERRPTR; - tSpiderObjectDef *class; - - // First: Find the function in the script - // TODO: Implement script-defined classes - #if 0 - { - tAST_Function *astClass; - for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next ) - { - if( strcmp(astClass->Name, ClassName) == 0 ) - break; - } - // Execute! - if(astClass) - { - tAST_BlockState bs; - tAST_Node *arg; - int i = 0; - - // Build a block State - bs.FirstVar = NULL; - bs.RetVal = NULL; - bs.Parent = NULL; - bs.BaseNamespace = &Script->Variant->RootNamespace; - bs.CurNamespace = NULL; - bs.Script = Script; - bs.Ident = giNextBlockIdent ++; - - for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ ) - { - if( i >= NArguments ) break; // TODO: Return gracefully - // TODO: Type checks - Variable_Define(&bs, - arg->DefVar.DataType, arg->DefVar.Name, - Arguments[i]); - } - - // Execute function - ret = AST_ExecuteNode(&bs, astFcn->Code); - if( ret != ERRPTR ) - { - SpiderScript_DereferenceValue(ret); // Dereference output of last block statement - ret = bs.RetVal; // Set to return value of block - } - bFound = 1; - - while(bs.FirstVar) - { - tAST_Variable *nextVar = bs.FirstVar->Next; - Variable_Destroy( bs.FirstVar ); - bs.FirstVar = nextVar; - } - } - } - #endif - - // Didn't find it in script? - if(!bFound) - { - class = NULL; // Just to allow the below code to be neat - - //if( !Namespace ) - // Namespace = &Script->Variant->RootNamespace; - - // Second: Scan current namespace - if( !class && Namespace ) - { - for( class = Namespace->Classes; class; class = class->Next ) - { - if( strcmp( class->Name, ClassName ) == 0 ) - break; - } - } - - #if 0 - // Third: Search the variant's global exports - if( !class ) - { - for( class = Script->Variant->Classes; class; class = fcn->Next ) - { - if( strcmp( class->Name, Function ) == 0 ) - break; - } - } - #endif - - #if 0 - // Fourth: Search language exports - if( !class ) - { - for( class = gpExports_First; class; class = fcn->Next ) - { - if( strcmp( class->Name, ClassName ) == 0 ) - break; - } - } - #endif - - // Execute! - if(class) - { - tSpiderObject *obj; - // TODO: Type Checking - - // Call constructor - obj = class->Constructor( NArguments, Arguments ); - if( obj == NULL || obj == ERRPTR ) - return (void *)obj; - - // Creatue return object - ret = malloc( sizeof(tSpiderValue) ); - ret->Type = SS_DATATYPE_OBJECT; - ret->ReferenceCount = 1; - ret->Object = obj; - bFound = 1; - } - } - - // Not found? - if(!bFound) - { - fprintf(stderr, "Undefined reference to class '%s'\n", ClassName); - return ERRPTR; - } - - return ret; -} - - /** * \brief Execute an AST node and return its value * \param Block Execution context @@ -376,7 +85,6 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) tAST_Node *node; tSpiderValue *ret = NULL, *tmpobj; tSpiderValue *op1, *op2; // Binary operations - int cmp; // Used in comparisons int i; switch(Node->Type) @@ -862,113 +570,6 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) SpiderScript_DereferenceValue(op2); break; - // Comparisons - case NODETYPE_EQUALS: - case NODETYPE_LESSTHAN: - case NODETYPE_GREATERTHAN: - case NODETYPE_LESSTHANEQUAL: - case NODETYPE_GREATERTHANEQUAL: - op1 = AST_ExecuteNode(Block, Node->BinOp.Left); - if(op1 == ERRPTR) return ERRPTR; - op2 = AST_ExecuteNode(Block, Node->BinOp.Right); - if(op2 == ERRPTR) { - SpiderScript_DereferenceValue(op1); - ret = ERRPTR; - break; - } - - if( !op1 || !op2 ) { - AST_RuntimeError(Node, "NULL Comparison (%p and %p)", op1, op2); - if(op1) SpiderScript_DereferenceValue(op1); - if(op2) SpiderScript_DereferenceValue(op2); - ret = SpiderScript_CreateInteger( !op1 && !op2 ); - break; - } - - // Convert types - if( op1->Type != op2->Type ) { - // If dynamically typed, convert op2 to op1's type - if(Block->Script->Variant->bImplicitCasts) - { - tmpobj = op2; - op2 = SpiderScript_CastValueTo(op1->Type, op2); - SpiderScript_DereferenceValue(tmpobj); - if(op2 == ERRPTR) { - SpiderScript_DereferenceValue(op1); - return ERRPTR; - } - } - // If statically typed, this should never happen, but catch it anyway - else { - AST_RuntimeError(Node, "Statically typed implicit cast %i %i", - op1->Type, op2->Type); - ret = ERRPTR; - break; - } - } - // Do operation - switch(op1->Type) - { - // - String Compare (does a strcmp, well memcmp) - case SS_DATATYPE_STRING: - // Call memcmp to do most of the work - cmp = memcmp( - op1->String.Data, op2->String.Data, - (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length - ); - // Handle reaching the end of the string - if( cmp == 0 ) { - if( op1->String.Length == op2->String.Length ) - cmp = 0; - else if( op1->String.Length < op2->String.Length ) - cmp = 1; - else - cmp = -1; - } - break; - - // - Integer Comparisons - case SS_DATATYPE_INTEGER: - if( op1->Integer == op2->Integer ) - cmp = 0; - else if( op1->Integer < op2->Integer ) - cmp = -1; - else - cmp = 1; - break; - // - Real Number Comparisons - case SS_DATATYPE_REAL: - cmp = (op1->Real - op2->Real) / op2->Real * 10000; // < 0.1% difference is equality - break; - default: - AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type); - ret = ERRPTR; - break; - } - - // Free intermediate objects - SpiderScript_DereferenceValue(op1); - SpiderScript_DereferenceValue(op2); - - // Error check - if( ret == ERRPTR ) - break; - - // Create return - switch(Node->Type) - { - case NODETYPE_EQUALS: ret = SpiderScript_CreateInteger(cmp == 0); break; - case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0); break; - case NODETYPE_GREATERTHAN: ret = SpiderScript_CreateInteger(cmp > 0); break; - case NODETYPE_LESSTHANEQUAL: ret = SpiderScript_CreateInteger(cmp <= 0); break; - case NODETYPE_GREATERTHANEQUAL: ret = SpiderScript_CreateInteger(cmp >= 0); break; - default: - AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type); - ret = ERRPTR; - break; - } - break; - // General Unary Operations case NODETYPE_BWNOT: // Bitwise NOT (~) case NODETYPE_NEGATE: // Negation (-) @@ -990,6 +591,11 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) case NODETYPE_BITSHIFTLEFT: case NODETYPE_BITSHIFTRIGHT: case NODETYPE_BITROTATELEFT: + case NODETYPE_EQUALS: + case NODETYPE_LESSTHAN: + case NODETYPE_GREATERTHAN: + case NODETYPE_LESSTHANEQUAL: + case NODETYPE_GREATERTHANEQUAL: // Get operands op1 = AST_ExecuteNode(Block, Node->BinOp.Left); if(op1 == ERRPTR) return ERRPTR; @@ -1149,6 +755,88 @@ tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int if(Right && Right != preCastValue) free(Right); return NULL; } + + // Catch comparisons + switch(Operation) + { + case NODETYPE_EQUALS: + case NODETYPE_LESSTHAN: + case NODETYPE_GREATERTHAN: + case NODETYPE_LESSTHANEQUAL: + case NODETYPE_GREATERTHANEQUAL: { + int cmp; + ret = NULL; + // Do operation + switch(Left->Type) + { + // - String Compare (does a strcmp, well memcmp) + case SS_DATATYPE_STRING: + // Call memcmp to do most of the work + cmp = memcmp( + Left->String.Data, Right->String.Data, + (Left->String.Length < Right->String.Length) ? Left->String.Length : Right->String.Length + ); + // Handle reaching the end of the string + if( cmp == 0 ) { + if( Left->String.Length == Right->String.Length ) + cmp = 0; + else if( Left->String.Length < Right->String.Length ) + cmp = 1; + else + cmp = -1; + } + break; + + // - Integer Comparisons + case SS_DATATYPE_INTEGER: + if( Left->Integer == Right->Integer ) + cmp = 0; + else if( Left->Integer < Right->Integer ) + cmp = -1; + else + cmp = 1; + break; + // - Real Number Comparisons + case SS_DATATYPE_REAL: + cmp = (Left->Real - Right->Real) / Right->Real * 10000; // < 0.1% difference is equality + break; + default: + AST_RuntimeError(Node, "TODO - Comparison of type %i", Left->Type); + ret = ERRPTR; + break; + } + + // Error check + if( ret != ERRPTR ) + { + if(Left->ReferenceCount == 1 && Left->Type != SS_DATATYPE_STRING) + SpiderScript_ReferenceValue(ret = Left); + else + ret = SpiderScript_CreateInteger(0); + + // Create return + switch(Operation) + { + case NODETYPE_EQUALS: ret->Integer = (cmp == 0); break; + case NODETYPE_LESSTHAN: ret->Integer = (cmp < 0); break; + case NODETYPE_GREATERTHAN: ret->Integer = (cmp > 0); break; + case NODETYPE_LESSTHANEQUAL: ret->Integer = (cmp <= 0); break; + case NODETYPE_GREATERTHANEQUAL: ret->Integer = (cmp >= 0); break; + default: + AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Operation); + SpiderScript_DereferenceValue(ret); + ret = ERRPTR; + break; + } + } + if(Right && Right != preCastValue) free(Right); + return ret; + } + + // Fall through and sort by type instead + default: + break; + } // Do operation switch(Left->Type) @@ -1372,29 +1060,3 @@ void Variable_Destroy(tAST_Variable *Variable) free(Variable); } -void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...) -{ - va_list args; - - if(Node) { - fprintf(stderr, "%s:%i: ", Node->File, Node->Line); - } - fprintf(stderr, "%s: ", Type); - va_start(args, Format); - vfprintf(stderr, Format, args); - va_end(args); - fprintf(stderr, "\n"); -} -void AST_RuntimeError(tAST_Node *Node, const char *Format, ...) -{ - va_list args; - - if(Node) { - fprintf(stderr, "%s:%i: ", Node->File, Node->Line); - } - fprintf(stderr, "error: "); - va_start(args, Format); - vfprintf(stderr, Format, args); - va_end(args); - fprintf(stderr, "\n"); -}