SpiderScript! (with a sample script)
authorJohn Hodge <[email protected]>
Tue, 17 Aug 2010 01:40:31 +0000 (09:40 +0800)
committerJohn Hodge <[email protected]>
Tue, 17 Aug 2010 01:40:31 +0000 (09:40 +0800)
Usermode/Libraries/libc.so_src/string.c
Usermode/Libraries/libspiderscript.so_src/Makefile
Usermode/Libraries/libspiderscript.so_src/Scripts/sample.isc [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/ast.c
Usermode/Libraries/libspiderscript.so_src/ast.h
Usermode/Libraries/libspiderscript.so_src/exec_ast.c
Usermode/Libraries/libspiderscript.so_src/exports.c [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/lex.c
Usermode/Libraries/libspiderscript.so_src/main.c
Usermode/Libraries/libspiderscript.so_src/parse.c
Usermode/Libraries/libspiderscript.so_src/tokens.h

index e85356d..4e8dfe2 100644 (file)
@@ -19,6 +19,19 @@ EXPORT int strcmp(const char *s1, const char *s2)
        return (int)*s1 - (int)*s2;
 }
 
+/**
+ * \fn EXPORT int strncmp(const char *s1, const char *s2)
+ * \brief Compare two strings
+ */
+EXPORT int strncmp(const char *s1, const char *s2, size_t n)
+{
+       if( n == 0 )    return 0;
+       while(n -- && *s1 == *s2 && *s1 != '\0' && *s2 != '\0') {
+               s1++; s2++;
+       }
+       return (int)*s1 - (int)*s2;
+}
+
 /**
  * \fn EXPORT char *strcpy(char *dst, const char *src)
  * \brief Copy a string to another
index fd42a31..954b2a7 100644 (file)
@@ -7,7 +7,7 @@ CPPFLAGS +=
 CFLAGS   += -Wall
 LDFLAGS  += -lc -lgcc -soname libspiderscript.so --no-allow-shlib-undefined
 
-OBJ = main.o lex.o parse.o ast.o exec_ast.o
+OBJ = main.o lex.o parse.o ast.o exec_ast.o exports.o
 BIN = ../libspiderscript.so
 
 include ../Makefile.tpl
diff --git a/Usermode/Libraries/libspiderscript.so_src/Scripts/sample.isc b/Usermode/Libraries/libspiderscript.so_src/Scripts/sample.isc
new file mode 100644 (file)
index 0000000..7e9a866
--- /dev/null
@@ -0,0 +1,36 @@
+
+# Should I use brackets in this language?
+# Well, considering that all whitespace is ignored, it might be an idea
+
+# Well, it would make VVV a little simpler
+# Just define a funciton with the name 'Sys.IO.Open'
+# Not a namespace Sys, with a child Sys
+
+$fp = Sys.IO.Open( "/Devices/ipstack" );
+$ifname = Sys.IO.IOCtl( $fp, 4, "/Devices/ne2k/0" );
+Sys.IO.Close($fp);
+
+# Let's see:
+#   b - Signed 8-bit integer, B - unsigned
+#   w - 16 bit
+#   l - 32 bit
+#   q - 64 bit
+#   f - 32-bit float
+#   d - 64-bit double
+#   Fields can be prefixed by a size for arrays (taking only one argument)
+#   * indicates a variable size array
+# E.g.
+#  Sys.Mem.MakeStruct( "L*B", $len, $len, $str );
+# Hmm.. that would mean I will need arrays... fuck it, do them later
+
+function SetIPv4($ifaceName, $addr)
+{
+       $fp = Sys.IO.Open( "/Devices/ipstack/$ifaceName" );
+       $data = Lang.MakeStruct( "l", 4 );
+       Sys.IO.IOCtl( $fp, 4, $data );
+       $data = Lang.Struct( "BBBB", $addr[0],  $addr[1],  $addr[2], $addr[3] );
+       Sys.IO.IOCtl( $fp, 6, $data );
+       Sys.IO.Close( $fp );
+}
+
+SetIPv4( $ifname, Lang.Array(10, 0, 2, 55) );
index e0e1e37..45b8176 100644 (file)
@@ -2,6 +2,7 @@
  * Acess2 Init
  * - Script AST Manipulator
  */
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "ast.h"
@@ -24,9 +25,9 @@ tAST_Function *AST_AppendFunction(tAST_Script *Script, const char *Name)
 {
        tAST_Function   *ret;
        
-       ret = malloc( sizeof(tAST_Function) );
+       ret = malloc( sizeof(tAST_Function) + strlen(Name) + 1 );
        ret->Next = NULL;
-       ret->Name = strdup(Name);
+       strcpy(ret->Name, Name);
        ret->Code = NULL;
        ret->Arguments = NULL;
        
@@ -41,6 +42,20 @@ tAST_Function *AST_AppendFunction(tAST_Script *Script, const char *Name)
        return ret;
 }
 
+void AST_AppendFunctionArg(tAST_Function *Function, tAST_Node *Node)
+{
+       if( !Function->Arguments ) {
+               Function->Arguments_Last = Function->Arguments = Node;
+       }
+       else {
+               Function->Arguments_Last->NextSibling = Node;
+               Function->Arguments_Last = Node;
+       }
+}
+
+/**
+ * \brief Set the code for a function
+ */
 void AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root)
 {
        Function->Code = Root;
@@ -50,6 +65,9 @@ void AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root)
  * \name Node Manipulation
  * \{
  */
+/**
+ * \brief Free a node and all subnodes
+ */
 void AST_FreeNode(tAST_Node *Node)
 {
        tAST_Node       *node;
@@ -81,12 +99,28 @@ void AST_FreeNode(tAST_Node *Node)
                AST_FreeNode(Node->Assign.Value);
                break;
        
+       // Casting
+       case NODETYPE_CAST:
+               AST_FreeNode(Node->Cast.Value);
+               break;
+       
+       // Define a variable
+       case NODETYPE_DEFVAR:
+               for( node = Node->DefVar.LevelSizes; node; )
+               {
+                       tAST_Node       *savedNext = node->NextSibling;
+                       AST_FreeNode(node);
+                       node = savedNext;
+               }
+               break;
+       
        // Unary Operations
        case NODETYPE_RETURN:
                AST_FreeNode(Node->UniOp.Value);
                break;
        
        // Binary Operations
+       case NODETYPE_INDEX:
        case NODETYPE_ADD:
        case NODETYPE_SUBTRACT:
        case NODETYPE_MULTIPLY:
@@ -130,14 +164,30 @@ tAST_Node *AST_NewCodeBlock(void)
 
 void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child)
 {
-       if(Parent->Type != NODETYPE_BLOCK)      return ;
-       
-       if(Parent->Block.FirstChild == NULL) {
-               Parent->Block.FirstChild = Parent->Block.LastChild = Child;
-       }
-       else {
-               Parent->Block.LastChild->NextSibling = Child;
-               Parent->Block.LastChild = Child;
+       Child->NextSibling = NULL;
+       switch( Parent->Type )
+       {
+       case NODETYPE_BLOCK:
+               if(Parent->Block.FirstChild == NULL) {
+                       Parent->Block.FirstChild = Parent->Block.LastChild = Child;
+               }
+               else {
+                       Parent->Block.LastChild->NextSibling = Child;
+                       Parent->Block.LastChild = Child;
+               }
+               break;
+       case NODETYPE_DEFVAR:
+               if(Parent->DefVar.LevelSizes == NULL) {
+                       Parent->DefVar.LevelSizes = Parent->DefVar.LevelSizes_Last = Child;
+               }
+               else {
+                       Parent->DefVar.LevelSizes_Last->NextSibling = Child;
+                       Parent->DefVar.LevelSizes_Last = Child;
+               }
+               break;
+       default:
+               fprintf(stderr, "BUG REPORT: AST_AppendNode on an invalid node type (%i)\n", Parent->Type);
+               break;
        }
 }
 
@@ -166,6 +216,19 @@ tAST_Node *AST_NewBinOp(int Operation, tAST_Node *Left, tAST_Node *Right)
        return ret;
 }
 
+/**
+ */
+tAST_Node *AST_NewUniOp(int Operation, tAST_Node *Value)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) );
+       
+       ret->NextSibling = NULL;
+       ret->Type = Operation;
+       ret->UniOp.Value = Value;
+       
+       return ret;
+}
+
 /**
  * \brief Create a new string node
  */
@@ -206,6 +269,20 @@ tAST_Node *AST_NewVariable(const char *Name)
        return ret;
 }
 
