void AST_FreeNode(tAST_Node *Node)
{
tAST_Node *node;
+
+ if(!Node) return ;
+
switch(Node->Type)
{
// Block of code
}
break;
+ // If node
+ case NODETYPE_IF:
+ AST_FreeNode(Node->If.Condition);
+ AST_FreeNode(Node->If.True);
+ AST_FreeNode(Node->If.False);
+ break;
+
+ // Looping Construct (For loop node)
+ case NODETYPE_LOOP:
+ AST_FreeNode(Node->For.Init);
+ AST_FreeNode(Node->For.Condition);
+ AST_FreeNode(Node->For.Increment);
+ AST_FreeNode(Node->For.Code);
+ break;
+
// Asignment
case NODETYPE_ASSIGN:
AST_FreeNode(Node->Assign.Dest);
}
}
+tAST_Node *AST_NewIf(tAST_Node *Condition, tAST_Node *True, tAST_Node *False)
+{
+ tAST_Node *ret = malloc( sizeof(tAST_Node) );
+ ret->NextSibling = NULL;
+ ret->Type = NODETYPE_IF;
+ ret->If.Condition = Condition;
+ ret->If.True = True;
+ ret->If.False = False;
+ return ret;
+}
+
+tAST_Node *AST_NewLoop(tAST_Node *Init, int bPostCheck, tAST_Node *Condition, tAST_Node *Increment, tAST_Node *Code)
+{
+ tAST_Node *ret = malloc( sizeof(tAST_Node) );
+ ret->NextSibling = NULL;
+ ret->Type = NODETYPE_LOOP;
+ ret->For.Init = Init;
+ ret->For.bCheckAfter = !!bPostCheck;
+ ret->For.Condition = Condition;
+ ret->For.Increment = Increment;
+ ret->For.Code = Code;
+ return ret;
+}
+
tAST_Node *AST_NewAssign(int Operation, tAST_Node *Dest, tAST_Node *Value)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) );
NODETYPE_ASSIGN, //!< Variable assignment operator
NODETYPE_FUNCTIONCALL, //!< Call a function
+ NODETYPE_IF, //!< Conditional
+ NODETYPE_LOOP, //!< Looping Construct
+
NODETYPE_INDEX, //!< Index into an array
NODETYPE_LOGICALAND, //!< Logical AND operator
char Name[];
} FunctionCall;
+ struct {
+ tAST_Node *Condition;
+ tAST_Node *True;
+ tAST_Node *False;
+ } If;
+
+ struct {
+ tAST_Node *Init;
+ int bCheckAfter;
+ tAST_Node *Condition;
+ tAST_Node *Increment;
+ tAST_Node *Code;
+ } For;
+
/**
* \note Used for \a NODETYPE_VARIABLE and \a NODETYPE_CONSTANT
*/
tAST_BlockState *Parent;
tSpiderScript *Script; //!< Script
tAST_Variable *FirstVar; //!< First variable in the list
+ tSpiderValue *RetVal;
};
struct sAST_Variable
extern tAST_Node *AST_NewCodeBlock(void);
extern void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child);
+
+extern tAST_Node *AST_NewIf(tAST_Node *Condition, tAST_Node *True, tAST_Node *False);
+
extern tAST_Node *AST_NewAssign(int Operation, tAST_Node *Dest, tAST_Node *Value);
extern tAST_Node *AST_NewBinOp(int Operation, tAST_Node *Left, tAST_Node *Right);
extern tAST_Node *AST_NewUniOp(int Operation, tAST_Node *Value);
*/
int Object_IsTrue(tSpiderValue *Value)
{
+ if( Value == ERRPTR ) return 0;
+ if( Value == NULL ) return 0;
+
switch( (enum eSpiderScript_DataTypes)Value->Type )
{
case SS_DATATYPE_UNDEF:
{
tAST_BlockState blockInfo;
blockInfo.FirstVar = NULL;
+ blockInfo.RetVal = NULL;
blockInfo.Parent = Block;
blockInfo.Script = Block->Script;
ret = NULL;
- for(node = Node->Block.FirstChild; node; node = node->NextSibling )
+ for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
{
- if(node->Type == NODETYPE_RETURN) {
- ret = AST_ExecuteNode(&blockInfo, node);
+ tmpobj = AST_ExecuteNode(&blockInfo, node);
+ if(tmpobj == ERRPTR) { // Error check
+ ret = ERRPTR;
break ;
}
- else {
- tmpobj = AST_ExecuteNode(&blockInfo, node);
- if(tmpobj == ERRPTR) { // Error check
- ret = ERRPTR;
- break ;
- }
- if(tmpobj) Object_Dereference(tmpobj); // Free unused value
- }
+ if(tmpobj) Object_Dereference(tmpobj); // Free unused value
}
// Clean up variables
while(blockInfo.FirstVar)
Variable_Destroy( blockInfo.FirstVar );
blockInfo.FirstVar = nextVar;
}
+
+ if( blockInfo.RetVal )
+ Block->RetVal = blockInfo.RetVal;
}
break;
}
break;
- // Return's special handling happens elsewhere
+ // Conditional
+ case NODETYPE_IF:
+ ret = AST_ExecuteNode(Block, Node->If.Condition);
+ if( Object_IsTrue(ret) ) {
+ AST_ExecuteNode(Block, Node->If.True);
+ }
+ else {
+ AST_ExecuteNode(Block, Node->If.False);
+ }
+ Object_Dereference(ret);
+ break;
+
+ // Loop
+ case NODETYPE_LOOP:
+ ret = AST_ExecuteNode(Block, Node->For.Init);
+ if( Node->For.bCheckAfter ) {
+ do {
+ Object_Dereference(ret);
+ ret = AST_ExecuteNode(Block, Node->For.Code);
+ Object_Dereference(ret);
+ ret = AST_ExecuteNode(Block, Node->For.Condition);
+ } while( Object_IsTrue(ret) );
+ }
+ else {
+ Object_Dereference(ret);
+ ret = AST_ExecuteNode(Block, Node->For.Condition);
+ while( Object_IsTrue(ret) ) {
+ Object_Dereference(ret);
+ ret = AST_ExecuteNode(Block, Node->For.Code);
+ Object_Dereference(ret);
+ ret = AST_ExecuteNode(Block, Node->For.Condition);
+ }
+ Object_Dereference(ret);
+ }
+ break;
+
+ // Return
case NODETYPE_RETURN:
ret = AST_ExecuteNode(Block, Node->UniOp.Value);
+ Block->RetVal = ret; // Return value set
break;
// Define a variable
// Execute!
if(fcn) {
tAST_BlockState bs;
- bs.FirstVar = NULL; //< TODO: Parameters
+ bs.FirstVar = NULL;
+ bs.RetVal = NULL;
bs.Parent = NULL;
bs.Script = Script;
{
}
}
ret = AST_ExecuteNode(&bs, fcn->Code);
+ //Object_Dereference(ret);
+ ret = bs.RetVal;
bFound = 1;
}
}
void SyntaxAssert(tParser *Parser, int Have, int Want);
+#define TODO(Parser, message...) do {\
+ fprintf(stderr, "TODO: "message);\
+ longjmp(Parser->JmpTarget, -1);\
+}while(0)
+
// === CODE ===
/**
* \brief Parse a buffer into a syntax tree
ret = AST_NewScript();
mainCode = AST_NewCodeBlock();
+ // Give us an error fallback
if( setjmp( parser.JmpTarget ) != 0 )
{
AST_FreeNode( mainCode );
return NULL;
}
+ // Parse the file!
while(Parser->Token != TOK_EOF)
{
switch( GetToken(Parser) )
tAST_Node *Parse_DoCodeBlock(tParser *Parser)
{
tAST_Node *ret;
- SyntaxAssert(Parser, GetToken(Parser), TOK_BRACE_OPEN );
+
+ // Check if we are being called for a one-liner
+ if( GetToken(Parser) != TOK_BRACE_OPEN ) {
+ PutBack(Parser);
+ return Parse_DoBlockLine(Parser);
+ }
ret = AST_NewCodeBlock();
break;
// Control Statements
- //case TOK_RWD_IF:
- // break;
+ case TOK_RWD_IF:
+ {
+ tAST_Node *cond, *true, *false = NULL;
+ GetToken(Parser); // eat the if
+ SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN);
+ cond = Parse_DoExpr0(Parser); // Get condition
+ SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
+ true = Parse_DoCodeBlock(Parser);
+ if( LookAhead(Parser) == TOK_RWD_ELSE ) {
+ GetToken(Parser);
+ false = Parse_DoCodeBlock(Parser);
+ }
+ ret = AST_NewIf(cond, true, false);
+ }
+ return ret;
+ case TOK_RWD_FOR:
+ case TOK_RWD_DO:
+ case TOK_RWD_WHILE:
+ TODO(Parser, "Implement if, for, do and while\n");
+ break;
// Define Variables
case TOKEN_GROUP_TYPES: