#include "common.h"
#include "ast.h"
+#define USE_AST_EXEC 1
#define TRACE_VAR_LOOKUPS 0
#define TRACE_NODE_RETURNS 0
tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right);
tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value);
+tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node, tSpiderValue *Array, int Index, tSpiderValue *SaveValue);
// - Variables
tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value);
int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value);
int giNextBlockIdent = 1;
// === CODE ===
+#if USE_AST_EXEC
tSpiderValue *AST_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Arguments)
{
tAST_BlockState bs;
case NODETYPE_CREATEOBJECT:
// Logical block (used to allocate `params`)
{
- tSpiderNamespace *ns = Block->CurNamespace;
+ const char *namespaces[] = {NULL}; // TODO: Default namespaces?
tSpiderValue *params[Node->FunctionCall.NumArgs];
i = 0;
+
+ // Get arguments
for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
{
params[i] = AST_ExecuteNode(Block, node);
}
i ++;
}
-
- if( !ns ) ns = Block->BaseNamespace;
-
+
+ // TODO: Check for cached function reference
+
// Call the function
if( Node->Type == NODETYPE_CREATEOBJECT )
{
ret = SpiderScript_CreateObject(Block->Script,
- ns,
Node->FunctionCall.Name,
+ namespaces,
Node->FunctionCall.NumArgs, params
);
}
else
{
ret = SpiderScript_ExecuteFunction(Block->Script,
- ns, Node->FunctionCall.Name,
- Node->FunctionCall.NumArgs, params
+ Node->FunctionCall.Name,
+ namespaces,
+ Node->FunctionCall.NumArgs, params,
+ NULL
);
}
break;
}
Block->CurNamespace = ns;
-
+
+ // TODO: Check type of child node (Scope, Constant or Function)
+
ret = AST_ExecuteNode(Block, Node->Scope.Element);
}
break;
case NODETYPE_ELEMENT:
tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
if(tmpobj == ERRPTR) return ERRPTR;
- if( !tmpobj || tmpobj->Type != SS_DATATYPE_OBJECT )
- {
- AST_RuntimeError(Node->Scope.Element, "Unable to dereference a non-object");
- ret = ERRPTR;
- break ;
- }
-
- for( i = 0; i < tmpobj->Object->Type->NAttributes; i ++ )
- {
- if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
- {
- ret = tmpobj->Object->Attributes[i];
- SpiderScript_ReferenceValue(ret);
- break;
- }
- }
- if( i == tmpobj->Object->Type->NAttributes )
- {
- AST_RuntimeError(Node->Scope.Element, "Unknown attribute '%s' of class '%s'",
- Node->Scope.Name, tmpobj->Object->Type->Name);
- ret = ERRPTR;
- }
+
+ ret = AST_ExecuteNode_Element(Block->Script, Node, tmpobj, Node->Scope.Name, ERRPTR);
break;
// Cast a value to another
return ERRPTR;
}
- if( !op1 || op1->Type != SS_DATATYPE_ARRAY )
+ if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
{
- // TODO: Implement "operator []" on objects
- AST_RuntimeError(Node, "Indexing non-array");
- ret = ERRPTR;
- break;
- }
-
- if( (!op2 || op2->Type != SS_DATATYPE_INTEGER) && !Block->Script->Variant->bImplicitCasts ) {
- AST_RuntimeError(Node, "Array index is not an integer");
- ret = ERRPTR;
- break;
+ if( !Block->Script->Variant->bImplicitCasts ) {
+ AST_RuntimeError(Node, "Array index is not an integer");
+ ret = ERRPTR;
+ break;
+ }
+ else {
+ tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
+ SpiderScript_DereferenceValue(op2);
+ op2 = tmpobj;
+ }
}
-
- if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
+
+ if( !op1 )
{
- tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
SpiderScript_DereferenceValue(op2);
- op2 = tmpobj;
- }
-
- if( op2->Integer >= op1->Array.Length ) {
- AST_RuntimeError(Node, "Array index out of bounds %i >= %i",
- op2->Integer, op1->Array.Length);
+ AST_RuntimeError(Node, "Indexing NULL value");
ret = ERRPTR;
break;
}
-
- ret = op1->Array.Items[ op2->Integer ];
- SpiderScript_ReferenceValue(ret);
-
+
+ ret = AST_ExecuteNode_Index(Block->Script, Node, op1, op2->Integer, ERRPTR);
+
SpiderScript_DereferenceValue(op1);
SpiderScript_DereferenceValue(op2);
break;
ret = &Node->Constant;
SpiderScript_ReferenceValue(ret);
break;
+ case NODETYPE_NULL:
+ ret = NULL;
+ break;
// --- Operations ---
// Boolean Operations
case NODETYPE_BITSHIFTRIGHT:
case NODETYPE_BITROTATELEFT:
case NODETYPE_EQUALS:
+ case NODETYPE_NOTEQUALS:
case NODETYPE_LESSTHAN:
case NODETYPE_GREATERTHAN:
case NODETYPE_LESSTHANEQUAL:
return ret;
}
+#endif
tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value)
{
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;
return ret;
}
+tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node,
+ tSpiderValue *Array, int Index, tSpiderValue *SaveValue)
+{
+ // Quick sanity check
+ if( !Array )
+ {
+ AST_RuntimeError(Node, "Indexing NULL, not a good idea");
+ return ERRPTR;
+ }
+
+ // Array?
+ if( SS_GETARRAYDEPTH(Array->Type) )
+ {
+ if( Index < 0 || Index >= Array->Array.Length ) {
+ AST_RuntimeError(Node, "Array index out of bounds %i not in (0, %i]",
+ Index, Array->Array.Length);
+ return ERRPTR;
+ }
+
+ if( SaveValue != ERRPTR )
+ {
+ if( SaveValue && SaveValue->Type != SS_DOWNARRAY(Array->Type) ) {
+ // TODO: Implicit casting
+ AST_RuntimeError(Node, "Type mismatch assiging to array element");
+ return ERRPTR;
+ }
+ SpiderScript_DereferenceValue( Array->Array.Items[Index] );
+ Array->Array.Items[Index] = SaveValue;
+ SpiderScript_ReferenceValue( Array->Array.Items[Index] );
+ return NULL;
+ }
+ else
+ {
+ SpiderScript_ReferenceValue( Array->Array.Items[Index] );
+ return Array->Array.Items[Index];
+ }
+ }
+ else
+ {
+ AST_RuntimeError(Node, "TODO - Implement indexing on non-arrays (type = %x)",
+ Array->Type);
+ return ERRPTR;
+ }
+}
+
+/**
+ * \brief Get/Set the value of an element/attribute of a class
+ * \param Script Executing script
+ * \param Node Current execution node (only used for AST_RuntimeError)
+ * \param Object Object value
+ * \param ElementName Name of the attribute to be accessed
+ * \param SaveValue Value to set the element to (if ERRPTR, element value is returned)
+ */
+tSpiderValue *AST_ExecuteNode_Element(tSpiderScript *Script, tAST_Node *Node,
+ tSpiderValue *Object, const char *ElementName, tSpiderValue *SaveValue)
+{
+ int i;
+ tSpiderValue *ret;
+
+ if( !Object ) {
+ AST_RuntimeError(Node, "Tried to access an element of NULL");
+ return ERRPTR;
+ }
+
+ switch( Object->Type )
+ {
+ case SS_DATATYPE_OBJECT: {
+ tSpiderObjectDef *class = Object->Object->Type;
+ for( i = 0; i < class->NAttributes; i ++ )
+ {
+ if( strcmp(ElementName, class->AttributeDefs[i].Name) == 0 )
+ {
+ if( SaveValue != ERRPTR ) {
+ Object->Object->Attributes[i] = SaveValue;
+ SpiderScript_ReferenceValue(SaveValue);
+ return NULL;
+ }
+ else {
+ ret = Object->Object->Attributes[i];
+ SpiderScript_ReferenceValue(ret);
+ return ret;
+ }
+ }
+ }
+ AST_RuntimeError(Node, "Unknown attribute '%s' of class '%s'",
+ ElementName, class->Name);
+ return ERRPTR; }
+ default:
+ AST_RuntimeError(Node, "Unable to get element of type %i", Object->Type);
+ return ERRPTR;
+ }
+}
+
+#if USE_AST_EXEC
/**
* \brief Define a variable
* \param Block Current block state
SpiderScript_DereferenceValue(Variable->Object);
free(Variable);
}
+#endif