case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
- case NODETYPE_EQUALS:
+ case NODETYPE_EQUALS: case NODETYPE_NOTEQUALS:
case NODETYPE_LESSTHAN: case NODETYPE_LESSTHANEQUAL:
case NODETYPE_GREATERTHAN: case NODETYPE_GREATERTHANEQUAL:
Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Left);
case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
- case NODETYPE_EQUALS:
+ case NODETYPE_EQUALS: case NODETYPE_NOTEQUALS:
case NODETYPE_LESSTHAN: case NODETYPE_LESSTHANEQUAL:
case NODETYPE_GREATERTHAN: case NODETYPE_GREATERTHANEQUAL:
AST_FreeNode( Node->BinOp.Left );
{
tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_ASSIGN, 0);
- if( Dest->Type != NODETYPE_VARIABLE && Dest->Type != NODETYPE_ELEMENT ) {
+ if( Dest->Type != NODETYPE_VARIABLE && Dest->Type != NODETYPE_ELEMENT && Dest->Type != NODETYPE_INDEX )
+ {
free(ret);
SyntaxError(Parser, 1, "Assign target is not a variable or attribute (instead %i)",
Dest->Type);
NODETYPE_LOGICALXOR, //!< Logical XOR operator
NODETYPE_EQUALS, //!< Comparison Equals
+ NODETYPE_NOTEQUALS, //!< Comparison Not Equals
NODETYPE_LESSTHAN, //!< Comparison Less Than
NODETYPE_LESSTHANEQUAL, //!< Comparison Less Than or Equal
NODETYPE_GREATERTHAN, //!< Comparison Greater Than
// === 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);
// 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 )
{
-
- ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
+ ret = AST_ConvertNode(Block, Node->Assign.Dest, 1);
if(ret) return ret;
ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
if(ret) return ret;
AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
break;
}
- printf("assign, op = %i\n", op);
+// printf("assign, op = %i\n", op);
Bytecode_AppendBinOp(Block->Handle, op);
}
else
if( bKeepValue )
Bytecode_AppendDuplicate(Block->Handle);
- // Set the variable value
- ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
+
+ ret = BC_SaveValue(Block, Node->Assign.Dest);
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);
Bytecode_AppendConstInt(Block->Handle, 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_ADD);
if(ret) return ret;
-
- ret = BC_Variable_SetValue(Block, Node->UniOp.Value);
- if(ret) return ret;
- // Doesn't push unless needed
+ ret = BC_SaveValue(Block, Node->UniOp.Value);
break;
-
+
// Function Call
case NODETYPE_METHODCALL:
case NODETYPE_FUNCTIONCALL:
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;
return ret;
}
+int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode)
+{
+ int ret;
+ switch(DestNode->Type)
+ {
+ // Variable, simple
+ case NODETYPE_VARIABLE:
+ ret = BC_Variable_SetValue( Block, DestNode );
+ break;
+ // Array index
+ case NODETYPE_INDEX:
+ ret = AST_ConvertNode(Block, DestNode->BinOp.Left, 1); // Array
+ if(ret) return ret;
+ ret = AST_ConvertNode(Block, DestNode->BinOp.Right, 1); // Offset
+ if(ret) return ret;
+ Bytecode_AppendSetIndex( Block->Handle );
+ break;
+ // Object element
+ case NODETYPE_ELEMENT:
+ ret = AST_ConvertNode(Block, DestNode->Scope.Element, 1);
+ if(ret) return ret;
+ 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 ret;
+}
+
/**
* \brief Define a variable
* \param Block Current block state
// --- Indexing / Scoping
void Bytecode_AppendElement(tBC_Function *Handle, const char *Name)
DEF_BC_STR(BC_OP_ELEMENT, Name)
+void Bytecode_AppendSetElement(tBC_Function *Handle, const char *Name)
+ DEF_BC_STR(BC_OP_SETELEMENT, Name)
void Bytecode_AppendIndex(tBC_Function *Handle)
DEF_BC_NONE(BC_OP_INDEX)
+void Bytecode_AppendSetIndex(tBC_Function *Handle)
+ DEF_BC_NONE(BC_OP_SETINDEX);
void Bytecode_AppendCreateObj(tBC_Function *Handle, const char *Name, int ArgumentCount)
DEF_BC_STRINT(BC_OP_CREATEOBJ, Name, ArgumentCount)
extern void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length);
// > Scoping
extern void Bytecode_AppendElement(tBC_Function *Handle, const char *Name); // Obj->SubObj
+extern void Bytecode_AppendSetElement(tBC_Function *Handle, const char *Name); // Set an object member
extern void Bytecode_AppendIndex(tBC_Function *Handle); // Index into an array
+extern void Bytecode_AppendSetIndex(tBC_Function *Handle); // Write an array element
// > Function Calls
extern void Bytecode_AppendCreateObj(tBC_Function *Handle, const char *Name, int ArgumentCount);
extern void Bytecode_AppendMethodCall(tBC_Function *Handle, const char *Name, int ArgumentCount);
BC_OP_CAST, //
BC_OP_ELEMENT, // = 16
+ BC_OP_SETELEMENT,
BC_OP_INDEX,
+ BC_OP_SETINDEX,
- BC_OP_ENTERCONTEXT, // = 18
+ BC_OP_ENTERCONTEXT, // = 20
BC_OP_LEAVECONTEXT,
BC_OP_DEFINEVAR,
// Operations
- BC_OP_LOGICNOT, // 21
+ BC_OP_LOGICNOT, // 23
BC_OP_LOGICAND,
BC_OP_LOGICOR,
BC_OP_LOGICXOR,
- BC_OP_BITNOT, // 25
+ BC_OP_BITNOT, // 27
BC_OP_BITAND,
BC_OP_BITOR,
BC_OP_BITXOR,
- BC_OP_BITSHIFTLEFT, // 29
+ BC_OP_BITSHIFTLEFT, // 31
BC_OP_BITSHIFTRIGHT,
BC_OP_BITROTATELEFT,
- BC_OP_NEG, // 32
+ BC_OP_NEG, // 34
BC_OP_ADD,
BC_OP_SUBTRACT,
BC_OP_MULTIPLY,
BC_OP_DIVIDE,
BC_OP_MODULO,
- BC_OP_EQUALS, // 38
+ BC_OP_EQUALS, // 40
BC_OP_NOTEQUALS,
BC_OP_LESSTHAN,
BC_OP_LESSTHANOREQUAL,
// Execute!
if(fcn)
{
+ #if 1
if( fcn->BCFcn )
ret = Bytecode_ExecuteFunction(Script, fcn, NArguments, Arguments);
else
+ #endif
ret = AST_ExecuteFunction(Script, fcn, NArguments, Arguments);
bFound = 1;
}
case NODETYPE_BITSHIFTRIGHT:
case NODETYPE_BITROTATELEFT:
case NODETYPE_EQUALS:
+ case NODETYPE_NOTEQUALS:
case NODETYPE_LESSTHAN:
case NODETYPE_GREATERTHAN:
case NODETYPE_LESSTHANEQUAL:
switch(Operation)
{
case NODETYPE_EQUALS:
+ case NODETYPE_NOTEQUALS:
case NODETYPE_LESSTHAN:
case NODETYPE_GREATERTHAN:
case NODETYPE_LESSTHANEQUAL:
switch(Operation)
{
case NODETYPE_EQUALS: ret->Integer = (cmp == 0); break;
+ case NODETYPE_NOTEQUALS: 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 SS_DATATYPE_INTEGER:
return !!Ent->Integer;
case SS_DATATYPE_REAL:
- return (-.5f < Ent->Real && Ent->Real < 0.5f);
+ return !(-.5f < Ent->Real && Ent->Real < 0.5f);
case SS_DATATYPE_OBJECT:
return Ent->Object != NULL;
case ET_FUNCTION_START:
Bytecode_int_StackPush(Stack, &val2);
Bytecode_int_DerefStackValue(&val1);
break;
+
case BC_OP_BITNOT:
- if(!ast_op) ast_op = NODETYPE_BWNOT;
+ if(!ast_op) ast_op = NODETYPE_BWNOT, opstr = "BITNOT";
+ case BC_OP_NEG:
+ if(!ast_op) ast_op = NODETYPE_NEGATE, opstr = "NEG";
STATE_HDR();
- DEBUG_F("UNIOP %i\n", ast_op);
+ DEBUG_F("%s\n", opstr);
GET_STACKVAL(val1);
pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
case BC_OP_EQUALS:
if(!ast_op) ast_op = NODETYPE_EQUALS, opstr = "EQUALS";
+ case BC_OP_NOTEQUALS:
+ if(!ast_op) ast_op = NODETYPE_NOTEQUALS, opstr = "NOTEQUALS";
case BC_OP_LESSTHAN:
if(!ast_op) ast_op = NODETYPE_LESSTHAN, opstr = "LESSTHAN";
case BC_OP_LESSTHANOREQUAL:
GET_STACKVAL(val2); // Right
GET_STACKVAL(val1); // Left
+ DEBUG_F(" ("); PRINT_STACKVAL(val1); DEBUG_F(")");
+ DEBUG_F(" ("); PRINT_STACKVAL(val2); DEBUG_F(")\n");
+
#define PERFORM_NUM_OP(_type, _field) if(val1.Type == _type && val1.Type == val2.Type) { \
switch(op->Operation) { \
case BC_OP_ADD: val1._field = val1._field + val2._field; break; \
case BC_OP_SUBTRACT: val1._field = val1._field - val2._field; break; \
case BC_OP_MULTIPLY: val1._field = val1._field * val2._field; break; \
case BC_OP_DIVIDE: val1._field = val1._field / val2._field; break; \
- case BC_OP_EQUALS: val1._field = val1._field == val2._field; break; \
- case BC_OP_LESSTHAN: val1._field = val1._field < val2._field; break; \
- case BC_OP_LESSTHANOREQUAL: val1._field = val1._field <= val2._field; break; \
- case BC_OP_GREATERTHAN: val1._field = val1._field > val2._field; break; \
- case BC_OP_GREATERTHANOREQUAL: val1._field = val1._field >= val2._field; break; \
+ \
+ case BC_OP_EQUALS: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = (val1._field == val2._field); break; \
+ case BC_OP_NOTEQUALS: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = (val1._field != val2._field); break; \
+ case BC_OP_LESSTHAN: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = val1._field < val2._field; break; \
+ case BC_OP_LESSTHANOREQUAL: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = val1._field <= val2._field; break; \
+ case BC_OP_GREATERTHAN: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = val1._field > val2._field; break; \
+ case BC_OP_GREATERTHANOREQUAL: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = val1._field >= val2._field; break; \
\
case BC_OP_BITAND: val1._field = (int64_t)val1._field & (int64_t)val2._field; break; \
case BC_OP_BITOR: val1._field = (int64_t)val1._field | (int64_t)val2._field; break; \
case BC_OP_MODULO: val1._field = (int64_t)val1._field % (int64_t)val2._field; break; \
default: AST_RuntimeError(NULL, "Invalid operation on datatype %i", _type); nextop = NULL; break;\
}\
+ DEBUG_F(" - Fast local op\n");\
PUT_STACKVAL(val1);\
break;\
}
if(val1.Type == SS_DATATYPE_OBJECT)
obj = val1.Object;
- else if(val1.Type == ET_REFERENCE && val1.Reference->Type == SS_DATATYPE_OBJECT)
+ else if(val1.Type == ET_REFERENCE && val1.Reference && val1.Reference->Type == SS_DATATYPE_OBJECT)
obj = val1.Reference->Object;
else {
// Error
// Logical NOT
case '!':
+ if( *File->CurPos == '=' ) {
+ File->CurPos ++;
+ ret = TOK_NOTEQUALS;
+ break;
+ }
ret = TOK_LOGICNOT;
break;
// Bitwise NOT
case TOK_EQUALS:
ret = AST_NewBinOp(Parser, NODETYPE_EQUALS, ret, _next(Parser));
break;
+ case TOK_NOTEQUALS:
+ ret = AST_NewBinOp(Parser, NODETYPE_NOTEQUALS, ret, _next(Parser));
+ break;
case TOK_LT:
ret = AST_NewBinOp(Parser, NODETYPE_LESSTHAN, ret, _next(Parser));
break;
TOK_ELEMENT,
// Comparisons
- TOK_EQUALS,
+ TOK_EQUALS, TOK_NOTEQUALS,
TOK_LT, TOK_LTE,
TOK_GT, TOK_GTE,
"TOK_SCOPE",
"TOK_ELEMENT",
- "TOK_EQUALS",
+ "TOK_EQUALS", "TOK_NOTEQUALS",
"TOK_LT", "TOK_LTE",
"TOK_GT", "TOK_GTE",
void SpiderScript_FreeValue(tSpiderValue *Value);
char *SpiderScript_DumpValue(tSpiderValue *Value);
// --- Operations
-tSpiderValue *SpiderScript_DoOp(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right);
-tSpiderValue *SpiderScript_int_DoOpInt(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right);
-tSpiderValue *SpiderScript_int_DoOpReal(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right);
-tSpiderValue *SpiderScript_int_DoOpString(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right);
+tSpiderValue *SpiderScript_DoOp(tSpiderValue *Left, enum eSpiderValueOps, int bCanCast, tSpiderValue *Right);
+tSpiderValue *SpiderScript_int_DoOpInt(tSpiderValue *Left, enum eSpiderValueOps, int bCanCast, tSpiderValue *Right);
+tSpiderValue *SpiderScript_int_DoOpReal(tSpiderValue *Left, enum eSpiderValueOps, int bCanCast, tSpiderValue *Right);
+tSpiderValue *SpiderScript_int_DoOpString(tSpiderValue *Left, enum eSpiderValueOps, int bCanCast, tSpiderValue *Right);
// === CODE ===
}
// ---
-tSpiderValue *SpiderScript_DoOp(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right)
+tSpiderValue *SpiderScript_DoOp(tSpiderValue *Left, enum eSpiderValueOps Operation, int bCanCast, tSpiderValue *Right)
{
switch(Left->Type)
{
case SS_DATATYPE_INTEGER:
return SpiderScript_int_DoOpInt(Left, Operation, bCanCast, Right);
+ default:
+ return NULL;
}
return NULL;
}
-tSpiderValue *SpiderScript_int_DoOpInt(tSpiderValue *Left, int Operation, int bCanCast, tSpiderValue *Right)
+tSpiderValue *SpiderScript_int_DoOpInt(tSpiderValue *Left, enum eSpiderValueOps Operation, int bCanCast, tSpiderValue *Right)
{
tSpiderValue *oldright = Right;
tSpiderValue *ret = NULL;
- int64_t rv;
+ int64_t rv = 0;
// Casting
if(Right && Right->Type != SS_DATATYPE_INTEGER) {
if(!bCanCast) return ERRPTR;
- Right = SpiderScript_CastValueTo(Right, SS_DATATYPE_INTEGER);
+ Right = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, Right);
}
// Do the operation
if(!Right) ret = ERRPTR;
else rv = Left->Integer + Right->Integer;
break;
+ case SS_VALUEOP_SUBTRACT:
+ if(!Right) ret = ERRPTR;
+ else rv = Left->Integer - Right->Integer;
+ break;
+ default:
+ ret = ERRPTR;
+ AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented integer operation %i", Operation);
+ break;
}
// Delete temporary value