+/**
+ * \brief Create a new variable definition node
+ */
+tAST_Node *AST_NewDefineVar(int Type, const char *Name)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
+       ret->NextSibling = NULL;
+       ret->Type = NODETYPE_DEFVAR;
+       ret->DefVar.DataType = Type;
+       ret->DefVar.LevelSizes = NULL;
+       strcpy(ret->DefVar.Name, Name);
+       return ret;
+}
+
 /**
  * \brief Create a new runtime constant reference node
  */
index 820167b..9179563 100644 (file)
@@ -5,10 +5,12 @@
 
 #include <spiderscript.h>
 
+typedef enum eAST_NodeTypes    tAST_NodeType;
 typedef struct sAST_Script     tAST_Script;
 typedef struct sAST_Function   tAST_Function;
 typedef struct sAST_Node       tAST_Node;
-typedef enum eAST_NodeTypes    tAST_NodeType;
+typedef struct sAST_BlockState tAST_BlockState;
+typedef struct sAST_Variable   tAST_Variable;
 
 /**
  * \brief Node Types
@@ -25,10 +27,15 @@ enum eAST_NodeTypes
        NODETYPE_INTEGER,       //!< Integer Constant
        NODETYPE_REAL,  //!< Real Constant
        
+       NODETYPE_DEFVAR,        //!< Define a variable (Variable)
+       NODETYPE_CAST,  //!< Cast a value to another (Uniop)
+       
        NODETYPE_RETURN,        //!< Return from a function (reserved word)
        NODETYPE_ASSIGN,        //!< Variable assignment operator
        NODETYPE_FUNCTIONCALL,  //!< Call a function
        
+       NODETYPE_INDEX, //!< Index into an array
+       
        NODETYPE_LOGICALAND,    //!< Logical AND operator
        NODETYPE_LOGICALOR,     //!< Logical OR operator
        NODETYPE_LOGICALXOR,    //!< Logical XOR operator
@@ -56,6 +63,7 @@ struct sSpiderScript
 {
        tSpiderVariant  *Variant;
        tAST_Script     *Script;
+       char    *CurNamespace;  //!< Current namespace prefix (NULL = Root) - No trailing .
 };
 
 struct sAST_Script
@@ -66,10 +74,11 @@ struct sAST_Script
 
 struct sAST_Function
 {
-       tAST_Function   *Next;
-       char    *Name;
-       tAST_Node       *Code;
-       tAST_Node       *Arguments;     // HACKJOB (Only NODETYPE_VARIABLE is allowed)
+       tAST_Function   *Next;  //!< Next function in list
+       tAST_Node       *Code;  //!< Function Code
+       tAST_Node       *Arguments;     // HACKJOB (Only NODETYPE_DEFVAR is allowed)
+       tAST_Node       *Arguments_Last;
+       char    Name[]; //!< Function Name
 };
 
 struct sAST_Node
@@ -118,32 +127,66 @@ struct sAST_Node
                        char    Name[];
                }       Variable;
                
+               struct {
+                        int    DataType;
+                        int    Depth;
+                       tAST_Node       *LevelSizes;
+                       tAST_Node       *LevelSizes_Last;
+                       char    Name[];
+               }       DefVar;
+               
+               struct {
+                        int    DataType;
+                        tAST_Node      *Value;
+               }       Cast;
+               
                uint64_t        Integer;
                double  Real;
        };
 };
 
+/**
+ * \brief Code Block state (stores local variables)
+ */
+struct sAST_BlockState
+{
+       tAST_BlockState *Parent;
+       tSpiderScript   *Script;        //!< Script
+       tAST_Variable   *FirstVar;      //!< First variable in the list
+};
+
+struct sAST_Variable
+{
+       tAST_Variable   *Next;
+        int    Type;   // Only used for static typing
+       tSpiderObject   *Object;
+       char    Name[];
+};
+
 // === FUNCTIONS ===
-tAST_Script    *AST_NewScript(void);
+extern tAST_Script     *AST_NewScript(void);
 
-tAST_Function  *AST_AppendFunction(tAST_Script *Script, const char *Name);
-void   AST_AppendFunctionArg(tAST_Function *Function, int Type, tAST_Node *Arg);
-void   AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root);
+extern tAST_Function   *AST_AppendFunction(tAST_Script *Script, const char *Name);
+extern void    AST_AppendFunctionArg(tAST_Function *Function, tAST_Node *Arg);
+extern void    AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root);
 
-tAST_Node      *AST_NewString(const char *String, int Length);
-tAST_Node      *AST_NewInteger(uint64_t Value);
-tAST_Node      *AST_NewVariable(const char *Name);
-tAST_Node      *AST_NewConstant(const char *Name);
-tAST_Node      *AST_NewFunctionCall(const char *Name);
-void   AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg);
+extern tAST_Node       *AST_NewString(const char *String, int Length);
+extern tAST_Node       *AST_NewInteger(uint64_t Value);
+extern tAST_Node       *AST_NewVariable(const char *Name);
+extern tAST_Node       *AST_NewDefineVar(int Type, const char *Name);
+extern tAST_Node       *AST_NewConstant(const char *Name);
+extern tAST_Node       *AST_NewFunctionCall(const char *Name);
+extern void    AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg);
 
-tAST_Node      *AST_NewCodeBlock(void);
-void   AST_AppendNode(tAST_Node *Parent, tAST_Node *Child);
-tAST_Node      *AST_NewAssign(int Operation, tAST_Node *Dest, tAST_Node *Value);
-tAST_Node      *AST_NewBinOp(int Operation, tAST_Node *Left, tAST_Node *Right);
+extern tAST_Node       *AST_NewCodeBlock(void);
+extern void    AST_AppendNode(tAST_Node *Parent, tAST_Node *Child);
+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);
 
-void   AST_FreeNode(tAST_Node *Node);
+extern void    AST_FreeNode(tAST_Node *Node);
 
-tSpiderVariable        *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node);
+// exec_ast.h
+extern tSpiderObject   *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
 
 #endif
index 90045bc..cf7416a 100644 (file)
@@ -5,41 +5,45 @@
 #include <string.h>
 #include "ast.h"
 
-#define ERRPTR ((void*)((intptr_t)0-1))
-
 // === PROTOTYPES ===
-void   Object_Dereference(tSpiderVariable *Object);
-void   Object_Reference(tSpiderVariable *Object);
-tSpiderVariable        *Object_CreateInteger(uint64_t Value);
-tSpiderVariable        *Object_CreateReal(double Value);
-tSpiderVariable        *Object_CreateString(int Length, const char *Data);
-tSpiderVariable        *Object_CastTo(int Type, tSpiderVariable *Source);
- int   Object_IsTrue(tSpiderVariable *Value);
+void   Object_Dereference(tSpiderObject *Object);
+void   Object_Reference(tSpiderObject *Object);
+tSpiderObject  *Object_CreateInteger(uint64_t Value);
+tSpiderObject  *Object_CreateReal(double Value);
+tSpiderObject  *Object_CreateString(int Length, const char *Data);
+tSpiderObject  *Object_CastTo(int Type, tSpiderObject *Source);
+ int   Object_IsTrue(tSpiderObject *Value);
+
+tSpiderObject  *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
 
-void   Variable_SetValue(tSpiderScript *Script, const char *Name, tSpiderVariable *Value);
-tSpiderVariable        *Variable_GetValue(tSpiderScript *Script, const char *Name);
+tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
+void   Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderObject *Value);
+tSpiderObject  *Variable_GetValue(tAST_BlockState *Block, const char *Name);
+void   Variable_Destroy(tAST_Variable *Variable);
 
 // === CODE ===
 /**
  * \brief Dereference a created object
  */
-void Object_Dereference(tSpiderVariable *Object)
+void Object_Dereference(tSpiderObject *Object)
 {
+       if(!Object)     return ;
        Object->ReferenceCount --;
        if( Object->ReferenceCount == 0 )       free(Object);
 }
 
-void Object_Reference(tSpiderVariable *Object)
+void Object_Reference(tSpiderObject *Object)
 {
+       if(!Object)     return ;
        Object->ReferenceCount ++;
 }
 
 /**
  * \brief Create an integer object
  */
-tSpiderVariable        *Object_CreateInteger(uint64_t Value)
+tSpiderObject *Object_CreateInteger(uint64_t Value)
 {
-       tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) );
+       tSpiderObject   *ret = malloc( sizeof(tSpiderObject) );
        ret->Type = SS_DATATYPE_INTEGER;
        ret->ReferenceCount = 1;
        ret->Integer = Value;
@@ -49,9 +53,9 @@ tSpiderVariable       *Object_CreateInteger(uint64_t Value)
 /**
  * \brief Create an real number object
  */
