X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;ds=sidebyside;f=Usermode%2FLibraries%2Flibspiderscript.so_src%2Fast_to_bytecode.c;h=c45e7a51ffdb17515cfdc012d54a16ba6aa37581;hb=da93bf59c8d6d7cd4a5547f444197abf0490d399;hp=58cc5f822609c6b90aa0b8b78ec8c464db882db2;hpb=a18890d3ecb360989383d727017a21c103fee865;p=tpg%2Facess2.git diff --git a/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c b/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c index 58cc5f82..c45e7a51 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c +++ b/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c @@ -13,8 +13,9 @@ #include "bytecode_ops.h" #define TRACE_VAR_LOOKUPS 0 -#define TRACE_NODE_RETURNS 0 +#define TRACE_TYPE_STACK 0 #define MAX_NAMESPACE_DEPTH 10 +#define MAX_STACK_DEPTH 10 // This is for one function, so shouldn't need more // === IMPORTS === extern tSpiderFunction *gpExports_First; @@ -28,20 +29,31 @@ typedef struct sAST_BlockInfo int BreakTarget; int ContinueTarget; - + + int NamespaceDepth; const char *CurNamespaceStack[MAX_NAMESPACE_DEPTH]; + + int StackDepth; + int Stack[MAX_STACK_DEPTH]; // Stores types of stack values + + tAST_Variable *FirstVar; } tAST_BlockInfo; // === PROTOTYPES === // Node Traversal int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue); + int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode); // Variables int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name); int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode); int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode); +void BC_Variable_Clear(tAST_BlockInfo *Block); // - Errors void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...); void AST_RuntimeError(tAST_Node *Node, const char *Format, ...); +// - Type stack + int _StackPush(tAST_BlockInfo *Block, tAST_Node *Node, int Type); + int _StackPop(tAST_BlockInfo *Block, tAST_Node *Node, int WantedType); // === GLOBALS === // int giNextBlockIdent = 1; @@ -65,6 +77,7 @@ tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn) { tBC_Function *ret; tAST_BlockInfo bi = {0}; + int i; // TODO: Return BCFcn instead? if(Fcn->BCFcn) return Fcn->BCFcn; @@ -73,11 +86,22 @@ tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn) if(!ret) return NULL; bi.Handle = ret; + + // Parse arguments + for( i = 0; i < Fcn->ArgumentCount; i ++ ) + { + BC_Variable_Define(&bi, Fcn->Arguments[i].Type, Fcn->Arguments[i].Name); + } + if( AST_ConvertNode(&bi, Fcn->ASTFcn, 0) ) { + AST_RuntimeError(Fcn->ASTFcn, "Error in converting function"); Bytecode_DeleteFunction(ret); + BC_Variable_Clear(&bi); return NULL; } + BC_Variable_Clear(&bi); + Bytecode_AppendConstInt(ret, 0); // TODO: NULL Bytecode_AppendReturn(ret); @@ -90,6 +114,7 @@ tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn) #define CHECK_IF_NEEDED(b_warn) do { if(!bKeepValue) {\ if(b_warn)AST_RuntimeMessage(Node, "Bytecode", "Operation without saving");\ Bytecode_AppendDelete(Block->Handle);\ + _StackPop(Block, Node, SS_DATATYPE_UNDEF);\ } } while(0) /** @@ -123,28 +148,37 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) node; node = node->NextSibling ) { - AST_ConvertNode(Block, node, 0); + ret = AST_ConvertNode(&blockInfo, node, 0); + if(ret) return ret; + if( blockInfo.StackDepth != 0 ) { + AST_RuntimeError(node, "Stack not reset at end of node"); + blockInfo.StackDepth = 0; + } } + + BC_Variable_Clear(&blockInfo); } Bytecode_AppendLeaveContext(Block->Handle); // Leave this context break; // Assignment case NODETYPE_ASSIGN: - // TODO: Support assigning to object attributes - if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) { - AST_RuntimeError(Node, "LVALUE of assignment is not a variable"); - return -1; - } - // Perform assignment operation if( Node->Assign.Operation != NODETYPE_NOP ) { + int t1, t2; - ret = BC_Variable_GetValue(Block, Node->Assign.Dest); + ret = AST_ConvertNode(Block, Node->Assign.Dest, 1); if(ret) return ret; + t1 = _StackPop(Block, Node, SS_DATATYPE_UNDEF); + if(t1 < 0) return -1; + ret = AST_ConvertNode(Block, Node->Assign.Value, 1); if(ret) return ret; + t2 = _StackPop(Block, Node, SS_DATATYPE_UNDEF); + if(t2 < 0) return -1; + + switch(Node->Assign.Operation) { // General Binary Operations @@ -164,7 +198,9 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation); break; } - printf("assign, op = %i\n", op); +// printf("assign, op = %i\n", op); + ret = _StackPush(Block, Node, t1); + if(ret < 0) return -1; Bytecode_AppendBinOp(Block->Handle, op); } else @@ -173,21 +209,23 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) if(ret) return ret; } - if( bKeepValue ) + if( bKeepValue ) { + ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF); + if(ret < 0) return -1; + ret = _StackPush(Block, Node, ret); + if(ret < 0) return -1; + ret = _StackPush(Block, Node, ret); + if(ret < 0) return -1; Bytecode_AppendDuplicate(Block->Handle); - // Set the variable value - ret = BC_Variable_SetValue( Block, Node->Assign.Dest ); + } + + ret = BC_SaveValue(Block, Node->Assign.Dest); + if(ret) return ret; break; // Post increment/decrement case NODETYPE_POSTINC: case NODETYPE_POSTDEC: - // TODO: Support assigning to object attributes - if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) { - AST_RuntimeError(Node, "LVALUE of assignment is not a variable"); - return -1; - } - // Save original value if requested if(bKeepValue) { ret = BC_Variable_GetValue(Block, Node->UniOp.Value); @@ -195,75 +233,104 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) } Bytecode_AppendConstInt(Block->Handle, 1); + ret = _StackPush(Block, Node, SS_DATATYPE_INTEGER); + if(ret < 0) return -1; - ret = BC_Variable_GetValue(Block, Node->UniOp.Value); + ret = AST_ConvertNode(Block, Node->UniOp.Value, 1); if(ret) return ret; if( Node->Type == NODETYPE_POSTDEC ) Bytecode_AppendBinOp(Block->Handle, BC_OP_SUBTRACT); else Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD); - if(ret) return ret; - - ret = BC_Variable_SetValue(Block, Node->UniOp.Value); + ret = _StackPop(Block, Node, SS_DATATYPE_INTEGER); // TODO: Check for objects too + if(ret < 0) return -1; + ret = BC_SaveValue(Block, Node->UniOp.Value); if(ret) return ret; - // Doesn't push unless needed break; - + // Function Call - case NODETYPE_METHODCALL: - case NODETYPE_FUNCTIONCALL: - case NODETYPE_CREATEOBJECT: { + case NODETYPE_METHODCALL: { int nargs = 0; + + ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1); + if(ret) return ret; - // Put the object earlier on the stack to the arguments (for exec) - if( Node->Type == NODETYPE_METHODCALL ) { - ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1); + // Push arguments to the stack + for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) + { + ret = AST_ConvertNode(Block, node, 1); if(ret) return ret; - } + nargs ++; + + // TODO: Check arguments? Need to get the types somehow + ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF); + if(ret < 0) return -1; + } + + ret = _StackPop(Block, Node, SS_DATATYPE_OBJECT); + if(ret < 0) return -1; + Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs); + ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF); + if(ret < 0) return -1; + + CHECK_IF_NEEDED(0); // Don't warn + // TODO: Implement warn_unused_ret + + } break; + case NODETYPE_FUNCTIONCALL: + case NODETYPE_CREATEOBJECT: { + int nargs = 0; + + // Get name (mangled into a single string) + int newnamelen = 0; + char *manglename; + for( i = 0; i < Block->NamespaceDepth; i ++ ) + newnamelen += strlen(Block->CurNamespaceStack[i]) + 1; + newnamelen += strlen(Node->FunctionCall.Name) + 1; +// newnamelen += 1; + + manglename = alloca(newnamelen); + newnamelen = 0; + for( i = 0; i < Block->NamespaceDepth; i ++ ) { + strcpy(manglename+newnamelen, Block->CurNamespaceStack[i]); + newnamelen += strlen(Block->CurNamespaceStack[i]) + 1; + manglename[ newnamelen - 1 ] = BC_NS_SEPARATOR; + } + strcpy(manglename + newnamelen, Node->FunctionCall.Name); + newnamelen += strlen(Node->FunctionCall.Name) + 1; +// manglename[ newnamelen ] = '\0'; // Zero length terminator + Block->NamespaceDepth = 0; + + // Push arguments to the stack for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) { + // TODO: Type Checking ret = AST_ConvertNode(Block, node, 1); if(ret) return ret; nargs ++; + + // TODO: Check arguments? Need to get the types somehow + ret = _StackPop(Block, node, SS_DATATYPE_UNDEF); + if(ret < 0) return -1; } // Call the function - if( Node->Type == NODETYPE_METHODCALL ) + if( Node->Type == NODETYPE_CREATEOBJECT ) { - // TODO: Sanity check stack top - Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs); + Bytecode_AppendCreateObj(Block->Handle, manglename, nargs); } else { - int newnamelen = 0; - char *manglename; - for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ ) - newnamelen = strlen(Block->CurNamespaceStack[i]) + 1; - newnamelen += strlen(Node->FunctionCall.Name) + 1; - manglename = alloca(newnamelen); - manglename[0] = 0; - for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ ) { - int pos; - strcat(manglename, Block->CurNamespaceStack[i]); - pos = strlen(manglename); - manglename[pos] = BC_NS_SEPARATOR; - manglename[pos+1] = '\0'; - } - strcat(manglename, Node->FunctionCall.Name); - - if( Node->Type == NODETYPE_CREATEOBJECT ) - { - // TODO: Sanity check stack top - Bytecode_AppendCreateObj(Block->Handle, manglename, nargs); - } - else - { - Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs); - } + Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs); } + + // TODO: Get return type + ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF); + if(ret < 0) return -1; + CHECK_IF_NEEDED(0); // Don't warn // TODO: Implement warn_unused_ret } break; @@ -273,6 +340,9 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) int if_end; ret = AST_ConvertNode(Block, Node->If.Condition, 1); if(ret) return ret; + // TODO: Should be boolean/integer, but meh + ret = _StackPop(Block, Node->If.Condition, SS_DATATYPE_UNDEF); + if(ret < 0) return -1; if_end = Bytecode_AllocateLabel(Block->Handle); @@ -303,7 +373,7 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) // Loop case NODETYPE_LOOP: { - int loop_start, loop_end; + int loop_start, loop_end, code_end; int saved_break, saved_continue; const char *saved_tag; @@ -312,13 +382,14 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) if(ret) return ret; loop_start = Bytecode_AllocateLabel(Block->Handle); + code_end = Bytecode_AllocateLabel(Block->Handle); loop_end = Bytecode_AllocateLabel(Block->Handle); saved_break = Block->BreakTarget; saved_continue = Block->ContinueTarget; saved_tag = Block->Tag; Block->BreakTarget = loop_end; - Block->ContinueTarget = loop_end; + Block->ContinueTarget = code_end; Block->Tag = Node->For.Tag; Bytecode_SetLabel(Block->Handle, loop_start); @@ -329,22 +400,30 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) ret = AST_ConvertNode(Block, Node->For.Condition, 1); if(ret) return ret; Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT); + ret = _StackPop(Block, Node->For.Condition, SS_DATATYPE_UNDEF); // Boolean? + if(ret < 0) return -1; Bytecode_AppendCondJump(Block->Handle, loop_end); } // Code ret = AST_ConvertNode(Block, Node->For.Code, 0); if(ret) return ret; - + + Bytecode_SetLabel(Block->Handle, code_end); + // Increment ret = AST_ConvertNode(Block, Node->For.Increment, 0); if(ret) return ret; +// ret = _StackPop(Block, Node->For.Increment, SS_DATATYPE_UNDEF); // TODO: Check if needed +// if(ret < 0) return -1; // Tail check if( Node->For.bCheckAfter ) { ret = AST_ConvertNode(Block, Node->For.Condition, 1); if(ret) return ret; + ret = _StackPop(Block, Node->If.Condition, SS_DATATYPE_UNDEF); // Boolean? + if(ret < 0) return ret; Bytecode_AppendCondJump(Block->Handle, loop_start); } else @@ -364,13 +443,20 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) ret = AST_ConvertNode(Block, Node->UniOp.Value, 1); if(ret) return ret; Bytecode_AppendReturn(Block->Handle); + ret = _StackPop(Block, Node->UniOp.Value, SS_DATATYPE_UNDEF); // + if(ret < 0) return -1; break; case NODETYPE_BREAK: case NODETYPE_CONTINUE: { tAST_BlockInfo *bi = Block; if( Node->Variable.Name[0] ) { - while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0) bi = bi->Parent; + while(bi && (!bi->Tag || strcmp(bi->Tag, Node->Variable.Name) != 0)) + bi = bi->Parent; + } + else { + while(bi && !bi->Tag) + bi = bi->Parent; } if( !bi ) return 1; // TODO: Check if BreakTarget/ContinueTarget are valid @@ -389,28 +475,33 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) { ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1); if(ret) return ret; + ret = _StackPop(Block, Node->DefVar.InitialValue, Node->DefVar.DataType); + if(ret < 0) return -1; Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name); } break; // Scope case NODETYPE_SCOPE: - for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ ); - if( i == MAX_NAMESPACE_DEPTH ) { - AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", i); + if( Block->NamespaceDepth == MAX_NAMESPACE_DEPTH ) { + AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", MAX_NAMESPACE_DEPTH); return 2; } - Block->CurNamespaceStack[i] = Node->Scope.Name; - ret = AST_ConvertNode(Block, Node->Scope.Element, 2); - Block->CurNamespaceStack[i] = NULL; - CHECK_IF_NEEDED(0); // No warning? - // TODO: Will this collide with _CALLFUNCTION etc? + Block->CurNamespaceStack[ Block->NamespaceDepth ] = Node->Scope.Name; + Block->NamespaceDepth ++; + ret = AST_ConvertNode(Block, Node->Scope.Element, bKeepValue); + if(ret) return ret; + if( Block->NamespaceDepth != 0 ) { + AST_RuntimeError(Node, "Namespace scope used but no element at the end"); + } + bAddedValue = 0; break; // Variable case NODETYPE_VARIABLE: ret = BC_Variable_GetValue( Block, Node ); CHECK_IF_NEEDED(1); + if(ret) return ret; break; // Element of an Object @@ -418,7 +509,15 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) ret = AST_ConvertNode( Block, Node->Scope.Element, 1 ); if(ret) return ret; + // TODO: Support elements for non-objects + ret = _StackPop(Block, Node, SS_DATATYPE_OBJECT); + if(ret < 0) return -1; + Bytecode_AppendElement(Block->Handle, Node->Scope.Name); + + // TODO: Somehow know this at compile time? + ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF); + if(ret < 0) return -1; CHECK_IF_NEEDED(1); break; @@ -426,18 +525,45 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) case NODETYPE_CAST: ret = AST_ConvertNode(Block, Node->Cast.Value, 1); if(ret) return ret; + ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF); + if(ret < 0) return -1; + Bytecode_AppendCast(Block->Handle, Node->Cast.DataType); + ret = _StackPush(Block, Node, Node->Cast.DataType); + if(ret < 0) return -1; CHECK_IF_NEEDED(1); break; // Index into an array case NODETYPE_INDEX: - ret = AST_ConvertNode(Block, Node->BinOp.Left, 1); // Array + // - Array + ret = AST_ConvertNode(Block, Node->BinOp.Left, 1); if(ret) return ret; - ret = AST_ConvertNode(Block, Node->BinOp.Right, 1); // Offset + // > Type check + ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF); + if(ret < 0) return -1; + if(ret != SS_DATATYPE_ARRAY && SS_GETARRAYDEPTH(ret) == 0) { + AST_RuntimeError(Node, "Type mismatch, Expected an array, got %i", + ret); + return -2; + } + i = ret; // Hackily save the datatype + + // - Offset + ret = AST_ConvertNode(Block, Node->BinOp.Right, 1); if(ret) return ret; + ret = _StackPop(Block, Node, SS_DATATYPE_INTEGER); + if(ret < 0) return -1; Bytecode_AppendIndex(Block->Handle); + + // Update the array depth + if( i != SS_DATATYPE_ARRAY ) { + i = SS_DOWNARRAY(i); // Decrease the array level + } + ret = _StackPush(Block, Node, i); + if(ret < 0) return -1; + CHECK_IF_NEEDED(1); break; @@ -445,23 +571,35 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) case NODETYPE_CONSTANT: // TODO: Scan namespace for constant name AST_RuntimeError(Node, "TODO - Runtime Constants"); - ret = -1; - break; + Block->NamespaceDepth = 0; + return -1; // Constant Values case NODETYPE_STRING: Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length); + ret = _StackPush(Block, Node, SS_DATATYPE_STRING); + if(ret < 0) return -1; CHECK_IF_NEEDED(1); break; case NODETYPE_INTEGER: Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer); + ret = _StackPush(Block, Node, SS_DATATYPE_INTEGER); + if(ret < 0) return -1; CHECK_IF_NEEDED(1); break; case NODETYPE_REAL: Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real); + ret = _StackPush(Block, Node, SS_DATATYPE_REAL); + if(ret < 0) return -1; CHECK_IF_NEEDED(1); break; - + case NODETYPE_NULL: + Bytecode_AppendConstNull(Block->Handle); + ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF); + if(ret < 0) return -1; + CHECK_IF_NEEDED(1); + break; + // --- Operations --- // Boolean Operations case NODETYPE_LOGICALNOT: // Logical NOT (!) @@ -472,7 +610,13 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) if(!op) op = BC_OP_NEG; ret = AST_ConvertNode(Block, Node->UniOp.Value, 1); if(ret) return ret; + ret = _StackPop(Block, Node->UniOp.Value, SS_DATATYPE_UNDEF); // TODO: Integer/Real/Undef + if(ret < 0) return -1; + Bytecode_AppendUniOp(Block->Handle, op); + ret = _StackPush(Block, Node, ret); // TODO: Logic = _INTEGER, Neg = No change + if(ret < 0) return -1; + CHECK_IF_NEEDED(1); break; @@ -481,8 +625,9 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) case NODETYPE_LOGICALOR: if(!op) op = BC_OP_LOGICOR; case NODETYPE_LOGICALXOR: if(!op) op = BC_OP_LOGICXOR; // Comparisons - case NODETYPE_EQUALS: if(!op) op = BC_OP_EQUALS; - case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN; + case NODETYPE_EQUALS: if(!op) op = BC_OP_EQUALS; + case NODETYPE_NOTEQUALS: if(!op) op = BC_OP_NOTEQUALS; + case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN; case NODETYPE_GREATERTHAN: if(!op) op = BC_OP_GREATERTHAN; case NODETYPE_LESSTHANEQUAL: if(!op) op = BC_OP_LESSTHANOREQUAL; case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL; @@ -500,29 +645,74 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) case NODETYPE_BITROTATELEFT: if(!op) op = BC_OP_BITROTATELEFT; ret = AST_ConvertNode(Block, Node->BinOp.Left, 1); if(ret) return ret; + ret = _StackPop(Block, Node->BinOp.Left, SS_DATATYPE_UNDEF); // TODO: Integer/Real/Object + if(ret < 0) return -1; + ret = AST_ConvertNode(Block, Node->BinOp.Right, 1); if(ret) return ret; - + ret = _StackPop(Block, Node->BinOp.Right, SS_DATATYPE_UNDEF); // TODO: Integer/Real/Object + if(ret < 0) return -1; + Bytecode_AppendBinOp(Block->Handle, op); + _StackPush(Block, Node, ret); CHECK_IF_NEEDED(1); break; default: - ret = -1; AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type); - break; + return -1; } - #if TRACE_NODE_RETURNS - if(ret && ret != ERRPTR) { - AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type); - } - else { - AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret); - } - #endif + return 0; +} - return ret; +int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode) +{ + int ret, type; + switch(DestNode->Type) + { + // Variable, simple + case NODETYPE_VARIABLE: + ret = BC_Variable_SetValue( Block, DestNode ); + if(ret) return ret; + break; + // Array index + case NODETYPE_INDEX: + ret = AST_ConvertNode(Block, DestNode->BinOp.Left, 1); // Array + if(ret) return ret; + ret = _StackPop(Block, DestNode->BinOp.Left, SS_DATATYPE_UNDEF); + if(ret < 0) return -1; + if(ret != SS_DATATYPE_ARRAY && SS_GETARRAYDEPTH(ret) == 0) { + AST_RuntimeError(DestNode, "Type mismatch, Expected an array, got %i", + ret); + return -2; + } + type = SS_DOWNARRAY(ret); + + ret = AST_ConvertNode(Block, DestNode->BinOp.Right, 1); // Offset + if(ret) return ret; + ret = _StackPop(Block, DestNode->BinOp.Right, SS_DATATYPE_INTEGER); + if(ret < 0) return -1; + + Bytecode_AppendSetIndex( Block->Handle ); + _StackPop(Block, DestNode, type); + break; + // Object element + case NODETYPE_ELEMENT: + ret = AST_ConvertNode(Block, DestNode->Scope.Element, 1); + if(ret) return ret; + ret = _StackPop(Block, DestNode->Scope.Element, SS_DATATYPE_OBJECT); + if(ret < 0) return -1; + + Bytecode_AppendSetElement( Block->Handle, DestNode->Scope.Name ); + break; + // Anything else + default: + // TODO: Support assigning to object attributes + AST_RuntimeError(DestNode, "Assignment target is not a LValue"); + return -1; + } + return 0; } /** @@ -534,14 +724,13 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) */ int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name) { - #if 0 tAST_Variable *var, *prev = NULL; for( var = Block->FirstVar; var; prev = var, var = var->Next ) { if( strcmp(var->Name, Name) == 0 ) { AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name); - return ERRPTR; + return -1; } } @@ -553,69 +742,44 @@ int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name) if(prev) prev->Next = var; else Block->FirstVar = var; - return var; - #else Bytecode_AppendDefineVar(Block->Handle, Name, Type); return 0; - #endif } tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType) { - #if 0 tAST_Variable *var = NULL; + tAST_BlockInfo *bs; - // Speed hack - if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) { - var = VarNode->ValueCache; - #if TRACE_VAR_LOOKUPS - AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)", - VarNode->Variable.Name, var, - VarNode->BlockState, VarNode->BlockIdent - ); - #endif - } - else + for( bs = Block; bs; bs = bs->Parent ) { - tAST_BlockInfo *bs; - for( bs = Block; bs; bs = bs->Parent ) - { - for( var = bs->FirstVar; var; var = var->Next ) - { - if( strcmp(var->Name, VarNode->Variable.Name) == 0 ) - break; - } - if(var) break; - } - - if( !var ) + for( var = bs->FirstVar; var; var = var->Next ) { - if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) { - // Define variable - var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL); - } - else - { - AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name); - return NULL; - } + if( strcmp(var->Name, VarNode->Variable.Name) == 0 ) + break; } - - #if TRACE_VAR_LOOKUPS - AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)", - VarNode->Variable.Name, var, - Block, Block->Ident); - #endif - - VarNode->ValueCache = var; - VarNode->BlockState = Block; - VarNode->BlockIdent = Block->Ident; + if(var) break; + } + + if( !var ) + { +// if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) { +// // Define variable +// var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL); +// } +// else +// { + AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name); + return NULL; +// } } + + #if TRACE_VAR_LOOKUPS + AST_RuntimeMessage(VarNode, "debug", "Variable lookup of '%s' %p type %i", + VarNode->Variable.Name, var, var->Type); + #endif return var; - #else - return (void*)1; - #endif } /** @@ -626,11 +790,13 @@ int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode) { tAST_Variable *var; + // TODO: Implicit definition type var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF); if(!var) return -1; // TODO: Check types + _StackPop(Block, VarNode, var->Type); Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name); return 0; } @@ -645,10 +811,23 @@ int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode) var = BC_Variable_Lookup(Block, VarNode, 0); if(!var) return -1; + _StackPush(Block, VarNode, var->Type); Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name); return 0; } +void BC_Variable_Clear(tAST_BlockInfo *Block) +{ + tAST_Variable *var; + for( var = Block->FirstVar; var; ) + { + tAST_Variable *tv = var->Next; + free( var ); + var = tv; + } + Block->FirstVar = NULL; +} + #if 0 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...) { @@ -677,3 +856,42 @@ void AST_RuntimeError(tAST_Node *Node, const char *Format, ...) fprintf(stderr, "\n"); } #endif + +int _StackPush(tAST_BlockInfo *Block, tAST_Node *Node, int Type) +{ + if(Block->StackDepth == MAX_STACK_DEPTH - 1) { + AST_RuntimeError(Node, "BUG - Stack overflow in AST-Bytecode conversion (node=%i)", + Node->Type); + return -1; + } + + #if TRACE_TYPE_STACK + AST_RuntimeMessage(Node, "_StackPush", "%x - NT%i", Type, Node->Type); + #endif + Block->Stack[ ++Block->StackDepth ] = Type; + return Type; +} + +int _StackPop(tAST_BlockInfo *Block, tAST_Node *Node, int WantedType) +{ + if(Block->StackDepth == 0) { + AST_RuntimeError(Node, "BUG - Stack underflow in AST-Bytecode conversion (node=%i)", + Node->Type); + return -1; + } + #if TRACE_TYPE_STACK + AST_RuntimeMessage(Node, "_StackPop", "%x(?==%x) - NT%i", + Block->Stack[ Block->StackDepth ], WantedType, Node->Type); + #endif + if(WantedType != SS_DATATYPE_UNDEF && Block->Stack[ Block->StackDepth ] != SS_DATATYPE_UNDEF) + { + if( Block->Stack[ Block->StackDepth ] != WantedType ) { + AST_RuntimeError(Node, "AST-Bytecode - Type mismatch (wanted %x got %x)", + WantedType, Block->Stack[ Block->StackDepth ]); + // TODO: Message? + return -2; + } + } + return Block->Stack[Block->StackDepth--]; +} +