-tSpiderVariable        *Object_CreateReal(double Value)
+tSpiderObject *Object_CreateReal(double Value)
 {
-       tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) );
+       tSpiderObject   *ret = malloc( sizeof(tSpiderObject) );
        ret->Type = SS_DATATYPE_REAL;
        ret->ReferenceCount = 1;
        ret->Real = Value;
@@ -61,9 +65,9 @@ tSpiderVariable       *Object_CreateReal(double Value)
 /**
  * \brief Create an string object
  */
-tSpiderVariable        *Object_CreateString(int Length, const char *Data)
+tSpiderObject *Object_CreateString(int Length, const char *Data)
 {
-       tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) + Length + 1 );
+       tSpiderObject   *ret = malloc( sizeof(tSpiderObject) + Length + 1 );
        ret->Type = SS_DATATYPE_STRING;
        ret->ReferenceCount = 1;
        ret->String.Length = Length;
@@ -73,10 +77,36 @@ tSpiderVariable     *Object_CreateString(int Length, const char *Data)
 }
 
 /**
+ * \brief Concatenate two strings
  */
-tSpiderVariable        *Object_CastTo(int Type, tSpiderVariable *Source)
+tSpiderObject *Object_StringConcat(tSpiderObject *Str1, tSpiderObject *Str2)
 {
-       tSpiderVariable *ret;
+        int    newLen = 0;
+       tSpiderObject   *ret;
+       if(Str1)        newLen += Str1->String.Length;
+       if(Str2)        newLen += Str2->String.Length;
+       ret = malloc( sizeof(tSpiderObject) + newLen + 1 );
+       ret->Type = SS_DATATYPE_STRING;
+       ret->ReferenceCount = 1;
+       ret->String.Length = newLen;
+       if(Str1)
+               memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
+       if(Str2) {
+               if(Str1)
+                       memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
+               else
+                       memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
+       }
+       ret->String.Data[ newLen ] = '\0';
+       return ret;
+}
+
+/**
+ * \brief Cast one object to another
+ */
+tSpiderObject *Object_CastTo(int Type, tSpiderObject *Source)
+{
+       tSpiderObject   *ret = ERRPTR;
        // Check if anything needs to be done
        if( Source->Type == Type ) {
                Object_Reference(Source);
@@ -92,7 +122,7 @@ tSpiderVariable      *Object_CastTo(int Type, tSpiderVariable *Source)
                return ERRPTR;
        
        case SS_DATATYPE_INTEGER:
-               ret = malloc(sizeof(tSpiderVariable));
+               ret = malloc(sizeof(tSpiderObject));
                ret->Type = SS_DATATYPE_INTEGER;
                ret->ReferenceCount = 1;
                switch(Source->Type)
@@ -102,9 +132,14 @@ tSpiderVariable    *Object_CastTo(int Type, tSpiderVariable *Source)
                case SS_DATATYPE_REAL:  ret->Integer = Source->Real;    break;
                default:
                        fprintf(stderr, "Object_CastTo - Invalid cast from %i\n", Source->Type);
+                       free(ret);
+                       ret = ERRPTR;
                        break;
                }
                break;
+       default:
+               fprintf(stderr, "BUG REPORT: Unimplemented cast target\n");
+               break;
        }
        
        return ret;
@@ -113,7 +148,7 @@ tSpiderVariable     *Object_CastTo(int Type, tSpiderVariable *Source)
 /**
  * \brief Condenses a value down to a boolean
  */
-int Object_IsTrue(tSpiderVariable *Value)
+int Object_IsTrue(tSpiderObject *Value)
 {
        switch(Value->Type)
        {
@@ -139,33 +174,53 @@ int Object_IsTrue(tSpiderVariable *Value)
        return 0;
 }
 
-tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
+/**
+ * \brief Execute an AST node and return its value
+ */
+tSpiderObject *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
 {
        tAST_Node       *node;
-       tSpiderVariable *ret, *tmpvar;
-       tSpiderVariable *op1, *op2;     // Binary operations
+       tSpiderObject   *ret, *tmpobj;
+       tSpiderObject   *op1, *op2;     // Binary operations
         int    cmp;    // Used in comparisons
        
        switch(Node->Type)
        {
        // No Operation
-       case NODETYPE_NOP:      ret = NULL;     break ;
+       case NODETYPE_NOP:      ret = NULL;     break;
        
        // Code block
        case NODETYPE_BLOCK:
-               ret = NULL;
-               for(node = Node->Block.FirstChild; node; node = node->NextSibling )
                {
-                       if(node->Type == NODETYPE_RETURN) {
-                               ret = AST_ExecuteNode(Script, node);
-                               break ;
+                       tAST_BlockState blockInfo;
+                       blockInfo.FirstVar = NULL;
+                       blockInfo.Parent = Block;
+                       blockInfo.Script = Block->Script;
+                       ret = NULL;
+                       for(node = Node->Block.FirstChild; node; node = node->NextSibling )
+                       {
+                               if(node->Type == NODETYPE_RETURN) {
+                                       ret = AST_ExecuteNode(&blockInfo, node);
+                                       break ;
+                               }
+                               else {
+                                       tmpobj = AST_ExecuteNode(&blockInfo, node);
+                                       if(tmpobj == ERRPTR) {  // Error check
+                                               ret = ERRPTR;
+                                               break ;
+                                       }
+                                       if(tmpobj)      Object_Dereference(tmpobj);     // Free unused value
+                               }
                        }
-                       else {
-                               tmpvar = AST_ExecuteNode(Script, node);
-                               if(tmpvar == ERRPTR)    return ERRPTR;  // Error check
-                               if(tmpvar)      Object_Dereference(tmpvar);     // Free unused value
+                       // Clean up variables
+                       while(blockInfo.FirstVar)
+                       {
+                               tAST_Variable   *nextVar = blockInfo.FirstVar->Next;
+                               Variable_Destroy( blockInfo.FirstVar );
+                               blockInfo.FirstVar = nextVar;
                        }
                }
+               
                break;
        
        // Assignment
@@ -174,28 +229,80 @@ tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
                        fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
                        return ERRPTR;
                }
-               ret = AST_ExecuteNode(Script, Node->Assign.Value);
-               // TODO: Apply operation
-               Variable_SetValue( Script, Node->Assign.Dest->Variable.Name, ret );
+               ret = AST_ExecuteNode(Block, Node->Assign.Value);
+               if(ret != ERRPTR)
+                       Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret );
                break;
        
+       // Function Call
        case NODETYPE_FUNCTIONCALL:
-               // TODO: Find a function from the export list in variant
-               //SpiderScript_ExecuteMethod(Script, Node->FunctionCall.Name
-               ret = ERRPTR;
-               fprintf(stderr, "TODO: Implement function calls\n");
+               {
+                        int    nParams = 0;
+                       for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
+                               nParams ++;
+                       }
+                       // Logical block (used to allocate `params`)
+                       {
+                               tSpiderObject   *params[nParams];
+                                int    i=0;
+                               for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
+                                       params[i] = AST_ExecuteNode(Block, node);
+                                       if( params[i] == ERRPTR ) {
+                                               while(i--)      Object_Dereference(params[i]);
+                                               ret = ERRPTR;
+                                               goto _return;
+                                       }
+                                       i ++;
+                               }
+                               
+                               // Call the function (SpiderScript_ExecuteMethod does the
+                               // required namespace handling)
+                               ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
+                               
+                               // Dereference parameters
+                               while(i--)      Object_Dereference(params[i]);
+                               
+                               // falls out
+                       }
+               }
                break;
        
        // Return's special handling happens elsewhere
        case NODETYPE_RETURN:
-               ret = AST_ExecuteNode(Script, Node->UniOp.Value);
+               ret = AST_ExecuteNode(Block, Node->UniOp.Value);
                break;
        
-       // Variable
-       case NODETYPE_VARIABLE: ret = Variable_GetValue( Script, Node->Variable.Name ); break;
+       // Define a variable
+       case NODETYPE_DEFVAR:
+               ret = NULL;
+               if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
+                       ret = ERRPTR;
+               break;
        
+       // Variable
+       case NODETYPE_VARIABLE:
+               ret = Variable_GetValue( Block, Node->Variable.Name );
+               break;
+
+       // Cast a value to another
+       case NODETYPE_CAST:
+               ret = Object_CastTo(
+                       Node->Cast.DataType,
+                       AST_ExecuteNode(Block, Node->Cast.Value)
+                       );
+               break;
+
+       // Index into an array
+       case NODETYPE_INDEX:
+               fprintf(stderr, "TODO: Array indexing\n");
+               ret = ERRPTR;
+               break;
+
        // TODO: Implement runtime constants
-       case NODETYPE_CONSTANT: ret = ERRPTR;   break;
+       case NODETYPE_CONSTANT:
+               fprintf(stderr, "TODO: Runtime Constants\n");
+               ret = ERRPTR;
+               break;
        // Constant Values
        case NODETYPE_STRING:   ret = Object_CreateString( Node->String.Length, Node->String.Data );    break;
        case NODETYPE_INTEGER:  ret = Object_CreateInteger( Node->Integer );    break;
@@ -206,8 +313,14 @@ tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
        case NODETYPE_LOGICALAND:       // Logical AND (&&)
        case NODETYPE_LOGICALOR:        // Logical OR (||)
        case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
-               op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
-               op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
+               op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
+               if(op1 == ERRPTR)       return ERRPTR;
+               op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
+               if(op2 == ERRPTR) {
+                       Object_Dereference(op1);
+                       return ERRPTR;
+               }
+               
                switch( Node->Type )
                {
                case NODETYPE_LOGICALAND:
@@ -221,14 +334,23 @@ tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
                        break;
                default:        break;
                }
+               
+               // Free intermediate objects
+               Object_Dereference(op1);
+               Object_Dereference(op2);
                break;
        
        // Comparisons
        case NODETYPE_EQUALS:
        case NODETYPE_LESSTHAN:
        case NODETYPE_GREATERTHAN:
-               op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
-               op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
+               op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
+               if(op1 == ERRPTR)       return ERRPTR;
+               op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
+               if(op2 == ERRPTR) {
+                       Object_Dereference(op1);
+                       return ERRPTR;
+               }
                
                // No conversion done for NULL
                // TODO: Determine if this will ever be needed
@@ -242,14 +364,19 @@ tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
                // Convert types
                if( op1->Type != op2->Type ) {
                        // If dynamically typed, convert op2 to op1's type
-                       if(Script->Variant->bDyamicTyped)
+                       if(Block->Script->Variant->bDyamicTyped)
                        {
-                               tmpvar = op2;
+                               tmpobj = op2;
                                op2 = Object_CastTo(op1->Type, op2);
-                               Object_Dereference(tmpvar);
+                               Object_Dereference(tmpobj);
+                               if(op2 == ERRPTR) {
+                                       Object_Dereference(op1);
+                                       return ERRPTR;
+                               }
                        }
                        // If statically typed, this should never happen, but catch it anyway
                        else {
+                               fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
                                ret = ERRPTR;
                                break;
                        }
@@ -308,20 +435,30 @@ tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
        case NODETYPE_BITSHIFTRIGHT:
        case NODETYPE_BITROTATELEFT:
                // Get operands
-               op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
-               op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
+               op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
+               if(op1 == ERRPTR)       return ERRPTR;
+               op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
+               if(op2 == ERRPTR) {
+                       Object_Dereference(op1);
+                       return ERRPTR;
+               }
                
                // Convert types
-               if( op1->Type != op2->Type ) {
+               if( op1 && op2 && op1->Type != op2->Type ) {
                        // If dynamically typed, convert op2 to op1's type
-                       if(Script->Variant->bDyamicTyped)
+                       if(Block->Script->Variant->bDyamicTyped)
                        {
-                               tmpvar = op2;
+                               tmpobj = op2;
                                op2 = Object_CastTo(op1->Type, op2);
-                               Object_Dereference(tmpvar);
+                               Object_Dereference(tmpobj);
+                               if(op2 == ERRPTR) {
+                                       Object_Dereference(op1);
+                                       return ERRPTR;
+                               }
                        }
                        // If statically typed, this should never happen, but catch it anyway
                        else {
+                               fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
                                ret = ERRPTR;
                                break;
                        }
@@ -335,8 +472,11 @@ tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
                case SS_DATATYPE_STRING:
                        switch(Node->Type)
                        {
+                       case NODETYPE_ADD:      // Concatenate
+                               ret = Object_StringConcat(op1, op2);
+                               break;
                        default:
-                               fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Node->Type);
+                               fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type);
                                ret = ERRPTR;
                                break;
                        }
@@ -375,5 +515,111 @@ tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
        //      fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
        //      break;
        }
+_return:
        return ret;
 }
+
+/**
+ * \brief Define a variable
+ * \param Block        Current block state
+ * \param Type Type of the variable
+ * \param Name Name of the variable
+ * \return Boolean Failure
+ */
+tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
+{
+       tAST_Variable   *var, *prev = NULL;
+       
+       for( var = Block->FirstVar; var; prev = var, var = var->Next )
+       {
+               if( strcmp(var->Name, Name) == 0 ) {
+                       fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name);
+                       return ERRPTR;
+               }
+       }
+       
+       var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
+       var->Next = NULL;
+       var->Type = Type;
+       var->Object = NULL;
+       strcpy(var->Name, Name);
+       
+       if(prev)        prev->Next = var;
+       else    Block->FirstVar = var;
+       
+       //printf("Defined variable %s (%i)\n", Name, Type);
+       
+       return var;
+}
+
+/**
+ * \brief Set the value of a variable
+ */
+void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderObject *Value)
+{
+       tAST_Variable   *var;
+       tAST_BlockState *bs;
+       
+       for( bs = Block; bs; bs = bs->Parent )
+       {
+               for( var = bs->FirstVar; var; var = var->Next )
+               {
+                       if( strcmp(var->Name, Name) == 0 ) {
+                               if( !Block->Script->Variant->bDyamicTyped
+                                && (Value && var->Type != Value->Type) ) {
+                                       fprintf(stderr, "ERROR: Type mismatch assigning to '%s'\n", Name);
+                                       return ;
+                               }
+                               Object_Reference(Value);
+                               Object_Dereference(var->Object);
+                               var->Object = Value;
+                               return ;
+                       }
+               }
+       }
+       
+       if( Block->Script->Variant->bDyamicTyped )
+       {
+               // Define variable
+               var = Variable_Define(Block, Value->Type, Name);
+               Object_Reference(Value);
+               var->Object = Value;
+       }
+       else
+       {
+               fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name);
+       }
+}
+
+/**
+ * \brief Get the value of a variable
+ */
+tSpiderObject *Variable_GetValue(tAST_BlockState *Block, const char *Name)
+{
+       tAST_Variable   *var;
+       tAST_BlockState *bs;
+       
+       for( bs = Block; bs; bs = bs->Parent )
+       {
+               for( var = bs->FirstVar; var; var = var->Next )
+               {
+                       if( strcmp(var->Name, Name) == 0 ) {
+                               Object_Reference(var->Object);
+                               return var->Object;
+                       }
+               }
+       }
+       
+       fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name);
+       
+       return ERRPTR;
+}
+
+/**
+ * \brief Destorys a variable
+ */
+void Variable_Destroy(tAST_Variable *Variable)
+{
+       Object_Dereference(Variable->Object);
+       free(Variable);
+}
diff --git a/Usermode/Libraries/libspiderscript.so_src/exports.c b/Usermode/Libraries/libspiderscript.so_src/exports.c
new file mode 100644 (file)
index 0000000..bce3e79
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Acess2 - SpiderScript
+ * - Script Exports (Lang. Namespace)
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <spiderscript.h>
+
+// === PROTOTYPES ===
+tSpiderObject  *Exports_Lang_Struct(tSpiderScript *Script, int NArgs, tSpiderObject **Args);
+
+// === GLOBALS ===
+ int   gaExports_Lang_Struct_Args[] = {SS_DATATYPE_STRING,-1};
+
+tSpiderFunction        gaSpiderScript_Exports[] = {
+       {"Lang.Struct", Exports_Lang_Struct, gaExports_Lang_Struct_Args}
+};
+const int      giSpiderScript_NumExports = sizeof(gaSpiderScript_Exports)/sizeof(tSpiderFunction);
+
+// === CODE ===
+tSpiderObject *Exports_Lang_Struct(tSpiderScript *Script, int NArgs, tSpiderObject **Args)
+{
+        int    i;
+       printf("Exports_Lang_Struct: (Script=%p, NArgs=%i, Args=%p)\n", Script, NArgs, Args);
+       
+       for( i = 0; i < NArgs; i ++ )
+       {
+               printf(" Args[%i] = {Type: %i, ", i, Args[i]->Type);
+               switch(Args[i]->Type)
+               {
+               case SS_DATATYPE_INTEGER:
+                       printf(" Integer: 0x%lx", Args[i]->Integer);
+                       break;
+               case SS_DATATYPE_REAL:
+                       printf(" Real: %f", Args[i]->Real);
+                       break;
+               case SS_DATATYPE_STRING:
+                       printf(" Length: %i, Data = '%s'", Args[i]->String.Length, Args[i]->String.Data);
+                       break;
+               default:
+                       break;
+               }
+               printf("}\n");
+       }
+       
+       return NULL;
+}
index 6badd45..25a7aa7 100644 (file)
@@ -1,14 +1,22 @@
 /*
- * Acess2 init
+ * SpiderScript
  * - Script Lexer
  */
 #include "tokens.h"
 #include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define USE_SCOPE_CHAR 0
+
+#define DEBUG  0
+
+#define ARRAY_SIZE(x)  ((sizeof(x))/(sizeof((x)[0])))
 
 // === PROTOTYPES ===
  int   is_ident(char ch);
- int   isdigit(char ch);
- int   isspace(char ch);
+ int   isdigit(int ch);
+ int   isspace(int ch);
  int   GetToken(tParser *File);
 
 // === CONSTANTS ===
@@ -17,8 +25,12 @@ const struct {
        const char      *Name;
 } csaReservedWords[] = {
        {TOK_RWD_FUNCTION, "function"},
-       {TOK_RWD_INTEGER, "integer"},
-       {TOK_RWD_REAL, "string"}
+       {TOK_RWD_RETURN, "return"},
+       {TOK_RWD_VOID, "void"},
+       {TOK_RWD_OBJECT, "Object"},
+       {TOK_RWD_INTEGER, "Integer"},
+       {TOK_RWD_REAL, "Real"},
+       {TOK_RWD_STRING, "String"}
 };
 
 // === CODE ===
@@ -31,19 +43,43 @@ int GetToken(tParser *File)
         int    ret;
        
        if( File->NextToken != -1 ) {
+               // Save Last
+               File->LastToken = File->Token;
+               File->LastTokenStr = File->TokenStr;
+               File->LastTokenLen = File->TokenLen;
+               File->LastLine = File->CurLine;
+               // Restore Next
                File->Token = File->NextToken;
                File->TokenStr = File->NextTokenStr;
                File->TokenLen = File->NextTokenLen;
+               File->CurLine = File->NextLine;
+               // Set State
+               File->CurPos = File->TokenStr + File->TokenLen;
                File->NextToken = -1;
+               {
+                       char    buf[ File->TokenLen + 1];
+                       memcpy(buf, File->TokenStr, File->TokenLen);
+                       buf[File->TokenLen] = 0;
+                       #if DEBUG
+                       printf(" GetToken: FAST Return %i (%i long) (%s)\n", File->Token, File->TokenLen, buf);
+                       #endif
+               }
                return File->Token;
        }
        
+       //printf("  GetToken: File=%p, File->CurPos = %p\n", File, File->CurPos);
+       
        // Clear whitespace (including comments)
        for( ;; )
        {
                // Whitespace
                while( isspace( *File->CurPos ) )
+               {
+                       //printf("whitespace 0x%x, line = %i\n", *File->CurPos, File->CurLine);
+                       if( *File->CurPos == '\n' )
+                               File->CurLine ++;
                        File->CurPos ++;
+               }
                
                // # Line Comments
                if( *File->CurPos == '#' ) {
@@ -61,9 +97,13 @@ int GetToken(tParser *File)
                
                // C-Style Block Comments
                if( *File->CurPos == '/' && File->CurPos[1] == '*' ) {
-                       File->CurPos += 2;
+                       File->CurPos += 2;      // Eat the '/*'
                        while( *File->CurPos && !(File->CurPos[-1] == '*' && *File->CurPos == '/') )
+                       {
+                               if( *File->CurPos == '\n' )     File->CurLine ++;
                                File->CurPos ++;
+                       }
+                       File->CurPos ++;        // Eat the '/'
                        continue ;
                }
                
@@ -75,11 +115,14 @@ int GetToken(tParser *File)
        File->LastToken = File->Token;
        File->LastTokenStr = File->TokenStr;
        File->LastTokenLen = File->TokenLen;
+       File->LastLine = File->CurLine;
        
        // Read token
        File->TokenStr = File->CurPos;
        switch( *File->CurPos++ )
        {
+       case '\0':      ret = TOK_EOF;  break;
+       
        // Operations
        case '/':       ret = TOK_DIV;  break;
        case '*':       ret = TOK_MUL;  break;
@@ -95,9 +138,9 @@ int GetToken(tParser *File)
        
        // Strings
        case '"':
-               File->TokenStr ++;
                while( *File->CurPos && !(*File->CurPos == '"' && *File->CurPos != '\\') )
                        File->CurPos ++;
+               File->CurPos ++;
                ret = TOK_STR;
                break;
        
@@ -111,7 +154,10 @@ int GetToken(tParser *File)
        
        // Core symbols
        case ';':       ret = TOK_SEMICOLON;    break;
+       case ',':       ret = TOK_COMMA;        break;
+       #if USE_SCOPE_CHAR
        case '.':       ret = TOK_SCOPE;        break;
+       #endif
        
        // Equals
        case '=':
@@ -128,7 +174,6 @@ int GetToken(tParser *File)
        // Variables
        // \$[0-9]+ or \$[_a-zA-Z][_a-zA-Z0-9]*
        case '$':
-               File->TokenStr ++;
                // Numeric Variable
                if( isdigit( *File->CurPos ) ) {
                        while( isdigit(*File->CurPos) )
@@ -136,7 +181,7 @@ int GetToken(tParser *File)
                }
                // Ident Variable
                else {
-                       while( is_ident(*File->CurPos) )
+                       while( is_ident(*File->CurPos) || isdigit(*File->CurPos) )
                                File->CurPos ++;
                }
                ret = TOK_VARIABLE;
@@ -144,6 +189,7 @@ int GetToken(tParser *File)
        
        // Default (Numbers and Identifiers)
        default:
+               File->CurPos --;
                // Numbers
                if( isdigit(*File->CurPos) )
                {
@@ -160,16 +206,49 @@ int GetToken(tParser *File)
                        while( is_ident(*File->CurPos) || isdigit(*File->CurPos) )
                                File->CurPos ++;
                        
+                       // This is set later too, but we use it below
+                       File->TokenLen = File->CurPos - File->TokenStr;
                        ret = TOK_IDENT;
+                       
+                       // Check if it's a reserved word
+                       {
+                               char    buf[File->TokenLen + 1];
+                                int    i;
+                               memcpy(buf, File->TokenStr, File->TokenLen);
+                               buf[File->TokenLen] = 0;
+                               for( i = 0; i < ARRAY_SIZE(csaReservedWords); i ++ )
+                               {
+                                       if(strcmp(csaReservedWords[i].Name, buf) == 0) {
+                                               ret = csaReservedWords[i].Value;
+                                               break ;
+                                       }
+                               }
+                       }
+                       // If there's no match, just keep ret as TOK_IDENT
+                       
                        break;
                }
                // Syntax Error
-               ret = 0;
+               ret = TOK_INVAL;
+               
+               fprintf(stderr, "Syntax Error: Unknown symbol '%c'\n", *File->CurPos);
+               longjmp(File->JmpTarget, 1);
+               
                break;
        }
        // Return
        File->Token = ret;
        File->TokenLen = File->CurPos - File->TokenStr;
+       
+       #if DEBUG
+       {
+               char    buf[ File->TokenLen + 1];
+               memcpy(buf, File->TokenStr, File->TokenLen);
+               buf[File->TokenLen] = 0;
+               //printf("  GetToken: File->CurPos = %p\n", File->CurPos);
+               printf(" GetToken: Return %i (%i long) (%s)\n", ret, File->TokenLen, buf);
+       }
+       #endif
        return ret;
 }
 
@@ -177,13 +256,20 @@ void PutBack(tParser *File)
 {
        if( File->LastToken == -1 ) {
                // ERROR:
+               fprintf(stderr, "INTERNAL ERROR: Putback when LastToken==-1\n");
+               longjmp( File->JmpTarget, -1 );
                return ;
        }
+       #if DEBUG
+       printf(" PutBack: Was on %i\n", File->Token);
+       #endif
        // Save
+       File->NextLine = File->CurLine;
        File->NextToken = File->Token;
        File->NextTokenStr = File->TokenStr;
        File->NextTokenLen = File->TokenLen;
        // Restore
+       File->CurLine = File->LastLine;
        File->Token = File->LastToken;
        File->TokenStr = File->LastTokenStr;
        File->TokenLen = File->LastTokenLen;
@@ -194,6 +280,7 @@ void PutBack(tParser *File)
 
 int LookAhead(tParser *File)
 {
+       // TODO: Should I save the entire state here?
         int    ret = GetToken(File);
        PutBack(File);
        return ret;
@@ -207,19 +294,22 @@ int LookAhead(tParser *File)
 int is_ident(char ch)
 {
        if('a' <= ch && ch <= 'z')      return 1;
-       if('Z' <= ch && ch <= 'Z')      return 1;
+       if('A' <= ch && ch <= 'Z')      return 1;
        if(ch == '_')   return 1;
+       #if !USE_SCOPE_CHAR
+       if(ch == '.')   return 1;
+       #endif
        if(ch < 0)      return 1;
        return 0;
 }
 
-int isdigit(char ch)
+int isdigit(int ch)
 {
        if('0' <= ch && ch <= '9')      return 1;
        return 0;
 }
 
-int isspace(char ch)
+int isspace(int ch)
 {
        if(' ' == ch)   return 1;
        if('\t' == ch)  return 1;
index ce39c08..e5c225c 100644 (file)
 
 // === IMPORTS ===
 extern tAST_Script     *Parse_Buffer(tSpiderVariant *Variant, char *Buffer);
+extern const int       giSpiderScript_NumExports;
+extern tSpiderFunction gaSpiderScript_Exports[];
+extern tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
+extern void    Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderObject *Value);
 
 // === CODE ===
 /**
@@ -42,13 +46,21 @@ tSpiderScript *SpiderScript_ParseFile(tSpiderVariant *Variant, const char *Filen
        fLen = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        
-       data = malloc(fLen);
+       // Allocate and read data
+       data = malloc(fLen + 1);
        if(!data)       return NULL;
        fread(data, fLen, 1, fp);
+       data[fLen] = '\0';
        
        fclose(fp);
        
+       ret->CurNamespace = NULL;
        ret->Script = Parse_Buffer(Variant, data);
+       if( ret->Script == NULL ) {
+               free(data);
+               free(ret);
+               return NULL;
+       }
        
        free(data);
        
@@ -57,21 +69,105 @@ tSpiderScript *SpiderScript_ParseFile(tSpiderVariant *Variant, const char *Filen
 
 /**
  * \brief Execute a script function
- * \todo Arguments?
+ * \param Script       Script context to execute in
+ * \param Function     Function name to execute
+ * \param NArguments   Number of arguments to pass
+ * \param Arguments    Arguments passed
  */
-tSpiderVariable *SpiderScript_ExecuteMethod(tSpiderScript *Script, const char *Function)
+tSpiderObject *SpiderScript_ExecuteMethod(tSpiderScript *Script,
+       const char *Function, int NArguments, tSpiderObject **Arguments)
 {
-       tAST_Function   *fcn = Script->Script->Functions;
+       char    *trueName = NULL;
+        int    i;
+        int    bFound = 0;     // Used to keep nesting levels down
+       tSpiderObject   *ret = ERRPTR;
+       
+       // Handle namespaces
+       if( Function[0] == '.' ) {
+               trueName = (char*)&Function[1];
+       }
+       else if( !Script->CurNamespace ) {
+               trueName = (char*)Function;
+       }
+       else {
+                int    len = strlen(Script->CurNamespace) + 1 + strlen(Function);
+               trueName = malloc( len + 1 );
+               strcpy(trueName, Script->CurNamespace);
+               strcat(trueName, ".");
+               strcat(trueName, Function);
+       }
+       
+       // First: Find the function in the script
+       {
+               tAST_Function   *fcn = Script->Script->Functions;
+               for( ; fcn; fcn = fcn->Next ) {
+                       if( strcmp(fcn->Name, trueName) == 0 )
+                               break;
+               }
+               // Execute!
+               if(fcn) {
+                       tAST_BlockState bs;
+                       bs.FirstVar = NULL;     //< TODO: Parameters
+                       bs.Parent = NULL;
+                       bs.Script = Script;
+                       {
+                               tAST_Node       *arg;
+                                int    i = 0;
+                               for( arg = fcn->Arguments; arg; arg = arg->NextSibling, i++ )
+                               {
+                                       // TODO: Type checks
+                                       Variable_Define(&bs, arg->DefVar.DataType, arg->DefVar.Name);
+                                       if( i >= NArguments )   break;  // TODO: Return gracefully
+                                       Variable_SetValue(&bs, arg->DefVar.Name, Arguments[i]);
+                               }
+                       }
+                       ret = AST_ExecuteNode(&bs, fcn->Code);
+                       bFound = 1;
+               }
+       }
+               
+       // Didn't find it in script?
+       if(!bFound)
+       {       
+               // Second: Search the variant's exports
+               for( i = 0; i < Script->Variant->NFunctions; i ++ )
+               {
+                       if( strcmp( Script->Variant->Functions[i].Name, trueName) == 0 )
+                               break;
+               }
+               // Execute!
+               if(i < Script->Variant->NFunctions) {
+                       ret = Script->Variant->Functions[i].Handler( Script, NArguments, Arguments );
+                       bFound = 1;
+               }
+       }
        
-       // Find the function
-       for( ; fcn; fcn = fcn->Next ) {
-               if( strcmp(fcn->Name, Function) == 0 )
-                       break;
+       // Not in variant exports? Search the language internal ones
+       if(!bFound)
+       {
+               for( i = 0; i < giSpiderScript_NumExports; i ++ )
+               {
+                       if( strcmp( gaSpiderScript_Exports[i].Name, trueName ) == 0 )
+                               break;
+               }
+               // Execute!
+               if(i < giSpiderScript_NumExports) {
+                       ret = gaSpiderScript_Exports[i].Handler( Script, NArguments, Arguments );
+                       bFound = 1;
+               }
        }
-       if(!fcn)        return NULL;
        
-       // Execute!
-       return AST_ExecuteNode(Script, fcn->Code);
+       // Not found?
+       if(!bFound)
+       {
+               fprintf(stderr, "Undefined reference to '%s'\n", trueName);
+       }
+       
+       if( trueName != Function && trueName != &Function[1] )
+               free(trueName);
+       
+       return ret;
+       
 }
 
 /**
@@ -99,4 +195,9 @@ void SpiderScript_Free(tSpiderScript *Script)
                free( fcn );
                fcn = nextFcn;
        }
+       
+       // TODO: Pass this off to AST for a proper cleanup
+       free(Script->Script);
+       
+       free(Script);
 }
index 2ccf5d8..31dabad 100644 (file)
@@ -6,13 +6,17 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <spiderscript.h>
+#define WANT_TOKEN_STRINGS     1
 #include "tokens.h"
 #include "ast.h"
 
+#define DEBUG  0
+
 // === PROTOTYPES ===
 tAST_Script    *Parse_Buffer(tSpiderVariant *Variant, char *Buffer);
 tAST_Node      *Parse_DoCodeBlock(tParser *Parser);
-tAST_Node      *Parse_DoExpr(tParser *Parser);
+tAST_Node      *Parse_DoBlockLine(tParser *Parser);
+tAST_Node      *Parse_GetVarDef(tParser *Parser, int Type);
 
 tAST_Node      *Parse_DoExpr0(tParser *Parser);        // Assignment
 tAST_Node      *Parse_DoExpr1(tParser *Parser);        // Boolean Operators
@@ -30,7 +34,7 @@ tAST_Node     *Parse_GetNumeric(tParser *Parser);
 tAST_Node      *Parse_GetVariable(tParser *Parser);
 tAST_Node      *Parse_GetIdent(tParser *Parser);
 
-void   SyntaxAssert(int Have, int Want);
+void   SyntaxAssert(tParser *Parser, int Have, int Want);
 
 // === CODE ===
 /**
@@ -44,35 +48,99 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer)
        tAST_Node       *mainCode;
        char    *name;
        tAST_Function   *fcn;
+        int    type;
+       
+       #if DEBUG >= 2
+       printf("Parse_Buffer: (Variant=%p, Buffer=%p)\n", Variant, Buffer);
+       #endif
        
        // Initialise parser
+       parser.LastToken = -1;
+       parser.NextToken = -1;
+       parser.CurLine = 1;
        parser.BufStart = Buffer;
        parser.CurPos = Buffer;
        
        ret = AST_NewScript();
        mainCode = AST_NewCodeBlock();
        
-       for(;;)
+       if( setjmp( parser.JmpTarget ) != 0 )
+       {
+               AST_FreeNode( mainCode );
+               return NULL;
+       }
+       
+       while(Parser->Token != TOK_EOF)
        {
                switch( GetToken(Parser) )
                {
-               case TOK_RWD_FUNCTION:                  
-                       // Define a function
-                       SyntaxAssert( GetToken(Parser), TOK_IDENT );
+               case TOK_EOF:
+                       break;
+               
+               // Typed variables/functions
+               case TOKEN_GROUP_TYPES:
+                       {
+                        int    tok, type;
+                       TOKEN_GET_DATATYPE(type, Parser->Token);
+                       
+                       tok = GetToken(Parser);
+                       // Define a function (pass on to the other function definition code)
+                       if( tok == TOK_IDENT ) {
+                               goto defFcn;
+                       }
+                       // Define a variable
+                       else if( tok == TOK_VARIABLE ) {
+                               AST_AppendNode( mainCode, Parse_GetVarDef(Parser, type) );
+                               SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
+                       }
+                       else {
+                               fprintf(stderr, "ERROR: Unexpected %s, expected TOK_IDENT or TOK_VARIABLE\n",
+                                       csaTOKEN_NAMES[tok]);
+                       }
+                       }
+                       break;
+               
+               // Define a function
+               case TOK_RWD_FUNCTION:
+                       if( !Variant->bDyamicTyped ) {
+                               fprintf(stderr, "ERROR: Attempt to create a dynamic function\n");
+                               longjmp(Parser->JmpTarget, -1);
+                       }
+                       type = SS_DATATYPE_DYNAMIC;
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
+               defFcn:
                        name = strndup( Parser->TokenStr, Parser->TokenLen );
                        fcn = AST_AppendFunction( ret, name );
+                       #if DEBUG
+                       printf("DefFCN %s\n", name);
+                       #endif
                        free(name);
                        
-                       SyntaxAssert( GetToken(Parser), TOK_PAREN_OPEN );
-                       // TODO: Arguments
-                       SyntaxAssert( GetToken(Parser), TOK_PAREN_CLOSE );
+                       // Get arguments
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN );
+                       if( LookAhead(Parser) != TOK_PAREN_CLOSE )
+                       {
+                               do {
+                                       type = SS_DATATYPE_DYNAMIC;
+                                       GetToken(Parser);
+                                       // Non dynamic typed variants must use data types
+                                       if( !Variant->bDyamicTyped ) {
+                                               TOKEN_GET_DATATYPE(type, Parser->Token);
+                                               GetToken(Parser);
+                                       }
+                                       AST_AppendFunctionArg(fcn, Parse_GetVarDef(Parser, type)); 
+                               }       while(GetToken(Parser) == TOK_COMMA);
+                       }
+                       else
+                               GetToken(Parser);
+                       SyntaxAssert(Parser, Parser->Token, TOK_PAREN_CLOSE );
                        
                        AST_SetFunctionCode( fcn, Parse_DoCodeBlock(Parser) );
                        break;
                
                default:
-                       PutBack(&parser);
-                       AST_AppendNode( mainCode, Parse_DoExpr(Parser) );
+                       PutBack(Parser);
+                       AST_AppendNode( mainCode, Parse_DoBlockLine(Parser) );
                        break;
                }
        }
@@ -80,6 +148,8 @@ tAST_Script  *Parse_Buffer(tSpiderVariant *Variant, char *Buffer)
        fcn = AST_AppendFunction( ret, "" );
        AST_SetFunctionCode( fcn, mainCode );
        
+       printf("---- %p parsed as SpiderScript ----\n", Buffer);
+       
        return ret;
 }
 
@@ -89,24 +159,93 @@ tAST_Script        *Parse_Buffer(tSpiderVariant *Variant, char *Buffer)
 tAST_Node *Parse_DoCodeBlock(tParser *Parser)
 {
        tAST_Node       *ret;
-       SyntaxAssert( GetToken(Parser), TOK_BRACE_OPEN );
+       SyntaxAssert(Parser, GetToken(Parser), TOK_BRACE_OPEN );
        
        ret = AST_NewCodeBlock();
        
-       while( GetToken(Parser) != TOK_BRACE_CLOSE )
+       while( LookAhead(Parser) != TOK_BRACE_CLOSE )
+       {
+               AST_AppendNode( ret, Parse_DoBlockLine(Parser) );
+       }
+       GetToken(Parser);       // Omnomnom
+       return ret;
+}
+
+/**
+ * \brief Parse a line in a block
+ */
+tAST_Node *Parse_DoBlockLine(tParser *Parser)
+{
+       tAST_Node       *ret;
+       
+       //printf("Parse_DoBlockLine: Line %i\n", Parser->CurLine);
+       
+       switch(LookAhead(Parser))
        {
-               AST_AppendNode( ret, Parse_DoExpr(Parser) );
-               SyntaxAssert( GetToken(Parser), TOK_SEMICOLON );
+       
+       // Return from a method
+       case TOK_RWD_RETURN:
+               //printf("return\n");
+               GetToken(Parser);
+               ret = AST_NewUniOp(NODETYPE_RETURN, Parse_DoExpr0(Parser));
+               break;
+       
+       // Define Variables
+       case TOK_RWD_OBJECT:
+       case TOK_RWD_STRING:
+       case TOK_RWD_REAL:
+       case TOK_RWD_INTEGER:
+               {
+                        int    type;
+                       
+                       switch(GetToken(Parser))
+                       {
+                       case TOK_RWD_INTEGER:   type = SS_DATATYPE_INTEGER;     break;
+                       case TOK_RWD_OBJECT:    type = SS_DATATYPE_OBJECT;      break;
+                       case TOK_RWD_REAL:      type = SS_DATATYPE_REAL;        break;
+                       case TOK_RWD_STRING:    type = SS_DATATYPE_STRING;      break;
+                       }
+                       
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE);
+                       
+                       ret = Parse_GetVarDef(Parser, type);
+               }
+               break;
+       
+       // Default
+       default:
+               //printf("exp0\n");
+               ret = Parse_DoExpr0(Parser);
+               break;
        }
+       
+       SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON );
        return ret;
 }
 
 /**
- * \brief Parse an expression
+ * \brief Get a variable definition
  */
-tAST_Node *Parse_DoExpr(tParser *Parser)
+tAST_Node *Parse_GetVarDef(tParser *Parser, int Type)
 {
-       return Parse_DoExpr0(Parser);
+       char    name[Parser->TokenLen];
+       tAST_Node       *ret;
+       
+       SyntaxAssert(Parser, Parser->Token, TOK_VARIABLE);
+       
+       // copy the name (trimming the $)
+       memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
+       name[Parser->TokenLen-1] = 0;
+       // Define the variable
+       ret = AST_NewDefineVar(Type, name);
+       // Handle arrays
+       while( LookAhead(Parser) == TOK_SQUARE_OPEN )
+       {
+               GetToken(Parser);
+               AST_AppendNode(ret, Parse_DoExpr0(Parser));
+               SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
+       }
+       return ret;
 }
 
 /**
@@ -126,14 +265,18 @@ tAST_Node *Parse_DoExpr0(tParser *Parser)
        #if 0
        case TOK_DIV_EQU:
                GetToken(Parser);               // Eat Token
-               ret = AST_NewAssignOp(ret, NODETYPE_DIVIDE, DoExpr0(Parser));
+               ret = AST_NewAssign(NODETYPE_DIVIDE, ret, Parse_DoExpr0(Parser));
                break;
        case TOK_MULT_EQU:
                GetToken(Parser);               // Eat Token
-               ret = AST_NewAssignOp(ret, NODETYPE_MULTIPLY, DoExpr0(Parser));
+               ret = AST_NewAssign(NODETYPE_MULTIPLY, ret, Parse_DoExpr0(Parser));
                break;
        #endif
-       default:        break;
+       default:
+               #if DEBUG >= 2
+               printf("Parse_DoExpr0: Parser->Token = %i\n", Parser->Token);
+               #endif
+               break;
        }
        return ret;
 }
@@ -290,12 +433,18 @@ tAST_Node *Parse_DoExpr6(tParser *Parser)
 // --------------------
 tAST_Node *Parse_DoParen(tParser *Parser)
 {
+       #if DEBUG >= 2
+       printf("Parse_DoParen: (Parser=%p)\n", Parser);
+       #endif
        if(LookAhead(Parser) == TOK_PAREN_OPEN)
        {
                tAST_Node       *ret;
                GetToken(Parser);
+               
+               // TODO: Handle casts here
+               
                ret = Parse_DoExpr0(Parser);
-               SyntaxAssert(GetToken(Parser), TOK_PAREN_CLOSE);
+               SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
                return ret;
        }
        else
@@ -309,6 +458,10 @@ tAST_Node *Parse_DoValue(tParser *Parser)
 {
         int    tok = LookAhead(Parser);
 
+       #if DEBUG >= 2
+       printf("Parse_DoValue: tok = %i\n", tok);
+       #endif
+
        switch(tok)
        {
        case TOK_STR:   return Parse_GetString(Parser);
@@ -317,8 +470,9 @@ tAST_Node *Parse_DoValue(tParser *Parser)
        case TOK_VARIABLE:      return Parse_GetVariable(Parser);
 
        default:
-               //ParseError2( tok, TOK_T_VALUE );
-               return NULL;
+               fprintf(stderr, "Syntax Error: Unexpected %s on line %i, Expected TOK_T_VALUE\n",
+                       csaTOKEN_NAMES[tok], Parser->CurLine);
+               longjmp( Parser->JmpTarget, -1 );
        }
 }
 
@@ -350,12 +504,24 @@ tAST_Node *Parse_GetNumeric(tParser *Parser)
  */
 tAST_Node *Parse_GetVariable(tParser *Parser)
 {
-       char    *name;
        tAST_Node       *ret;
-       SyntaxAssert( GetToken(Parser), TOK_VARIABLE );
-       name = strndup( Parser->TokenStr+1, Parser->TokenLen-1 );
-       ret = AST_NewVariable( name );
-       free(name);
+       SyntaxAssert( Parser, GetToken(Parser), TOK_VARIABLE );
+       {
+               char    name[Parser->TokenLen];
+               memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
+               name[Parser->TokenLen-1] = 0;
+               ret = AST_NewVariable( name );
+               #if DEBUG >= 2
+               printf("Parse_GetVariable: name = '%s'\n", name);
+               #endif
+       }
+       // Handle array references
+       while( LookAhead(Parser) == TOK_SQUARE_OPEN )
+       {
+               GetToken(Parser);
+               ret = AST_NewBinOp(NODETYPE_INDEX, ret, Parse_DoExpr0(Parser));
+               SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
+       }
        return ret;
 }
 
@@ -366,11 +532,22 @@ tAST_Node *Parse_GetIdent(tParser *Parser)
 {
        tAST_Node       *ret;
        char    *name;
-       SyntaxAssert( GetToken(Parser), TOK_IDENT );
+       SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
        name = strndup( Parser->TokenStr, Parser->TokenLen );
        
+       #if 0
+       while( GetToken(Parser) == TOK_SCOPE )
+       {
+               ret = AST_New
+       }
+       PutBack(Parser);
+       #endif
+       
        if( GetToken(Parser) == TOK_PAREN_OPEN )
        {
+               #if DEBUG >= 2
+               printf("Parse_GetIdent: Calling '%s'\n", name);
+               #endif
                // Function Call
                ret = AST_NewFunctionCall( name );
                // Read arguments
@@ -378,13 +555,22 @@ tAST_Node *Parse_GetIdent(tParser *Parser)
                {
                        PutBack(Parser);
                        do {
+                               #if DEBUG >= 2
+                               printf(" Parse_GetIdent: Argument\n");
+                               #endif
                                AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
                        } while(GetToken(Parser) == TOK_COMMA);
-                       SyntaxAssert( Parser->Token, TOK_PAREN_CLOSE );
+                       SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
+                       #if DEBUG >= 2
+                       printf(" Parse_GetIdent: All arguments parsed\n");
+                       #endif
                }
        }
        else {
                // Runtime Constant
+               #if DEBUG >= 2
+               printf("Parse_GetIdent: Referencing '%s'\n", name);
+               #endif
                PutBack(Parser);
                ret = AST_NewConstant( name );
        }
@@ -396,12 +582,12 @@ tAST_Node *Parse_GetIdent(tParser *Parser)
 /**
  * \brief Check for an error
  */
-void SyntaxAssert(int Have, int Want)
+void SyntaxAssert(tParser *Parser, int Have, int Want)
 {
        if(Have != Want) {
-               fprintf(stderr, "ERROR: Expected %i, got %i\n", Want, Have);
-               //longjmp(jmpTarget, 1);
-               return;
+               fprintf(stderr, "ERROR: SyntaxAssert Failed, Expected %s(%i), got %s(%i) on line %i\n",
+                       csaTOKEN_NAMES[Want], Want, csaTOKEN_NAMES[Have], Have, Parser->CurLine);
+               longjmp(Parser->JmpTarget, -1);
        }
 }
 
index 44c3a81..9ecb720 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef _TOKENS_H_
 #define _TOKENS_H_
 
+#include <setjmp.h>
+
 // === TYPES ===
 typedef struct
 {      
@@ -10,14 +12,19 @@ typedef struct
        char    *BufStart;
        char    *CurPos;
        
+        int    LastLine;
         int    LastToken, LastTokenLen;
        char    *LastTokenStr;
        
+        int    NextLine;
         int    NextToken, NextTokenLen;
        char    *NextTokenStr;
        
+        int    CurLine;
         int    Token, TokenLen;
        char    *TokenStr;
+       
+       jmp_buf JmpTarget;
 }      tParser;
 
 // === FUNCTIONS ===
@@ -37,6 +44,11 @@ enum eTokens
        TOK_IDENT,
        
        TOK_RWD_FUNCTION,
+       TOK_RWD_NAMESPACE,
+       TOK_RWD_RETURN,
+       
+       TOK_RWD_VOID,
+       TOK_RWD_OBJECT,
        TOK_RWD_STRING,
        TOK_RWD_INTEGER,
        TOK_RWD_REAL,
@@ -67,4 +79,69 @@ enum eTokens
        TOK_LAST
 };
 
+#define TOKEN_GROUP_TYPES      TOK_RWD_VOID:\
+       case TOK_RWD_OBJECT:\
+       case TOK_RWD_INTEGER:\
+       case TOK_RWD_STRING:\
+       case TOK_RWD_REAL
+#define TOKEN_GROUP_TYPES_STR  "TOK_RWD_VOID, TOK_RWD_OBJECT, TOK_RWD_INTEGER, TOK_RWD_STRING or TOK_RWD_REAL"
+
+#define TOKEN_GET_DATATYPE(_type, _tok) do { switch(_tok) {\
+       case TOK_RWD_VOID:  _type = SS_DATATYPE_UNDEF;  break;\
+       case TOK_RWD_INTEGER:_type = SS_DATATYPE_INTEGER;       break;\
+       case TOK_RWD_OBJECT: _type = SS_DATATYPE_OBJECT;        break;\
+       case TOK_RWD_REAL:   _type = SS_DATATYPE_REAL;  break;\
+       case TOK_RWD_STRING: _type = SS_DATATYPE_STRING;        break;\
+       default:fprintf(stderr,\
+       "ERROR: Unexpected %s, expected "TOKEN_GROUP_TYPES_STR"\n",csaTOKEN_NAMES[Parser->Token]);\
+       break;\
+       } } while(0)
+
+# if WANT_TOKEN_STRINGS
+const char * const csaTOKEN_NAMES[] = {
+       "TOK_INVAL",
+       "TOK_EOF",
+       
+       "TOK_STR",
+       "TOK_INTEGER",
+       "TOK_VARIABLE",
+       "TOK_IDENT",
+       
+       "TOK_RWD_FUNCTION",
+       "TOK_RWD_NAMESPACE",
+       "TOK_RWD_RETURN",
+       
+       "TOK_RWD_VOID",
+       "TOK_RWD_OBJECT",
+       "TOK_RWD_STRING",
+       "TOK_RWD_INTEGER",
+       "TOK_RWD_REAL",
+       
+       "TOK_ASSIGN",
+       "TOK_SEMICOLON",
+       "TOK_COMMA",
+       "TOK_SCOPE",
+       "TOK_ELEMENT",
+       
+       "TOK_EQUALS",
+       "TOK_LT",       "TOK_LTE",
+       "TOK_GT",       "TOK_GTE",
+       
+       "TOK_DIV",      "TOK_MUL",
+       "TOK_PLUS",     "TOK_MINUS",
+       "TOK_SHL",      "TOK_SHR",
+       "TOK_LOGICAND", "TOK_LOGICOR",  "TOK_LOGICXOR",
+       "TOK_AND",      "TOK_OR",       "TOK_XOR",
+       
+       "TOK_PAREN_OPEN",
+       "TOK_PAREN_CLOSE",
+       "TOK_BRACE_OPEN",
+       "TOK_BRACE_CLOSE",
+       "TOK_SQUARE_OPEN",
+       "TOK_SQUARE_CLOSE",
+       
+       "TOK_LAST"
+};
+# endif
+
 #endif

UCC git Repository :: git.ucc.asn.au