CPPFLAGS +=
CFLAGS += -Wall -Werror -O3
LDFLAGS +=
-# -lspiderscript
BIN = init
OBJ = main.o
#include <acess/sys.h>
#include <stdlib.h>
#include <stdio.h>
-//#include <spiderscript.h>
//#include "common.h"
// === CONSTANTS ===
#define NUM_TERMS 4
#define DEFAULT_TERMINAL "/Devices/VTerm/0"
#define DEFAULT_SHELL "/Acess/SBin/login"
-#define DEFAULT_SCRIPT "/Acess/Conf/BootConf.isc"
#define ARRAY_SIZE(x) ((sizeof(x))/(sizeof((x)[0])))
// === PROTOTYPES ===
-/*
-tSpiderVariable *Script_System_IO_Open(tSpiderScript *, int, tSpiderVariable *);
-*/
-
-// === GLOBALS ===
-/*
-tSpiderFunction gaScriptNS_IO_Fcns[] = {
- {"Open", Script_System_IO_Open}
-};
-tSpiderNamespace gaScriptNS_System[] = {
- {
- "IO",
- 0, NULL,
- ARRAY_SIZE(gaScriptNS_IO_Fcns), gaScriptNS_IO_Fcns,
- 0, NULL
- }
-};
-
-tSpiderNamespace gaScriptNamespaces[] = {
- {
- "System",
- ARRAY_SIZE(gaScriptNS_System), gaScriptNS_System,
- 0, NULL,
- 0, NULL
- }
-};
-
-tSpiderVariant gScriptVariant = {
- "init", 0,
- ARRAY_SIZE(gaScriptNamespaces), gaScriptNamespaces
-};
-*/
// === CODE ===
/**
return 42;
}
-/**
- * \brief Reads and parses the boot configuration script
- * \param Filename File to parse and execute
- */
-void ExecuteScript(const char *Filename)
-{
- /*
- tSpiderScript *script;
- script = SpiderScript_ParseFile(&gScriptVariant, Filename);
- SpiderScript_ExecuteMethod(script, "");
- SpiderScript_Free(script);
- */
-}
-
-/**
- * \brief Open a file
- */
-/*
-tSpiderVariable *Script_System_IO_Open(tSpiderScript *Script, int NArgs, tSpiderVariable *Args)
-{
- return NULL;
-}
-*/
+++ /dev/null
-# Acess 2
-#
-
-include ../Makefile.cfg
-
-CPPFLAGS +=
-CFLAGS += -Wall
-LDFLAGS += -lc -lgcc -soname libspiderscript.so --no-allow-shlib-undefined
-
-OBJ = main.o lex.o parse.o ast.o exports.o values.o
-OBJ += ast_to_bytecode.o bytecode_gen.o bytecode_makefile.o
-OBJ += exec.o exec_bytecode.o
-BIN = libspiderscript.so
-
-include ../Makefile.tpl
+++ /dev/null
-#<?php
-
-# 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) );
-*/
-
-
-return 42; // Script return value
-
-#?>
+++ /dev/null
-#<?php
-
-Object $fp;
-Integer $ifname;
-
-$fp = Sys.IO.Open( "/Devices/ipstack" );
-$ifname = Sys.IO.IOCtl( $fp, 4, "/Devices/ne2k/0" );
-Sys.IO.Close($fp);
-
-
-// Set the IPv4 address of an interface
-//void SetIPv4(String $ifaceName, Integer $addr[4])
-void SetIPv4(String $ifaceName, Integer $addr0, Integer $addr1, Integer $addr2, Integer $addr3)
-{
- Object $fp;
- Object $data;
- $fp = Sys.IO.Open( "/Devices/ipstack/"+$ifaceName );
- $data = Lang.Struct( "l", 4 );
- Sys.IO.IOCtl( $fp, 4, $data );
- //$data = Lang.Struct( "BBBB", $addr[0], $addr[1], $addr[2], $addr[3] );
- $data = Lang.Struct( "BBBB", $addr0, $addr1, $addr2, $addr3 );
- Sys.IO.IOCtl( $fp, 6, $data );
- Sys.IO.Close( $fp );
-}
-
-//SetIPv4( $ifname, Lang.IntArray(10, 0, 2, 55) );
-SetIPv4( $ifname, 10, 0, 2, 55 );
-
-#?>
+++ /dev/null
-/*
- * Acess2 Init
- * - Script AST Manipulator
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "common.h"
-#include "ast.h"
-
-// === IMPORTS ===
-extern void SyntaxError(tParser *Parser, int bFatal, const char *Message, ...);
-
-// === CODE ===
-/**
- * \brief Append a function to a script
- */
-int AST_AppendFunction(tSpiderScript *Script, const char *Name, int ReturnType, tAST_Node *Args, tAST_Node *Code)
-{
- tScript_Function *fcn;
- int arg_count = 0, arg_bytes = 0;
- tAST_Node *arg;
-
- // Count and size arguments
- for(arg = Args; arg; arg = arg->NextSibling)
- {
- arg_count ++;
- arg_bytes += sizeof(fcn->Arguments[0]) + strlen(Args->DefVar.Name) + 1;
- }
-
- // Allocate information
- fcn = malloc( sizeof(tScript_Function) + arg_bytes + strlen(Name) + 1 );
- if(!fcn) return -1;
- fcn->Next = NULL;
- fcn->Name = (char*)&fcn->Arguments[arg_count];
- strcpy(fcn->Name, Name);
- fcn->ReturnType = ReturnType;
- fcn->ArgumentCount = arg_count;
- fcn->ASTFcn = Code;
- fcn->BCFcn = NULL;
-
- // Set arguments
- arg_bytes = strlen(Name) + 1; // Used as an offset into fcn->Name
- arg_count = 0;
- for(arg = Args; arg; arg = arg->NextSibling)
- {
- fcn->Arguments[arg_count].Name = fcn->Name + arg_bytes;
- strcpy(fcn->Arguments[arg_count].Name, arg->DefVar.Name);
- fcn->Arguments[arg_count].Type = arg->DefVar.DataType;
- arg_bytes += strlen(arg->DefVar.Name) + 1;
- arg_count ++;
- }
-
- if(Script->LastFunction == NULL) {
- Script->Functions = Script->LastFunction = fcn;
- }
- else {
- Script->LastFunction->Next = fcn;
- Script->LastFunction = fcn;
- }
-
- return 0;
-}
-
-/**
- * \name Node Manipulation
- * \{
- */
-#define WRITE_N(_buffer, _offset, _len, _dataptr) do { \
- if(_buffer) memcpy((char*)_buffer + _offset, _dataptr, _len);\
- _offset += _len; \
-} while(0)
-
-#define WRITE_8(_buffer, _offset, _val) do {\
- uint8_t v = (_val);\
- WRITE_N(_buffer, _offset, 1, &v);\
-} while(0)
-#define WRITE_16(_buffer, _offset, _val) do {\
- uint16_t v = (_val);\
- WRITE_N(_buffer, _offset, 2, &v);\
-} while(0)
-#define WRITE_32(_buffer, _offset, _val) do {\
- uint32_t v = (_val);\
- WRITE_N(_buffer, _offset, 4, &v);\
-} while(0)
-#define WRITE_64(_buffer, _offset, _val) do {\
- uint64_t v = (_val);\
- WRITE_N(_buffer, _offset, 8, &v);\
-} while(0)
-#define WRITE_REAL(_buffer, _offset, _val) do {\
- double v = (_val);\
- WRITE_N(_buffer, _offset, sizeof(double), &v);\
-} while(0)
-
-#define WRITE_STR(_buffer, _offset, _string) do {\
- int len = strlen(_string);\
- WRITE_16(_buffer, _offset, len);\
- WRITE_N(_buffer, _offset, len, _string);\
- if((_offset & 1) == 1)WRITE_8(_buffer, _offset, 0); \
- if((_offset & 3) == 2)WRITE_16(_buffer, _offset, 0); \
-} while(0)
-#define WRITE_NODELIST(_buffer, _offset, _listHead) do {\
- tAST_Node *node; \
- size_t ptr = -1;\
- for(node=(_listHead); node; node = node->NextSibling) {\
- ptr = _offset;\
- _offset += AST_WriteNode(_buffer, _offset, node); \
- WRITE_32(_buffer, ptr, ptr); \
- } \
- if(ptr != -1){ptr -= 4; WRITE_32(_buffer, ptr, 0);} \
-} while(0)
-
-/**
- * \brief Writes a script dump to a buffer
- * \return Size of encoded data
- * \note If \a Buffer is NULL, no write is done, but the size is still returned
- */
-size_t AST_WriteScript(void *Buffer, tSpiderScript *Script)
-{
- tScript_Function *fcn;
- size_t ret = 0, ptr = 0;
- int i;
-
- for( fcn = Script->Functions; fcn; fcn = fcn->Next )
- {
-// printf("fcn = %p, fcn->Name = %p\n", fcn, fcn->Name);
- ptr = ret;
- WRITE_32(Buffer, ret, 0); // Next
- WRITE_STR(Buffer, ret, fcn->Name);
- WRITE_32(Buffer, ret, fcn->ArgumentCount);
- for( i = 0; i < fcn->ArgumentCount; i ++ )
- {
- WRITE_16(Buffer, ret, fcn->Arguments[i].Type);
- WRITE_STR(Buffer, ret, fcn->Arguments[i].Name);
- }
- ret += AST_WriteNode(Buffer, ret, fcn->ASTFcn);
- WRITE_32(Buffer, ptr, ret); // Actually set `Next`
- }
- if( ptr )
- {
- ptr -= 4;
- WRITE_32(Buffer, ptr, 0); // Clear next for final
- }
-
- return ret;
-}
-
-/**
- * \brief Write a node to a file
- */
-size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
-{
- size_t baseOfs = Offset;
-
- if(!Node) {
- //fprintf(stderr, "Possible Bug - NULL passed to AST_WriteNode\n");
- WRITE_32(Buffer, Offset, 0);
- WRITE_16(Buffer, Offset, NODETYPE_NOP);
- WRITE_16(Buffer, Offset, 0); // Line (0)
- return 0;
- }
-
- WRITE_32(Buffer, Offset, 0); // Next
- WRITE_16(Buffer, Offset, Node->Type);
- // TODO: Scan the buffer for the location of the filename (with NULL byte)
- // else, write the string at the end of the node
- WRITE_16(Buffer, Offset, Node->Line); // Line
- //WRITE_32(Buffer, Offset, 0); // File
-
- switch(Node->Type)
- {
- // Block of code
- case NODETYPE_BLOCK:
- WRITE_NODELIST(Buffer, Offset, Node->Block.FirstChild);
- break;
-
- // Function Call
- case NODETYPE_METHODCALL:
- Offset += AST_WriteNode(Buffer, Offset, Node->FunctionCall.Object);
- case NODETYPE_FUNCTIONCALL:
- case NODETYPE_CREATEOBJECT:
- // TODO: Search for the same function name and add a pointer
- WRITE_STR(Buffer, Offset, Node->FunctionCall.Name);
- WRITE_NODELIST(Buffer, Offset, Node->FunctionCall.FirstArg);
- break;
-
- // If node
- case NODETYPE_IF:
- Offset += AST_WriteNode(Buffer, Offset, Node->If.Condition);
- Offset += AST_WriteNode(Buffer, Offset, Node->If.True);
- Offset += AST_WriteNode(Buffer, Offset, Node->If.False);
- break;
-
- // Looping Construct (For loop node)
- case NODETYPE_LOOP:
- WRITE_8(Buffer, Offset, Node->For.bCheckAfter);
- WRITE_STR(Buffer, Offset, Node->For.Tag);
- Offset += AST_WriteNode(Buffer, Offset, Node->For.Init);
- Offset += AST_WriteNode(Buffer, Offset, Node->For.Condition);
- Offset += AST_WriteNode(Buffer, Offset, Node->For.Increment);
- Offset += AST_WriteNode(Buffer, Offset, Node->For.Code);
- break;
-
- // Asignment
- case NODETYPE_ASSIGN:
- WRITE_8(Buffer, Offset, Node->Assign.Operation);
- Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Dest);
- Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Value);
- break;
-
- // Casting
- case NODETYPE_CAST:
- WRITE_8(Buffer, Offset, Node->Cast.DataType);
- Offset += AST_WriteNode(Buffer, Offset, Node->Cast.Value);
- break;
-
- // Define a variable
- case NODETYPE_DEFVAR:
- WRITE_32(Buffer, Offset, Node->DefVar.DataType);
- // TODO: Duplicate compress the strings
- WRITE_STR(Buffer, Offset, Node->DefVar.Name);
- Offset += AST_WriteNode(Buffer, Offset, Node->DefVar.InitialValue);
- break;
-
- // Scope Reference
- case NODETYPE_SCOPE:
- case NODETYPE_ELEMENT:
- WRITE_STR(Buffer, Offset, Node->Scope.Name);
- Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
- break;
-
- // Unary Operations
- case NODETYPE_RETURN:
- case NODETYPE_BWNOT:
- case NODETYPE_LOGICALNOT:
- case NODETYPE_NEGATE:
- case NODETYPE_POSTINC:
- case NODETYPE_POSTDEC:
- Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
- break;
-
- // Binary Operations
- case NODETYPE_INDEX:
- case NODETYPE_ADD:
- case NODETYPE_SUBTRACT:
- case NODETYPE_MULTIPLY:
- case NODETYPE_DIVIDE:
- case NODETYPE_MODULO:
- case NODETYPE_BITSHIFTLEFT:
- case NODETYPE_BITSHIFTRIGHT:
- case NODETYPE_BITROTATELEFT:
- case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
- case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
- case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
- 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);
- Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Right);
- break;
-
- // Node types with no children
- case NODETYPE_NOP:
- break;
- case NODETYPE_VARIABLE:
- case NODETYPE_CONSTANT:
- case NODETYPE_BREAK:
- case NODETYPE_CONTINUE:
- // TODO: De-Duplicate the strings
- WRITE_STR(Buffer, Offset, Node->Variable.Name);
- break;
- case NODETYPE_STRING:
- WRITE_32(Buffer, Offset, Node->Constant.String.Length);
- WRITE_N(Buffer, Offset, Node->Constant.String.Length, Node->Constant.String.Data);
- break;
- case NODETYPE_INTEGER:
- WRITE_64(Buffer, Offset, Node->Constant.Integer);
- break;
- case NODETYPE_REAL:
- WRITE_REAL(Buffer, Offset, Node->Constant.Real);
- break;
- case NODETYPE_NULL:
- break;
-
- //default:
- // fprintf(stderr, "AST_WriteNode: Unknown node type %i\n", Node->Type);
- // break;
- }
-
- return Offset - baseOfs;
-}
-
-/**
- * \brief Free a node and all subnodes
- */
-void AST_FreeNode(tAST_Node *Node)
-{
- tAST_Node *node;
-
- if(!Node) return ;
-
- // Referenced counted file name
- (*(int*)(Node->File - sizeof(int))) -= 1;
- if( *(int*)(Node->File - sizeof(int)) == 0 )
- free( (void*)(Node->File - sizeof(int)) );
-
- switch(Node->Type)
- {
- // Block of code
- case NODETYPE_BLOCK:
- for( node = Node->Block.FirstChild; node; )
- {
- tAST_Node *savedNext = node->NextSibling;
- AST_FreeNode(node);
- node = savedNext;
- }
- break;
-
- // Function Call
- case NODETYPE_METHODCALL:
- AST_FreeNode(Node->FunctionCall.Object);
- case NODETYPE_FUNCTIONCALL:
- case NODETYPE_CREATEOBJECT:
- for( node = Node->FunctionCall.FirstArg; node; )
- {
- tAST_Node *savedNext = node->NextSibling;
- AST_FreeNode(node);
- node = savedNext;
- }
- 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);
- AST_FreeNode(Node->Assign.Value);
- break;
-
- // Casting
- case NODETYPE_CAST:
- AST_FreeNode(Node->Cast.Value);
- break;
-
- case NODETYPE_SCOPE:
- case NODETYPE_ELEMENT:
- AST_FreeNode(Node->Scope.Element);
- break;
-
- // Define a variable
- case NODETYPE_DEFVAR:
- AST_FreeNode(Node->DefVar.InitialValue);
- break;
-
- // Unary Operations
- case NODETYPE_RETURN:
- case NODETYPE_BWNOT:
- case NODETYPE_LOGICALNOT:
- case NODETYPE_NEGATE:
- case NODETYPE_POSTINC:
- case NODETYPE_POSTDEC:
- AST_FreeNode(Node->UniOp.Value);
- break;
-
- // Binary Operations
- case NODETYPE_INDEX:
- case NODETYPE_ADD:
- case NODETYPE_SUBTRACT:
- case NODETYPE_MULTIPLY:
- case NODETYPE_DIVIDE:
- case NODETYPE_MODULO:
- case NODETYPE_BITSHIFTLEFT:
- case NODETYPE_BITSHIFTRIGHT:
- case NODETYPE_BITROTATELEFT:
- case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
- case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
- case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
- case NODETYPE_EQUALS: case NODETYPE_NOTEQUALS:
- case NODETYPE_LESSTHAN: case NODETYPE_LESSTHANEQUAL:
- case NODETYPE_GREATERTHAN: case NODETYPE_GREATERTHANEQUAL:
- AST_FreeNode( Node->BinOp.Left );
- AST_FreeNode( Node->BinOp.Right );
- break;
-
- // Node types with no children
- case NODETYPE_NOP: break;
- case NODETYPE_NULL: break;
- case NODETYPE_VARIABLE: break;
- case NODETYPE_CONSTANT: break;
- case NODETYPE_BREAK:
- case NODETYPE_CONTINUE: break;
-
- case NODETYPE_STRING:
- case NODETYPE_INTEGER:
- case NODETYPE_REAL:
- if( Node->ValueCache )
- SpiderScript_DereferenceValue(Node->ValueCache);
- Node->ValueCache = NULL;
- break;
- }
- free( Node );
-}
-
-tAST_Node *AST_int_AllocateNode(tParser *Parser, int Type, int ExtraSize)
-{
- tAST_Node *ret = malloc( sizeof(tAST_Node) + ExtraSize );
- ret->NextSibling = NULL;
- ret->File = Parser->Filename; *(int*)(Parser->Filename - sizeof(int)) += 1;
- ret->Line = Parser->CurLine;
- ret->Type = Type;
-
- // Runtime Caching
- ret->BlockState = NULL;
- ret->BlockIdent = 0;
- ret->ValueCache = NULL;
-
- return ret;
-}
-
-tAST_Node *AST_NewCodeBlock(tParser *Parser)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_BLOCK, 0 );
-
- ret->Block.FirstChild = NULL;
- ret->Block.LastChild = NULL;
-
- return ret;
-}
-
-void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child)
-{
- // Ignore NULL children
- if( !Child ) return ;
-
- 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;
- default:
- fprintf(stderr, "BUG REPORT: AST_AppendNode on an invalid node type (%i)\n", Parent->Type);
- break;
- }
-}
-
-tAST_Node *AST_NewIf(tParser *Parser, tAST_Node *Condition, tAST_Node *True, tAST_Node *False)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_IF, 0);
- ret->If.Condition = Condition;
- ret->If.True = True;
- ret->If.False = False;
- return ret;
-}
-
-tAST_Node *AST_NewLoop(tParser *Parser, const char *Tag, tAST_Node *Init, int bPostCheck, tAST_Node *Condition, tAST_Node *Increment, tAST_Node *Code)
-{
- tAST_Node *ret;
- if(!Tag) Tag = "";
- // NOTE: The +3) & ~3 is to align the size to 4 bytes, and shut valgrind up
- // - GCC sometimes inlines strlen as a loop of dword reads, triggering valgrind
- ret = AST_int_AllocateNode(Parser, NODETYPE_LOOP, (strlen(Tag) + 1 + 3) & ~3);
- ret->For.Init = Init;
- ret->For.bCheckAfter = !!bPostCheck;
- ret->For.Condition = Condition;
- ret->For.Increment = Increment;
- ret->For.Code = Code;
- strcpy(ret->For.Tag, Tag);
- return ret;
-}
-
-tAST_Node *AST_NewAssign(tParser *Parser, int Operation, tAST_Node *Dest, tAST_Node *Value)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_ASSIGN, 0);
-
- 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);
- AST_FreeNode(Dest);
- AST_FreeNode(Value);
- return NULL;
- }
-
- ret->Assign.Operation = Operation;
- ret->Assign.Dest = Dest;
- ret->Assign.Value = Value;
-
- return ret;
-}
-
-tAST_Node *AST_NewCast(tParser *Parser, int Target, tAST_Node *Value)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CAST, 0);
-
- ret->Cast.DataType = Target;
- ret->Cast.Value = Value;
-
- return ret;
-}
-
-tAST_Node *AST_NewBinOp(tParser *Parser, int Operation, tAST_Node *Left, tAST_Node *Right)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, Operation, 0);
-
- ret->BinOp.Left = Left;
- ret->BinOp.Right = Right;
-
- return ret;
-}
-
-/**
- */
-tAST_Node *AST_NewUniOp(tParser *Parser, int Operation, tAST_Node *Value)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, Operation, 0);
-
- ret->UniOp.Value = Value;
-
- return ret;
-}
-
-tAST_Node *AST_NewBreakout(tParser *Parser, int Type, const char *DestTag)
-{
- int len = (DestTag ? strlen(DestTag) : 0);
- tAST_Node *ret = AST_int_AllocateNode(Parser, Type, len + 1);
-
- if( DestTag )
- strcpy(ret->Variable.Name, DestTag);
- else
- ret->Variable.Name[0] = '\0';
-
- return ret;
-}
-
-tAST_Node *AST_NewNop(tParser *Parser)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_NOP, 0);
-
- return ret;
-}
-
-/**
- * \brief Create a new string node
- */
-tAST_Node *AST_NewString(tParser *Parser, const char *String, int Length)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_STRING, Length + 1);
-
- ret->Constant.Type = SS_DATATYPE_STRING;
- ret->Constant.ReferenceCount = 1;
- ret->Constant.String.Length = Length;
- memcpy(ret->Constant.String.Data, String, Length);
- ret->Constant.String.Data[Length] = '\0';
-
- return ret;
-}
-
-/**
- * \brief Create a new integer node
- */
-tAST_Node *AST_NewInteger(tParser *Parser, int64_t Value)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_INTEGER, 0);
- ret->Constant.Type = SS_DATATYPE_INTEGER;
- ret->Constant.ReferenceCount = 1;
- ret->Constant.Integer = Value;
- return ret;
-}
-
-/**
- * \brief Create a new real number node
- */
-tAST_Node *AST_NewReal(tParser *Parser, double Value)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_REAL, 0);
- ret->Constant.Type = SS_DATATYPE_REAL;
- ret->Constant.ReferenceCount = 1;
- ret->Constant.Real = Value;
- return ret;
-}
-
-/**
- * \brief Return a null value
- */
-tAST_Node *AST_NewNull(tParser *Parser)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_NULL, 0);
-
- return ret;
-}
-
-/**
- * \brief Create a new variable reference node
- */
-tAST_Node *AST_NewVariable(tParser *Parser, const char *Name)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_VARIABLE, strlen(Name) + 1 );
- strcpy(ret->Variable.Name, Name);
- return ret;
-}
-
-/**
- * \brief Create a new variable definition node
- */
-tAST_Node *AST_NewDefineVar(tParser *Parser, int Type, const char *Name)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_DEFVAR, strlen(Name) + 1 );
-
- ret->DefVar.DataType = Type;
- ret->DefVar.InitialValue = NULL;
- strcpy(ret->DefVar.Name, Name);
-
- return ret;
-}
-
-/**
- * \brief Create a new runtime constant reference node
- */
-tAST_Node *AST_NewConstant(tParser *Parser, const char *Name)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CONSTANT, strlen(Name) + 1 );
-
- strcpy(ret->Variable.Name, Name);
-
- return ret;
-}
-
-/**
- * \brief Create a function call node
- * \note Argument list is manipulated using AST_AppendFunctionCallArg
- */
-tAST_Node *AST_NewFunctionCall(tParser *Parser, const char *Name)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_FUNCTIONCALL, strlen(Name) + 1 );
-
- ret->FunctionCall.Object = NULL;
- ret->FunctionCall.FirstArg = NULL;
- ret->FunctionCall.LastArg = NULL;
- ret->FunctionCall.NumArgs = 0;
- strcpy(ret->FunctionCall.Name, Name);
-
- return ret;
-}
-tAST_Node *AST_NewMethodCall(tParser *Parser, tAST_Node *Object, const char *Name)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_METHODCALL, strlen(Name) + 1 );
-
- ret->FunctionCall.Object = Object;
- ret->FunctionCall.FirstArg = NULL;
- ret->FunctionCall.LastArg = NULL;
- ret->FunctionCall.NumArgs = 0;
- strcpy(ret->FunctionCall.Name, Name);
-
- return ret;
-}
-
-tAST_Node *AST_NewCreateObject(tParser *Parser, const char *Name)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CREATEOBJECT, strlen(Name) + 1 );
-
- ret->FunctionCall.Object = NULL;
- ret->FunctionCall.FirstArg = NULL;
- ret->FunctionCall.LastArg = NULL;
- ret->FunctionCall.NumArgs = 0;
- strcpy(ret->FunctionCall.Name, Name);
-
- return ret;
-}
-
-/**
- * \brief Append an argument to a function call
- */
-void AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg)
-{
- if( Node->Type != NODETYPE_FUNCTIONCALL
- && Node->Type != NODETYPE_CREATEOBJECT
- && Node->Type != NODETYPE_METHODCALL)
- {
- fprintf(stderr, "BUG REPORT: AST_AppendFunctionCallArg on an invalid node type (%i)\n", Node->Type);
- return ;
- }
-
- if(Node->FunctionCall.LastArg) {
- Node->FunctionCall.LastArg->NextSibling = Arg;
- Node->FunctionCall.LastArg = Arg;
- }
- else {
- Node->FunctionCall.FirstArg = Arg;
- Node->FunctionCall.LastArg = Arg;
- }
- Node->FunctionCall.NumArgs ++;
-}
-
-/**
- * \brief Add a scope node
- */
-tAST_Node *AST_NewScopeDereference(tParser *Parser, const char *Name, tAST_Node *Child)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_SCOPE, strlen(Name) + 1 );
- ret->Scope.Element = Child;
- strcpy(ret->Scope.Name, Name);
- return ret;
-}
-
-/**
- * \brief Add a scope node
- */
-tAST_Node *AST_NewClassElement(tParser *Parser, tAST_Node *Object, const char *Name)
-{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_ELEMENT, strlen(Name) + 1 );
- ret->Scope.Element = Object;
- strcpy(ret->Scope.Name, Name);
- return ret;
-}
-
-/**
- * \}
- */
+++ /dev/null
-/*
- */
-#ifndef _AST_H_
-#define _AST_H_
-
-#include <spiderscript.h>
-#include "tokens.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 struct sAST_BlockState tAST_BlockState;
-typedef struct sAST_Variable tAST_Variable;
-
-/**
- * \brief Node Types
- */
-enum eAST_NodeTypes
-{
- NODETYPE_NOP,
-
- NODETYPE_BLOCK, //!< Node Block
-
- // 2
- NODETYPE_VARIABLE, //!< Variable
- NODETYPE_CONSTANT, //!< Runtime Constant
- NODETYPE_STRING, //!< String Constant
- NODETYPE_INTEGER, //!< Integer Constant
- NODETYPE_REAL, //!< Real Constant
- NODETYPE_NULL,
-
- // 8
- NODETYPE_DEFVAR, //!< Define a variable (Variable)
- NODETYPE_SCOPE, //!< Dereference a Namespace/Class static
- NODETYPE_ELEMENT, //!< Reference a class attribute
- NODETYPE_CAST, //!< Cast a value to another (Uniop)
-
- // 12
- NODETYPE_RETURN, //!< Return from a function (reserved word)
- NODETYPE_BREAK, //!< Break out of a loop
- NODETYPE_CONTINUE, //!< Next loop iteration
- NODETYPE_ASSIGN, //!< Variable assignment operator
- NODETYPE_POSTINC, //!< Post-increment (i++) - Uniop
- NODETYPE_POSTDEC, //!< Post-decrement (i--) - Uniop
- NODETYPE_FUNCTIONCALL, //!< Call a function
- NODETYPE_METHODCALL, //!< Call a class method
- NODETYPE_CREATEOBJECT, //!< Create an object
-
- // 21
- NODETYPE_IF, //!< Conditional
- NODETYPE_LOOP, //!< Looping Construct
-
- // 23
- NODETYPE_INDEX, //!< Index into an array
-
- // 24
- NODETYPE_LOGICALNOT, //!< Logical NOT operator
- NODETYPE_LOGICALAND, //!< Logical AND operator
- NODETYPE_LOGICALOR, //!< Logical OR operator
- 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
- NODETYPE_GREATERTHANEQUAL, //!< Comparison Greater Than or Equal
-
- NODETYPE_BWNOT, //!< Bitwise NOT
- NODETYPE_BWAND, //!< Bitwise AND
- NODETYPE_BWOR, //!< Bitwise OR
- NODETYPE_BWXOR, //!< Bitwise XOR
-
- NODETYPE_BITSHIFTLEFT, //!< Bitwise Shift Left (Grow)
- NODETYPE_BITSHIFTRIGHT, //!< Bitwise Shift Right (Shrink)
- NODETYPE_BITROTATELEFT, //!< Bitwise Rotate Left (Grow)
-
- NODETYPE_NEGATE, //!< Negagte
- NODETYPE_ADD, //!< Add
- NODETYPE_SUBTRACT, //!< Subtract
- NODETYPE_MULTIPLY, //!< Multiply
- NODETYPE_DIVIDE, //!< Divide
- NODETYPE_MODULO, //!< Modulus
-};
-
-struct sAST_Node
-{
- tAST_Node *NextSibling;
- tAST_NodeType Type;
-
- const char *File;
- int Line;
-
- void *BlockState; //!< BlockState pointer (for cache integrity)
- int BlockIdent; //!< Ident (same as above)
- void *ValueCache; //!< Cached value / pointer
-
- union
- {
- struct {
- tAST_Node *FirstChild;
- tAST_Node *LastChild;
- } Block;
-
- struct {
- int Operation;
- tAST_Node *Dest;
- tAST_Node *Value;
- } Assign;
-
- struct {
- tAST_Node *Value;
- } UniOp;
-
- struct {
- tAST_Node *Left;
- tAST_Node *Right;
- } BinOp;
-
- struct {
- tAST_Node *Object;
- tAST_Node *FirstArg;
- tAST_Node *LastArg;
- int NumArgs;
- 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;
- char Tag[];
- } For;
-
- /**
- * \note Used for \a NODETYPE_VARIABLE and \a NODETYPE_CONSTANT
- */
- struct {
- char _unused; // Shut GCC up
- char Name[];
- } Variable;
-
- struct {
- tAST_Node *Element;
- char Name[];
- } Scope; // Used by NODETYPE_SCOPE and NODETYPE_ELEMENT
-
- struct {
- int DataType;
- tAST_Node *InitialValue;
- char Name[];
- } DefVar;
-
- struct {
- int DataType;
- tAST_Node *Value;
- } Cast;
-
- // Used for NODETYPE_REAL, NODETYPE_INTEGER and NODETYPE_STRING
- tSpiderValue Constant;
- };
-};
-
-/**
- * \brief Code Block state (stores local variables)
- */
-struct sAST_BlockState
-{
- tAST_BlockState *Parent;
- tSpiderScript *Script; //!< Script
- tAST_Variable *FirstVar; //!< First variable in the list
- tSpiderValue *RetVal;
- tSpiderNamespace *BaseNamespace; //!< Base namespace (for entire block)
- tSpiderNamespace *CurNamespace; //!< Currently selected namespace
- int Ident; //!< ID number used for variable lookup caching
- const char *BreakTarget;
- int BreakType;
-};
-
-struct sAST_Variable
-{
- tAST_Variable *Next;
- int Type; // Only used for static typing
- tSpiderValue *Object;
- char Name[];
-};
-
-// === FUNCTIONS ===
-extern tAST_Script *AST_NewScript(void);
-extern size_t AST_WriteScript(void *Buffer, tSpiderScript *Script);
-extern size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node);
-
-extern int AST_AppendFunction(tSpiderScript *Script, const char *Name, int ReturnType, tAST_Node *FirstArg, tAST_Node *Code);
-
-extern tAST_Node *AST_NewNop(tParser *Parser);
-
-extern tAST_Node *AST_NewString(tParser *Parser, const char *String, int Length);
-extern tAST_Node *AST_NewInteger(tParser *Parser, int64_t Value);
-extern tAST_Node *AST_NewReal(tParser *Parser, double Value);
-extern tAST_Node *AST_NewNull(tParser *Parser);
-
-extern tAST_Node *AST_NewVariable(tParser *Parser, const char *Name);
-extern tAST_Node *AST_NewDefineVar(tParser *Parser, int Type, const char *Name);
-extern tAST_Node *AST_NewConstant(tParser *Parser, const char *Name);
-extern tAST_Node *AST_NewClassElement(tParser *Parser, tAST_Node *Object, const char *Name);
-
-extern tAST_Node *AST_NewFunctionCall(tParser *Parser, const char *Name);
-extern tAST_Node *AST_NewCreateObject(tParser *Parser, const char *Name);
-extern tAST_Node *AST_NewMethodCall(tParser *Parser, tAST_Node *Object, const char *Name);
-extern void AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg);
-
-extern tAST_Node *AST_NewCodeBlock(tParser *Parser);
-extern void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child);
-
-extern tAST_Node *AST_NewIf(tParser *Parser, tAST_Node *Condition, tAST_Node *True, tAST_Node *False);
-extern tAST_Node *AST_NewLoop(tParser *Parser, const char *Tag, tAST_Node *Init, int bPostCheck, tAST_Node *Condition, tAST_Node *Increment, tAST_Node *Code);
-
-extern tAST_Node *AST_NewAssign(tParser *Parser, int Operation, tAST_Node *Dest, tAST_Node *Value);
-extern tAST_Node *AST_NewCast(tParser *Parser, int Target, tAST_Node *Value);
-extern tAST_Node *AST_NewBinOp(tParser *Parser, int Operation, tAST_Node *Left, tAST_Node *Right);
-extern tAST_Node *AST_NewUniOp(tParser *Parser, int Operation, tAST_Node *Value);
-extern tAST_Node *AST_NewBreakout(tParser *Parser, int Type, const char *DestTag);
-extern tAST_Node *AST_NewScopeDereference(tParser *Parser, const char *Name, tAST_Node *Child);
-
-extern void AST_FreeNode(tAST_Node *Node);
-
-// exec_ast.h
-extern void Object_Dereference(tSpiderValue *Object);
-extern void Object_Reference(tSpiderValue *Object);
-extern tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
-extern tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right);
-extern tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value);
-extern tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node, tSpiderValue *Array, int Index, tSpiderValue *SaveValue);
-extern tSpiderValue *AST_ExecuteNode_Element(tSpiderScript *Script, tAST_Node *Node, tSpiderValue *Object, const char *Element, tSpiderValue *SaveValue);
-
-#endif
+++ /dev/null
-/*
- * SpiderScript Library
- *
- * AST to Bytecode Conversion
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include "common.h"
-#include "ast.h"
-#include "bytecode_gen.h"
-#include "bytecode_ops.h"
-
-#define TRACE_VAR_LOOKUPS 0
-#define TRACE_TYPE_STACK 0
-#define MAX_NAMESPACE_DEPTH 10
-#define MAX_STACK_DEPTH 10 // This is for one function, so shouldn't need more
-
-// === IMPORTS ===
-extern tSpiderFunction *gpExports_First;
-
-// === TYPES ===
-typedef struct sAST_BlockInfo
-{
- struct sAST_BlockInfo *Parent;
- void *Handle;
- const char *Tag;
-
- int BreakTarget;
- int ContinueTarget;
-
- int NamespaceDepth;
- const char *CurNamespaceStack[MAX_NAMESPACE_DEPTH];
-
- int StackDepth;
- int Stack[MAX_STACK_DEPTH]; // Stores types of stack values
-
- tAST_Variable *FirstVar;
-} tAST_BlockInfo;
-
-// === PROTOTYPES ===
-// Node Traversal
- int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue);
- int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode);
-// Variables
- int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name);
- int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
- int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
-void BC_Variable_Clear(tAST_BlockInfo *Block);
-// - Errors
-void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
-void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
-// - Type stack
- int _StackPush(tAST_BlockInfo *Block, tAST_Node *Node, int Type);
- int _StackPop(tAST_BlockInfo *Block, tAST_Node *Node, int WantedType);
-
-// === GLOBALS ===
-// int giNextBlockIdent = 1;
-
-// === CODE ===
-int SpiderScript_BytecodeScript(tSpiderScript *Script)
-{
- tScript_Function *fcn;
- for(fcn = Script->Functions; fcn; fcn = fcn->Next)
- {
- if( Bytecode_ConvertFunction(fcn) == 0 )
- return -1;
- }
- return 0;
-}
-
-/**
- * \brief Convert a function into bytecode
- */
-tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
-{
- tBC_Function *ret;
- tAST_BlockInfo bi = {0};
- int i;
-
- // TODO: Return BCFcn instead?
- if(Fcn->BCFcn) return Fcn->BCFcn;
-
- ret = Bytecode_CreateFunction(Fcn);
- if(!ret) return NULL;
-
- bi.Handle = ret;
-
- // Parse arguments
- for( i = 0; i < Fcn->ArgumentCount; i ++ )
- {
- BC_Variable_Define(&bi, Fcn->Arguments[i].Type, Fcn->Arguments[i].Name);
- }
-
- if( AST_ConvertNode(&bi, Fcn->ASTFcn, 0) )
- {
- AST_RuntimeError(Fcn->ASTFcn, "Error in converting function");
- Bytecode_DeleteFunction(ret);
- BC_Variable_Clear(&bi);
- return NULL;
- }
- BC_Variable_Clear(&bi);
-
-
- Bytecode_AppendConstInt(ret, 0); // TODO: NULL
- Bytecode_AppendReturn(ret);
- Fcn->BCFcn = ret;
-
- return ret;
-}
-
-// Indepotent operation
-#define CHECK_IF_NEEDED(b_warn) do { if(!bKeepValue) {\
- if(b_warn)AST_RuntimeMessage(Node, "Bytecode", "Operation without saving");\
- Bytecode_AppendDelete(Block->Handle);\
- _StackPop(Block, Node, SS_DATATYPE_UNDEF);\
-} } while(0)
-
-/**
- * \brief Convert a node into bytecode
- * \param Block Execution context
- * \param Node Node to execute
- */
-int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
-{
- tAST_Node *node;
- int ret = 0;
- int i, op = 0;
- int bAddedValue = 1; // Used to tell if the value needs to be deleted
-
- switch(Node->Type)
- {
- // No Operation
- case NODETYPE_NOP:
- bAddedValue = 0;
- break;
-
- // Code block
- case NODETYPE_BLOCK:
- Bytecode_AppendEnterContext(Block->Handle); // Create a new block
- {
- tAST_BlockInfo blockInfo = {0};
- blockInfo.Parent = Block;
- blockInfo.Handle = Block->Handle;
- // Loop over all nodes, or until the return value is set
- for(node = Node->Block.FirstChild;
- node;
- node = node->NextSibling )
- {
- ret = AST_ConvertNode(&blockInfo, node, 0);
- if(ret) return ret;
- if( blockInfo.StackDepth != 0 ) {
- AST_RuntimeError(node, "Stack not reset at end of node");
- blockInfo.StackDepth = 0;
- }
- }
-
- BC_Variable_Clear(&blockInfo);
- }
- Bytecode_AppendLeaveContext(Block->Handle); // Leave this context
- break;
-
- // Assignment
- case NODETYPE_ASSIGN:
- // Perform assignment operation
- if( Node->Assign.Operation != NODETYPE_NOP )
- {
- int t1, t2;
-
- ret = AST_ConvertNode(Block, Node->Assign.Dest, 1);
- if(ret) return ret;
- t1 = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
- if(t1 < 0) return -1;
-
- ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
- if(ret) return ret;
- t2 = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
- if(t2 < 0) return -1;
-
-
- switch(Node->Assign.Operation)
- {
- // General Binary Operations
- case NODETYPE_ADD: op = BC_OP_ADD; break;
- case NODETYPE_SUBTRACT: op = BC_OP_SUBTRACT; break;
- case NODETYPE_MULTIPLY: op = BC_OP_MULTIPLY; break;
- case NODETYPE_DIVIDE: op = BC_OP_DIVIDE; break;
- case NODETYPE_MODULO: op = BC_OP_MODULO; break;
- case NODETYPE_BWAND: op = BC_OP_BITAND; break;
- case NODETYPE_BWOR: op = BC_OP_BITOR; break;
- case NODETYPE_BWXOR: op = BC_OP_BITXOR; break;
- case NODETYPE_BITSHIFTLEFT: op = BC_OP_BITSHIFTLEFT; break;
- case NODETYPE_BITSHIFTRIGHT: op = BC_OP_BITSHIFTRIGHT; break;
- case NODETYPE_BITROTATELEFT: op = BC_OP_BITROTATELEFT; break;
-
- default:
- AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
- break;
- }
-// printf("assign, op = %i\n", op);
- ret = _StackPush(Block, Node, t1);
- if(ret < 0) return -1;
- Bytecode_AppendBinOp(Block->Handle, op);
- }
- else
- {
- ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
- if(ret) return ret;
- }
-
- if( bKeepValue ) {
- ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
- if(ret < 0) return -1;
- ret = _StackPush(Block, Node, ret);
- if(ret < 0) return -1;
- ret = _StackPush(Block, Node, ret);
- if(ret < 0) return -1;
- Bytecode_AppendDuplicate(Block->Handle);
- }
-
- ret = BC_SaveValue(Block, Node->Assign.Dest);
- if(ret) return ret;
- break;
-
- // Post increment/decrement
- case NODETYPE_POSTINC:
- case NODETYPE_POSTDEC:
- // Save original value if requested
- if(bKeepValue) {
- ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
- if(ret) return ret;
- }
-
- Bytecode_AppendConstInt(Block->Handle, 1);
- ret = _StackPush(Block, Node, SS_DATATYPE_INTEGER);
- if(ret < 0) return -1;
-
- ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
- if(ret) return ret;
-
- if( Node->Type == NODETYPE_POSTDEC )
- Bytecode_AppendBinOp(Block->Handle, BC_OP_SUBTRACT);
- else
- Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
-
- ret = _StackPop(Block, Node, SS_DATATYPE_INTEGER); // TODO: Check for objects too
- if(ret < 0) return -1;
- ret = BC_SaveValue(Block, Node->UniOp.Value);
- if(ret) return ret;
- break;
-
- // Function Call
- case NODETYPE_METHODCALL: {
- int nargs = 0;
-
- ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
- if(ret) return ret;
-
- // Push arguments to the stack
- for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
- {
- ret = AST_ConvertNode(Block, node, 1);
- if(ret) return ret;
- nargs ++;
-
- // TODO: Check arguments? Need to get the types somehow
- ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
- if(ret < 0) return -1;
- }
-
- ret = _StackPop(Block, Node, SS_DATATYPE_OBJECT);
- if(ret < 0) return -1;
- Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
-
- ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF);
- if(ret < 0) return -1;
-
- CHECK_IF_NEEDED(0); // Don't warn
- // TODO: Implement warn_unused_ret
-
- } break;
- case NODETYPE_FUNCTIONCALL:
- case NODETYPE_CREATEOBJECT: {
- int nargs = 0;
-
- // Get name (mangled into a single string)
- int newnamelen = 0;
- char *manglename;
- for( i = 0; i < Block->NamespaceDepth; i ++ )
- newnamelen += strlen(Block->CurNamespaceStack[i]) + 1;
- newnamelen += strlen(Node->FunctionCall.Name) + 1;
-// newnamelen += 1;
-
- manglename = alloca(newnamelen);
- newnamelen = 0;
- for( i = 0; i < Block->NamespaceDepth; i ++ ) {
- strcpy(manglename+newnamelen, Block->CurNamespaceStack[i]);
- newnamelen += strlen(Block->CurNamespaceStack[i]) + 1;
- manglename[ newnamelen - 1 ] = BC_NS_SEPARATOR;
- }
- strcpy(manglename + newnamelen, Node->FunctionCall.Name);
- newnamelen += strlen(Node->FunctionCall.Name) + 1;
-// manglename[ newnamelen ] = '\0'; // Zero length terminator
- Block->NamespaceDepth = 0;
-
- // Push arguments to the stack
- for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
- {
- // TODO: Type Checking
- ret = AST_ConvertNode(Block, node, 1);
- if(ret) return ret;
- nargs ++;
-
- // TODO: Check arguments? Need to get the types somehow
- ret = _StackPop(Block, node, SS_DATATYPE_UNDEF);
- if(ret < 0) return -1;
- }
-
- // Call the function
- if( Node->Type == NODETYPE_CREATEOBJECT )
- {
- Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
- }
- else
- {
- Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
- }
-
- // TODO: Get return type
- ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF);
- if(ret < 0) return -1;
-
- CHECK_IF_NEEDED(0); // Don't warn
- // TODO: Implement warn_unused_ret
- } break;
-
- // Conditional
- case NODETYPE_IF: {
- int if_end;
- ret = AST_ConvertNode(Block, Node->If.Condition, 1);
- if(ret) return ret;
- // TODO: Should be boolean/integer, but meh
- ret = _StackPop(Block, Node->If.Condition, SS_DATATYPE_UNDEF);
- if(ret < 0) return -1;
-
- if_end = Bytecode_AllocateLabel(Block->Handle);
-
- if( Node->If.False->Type != NODETYPE_NOP )
- {
- int if_true = Bytecode_AllocateLabel(Block->Handle);
-
- Bytecode_AppendCondJump(Block->Handle, if_true);
-
- // False
- ret = AST_ConvertNode(Block, Node->If.False, 0);
- if(ret) return ret;
- Bytecode_AppendJump(Block->Handle, if_end);
- Bytecode_SetLabel(Block->Handle, if_true);
- }
- else
- {
- Bytecode_AppendCondJumpNot(Block->Handle, if_end);
- }
-
- // True
- ret = AST_ConvertNode(Block, Node->If.True, 0);
- if(ret) return ret;
-
- // End
- Bytecode_SetLabel(Block->Handle, if_end);
- } break;
-
- // Loop
- case NODETYPE_LOOP: {
- int loop_start, loop_end, code_end;
- int saved_break, saved_continue;
- const char *saved_tag;
-
- // Initialise
- ret = AST_ConvertNode(Block, Node->For.Init, 0);
- if(ret) return ret;
-
- loop_start = Bytecode_AllocateLabel(Block->Handle);
- code_end = Bytecode_AllocateLabel(Block->Handle);
- loop_end = Bytecode_AllocateLabel(Block->Handle);
-
- saved_break = Block->BreakTarget;
- saved_continue = Block->ContinueTarget;
- saved_tag = Block->Tag;
- Block->BreakTarget = loop_end;
- Block->ContinueTarget = code_end;
- Block->Tag = Node->For.Tag;
-
- Bytecode_SetLabel(Block->Handle, loop_start);
-
- // Check initial condition
- if( !Node->For.bCheckAfter )
- {
- ret = AST_ConvertNode(Block, Node->For.Condition, 1);
- if(ret) return ret;
- Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
- ret = _StackPop(Block, Node->For.Condition, SS_DATATYPE_UNDEF); // Boolean?
- if(ret < 0) return -1;
- Bytecode_AppendCondJump(Block->Handle, loop_end);
- }
-
- // Code
- ret = AST_ConvertNode(Block, Node->For.Code, 0);
- if(ret) return ret;
-
- Bytecode_SetLabel(Block->Handle, code_end);
-
- // Increment
- ret = AST_ConvertNode(Block, Node->For.Increment, 0);
- if(ret) return ret;
-// ret = _StackPop(Block, Node->For.Increment, SS_DATATYPE_UNDEF); // TODO: Check if needed
-// if(ret < 0) return -1;
-
- // Tail check
- if( Node->For.bCheckAfter )
- {
- ret = AST_ConvertNode(Block, Node->For.Condition, 1);
- if(ret) return ret;
- ret = _StackPop(Block, Node->If.Condition, SS_DATATYPE_UNDEF); // Boolean?
- if(ret < 0) return ret;
- Bytecode_AppendCondJump(Block->Handle, loop_start);
- }
- else
- {
- Bytecode_AppendJump(Block->Handle, loop_start);
- }
-
- Bytecode_SetLabel(Block->Handle, loop_end);
-
- Block->BreakTarget = saved_break;
- Block->ContinueTarget = saved_continue;
- Block->Tag = saved_tag;
- } break;
-
- // Return
- case NODETYPE_RETURN:
- ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
- if(ret) return ret;
- Bytecode_AppendReturn(Block->Handle);
- ret = _StackPop(Block, Node->UniOp.Value, SS_DATATYPE_UNDEF); //
- if(ret < 0) return -1;
- break;
-
- case NODETYPE_BREAK:
- case NODETYPE_CONTINUE: {
- tAST_BlockInfo *bi = Block;
- if( Node->Variable.Name[0] ) {
- while(bi && (!bi->Tag || strcmp(bi->Tag, Node->Variable.Name) != 0))
- bi = bi->Parent;
- }
- else {
- while(bi && !bi->Tag)
- bi = bi->Parent;
- }
- if( !bi ) return 1;
- // TODO: Check if BreakTarget/ContinueTarget are valid
- if( Node->Type == NODETYPE_BREAK )
- Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
- else
- Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
- } break;
-
- // Define a variable
- case NODETYPE_DEFVAR:
- ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
- if(ret) return ret;
-
- if( Node->DefVar.InitialValue )
- {
- ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
- if(ret) return ret;
- ret = _StackPop(Block, Node->DefVar.InitialValue, Node->DefVar.DataType);
- if(ret < 0) return -1;
- Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
- }
- break;
-
- // Scope
- case NODETYPE_SCOPE:
- if( Block->NamespaceDepth == MAX_NAMESPACE_DEPTH ) {
- AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", MAX_NAMESPACE_DEPTH);
- return 2;
- }
- Block->CurNamespaceStack[ Block->NamespaceDepth ] = Node->Scope.Name;
- Block->NamespaceDepth ++;
- ret = AST_ConvertNode(Block, Node->Scope.Element, bKeepValue);
- if(ret) return ret;
- if( Block->NamespaceDepth != 0 ) {
- AST_RuntimeError(Node, "Namespace scope used but no element at the end");
- }
- bAddedValue = 0;
- break;
-
- // Variable
- case NODETYPE_VARIABLE:
- ret = BC_Variable_GetValue( Block, Node );
- CHECK_IF_NEEDED(1);
- if(ret) return ret;
- break;
-
- // Element of an Object
- case NODETYPE_ELEMENT:
- ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
- if(ret) return ret;
-
- // TODO: Support elements for non-objects
- ret = _StackPop(Block, Node, SS_DATATYPE_OBJECT);
- if(ret < 0) return -1;
-
- Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
-
- // TODO: Somehow know this at compile time?
- ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF);
- if(ret < 0) return -1;
- CHECK_IF_NEEDED(1);
- break;
-
- // Cast a value to another
- case NODETYPE_CAST:
- ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
- if(ret) return ret;
- ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
- if(ret < 0) return -1;
-
- Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
- ret = _StackPush(Block, Node, Node->Cast.DataType);
- if(ret < 0) return -1;
- CHECK_IF_NEEDED(1);
- break;
-
- // Index into an array
- case NODETYPE_INDEX:
- // - Array
- ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
- if(ret) return ret;
- // > Type check
- ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
- if(ret < 0) return -1;
- if(ret != SS_DATATYPE_ARRAY && SS_GETARRAYDEPTH(ret) == 0) {
- AST_RuntimeError(Node, "Type mismatch, Expected an array, got %i",
- ret);
- return -2;
- }
- i = ret; // Hackily save the datatype
-
- // - Offset
- ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
- if(ret) return ret;
- ret = _StackPop(Block, Node, SS_DATATYPE_INTEGER);
- if(ret < 0) return -1;
-
- Bytecode_AppendIndex(Block->Handle);
-
- // Update the array depth
- if( i != SS_DATATYPE_ARRAY ) {
- i = SS_DOWNARRAY(i); // Decrease the array level
- }
- ret = _StackPush(Block, Node, i);
- if(ret < 0) return -1;
-
- CHECK_IF_NEEDED(1);
- break;
-
- // TODO: Implement runtime constants
- case NODETYPE_CONSTANT:
- // TODO: Scan namespace for constant name
- AST_RuntimeError(Node, "TODO - Runtime Constants");
- Block->NamespaceDepth = 0;
- return -1;
-
- // Constant Values
- case NODETYPE_STRING:
- Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
- ret = _StackPush(Block, Node, SS_DATATYPE_STRING);
- if(ret < 0) return -1;
- CHECK_IF_NEEDED(1);
- break;
- case NODETYPE_INTEGER:
- Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
- ret = _StackPush(Block, Node, SS_DATATYPE_INTEGER);
- if(ret < 0) return -1;
- CHECK_IF_NEEDED(1);
- break;
- case NODETYPE_REAL:
- Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
- ret = _StackPush(Block, Node, SS_DATATYPE_REAL);
- if(ret < 0) return -1;
- CHECK_IF_NEEDED(1);
- break;
- case NODETYPE_NULL:
- Bytecode_AppendConstNull(Block->Handle);
- ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF);
- if(ret < 0) return -1;
- CHECK_IF_NEEDED(1);
- break;
-
- // --- Operations ---
- // Boolean Operations
- case NODETYPE_LOGICALNOT: // Logical NOT (!)
- if(!op) op = BC_OP_LOGICNOT;
- case NODETYPE_BWNOT: // Bitwise NOT (~)
- if(!op) op = BC_OP_BITNOT;
- case NODETYPE_NEGATE: // Negation (-)
- if(!op) op = BC_OP_NEG;
- ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
- if(ret) return ret;
- ret = _StackPop(Block, Node->UniOp.Value, SS_DATATYPE_UNDEF); // TODO: Integer/Real/Undef
- if(ret < 0) return -1;
-
- Bytecode_AppendUniOp(Block->Handle, op);
- ret = _StackPush(Block, Node, ret); // TODO: Logic = _INTEGER, Neg = No change
- if(ret < 0) return -1;
-
- CHECK_IF_NEEDED(1);
- break;
-
- // Logic
- case NODETYPE_LOGICALAND: if(!op) op = BC_OP_LOGICAND;
- 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_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;
- // General Binary Operations
- case NODETYPE_ADD: if(!op) op = BC_OP_ADD;
- case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
- case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
- case NODETYPE_DIVIDE: if(!op) op = BC_OP_DIVIDE;
- case NODETYPE_MODULO: if(!op) op = BC_OP_MODULO;
- case NODETYPE_BWAND: if(!op) op = BC_OP_BITAND;
- case NODETYPE_BWOR: if(!op) op = BC_OP_BITOR;
- case NODETYPE_BWXOR: if(!op) op = BC_OP_BITXOR;
- case NODETYPE_BITSHIFTLEFT: if(!op) op = BC_OP_BITSHIFTLEFT;
- case NODETYPE_BITSHIFTRIGHT: if(!op) op = BC_OP_BITSHIFTRIGHT;
- case NODETYPE_BITROTATELEFT: if(!op) op = BC_OP_BITROTATELEFT;
- ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
- if(ret) return ret;
- ret = _StackPop(Block, Node->BinOp.Left, SS_DATATYPE_UNDEF); // TODO: Integer/Real/Object
- if(ret < 0) return -1;
-
- ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
- if(ret) return ret;
- ret = _StackPop(Block, Node->BinOp.Right, SS_DATATYPE_UNDEF); // TODO: Integer/Real/Object
- if(ret < 0) return -1;
-
- Bytecode_AppendBinOp(Block->Handle, op);
- _StackPush(Block, Node, ret);
- CHECK_IF_NEEDED(1);
- break;
-
- default:
- AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
- return -1;
- }
-
- return 0;
-}
-
-int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode)
-{
- int ret, type;
- switch(DestNode->Type)
- {
- // Variable, simple
- case NODETYPE_VARIABLE:
- ret = BC_Variable_SetValue( Block, DestNode );
- if(ret) return ret;
- break;
- // Array index
- case NODETYPE_INDEX:
- ret = AST_ConvertNode(Block, DestNode->BinOp.Left, 1); // Array
- if(ret) return ret;
- ret = _StackPop(Block, DestNode->BinOp.Left, SS_DATATYPE_UNDEF);
- if(ret < 0) return -1;
- if(ret != SS_DATATYPE_ARRAY && SS_GETARRAYDEPTH(ret) == 0) {
- AST_RuntimeError(DestNode, "Type mismatch, Expected an array, got %i",
- ret);
- return -2;
- }
- type = SS_DOWNARRAY(ret);
-
- ret = AST_ConvertNode(Block, DestNode->BinOp.Right, 1); // Offset
- if(ret) return ret;
- ret = _StackPop(Block, DestNode->BinOp.Right, SS_DATATYPE_INTEGER);
- if(ret < 0) return -1;
-
- Bytecode_AppendSetIndex( Block->Handle );
- _StackPop(Block, DestNode, type);
- break;
- // Object element
- case NODETYPE_ELEMENT:
- ret = AST_ConvertNode(Block, DestNode->Scope.Element, 1);
- if(ret) return ret;
- ret = _StackPop(Block, DestNode->Scope.Element, SS_DATATYPE_OBJECT);
- if(ret < 0) return -1;
-
- Bytecode_AppendSetElement( Block->Handle, DestNode->Scope.Name );
- break;
- // Anything else
- default:
- // TODO: Support assigning to object attributes
- AST_RuntimeError(DestNode, "Assignment target is not a LValue");
- return -1;
- }
- return 0;
-}
-
-/**
- * \brief Define a variable
- * \param Block Current block state
- * \param Type Type of the variable
- * \param Name Name of the variable
- * \return Boolean Failure
- */
-int BC_Variable_Define(tAST_BlockInfo *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 ) {
- AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
- return -1;
- }
- }
-
- var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
- var->Next = NULL;
- var->Type = Type;
- strcpy(var->Name, Name);
-
- if(prev) prev->Next = var;
- else Block->FirstVar = var;
-
- Bytecode_AppendDefineVar(Block->Handle, Name, Type);
- return 0;
-}
-
-tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
-{
- tAST_Variable *var = NULL;
- tAST_BlockInfo *bs;
-
- for( bs = Block; bs; bs = bs->Parent )
- {
- for( var = bs->FirstVar; var; var = var->Next )
- {
- if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
- break;
- }
- if(var) break;
- }
-
- if( !var )
- {
-// if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
-// // Define variable
-// var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
-// }
-// else
-// {
- AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
- return NULL;
-// }
- }
-
- #if TRACE_VAR_LOOKUPS
- AST_RuntimeMessage(VarNode, "debug", "Variable lookup of '%s' %p type %i",
- VarNode->Variable.Name, var, var->Type);
- #endif
-
- return var;
-}
-
-/**
- * \brief Set the value of a variable
- * \return Boolean Failure
- */
-int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
-{
- tAST_Variable *var;
-
- // TODO: Implicit definition type
- var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
- if(!var) return -1;
-
- // TODO: Check types
-
- _StackPop(Block, VarNode, var->Type);
- Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
- return 0;
-}
-
-/**
- * \brief Get the value of a variable
- */
-int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
-{
- tAST_Variable *var;
-
- var = BC_Variable_Lookup(Block, VarNode, 0);
- if(!var) return -1;
-
- _StackPush(Block, VarNode, var->Type);
- Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
- return 0;
-}
-
-void BC_Variable_Clear(tAST_BlockInfo *Block)
-{
- tAST_Variable *var;
- for( var = Block->FirstVar; var; )
- {
- tAST_Variable *tv = var->Next;
- free( var );
- var = tv;
- }
- Block->FirstVar = NULL;
-}
-
-#if 0
-void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
-{
- va_list args;
-
- if(Node) {
- fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
- }
- fprintf(stderr, "%s: ", Type);
- va_start(args, Format);
- vfprintf(stderr, Format, args);
- va_end(args);
- fprintf(stderr, "\n");
-}
-void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
-{
- va_list args;
-
- if(Node) {
- fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
- }
- fprintf(stderr, "error: ");
- va_start(args, Format);
- vfprintf(stderr, Format, args);
- va_end(args);
- fprintf(stderr, "\n");
-}
-#endif
-
-int _StackPush(tAST_BlockInfo *Block, tAST_Node *Node, int Type)
-{
- if(Block->StackDepth == MAX_STACK_DEPTH - 1) {
- AST_RuntimeError(Node, "BUG - Stack overflow in AST-Bytecode conversion (node=%i)",
- Node->Type);
- return -1;
- }
-
- #if TRACE_TYPE_STACK
- AST_RuntimeMessage(Node, "_StackPush", "%x - NT%i", Type, Node->Type);
- #endif
- Block->Stack[ ++Block->StackDepth ] = Type;
- return Type;
-}
-
-int _StackPop(tAST_BlockInfo *Block, tAST_Node *Node, int WantedType)
-{
- if(Block->StackDepth == 0) {
- AST_RuntimeError(Node, "BUG - Stack underflow in AST-Bytecode conversion (node=%i)",
- Node->Type);
- return -1;
- }
- #if TRACE_TYPE_STACK
- AST_RuntimeMessage(Node, "_StackPop", "%x(?==%x) - NT%i",
- Block->Stack[ Block->StackDepth ], WantedType, Node->Type);
- #endif
- if(WantedType != SS_DATATYPE_UNDEF && Block->Stack[ Block->StackDepth ] != SS_DATATYPE_UNDEF)
- {
- if( Block->Stack[ Block->StackDepth ] != WantedType ) {
- AST_RuntimeError(Node, "AST-Bytecode - Type mismatch (wanted %x got %x)",
- WantedType, Block->Stack[ Block->StackDepth ]);
- // TODO: Message?
- return -2;
- }
- }
- return Block->Stack[Block->StackDepth--];
-}
-
+++ /dev/null
-/*
- * SpiderScript
- * - Bytecode definitions
- */
-#ifndef _BYTECODE_H_
-#define _BYTECODE_H_
-
-#include "bytecode_ops.h"
-
-#define BC_NS_SEPARATOR '@'
-
-typedef struct sBC_Op tBC_Op;
-typedef struct sBC_Function tBC_Function;
-
-struct sBC_Op
-{
- tBC_Op *Next;
- int Operation;
- char bUseInteger; // Used for serialisation
- char bUseString; // Used for serialisation
-
- void *CacheEnt; // Used to runtime cache function calls
-
- union {
- struct {
- int Integer;
- char String[];
- } StringInt;
-
- uint64_t Integer;
- double Real;
- } Content;
-};
-
-struct sBC_Function
-{
- int LabelCount;
- int LabelSpace;
- tBC_Op **Labels;
-
- int MaxVariableCount;
- // NOTE: These fields are invalid after compilation
- int VariableCount;
- int VariableSpace;
- const char **VariableNames;
- int CurContextDepth; // Used to get the real var count
-
- int OperationCount;
- tBC_Op *Operations;
- tBC_Op *OperationsEnd;
-};
-
-#endif
+++ /dev/null
-/*
- * SpiderScript Library
- * by John Hodge (thePowersGang)
- *
- * bytecode_gen.c
- * - Generate bytecode
- */
-#include <stdlib.h>
-#include <stdint.h>
-#include "bytecode_ops.h"
-#include <stdio.h>
-#include "bytecode_gen.h"
-#include <string.h>
-#include "bytecode.h"
-
-// === IMPORTS ===
-
-// === STRUCTURES ===
-
-// === PROTOTYPES ===
-tBC_Op *Bytecode_int_AllocateOp(int Operation, int ExtraBytes);
- int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name);
-
-// === GLOBALS ===
-
-// === CODE ===
-tBC_Op *Bytecode_int_AllocateOp(int Operation, int ExtraBytes)
-{
- tBC_Op *ret;
-
- ret = malloc(sizeof(tBC_Op) + ExtraBytes);
- if(!ret) return NULL;
-
- ret->Next = NULL;
- ret->Operation = Operation;
- ret->bUseInteger = 0;
- ret->bUseString = (ExtraBytes > 0);
- ret->CacheEnt = NULL;
-
- return ret;
-}
-
-tBC_Function *Bytecode_CreateFunction(tScript_Function *Fcn)
-{
- tBC_Function *ret;
- int i;
-
- ret = malloc(sizeof(tBC_Function));
- if(!ret) return NULL;
-
- ret->LabelSpace = ret->LabelCount = 0;
- ret->Labels = NULL;
-
- ret->MaxVariableCount = 0;
- ret->CurContextDepth = 0;
- ret->VariableCount = ret->VariableSpace = 0;
- ret->VariableNames = NULL;
-
- ret->OperationCount = 0;
- ret->Operations = NULL;
- ret->OperationsEnd = (void*)&ret->Operations;
-
- for( i = 0; i < Fcn->ArgumentCount; i ++ )
- {
- Bytecode_int_AddVariable(ret, Fcn->Arguments[i].Name);
- }
-
- return ret;
-}
-
-void Bytecode_DeleteFunction(tBC_Function *Fcn)
-{
- tBC_Op *op;
- for( op = Fcn->Operations; op; )
- {
- tBC_Op *nextop = op->Next;
- free(op);
- op = nextop;
- }
- free(Fcn->VariableNames);
- free(Fcn->Labels);
- free(Fcn);
-}
-
-int StringList_GetString(tStringList *List, const char *String, int Length)
-{
- int strIdx = 0;
- tString *ent;
- for(ent = List->Head; ent; ent = ent->Next, strIdx ++)
- {
- if(ent->Length == Length && memcmp(ent->Data, String, Length) == 0) break;
- }
- if( ent ) {
- ent->RefCount ++;
- }
- else {
- ent = malloc(sizeof(tString) + Length + 1);
- if(!ent) return -1;
- ent->Next = NULL;
- ent->Length = Length;
- ent->RefCount = 1;
- memcpy(ent->Data, String, Length);
- ent->Data[Length] = '\0';
-
- if(List->Head)
- List->Tail->Next = ent;
- else
- List->Head = ent;
- List->Tail = ent;
- List->Count ++;
- }
- return strIdx;
-}
-
-int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *LabelOffsets, tStringList *Strings)
-{
- tBC_Op *op;
- int len = 0, idx = 0;
- int i;
-
- void _put_byte(uint8_t byte)
- {
- uint8_t *buf = Output;
- if(Output) buf[len] = byte;
- len ++;
- }
-
- void _put_dword(uint32_t value)
- {
- uint8_t *buf = Output;
- if(Output) {
- buf[len+0] = value & 0xFF;
- buf[len+1] = value >> 8;
- buf[len+2] = value >> 16;
- buf[len+3] = value >> 24;
- }
- len += 4;
- }
-
- void _put_index(uint32_t value)
- {
- if( !Output && !value ) {
- len += 5;
- return ;
- }
- if( value < 0x8000 ) {
- _put_byte(value >> 8);
- _put_byte(value & 0xFF);
- }
- else if( value < 0x400000 ) {
- _put_byte( (value >> 16) | 0x80 );
- _put_byte(value >> 8);
- _put_byte(value & 0xFF);
- }
- else {
- _put_byte( 0xC0 );
- _put_byte(value >> 24);
- _put_byte(value >> 16);
- _put_byte(value >> 8 );
- _put_byte(value & 0xFF);
- }
- }
-
- void _put_qword(uint64_t value)
- {
- if( value < 0x80 ) { // 7 bits into 1 byte
- _put_byte(value);
- }
- else if( !(value >> (8+6)) ) { // 14 bits packed into 2 bytes
- _put_byte( 0x80 | ((value >> 8) & 0x3F) );
- _put_byte( value & 0xFF );
- }
- else if( !(value >> (32+5)) ) { // 37 bits into 5 bytes
- _put_byte( 0xC0 | ((value >> 32) & 0x1F) );
- _put_dword(value & 0xFFFFFFFF);
- }
- else {
- _put_byte( 0xE0 ); // 64 (actually 68) bits into 9 bytes
- _put_dword(value & 0xFFFFFFFF);
- _put_dword(value >> 32);
- }
- }
-
- void _put_double(double value)
- {
- // TODO: Machine agnostic
- if(Output) {
- *(double*)( (char*)Output + len ) = value;
- }
- len += sizeof(double);
- }
-
- void _put_string(const char *str, int len)
- {
- int strIdx = 0;
- if( Output ) {
- strIdx = StringList_GetString(Strings, str, len);
- }
-
- // TODO: Relocations
- _put_index(strIdx);
- }
-
- for( op = Function->Operations; op; op = op->Next, idx ++ )
- {
- // If first run, convert labels into byte offsets
- if( !Output )
- {
- for( i = 0; i < Function->LabelCount; i ++ )
- {
- if(LabelOffsets[i]) continue;
- if(op != Function->Labels[i]) continue;
-
- LabelOffsets[i] = len;
- }
- }
-
- _put_byte(op->Operation);
- switch(op->Operation)
- {
- // Relocate jumps (the value only matters if `Output` is non-NULL)
- case BC_OP_JUMP:
- case BC_OP_JUMPIF:
- case BC_OP_JUMPIFNOT:
- // TODO: Relocations?
- _put_index( LabelOffsets[op->Content.StringInt.Integer] );
- break;
- // Special case for inline values
- case BC_OP_LOADINT:
- _put_qword(op->Content.Integer);
- break;
- case BC_OP_LOADREAL:
- _put_double(op->Content.Real);
- break;
- case BC_OP_LOADSTR:
- _put_string(op->Content.StringInt.String, op->Content.StringInt.Integer);
- break;
- // Everthing else just gets handled nicely
- default:
- if( op->bUseString )
- _put_string(op->Content.StringInt.String, strlen(op->Content.StringInt.String));
- if( op->bUseInteger )
- _put_index(op->Content.StringInt.Integer);
- break;
- }
- }
-
- return len;
-}
-
-char *Bytecode_SerialiseFunction(const tBC_Function *Function, int *Length, tStringList *Strings)
-{
- int len;
- int *label_offsets;
- char *code;
-
- label_offsets = calloc( sizeof(int), Function->LabelCount );
- if(!label_offsets) return NULL;
-
- len = Bytecode_int_Serialize(Function, NULL, label_offsets, Strings);
-
- code = malloc(len);
-
- // Update length to the correct length (may decrease due to encoding)
- len = Bytecode_int_Serialize(Function, code, label_offsets, Strings);
-
- free(label_offsets);
-
- *Length = len;
-
- return code;
-}
-
-int Bytecode_AllocateLabel(tBC_Function *Handle)
-{
- int ret;
-
- if( Handle->LabelCount == Handle->LabelSpace ) {
- void *tmp;
- Handle->LabelSpace += 20; // TODO: Don't hardcode increment
- tmp = realloc(Handle->Labels, Handle->LabelSpace * sizeof(Handle->Labels[0]));
- if( !tmp ) {
- Handle->LabelSpace -= 20;
- return -1;
- }
- Handle->Labels = tmp;
- }
- ret = Handle->LabelCount ++;
- Handle->Labels[ret] = 0;
- return ret;
-}
-
-void Bytecode_SetLabel(tBC_Function *Handle, int Label)
-{
- if(Label < 0) return ;
-
- if(Label >= Handle->LabelCount) return ;
-
- Handle->Labels[Label] = Handle->OperationsEnd;
- return ;
-}
-
-void Bytecode_int_AppendOp(tBC_Function *Fcn, tBC_Op *Op)
-{
- Op->Next = NULL;
- if( Fcn->Operations )
- Fcn->OperationsEnd->Next = Op;
- else
- Fcn->Operations = Op;
- Fcn->OperationsEnd = Op;
-}
-
-int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
-{
- if(Handle->VariableCount == Handle->VariableSpace) {
- void *tmp;
- Handle->VariableSpace += 10;
- tmp = realloc(Handle->VariableNames, Handle->VariableSpace * sizeof(Handle->VariableNames[0]));
- if(!tmp) return -1; // TODO: Error
- Handle->VariableNames = tmp;
- }
- Handle->VariableNames[Handle->VariableCount] = Name;
- Handle->VariableCount ++;
- // Get max count (used when executing to get the frame size)
- if(Handle->VariableCount - Handle->CurContextDepth >= Handle->MaxVariableCount)
- Handle->MaxVariableCount = Handle->VariableCount - Handle->CurContextDepth;
-// printf("_AddVariable: %s given %i\n", Name, Handle->VariableCount - Handle->CurContextDepth - 1);
- return Handle->VariableCount - Handle->CurContextDepth - 1;
-}
-
-int Bytecode_int_GetVarIndex(tBC_Function *Handle, const char *Name)
-{
- int i, context_depth = Handle->CurContextDepth;
- // Get the start of this context
- for( i = Handle->VariableCount; i --; )
- {
- if( !Handle->VariableNames[i] ) {
- context_depth --;
- continue ;
- }
- if( strcmp(Name, Handle->VariableNames[i]) == 0 )
- return i - context_depth;
- }
- return -1;
-}
-
-#define DEF_BC_NONE(_op) { \
- tBC_Op *op = Bytecode_int_AllocateOp(_op, 0); \
- op->Content.Integer = 0; \
- op->bUseInteger = 0; \
- Bytecode_int_AppendOp(Handle, op);\
-}
-
-#define DEF_BC_INT(_op, _int) {\
- tBC_Op *op = Bytecode_int_AllocateOp(_op, 0);\
- op->Content.StringInt.Integer = _int;\
- op->bUseInteger = 1;\
- op->bUseString = 0;\
- Bytecode_int_AppendOp(Handle, op);\
-}
-
-#define DEF_BC_STRINT(_op, _str, _int) { \
- tBC_Op *op = Bytecode_int_AllocateOp(_op, strlen(_str));\
- op->Content.StringInt.Integer = _int;\
- strcpy(op->Content.StringInt.String, _str);\
- op->bUseInteger = 1;\
- op->bUseString = 1;\
- Bytecode_int_AppendOp(Handle, op);\
-}
-#define DEF_BC_STR(_op, _str) {\
- tBC_Op *op = Bytecode_int_AllocateOp(_op, strlen(_str));\
- strcpy(op->Content.StringInt.String, _str);\
- op->bUseInteger = 0;\
- Bytecode_int_AppendOp(Handle, op);\
-}
-
-// --- Flow Control
-void Bytecode_AppendJump(tBC_Function *Handle, int Label)
- DEF_BC_INT(BC_OP_JUMP, Label)
-void Bytecode_AppendCondJump(tBC_Function *Handle, int Label)
- DEF_BC_INT(BC_OP_JUMPIF, Label)
-void Bytecode_AppendCondJumpNot(tBC_Function *Handle, int Label)
- DEF_BC_INT(BC_OP_JUMPIFNOT, Label)
-void Bytecode_AppendReturn(tBC_Function *Handle)
- DEF_BC_NONE(BC_OP_RETURN);
-
-// --- Variables
-void Bytecode_AppendLoadVar(tBC_Function *Handle, const char *Name)
- DEF_BC_INT(BC_OP_LOADVAR, Bytecode_int_GetVarIndex(Handle, Name))
-// DEF_BC_STR(BC_OP_LOADVAR, Name)
-void Bytecode_AppendSaveVar(tBC_Function *Handle, const char *Name) // (Obj->)?var =
- DEF_BC_INT(BC_OP_SAVEVAR, Bytecode_int_GetVarIndex(Handle, Name))
-// DEF_BC_STR(BC_OP_SAVEVAR, Name)
-
-// --- Constants
-void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value)
-{
- tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT, 0);
- op->Content.Integer = Value;
- Bytecode_int_AppendOp(Handle, op);
-}
-void Bytecode_AppendConstReal(tBC_Function *Handle, double Value)
-{
- tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADREAL, 0);
- op->Content.Real = Value;
- Bytecode_int_AppendOp(Handle, op);
-}
-void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length)
-{
- tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADSTR, Length+1);
- op->Content.StringInt.Integer = Length;
- memcpy(op->Content.StringInt.String, Data, Length);
- op->Content.StringInt.String[Length] = 0;
- Bytecode_int_AppendOp(Handle, op);
-}
-void Bytecode_AppendConstNull(tBC_Function *Handle)
- DEF_BC_NONE(BC_OP_LOADNULL)
-
-// --- 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)
-void Bytecode_AppendMethodCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
- DEF_BC_STRINT(BC_OP_CALLMETHOD, Name, ArgumentCount)
-void Bytecode_AppendFunctionCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
- DEF_BC_STRINT(BC_OP_CALLFUNCTION, Name, ArgumentCount)
-
-void Bytecode_AppendBinOp(tBC_Function *Handle, int Operation)
- DEF_BC_NONE(Operation)
-void Bytecode_AppendUniOp(tBC_Function *Handle, int Operation)
- DEF_BC_NONE(Operation)
-void Bytecode_AppendCast(tBC_Function *Handle, int Type)
- DEF_BC_INT(BC_OP_CAST, Type)
-void Bytecode_AppendDuplicate(tBC_Function *Handle)
- DEF_BC_NONE(BC_OP_DUPSTACK);
-void Bytecode_AppendDelete(tBC_Function *Handle)
- DEF_BC_NONE(BC_OP_DELSTACK);
-
-// Does some bookeeping to allocate variable slots at compile time
-void Bytecode_AppendEnterContext(tBC_Function *Handle)
-{
- Handle->CurContextDepth ++;
- Bytecode_int_AddVariable(Handle, NULL); // NULL to record the extent of this
-
- DEF_BC_NONE(BC_OP_ENTERCONTEXT)
-}
-void Bytecode_AppendLeaveContext(tBC_Function *Handle)
-{
- int i;
- for( i = Handle->VariableCount; i --; )
- {
- if( Handle->VariableNames[i] == NULL ) break;
- }
- Handle->CurContextDepth --;
- Handle->VariableCount = i;
-
- DEF_BC_NONE(BC_OP_LEAVECONTEXT);
-}
-//void Bytecode_AppendImportNamespace(tBC_Function *Handle, const char *Name);
-// DEF_BC_STRINT(BC_OP_IMPORTNS, Name, 0)
-void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type)
-{
- int i;
- #if 1
- // Get the start of this context
- for( i = Handle->VariableCount; i --; )
- {
- if( Handle->VariableNames[i] == NULL ) break;
- }
- // Check for duplicate allocation
- for( i ++; i < Handle->VariableCount; i ++ )
- {
- if( strcmp(Name, Handle->VariableNames[i]) == 0 )
- return ;
- }
- #endif
-
- i = Bytecode_int_AddVariable(Handle, Name);
-// printf("Variable %s given slot %i\n", Name, i);
-
- DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, (Type&0xFFFF) | (i << 16))
-}
+++ /dev/null
-/*
- * SpiderScript Library
- * - By John Hodge (thePowersGang)
- *
- * bytecode_gen.h
- * - Bytecode Generation header
- */
-#ifndef _BYTECODE_GEN_H_
-#define _BYTECODE_GEN_H_
-
-#include "common.h"
-#include "ast.h"
-#include "bytecode.h"
-
-typedef struct sStringList tStringList;
-typedef struct sString tString;
-
-struct sString
-{
- tString *Next;
- int Length;
- int RefCount;
- char Data[];
-};
-
-struct sStringList
-{
- tString *Head;
- tString *Tail;
- int Count;
-};
-
-
-extern int Bytecode_ConvertScript(tSpiderScript *Script, const char *DestFile);
-extern tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn);
-extern tBC_Function *Bytecode_NewBlankFunction(void);
-extern void Bytecode_DeleteFunction(tBC_Function *Fcn);
-
-extern char *Bytecode_SerialiseFunction(const tBC_Function *Function, int *Length, tStringList *Strings);
-extern int StringList_GetString(tStringList *List, const char *String, int Length);
-extern tBC_Function *Bytecode_CreateFunction(tScript_Function *Fcn);
-
-extern int Bytecode_AllocateLabel(tBC_Function *Handle);
-extern void Bytecode_SetLabel(tBC_Function *Handle, int Label);
-// Bytecode adding
-// - Flow Control
-extern void Bytecode_AppendJump(tBC_Function *Handle, int Label);
-extern void Bytecode_AppendCondJump(tBC_Function *Handle, int Label);
-extern void Bytecode_AppendCondJumpNot(tBC_Function *Handle, int Label);
-extern void Bytecode_AppendReturn(tBC_Function *Handle);
-// - Operation Stack
-// > Load/Store
-extern void Bytecode_AppendLoadVar(tBC_Function *Handle, const char *Name);
-extern void Bytecode_AppendSaveVar(tBC_Function *Handle, const char *Name); // (Obj->)?var =
-extern void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value);
-extern void Bytecode_AppendConstReal(tBC_Function *Handle, double Value);
-extern void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length);
-extern void Bytecode_AppendConstNull(tBC_Function *Handle);
-// > 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);
-extern void Bytecode_AppendFunctionCall(tBC_Function *Handle, const char *Name, int ArgumentCount);
-// > Manipulation
-extern void Bytecode_AppendBinOp(tBC_Function *Handle, int Operation);
-extern void Bytecode_AppendUniOp(tBC_Function *Handle, int Operation);
-extern void Bytecode_AppendCast(tBC_Function *Handlde, int Type);
-extern void Bytecode_AppendDuplicate(tBC_Function *Handlde);
-extern void Bytecode_AppendDelete(tBC_Function *Handle);
-// - Context
-// TODO: Are contexts needed? Should variables be allocated like labels?
-extern void Bytecode_AppendEnterContext(tBC_Function *Handle);
-extern void Bytecode_AppendLeaveContext(tBC_Function *Handle);
-//extern void Bytecode_AppendImportNamespace(tBC_Function *Handle, const char *Name);
-extern void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type);
-
-#endif
-
+++ /dev/null
-/*
- * SpiderScript Library
- * by John Hodge (thePowersGang)
- *
- * bytecode_makefile.c
- * - Generate a bytecode file
- */
-#include <stdlib.h>
-#include "ast.h"
-#include "bytecode_gen.h"
-#include <stdio.h>
-#include <string.h>
-
-// === IMPORTS ===
-
-// === PROTOTYPES ===
-
-// === GLOBALS ===
-
-// === CODE ===
-int SpiderScript_SaveBytecode(tSpiderScript *Script, const char *DestFile)
-{
- tStringList strings = {0};
- tScript_Function *fcn;
- FILE *fp;
- int fcn_hdr_offset = 0;
- int fcn_count = 0;
- int strtab_ofs;
- int i;
-
- void _put8(uint8_t val)
- {
- fwrite(&val, 1, 1, fp);
- }
- void _put32(uint32_t val)
- {
- _put8(val & 0xFF);
- _put8(val >> 8);
- _put8(val >> 16);
- _put8(val >> 24);
- }
-
- fp = fopen(DestFile, "wb");
- if(!fp) return 1;
- // Create header
- fwrite("SSBC\r\n\xBC\x55", 8, 1, fp);
- _put32(0); // Function count, to be filled
- _put32(0); // String count
- _put32(0); // String table offset
- // TODO: Variant info
-
- fcn_hdr_offset = ftell(fp);
-
- // Create function descriptors
- for(fcn = Script->Functions; fcn; fcn = fcn->Next, fcn_count ++)
- {
- _put32( StringList_GetString(&strings, fcn->Name, strlen(fcn->Name)) );
- _put32( 0 ); // Code offset
- // TODO: Namespace
- _put8( fcn->ReturnType );
-
- if(fcn->ArgumentCount > 255) {
- // ERROR: Too many args
- return 2;
- }
- _put8( fcn->ArgumentCount );
-
- // Argument types?
- for( i = 0; i < fcn->ArgumentCount; i ++ )
- {
- _put32( StringList_GetString(&strings, fcn->Arguments[i].Name, strlen(fcn->Arguments[i].Name)) );
- _put8( fcn->Arguments[i].Type );
- }
- }
-
- // Put function code in
- for(fcn = Script->Functions; fcn; fcn = fcn->Next)
- {
- char *code;
- int len, code_pos;
-
- // Fix header
- code_pos = ftell(fp);
- fseek(fp, SEEK_SET, fcn_hdr_offset + 4);
- _put32( code_pos );
- fseek(fp, SEEK_SET, code_pos );
-
- fcn_hdr_offset += 4+4+1+1+(4+1)*fcn->ArgumentCount;
-
- // Write code
- if( !fcn->BCFcn )
- Bytecode_ConvertFunction(fcn);
- if( !fcn->BCFcn )
- {
- fclose(fp);
- return 1;
- }
- code = Bytecode_SerialiseFunction(fcn->BCFcn, &len, &strings);
- fwrite(code, len, 1, fp);
- free(code);
- }
-
- // String table
- strtab_ofs = ftell(fp);
- {
- int string_offset = strtab_ofs + (4+4)*strings.Count;
- tString *str;
- // Array
- for(str = strings.Head; str; str = str->Next)
- {
- _put32(str->Length);
- _put32(string_offset);
- string_offset += str->Length + 1;
- }
- // Data
- for(str = strings.Head; str;)
- {
- tString *nextstr = str->Next;
- fwrite(str->Data, str->Length, 1, fp);
- _put8(0); // NULL separator
- free(str);
- str = nextstr;
- }
- strings.Head = NULL;
- strings.Tail = NULL;
- }
-
- // Fix header
- fseek(fp, 8, SEEK_SET);
- _put32(fcn_count);
- _put32(strings.Count);
- _put32(strtab_ofs);
-
- fclose(fp);
-
- return 0;
-}
-
+++ /dev/null
-/**
- */
-#ifndef _BYTECODE_OPS_H_
-#define _BYTECODE_OPS_H_
-
-enum eBC_Ops
-{
- BC_OP_NOP,
-
- BC_OP_JUMP,
- BC_OP_JUMPIF,
- BC_OP_JUMPIFNOT,
-
- BC_OP_RETURN, // = 4
- BC_OP_CALLFUNCTION,
- BC_OP_CALLMETHOD,
- BC_OP_CREATEOBJ,
-
- BC_OP_LOADVAR, // = 8
- BC_OP_SAVEVAR,
-
- BC_OP_LOADINT, // = 10
- BC_OP_LOADREAL,
- BC_OP_LOADSTR,
- BC_OP_LOADNULL,
-
- BC_OP_DUPSTACK, // = 14
- BC_OP_DELSTACK, //
- BC_OP_CAST, //
-
- BC_OP_ELEMENT, // = 17
- BC_OP_SETELEMENT,
- BC_OP_INDEX,
- BC_OP_SETINDEX,
-
- BC_OP_ENTERCONTEXT, // = 21
- BC_OP_LEAVECONTEXT,
- BC_OP_DEFINEVAR,
-
- // Operations
- BC_OP_LOGICNOT, // 24
- BC_OP_LOGICAND,
- BC_OP_LOGICOR,
- BC_OP_LOGICXOR,
-
- BC_OP_BITNOT, // 28
- BC_OP_BITAND,
- BC_OP_BITOR,
- BC_OP_BITXOR,
-
- BC_OP_BITSHIFTLEFT, // 32
- BC_OP_BITSHIFTRIGHT,
- BC_OP_BITROTATELEFT,
-
- BC_OP_NEG, // 35
- BC_OP_ADD,
- BC_OP_SUBTRACT,
- BC_OP_MULTIPLY,
- BC_OP_DIVIDE,
- BC_OP_MODULO,
-
- BC_OP_EQUALS, // 41
- BC_OP_NOTEQUALS,
- BC_OP_LESSTHAN,
- BC_OP_LESSTHANOREQUAL,
- BC_OP_GREATERTHAN,
- BC_OP_GREATERTHANOREQUAL
-};
-
-#endif
+++ /dev/null
-/*
- * SpiderScript Library
- * by John Hodge (thePowersGang)
- *
- * bytecode_gen.c
- * - Generate bytecode
- */
-#include <stdlib.h>
-#include "bytecode_ops.h"
-
-// Patterns:
-// TODO: Figure out what optimisations can be done
-
-int Bytecode_OptimizeFunction(tBC_Function *Function)
-{
- for( op = Function->Operations; op; op = op->Next, idx ++ )
- {
- }
-}
+++ /dev/null
-/*
- * SpiderScript
- * - By John Hodge (thePowersGang)
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-#include <spiderscript.h>
-
-typedef struct sScript_Function tScript_Function;
-typedef struct sScript_Arg tScript_Arg;
-
-struct sSpiderScript
-{
- tSpiderVariant *Variant;
- tScript_Function *Functions;
- tScript_Function *LastFunction;
- char *CurNamespace; //!< Current namespace prefix (NULL = Root) - No trailing .
-};
-
-struct sScript_Arg
-{
- int Type;
- char *Name;
-};
-
-struct sScript_Function
-{
- tScript_Function *Next;
- // char *Namespace;
- char *Name;
-
- int ReturnType;
-
- struct sAST_Node *ASTFcn;
- struct sBC_Function *BCFcn;
-
- int ArgumentCount;
- tScript_Arg Arguments[];
-};
-
-#endif
-
+++ /dev/null
-/*
-* SpiderScript Library
-* by John Hodge (thePowersGang)
-*
-* bytecode_makefile.c
-* - Generate a bytecode file
-*/
-#include <stdlib.h>
-#include "common.h"
-#include "ast.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-
-#define BC_NS_SEPARATOR '@'
-
-// === IMPORTS ===
-extern tSpiderFunction *gpExports_First;
-extern tSpiderNamespace gExportNamespaceRoot;
-extern tSpiderValue *AST_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Arguments);
-extern tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args);
-
-// === PROTOTYPES ===
-void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
-void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
-
-// === CODE ===
-void *SpiderScript_int_GetNamespace(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
- const char *BasePath, const char *ItemPath,
- const char **ItemName
- )
-{
- int len;
- const char *name;
- const char *end;
- int bTriedBase;
-
- tSpiderNamespace *lastns, *ns;
-
- // Prepend the base namespace
- if( BasePath ) {
- name = BasePath;
- bTriedBase = 0;
- }
- else {
- bTriedBase = 1;
- name = ItemPath;
- }
-
- // Scan
- lastns = RootNamespace;
- do {
- end = strchr(name, BC_NS_SEPARATOR);
- if(!end) {
- if( !bTriedBase )
- len = strlen(name);
- else
- break;
- }
- else {
- len = end - name;
- }
-
- // Check for this level
- for( ns = lastns->FirstChild; ns; ns = ns->Next )
- {
-// printf("%p %.*s == %s\n", lastns, len, name, ns->Name);
- if( strncmp(name, ns->Name, len) == 0 && ns->Name[len] == 0 )
- break ;
- }
-
- if(!ns) return NULL;
-
- if(!end && !bTriedBase) {
- end = ItemPath - 1; // -1 to counter (name = end + 1)
- bTriedBase = 1;
- }
-
- lastns = ns;
- name = end + 1;
- } while( end );
-
- *ItemName = name;
-
- return lastns;
-}
-
-tSpiderFunction *SpiderScript_int_GetNativeFunction(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
- const char *BasePath, const char *FunctionPath)
-{
- tSpiderNamespace *ns;
- const char *name;
- tSpiderFunction *fcn;
-
- ns = SpiderScript_int_GetNamespace(Script, RootNamespace, BasePath, FunctionPath, &name);
- if(!ns) return NULL;
-
- for( fcn = ns->Functions; fcn; fcn = fcn->Next )
- {
- if( strcmp(name, fcn->Name) == 0 )
- return fcn;
- }
-
- return NULL;
-}
-
-tSpiderObjectDef *SpiderScript_int_GetNativeClass(tSpiderScript *Script, tSpiderNamespace *RootNamespace,
- const char *BasePath, const char *ClassPath
- )
-{
- tSpiderNamespace *ns;
- const char *name;
- tSpiderObjectDef *class;
-
- ns = SpiderScript_int_GetNamespace(Script, RootNamespace, BasePath, ClassPath, &name);
- if(!ns) return NULL;
-
- for( class = ns->Classes; class; class = class->Next )
- {
- if( strcmp(name, class->Name) == 0 )
- return class;
- }
-
- return NULL;
-}
-
-/**
- * \brief Execute a script function
- * \param Script Script context to execute in
- * \param Namespace Namespace to search for the function
- * \param Function Function name to execute
- * \param NArguments Number of arguments to pass
- * \param Arguments Arguments passed
- */
-tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
- const char *Function,
- const char *DefaultNamespaces[],
- int NArguments, tSpiderValue **Arguments,
- void **FunctionIdent
- )
-{
- tSpiderValue *ret = ERRPTR;
- tSpiderFunction *fcn = NULL;
- tScript_Function *sfcn;
- int i;
-
- if( FunctionIdent && *FunctionIdent ) {
- if( *(intptr_t*)FunctionIdent & 1 ) {
- sfcn = (void*)( *(intptr_t*)FunctionIdent & ~1 );
- goto _exec_sfcn;
- }
- else {
- fcn = *FunctionIdent;
- goto _exec_fcn;
- }
- }
-
- // Scan list, Last item should always be NULL, so abuse that to check non-prefixed
- for( i = 0; i == 0 || (DefaultNamespaces && DefaultNamespaces[i-1]); i ++ )
- {
- const char *ns = DefaultNamespaces ? DefaultNamespaces[i] : NULL;
- fcn = SpiderScript_int_GetNativeFunction(Script, &Script->Variant->RootNamespace, ns, Function);
- if( fcn ) break;
-
- fcn = SpiderScript_int_GetNativeFunction(Script, &gExportNamespaceRoot, ns, Function);
- if( fcn ) break;
-
- // TODO: Script namespacing
- }
-
- // Search the variant's global exports
- if( !fcn )
- {
- for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
- {
- if( strcmp( fcn->Name, Function ) == 0 )
- break;
- }
- }
-
- // Fourth: Search language exports
- if( !fcn )
- {
- for( fcn = gpExports_First; fcn; fcn = fcn->Next )
- {
- if( strcmp( fcn->Name, Function ) == 0 )
- break;
- }
- }
-
- // Find the function in the script?
- // TODO: Script namespacing
- if( !fcn && strchr(Function, BC_NS_SEPARATOR) == NULL )
- {
- for( sfcn = Script->Functions; sfcn; sfcn = sfcn->Next )
- {
- if( strcmp(sfcn->Name, Function) == 0 )
- break;
- }
- _exec_sfcn:
- // Execute!
- if(sfcn)
- {
- if( sfcn->BCFcn )
- ret = Bytecode_ExecuteFunction(Script, sfcn, NArguments, Arguments);
- else
- ret = AST_ExecuteFunction(Script, sfcn, NArguments, Arguments);
-
- if( FunctionIdent ) {
- *FunctionIdent = sfcn;
- // Abuses alignment requirements on almost all platforms
- *(intptr_t*)FunctionIdent |= 1;
- }
-
- return ret;
- }
- }
-
-_exec_fcn:
- if(fcn)
- {
- // Execute!
- // TODO: Type Checking
- ret = fcn->Handler( Script, NArguments, Arguments );
-
- if( FunctionIdent )
- *FunctionIdent = fcn;
-
- return ret;
- }
- else
- {
- fprintf(stderr, "Undefined reference to function '%s'\n", Function);
- return ERRPTR;
- }
-}
-
-/**
- * \brief Execute an object method function
- * \param Script Script context to execute in
- * \param Object Object in which to find the method
- * \param MethodName Name of method to call
- * \param NArguments Number of arguments to pass
- * \param Arguments Arguments passed
- */
-tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
- tSpiderObject *Object, const char *MethodName,
- int NArguments, tSpiderValue **Arguments)
-{
- tSpiderFunction *fcn;
- tSpiderValue this;
- tSpiderValue *newargs[NArguments+1];
- int i;
-
- // TODO: Support program defined objects
-
- // Search for the function
- for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
- {
- if( strcmp(fcn->Name, MethodName) == 0 )
- break;
- }
- // Error
- if( !fcn )
- {
- AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
- Object->Type->Name, MethodName);
- return ERRPTR;
- }
-
- // Create the "this" argument
- this.Type = SS_DATATYPE_OBJECT;
- this.ReferenceCount = 1;
- this.Object = Object;
- newargs[0] = &this;
- memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
-
- // Check the type of the arguments
- for( i = 0; fcn->ArgTypes[i]; i ++ )
- {
- if( i >= NArguments ) {
- for( ; fcn->ArgTypes[i]; i ++ ) ;
- AST_RuntimeError(NULL, "Argument count mismatch (%i passed, %i expected)",
- NArguments, i);
- return ERRPTR;
- }
- if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
- {
- AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
- Arguments[i]->Type, fcn->ArgTypes[i]);
- return ERRPTR;
- }
- }
-
- // Call handler
- return fcn->Handler(Script, NArguments+1, newargs);
-}
-
-/**
- * \brief Execute a script function
- * \param Script Script context to execute in
- * \param Function Function name to execute
- * \param NArguments Number of arguments to pass
- * \param Arguments Arguments passed
- */
-tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
- const char *ClassPath, const char *DefaultNamespaces[],
- int NArguments, tSpiderValue **Arguments)
-{
- tSpiderValue *ret = ERRPTR;
- tSpiderObjectDef *class;
- int i;
-
- // Scan list, Last item should always be NULL, so abuse that to check non-prefixed
- for( i = 0; i == 0 || DefaultNamespaces[i-1]; i ++ )
- {
- const char *ns = DefaultNamespaces[i];
- class = SpiderScript_int_GetNativeClass(Script, &Script->Variant->RootNamespace, ns, ClassPath);
- if( class ) break;
-
- class = SpiderScript_int_GetNativeClass(Script, &gExportNamespaceRoot, ns, ClassPath);
- if( class ) break;
-
- // TODO: Language defined classes
- }
-
- // First: Find the function in the script
- // TODO: Implement script-defined classes
- #if 0
- {
- tAST_Function *astClass;
- for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
- {
- if( strcmp(astClass->Name, ClassName) == 0 )
- break;
- }
- // Execute!
- if(astClass)
- {
- tAST_BlockState bs;
- tAST_Node *arg;
- int i = 0;
-
- // Build a block State
- bs.FirstVar = NULL;
- bs.RetVal = NULL;
- bs.Parent = NULL;
- bs.BaseNamespace = &Script->Variant->RootNamespace;
- bs.CurNamespace = NULL;
- bs.Script = Script;
- bs.Ident = giNextBlockIdent ++;
-
- for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
- {
- if( i >= NArguments ) break; // TODO: Return gracefully
- // TODO: Type checks
- Variable_Define(&bs,
- arg->DefVar.DataType, arg->DefVar.Name,
- Arguments[i]);
- }
-
- // Execute function
- ret = AST_ExecuteNode(&bs, astFcn->Code);
- if( ret != ERRPTR )
- {
- SpiderScript_DereferenceValue(ret); // Dereference output of last block statement
- ret = bs.RetVal; // Set to return value of block
- }
- bFound = 1;
-
- while(bs.FirstVar)
- {
- tAST_Variable *nextVar = bs.FirstVar->Next;
- Variable_Destroy( bs.FirstVar );
- bs.FirstVar = nextVar;
- }
- }
- }
- #endif
-
- // Execute!
- if(class)
- {
- tSpiderObject *obj;
- // TODO: Type Checking
-
- // Call constructor
- obj = class->Constructor( NArguments, Arguments );
- if( obj == NULL || obj == ERRPTR )
- return (void *)obj;
-
- // Creatue return object
- ret = malloc( sizeof(tSpiderValue) );
- ret->Type = SS_DATATYPE_OBJECT;
- ret->ReferenceCount = 1;
- ret->Object = obj;
-
- return ret;
- }
- else // Not found?
- {
- fprintf(stderr, "Undefined reference to class '%s'\n", ClassPath);
- return ERRPTR;
- }
-}
-
-void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
-{
- va_list args;
-
- if(Node) {
- fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
- }
- fprintf(stderr, "%s: ", Type);
- va_start(args, Format);
- vfprintf(stderr, Format, args);
- va_end(args);
- fprintf(stderr, "\n");
-}
-void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
-{
- va_list args;
-
- if(Node) {
- fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
- }
- fprintf(stderr, "error: ");
- va_start(args, Format);
- vfprintf(stderr, Format, args);
- va_end(args);
- fprintf(stderr, "\n");
-}
+++ /dev/null
-/*
- * SpiderScript Library
- *
- * AST Execution
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include "common.h"
-#include "ast.h"
-
-#define USE_AST_EXEC 1
-#define TRACE_VAR_LOOKUPS 0
-#define TRACE_NODE_RETURNS 0
-
-// === IMPORTS ===
-
-// === PROTOTYPES ===
-// - Node Execution
-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);
-tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode);
-void Variable_Destroy(tAST_Variable *Variable);
-// - Errors
-void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
-void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
-
-// === GLOBALS ===
- int giNextBlockIdent = 1;
-
-// === CODE ===
-#if USE_AST_EXEC
-tSpiderValue *AST_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Arguments)
-{
- tAST_BlockState bs;
- tSpiderValue *ret;
- int i = 0;
-
- // Build a block State
- bs.FirstVar = NULL;
- bs.RetVal = NULL;
- bs.Parent = NULL;
- bs.BaseNamespace = &Script->Variant->RootNamespace;
- bs.CurNamespace = NULL;
- bs.Script = Script;
- bs.Ident = giNextBlockIdent ++;
-
- // Parse arguments
- for( i = 0; i < Fcn->ArgumentCount; i ++ )
- {
- if( i >= NArguments ) break; // TODO: Return gracefully
- // TODO: Type checks
- Variable_Define(&bs,
- Fcn->Arguments[i].Type, Fcn->Arguments[i].Name,
- Arguments[i]);
- }
-
- // Execute function
- ret = AST_ExecuteNode(&bs, Fcn->ASTFcn);
- if(ret != ERRPTR)
- {
- SpiderScript_DereferenceValue(ret); // Dereference output of last block statement
- ret = bs.RetVal; // Set to return value of block
- }
-
- while(bs.FirstVar)
- {
- tAST_Variable *nextVar = bs.FirstVar->Next;
- Variable_Destroy( bs.FirstVar );
- bs.FirstVar = nextVar;
- }
- return ret;
-}
-
-/**
- * \brief Execute an AST node and return its value
- * \param Block Execution context
- * \param Node Node to execute
- */
-tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
-{
- tAST_Node *node;
- tSpiderValue *ret = NULL, *tmpobj;
- tSpiderValue *op1, *op2; // Binary operations
- int i;
-
- switch(Node->Type)
- {
- // No Operation
- case NODETYPE_NOP:
- ret = NULL;
- break;
-
- // Code block
- case NODETYPE_BLOCK:
- {
- tAST_BlockState blockInfo;
- blockInfo.Parent = Block;
- blockInfo.Script = Block->Script;
- blockInfo.FirstVar = NULL;
- blockInfo.RetVal = NULL;
- blockInfo.BaseNamespace = Block->BaseNamespace;
- blockInfo.CurNamespace = NULL;
- blockInfo.BreakTarget = NULL;
- blockInfo.Ident = giNextBlockIdent ++;
- ret = NULL;
- // Loop over all nodes, or until the return value is set
- for(node = Node->Block.FirstChild;
- node && !blockInfo.RetVal && !blockInfo.BreakTarget;
- node = node->NextSibling )
- {
- ret = AST_ExecuteNode(&blockInfo, node);
- if(ret == ERRPTR) break; // Error check
- if(ret != NULL) SpiderScript_DereferenceValue(ret); // Free unused value
- }
- // Clean up variables
- while(blockInfo.FirstVar)
- {
- tAST_Variable *nextVar = blockInfo.FirstVar->Next;
- Variable_Destroy( blockInfo.FirstVar );
- blockInfo.FirstVar = nextVar;
- }
- // Clear ret if not an error
- if(ret != ERRPTR) ret = NULL;
-
- // Set parent's return value if needed
- if( blockInfo.RetVal )
- Block->RetVal = blockInfo.RetVal;
- if( blockInfo.BreakTarget ) {
- Block->BreakTarget = blockInfo.BreakTarget;
- Block->BreakType = blockInfo.BreakType;
- }
-
- // TODO: Unset break if break type deontes a block break
- }
-
- break;
-
- // Assignment
- case NODETYPE_ASSIGN:
- // TODO: Support assigning to object attributes
- if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
- AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
- return ERRPTR;
- }
- ret = AST_ExecuteNode(Block, Node->Assign.Value);
- if(ret == ERRPTR) return ERRPTR;
-
- // Perform assignment operation
- if( Node->Assign.Operation != NODETYPE_NOP )
- {
- tSpiderValue *varVal, *value;
-
- varVal = Variable_GetValue(Block, Node->Assign.Dest);
- if(varVal == ERRPTR) return ERRPTR;
- #if 0
- #else
- if(varVal && varVal->ReferenceCount == 2) {
- SpiderScript_DereferenceValue(varVal);
-// printf("pre: (%s) varVal->ReferenceCount = %i\n",
-// Node->Assign.Dest->Variable.Name,
-// varVal->ReferenceCount);
- }
- #endif
- value = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Assign.Operation, varVal, ret);
- if(value == ERRPTR) return ERRPTR;
-
- if(ret) SpiderScript_DereferenceValue(ret);
- #if 0
- if(varVal) SpiderScript_DereferenceValue(varVal);
- #else
- if(varVal && varVal->ReferenceCount == 1) {
- SpiderScript_ReferenceValue(varVal);
-// printf("post: varVal->ReferenceCount = %i\n", varVal->ReferenceCount);
- break; // If varVal was non-null, it has been updated by _BinOp
- }
- #endif
- // Else, it was NULL, so has to be assigned
- ret = value;
- }
-
- // Set the variable value
- if( Variable_SetValue( Block, Node->Assign.Dest, ret ) ) {
- SpiderScript_DereferenceValue( ret );
- return ERRPTR;
- }
- break;
-
- // Post increment/decrement
- case NODETYPE_POSTINC:
- case NODETYPE_POSTDEC:
- {
- tSpiderValue *varVal, *value;
- static tSpiderValue one = {
- .Type = SS_DATATYPE_INTEGER,
- .ReferenceCount = 1,
- {.Integer = 1}
- };
-
- // TODO: Support assigning to object attributes
- if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
- AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
- return ERRPTR;
- }
-
- // Get values (current variable contents and a static one)
- varVal = Variable_GetValue(Block, Node->UniOp.Value);
-
- if( Node->Type == NODETYPE_POSTDEC )
- value = AST_ExecuteNode_BinOp(Block->Script, Node, NODETYPE_SUBTRACT, varVal, &one);
- else
- value = AST_ExecuteNode_BinOp(Block->Script, Node, NODETYPE_ADD, varVal, &one);
- if( value == ERRPTR )
- return ERRPTR;
-
- ret = varVal;
-
- if( Variable_SetValue( Block, Node->UniOp.Value, value ) ) {
- SpiderScript_DereferenceValue( ret );
- return ERRPTR;
- }
- SpiderScript_DereferenceValue( value );
- }
- break;
-
- // Function Call
- case NODETYPE_METHODCALL:
- case NODETYPE_FUNCTIONCALL:
- case NODETYPE_CREATEOBJECT:
- // Logical block (used to allocate `params`)
- {
- 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);
- if( params[i] == ERRPTR ) {
- while(i--) SpiderScript_DereferenceValue(params[i]);
- ret = ERRPTR;
- goto _return;
- }
- i ++;
- }
-
- // TODO: Check for cached function reference
-
- // Call the function
- if( Node->Type == NODETYPE_CREATEOBJECT )
- {
- ret = SpiderScript_CreateObject(Block->Script,
- Node->FunctionCall.Name,
- namespaces,
- Node->FunctionCall.NumArgs, params
- );
- }
- else if( Node->Type == NODETYPE_METHODCALL )
- {
- tSpiderValue *obj = AST_ExecuteNode(Block, Node->FunctionCall.Object);
- if( !obj || obj == ERRPTR || obj->Type != SS_DATATYPE_OBJECT ) {
- AST_RuntimeError(Node->FunctionCall.Object,
- "Type Mismatch - Required SS_DATATYPE_OBJECT for method call");
- while(i--) SpiderScript_DereferenceValue(params[i]);
- ret = ERRPTR;
- break;
- }
- ret = SpiderScript_ExecuteMethod(Block->Script,
- obj->Object, Node->FunctionCall.Name,
- Node->FunctionCall.NumArgs, params
- );
- SpiderScript_DereferenceValue(obj);
- }
- else
- {
- ret = SpiderScript_ExecuteFunction(Block->Script,
- Node->FunctionCall.Name,
- namespaces,
- Node->FunctionCall.NumArgs, params,
- NULL
- );
- }
-
-
- // Dereference parameters
- while(i--) SpiderScript_DereferenceValue(params[i]);
-
- // falls out
- }
- break;
-
- // Conditional
- case NODETYPE_IF:
- ret = AST_ExecuteNode(Block, Node->If.Condition);
- if( ret == ERRPTR ) break;
- if( SpiderScript_IsValueTrue(ret) ) {
- tmpobj = AST_ExecuteNode(Block, Node->If.True);
- }
- else {
- tmpobj = AST_ExecuteNode(Block, Node->If.False);
- }
- SpiderScript_DereferenceValue(ret);
- if( tmpobj == ERRPTR ) return ERRPTR;
- SpiderScript_DereferenceValue(tmpobj);
- ret = NULL;
- break;
-
- // Loop
- case NODETYPE_LOOP:
- // Initialise
- ret = AST_ExecuteNode(Block, Node->For.Init);
- if(ret == ERRPTR) break;
-
- // Check initial condition
- if( !Node->For.bCheckAfter )
- {
- SpiderScript_DereferenceValue(ret);
-
- ret = AST_ExecuteNode(Block, Node->For.Condition);
- if(ret == ERRPTR) return ERRPTR;
- if(!SpiderScript_IsValueTrue(ret)) {
- SpiderScript_DereferenceValue(ret);
- ret = NULL;
- break;
- }
- }
-
- // Perform loop
- for( ;; )
- {
- SpiderScript_DereferenceValue(ret);
-
- // Code
- ret = AST_ExecuteNode(Block, Node->For.Code);
- if(ret == ERRPTR) return ERRPTR;
- SpiderScript_DereferenceValue(ret);
-
- if(Block->BreakTarget)
- {
- if( Block->BreakTarget[0] == '\0' || strcmp(Block->BreakTarget, Node->For.Tag) == 0 )
- {
- // Ours
- free((void*)Block->BreakTarget); Block->BreakTarget = NULL;
- if( Block->BreakType == NODETYPE_CONTINUE ) {
- // Continue, just keep going
- }
- else
- break;
- }
- else
- break; // Break out of this loop
- }
-
- // Increment
- ret = AST_ExecuteNode(Block, Node->For.Increment);
- if(ret == ERRPTR) return ERRPTR;
- SpiderScript_DereferenceValue(ret);
-
- // Check condition
- ret = AST_ExecuteNode(Block, Node->For.Condition);
- if(ret == ERRPTR) return ERRPTR;
- if(!SpiderScript_IsValueTrue(ret)) break;
- }
- SpiderScript_DereferenceValue(ret);
- ret = NULL;
- break;
-
- // Return
- case NODETYPE_RETURN:
- ret = AST_ExecuteNode(Block, Node->UniOp.Value);
- if(ret == ERRPTR) break;
- Block->RetVal = ret; // Return value set
- ret = NULL; // the `return` statement does not return a value
- break;
-
- case NODETYPE_BREAK:
- case NODETYPE_CONTINUE:
- Block->BreakTarget = strdup(Node->Variable.Name);
- Block->BreakType = Node->Type;
- break;
-
- // Define a variable
- case NODETYPE_DEFVAR:
- if( Node->DefVar.InitialValue ) {
- tmpobj = AST_ExecuteNode(Block, Node->DefVar.InitialValue);
- if(tmpobj == ERRPTR) return ERRPTR;
- }
- else {
- tmpobj = NULL;
- }
- // TODO: Handle arrays
- ret = NULL;
- if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name, tmpobj) == ERRPTR )
- ret = ERRPTR;
- SpiderScript_DereferenceValue(tmpobj);
- break;
-
- // Scope
- case NODETYPE_SCOPE:
- {
- tSpiderNamespace *ns;
-
- // Set current namespace if unset
- if( !Block->CurNamespace )
- Block->CurNamespace = Block->BaseNamespace;
-
- // Empty string means use the root namespace
- if( Node->Scope.Name[0] == '\0' )
- {
- ns = &Block->Script->Variant->RootNamespace;
- }
- else
- {
- // Otherwise scan the current namespace for the element
- for( ns = Block->CurNamespace->FirstChild; ns; ns = ns->Next )
- {
- if( strcmp(ns->Name, Node->Scope.Name) == 0 )
- break;
- }
- }
- if(!ns) {
- AST_RuntimeError(Node, "Unknown namespace '%s'", Node->Scope.Name);
- ret = ERRPTR;
- break;
- }
- Block->CurNamespace = ns;
-
- // TODO: Check type of child node (Scope, Constant or Function)
-
- ret = AST_ExecuteNode(Block, Node->Scope.Element);
- }
- break;
-
- // Variable
- case NODETYPE_VARIABLE:
- ret = Variable_GetValue( Block, Node );
- break;
-
- // Element of an Object
- case NODETYPE_ELEMENT:
- tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
- if(tmpobj == ERRPTR) return ERRPTR;
-
- ret = AST_ExecuteNode_Element(Block->Script, Node, tmpobj, Node->Scope.Name, ERRPTR);
- break;
-
- // Cast a value to another
- case NODETYPE_CAST:
- {
- tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
- if(tmpobj == ERRPTR) return ERRPTR;
- ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
- SpiderScript_DereferenceValue(tmpobj);
- }
- break;
-
- // Index into an array
- case NODETYPE_INDEX:
- op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
- if(op1 == ERRPTR) return ERRPTR;
- op2 = AST_ExecuteNode(Block, Node->BinOp.Right); // Offset
- if(op2 == ERRPTR) {
- SpiderScript_DereferenceValue(op1);
- return ERRPTR;
- }
-
- if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
- {
- 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( !op1 )
- {
- SpiderScript_DereferenceValue(op2);
- AST_RuntimeError(Node, "Indexing NULL value");
- ret = ERRPTR;
- break;
- }
-
- ret = AST_ExecuteNode_Index(Block->Script, Node, op1, op2->Integer, ERRPTR);
-
- SpiderScript_DereferenceValue(op1);
- SpiderScript_DereferenceValue(op2);
- break;
-
- // TODO: Implement runtime constants
- case NODETYPE_CONSTANT:
- // TODO: Scan namespace for constant name
- AST_RuntimeError(Node, "TODO - Runtime Constants");
- ret = ERRPTR;
- break;
-
- // Constant Values
- case NODETYPE_STRING:
- case NODETYPE_INTEGER:
- case NODETYPE_REAL:
- ret = &Node->Constant;
- SpiderScript_ReferenceValue(ret);
- break;
- case NODETYPE_NULL:
- ret = NULL;
- break;
-
- // --- Operations ---
- // Boolean Operations
- case NODETYPE_LOGICALNOT: // Logical NOT (!)
- op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
- if(op1 == ERRPTR) return ERRPTR;
- ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
- SpiderScript_DereferenceValue(op1);
- break;
- case NODETYPE_LOGICALAND: // Logical AND (&&)
- case NODETYPE_LOGICALOR: // Logical OR (||)
- case NODETYPE_LOGICALXOR: // Logical XOR (^^)
- op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
- if(op1 == ERRPTR) return ERRPTR;
- op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
- if(op2 == ERRPTR) {
- SpiderScript_DereferenceValue(op1);
- return ERRPTR;
- }
-
- switch( Node->Type )
- {
- case NODETYPE_LOGICALAND:
- ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
- break;
- case NODETYPE_LOGICALOR:
- ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
- break;
- case NODETYPE_LOGICALXOR:
- ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
- break;
- default: break;
- }
-
- // Free intermediate objects
- SpiderScript_DereferenceValue(op1);
- SpiderScript_DereferenceValue(op2);
- break;
-
- // General Unary Operations
- case NODETYPE_BWNOT: // Bitwise NOT (~)
- case NODETYPE_NEGATE: // Negation (-)
- op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
- if(op1 == ERRPTR) return ERRPTR;
- ret = AST_ExecuteNode_UniOp(Block->Script, Node, Node->Type, op1);
- SpiderScript_DereferenceValue(op1);
- break;
-
- // General Binary Operations
- case NODETYPE_ADD:
- case NODETYPE_SUBTRACT:
- case NODETYPE_MULTIPLY:
- case NODETYPE_DIVIDE:
- case NODETYPE_MODULO:
- case NODETYPE_BWAND:
- case NODETYPE_BWOR:
- case NODETYPE_BWXOR:
- case NODETYPE_BITSHIFTLEFT:
- case NODETYPE_BITSHIFTRIGHT:
- case NODETYPE_BITROTATELEFT:
- case NODETYPE_EQUALS:
- case NODETYPE_NOTEQUALS:
- case NODETYPE_LESSTHAN:
- case NODETYPE_GREATERTHAN:
- case NODETYPE_LESSTHANEQUAL:
- case NODETYPE_GREATERTHANEQUAL:
- // Get operands
- op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
- if(op1 == ERRPTR) return ERRPTR;
- op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
- if(op2 == ERRPTR) {
- SpiderScript_DereferenceValue(op1);
- return ERRPTR;
- }
-
- ret = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Type, op1, op2);
-
- // Free intermediate objects
- SpiderScript_DereferenceValue(op1);
- SpiderScript_DereferenceValue(op2);
- break;
-
- //default:
- // ret = NULL;
- // AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i", Node->Type);
- // break;
- }
-_return:
- // Reset namespace when no longer needed
- if( Node->Type != NODETYPE_SCOPE )
- Block->CurNamespace = NULL;
-
- #if TRACE_NODE_RETURNS
- if(ret && ret != ERRPTR) {
- AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
- }
- else {
- AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
- }
- #endif
-
- return ret;
-}
-#endif
-
-tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value)
-{
- tSpiderValue *ret;
- #if 0
- if( Value->Type == SS_DATATYPE_OBJECT )
- {
- const char *fcnname;
- switch(Operation)
- {
- case NODETYPE_NEGATE: fcnname = "-ve"; break;
- case NODETYPE_BWNOT: fcnname = "~"; break;
- default: fcnname = NULL; break;
- }
-
- if( fcnname )
- {
- ret = Object_ExecuteMethod(Value->Object, fcnname, );
- if( ret != ERRPTR )
- return ret;
- }
- }
- #endif
- switch(Value->Type)
- {
- // Integer Operations
- case SS_DATATYPE_INTEGER:
- if( Value->ReferenceCount == 1 )
- SpiderScript_ReferenceValue(ret = Value);
- else
- ret = SpiderScript_CreateInteger(0);
- switch(Operation)
- {
- case NODETYPE_NEGATE: ret->Integer = -Value->Integer; break;
- case NODETYPE_BWNOT: ret->Integer = ~Value->Integer; break;
- default:
- AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
- SpiderScript_DereferenceValue(ret);
- ret = ERRPTR;
- break;
- }
- break;
- // Real number Operations
- case SS_DATATYPE_REAL:
- switch(Operation)
- {
- case NODETYPE_NEGATE: ret = SpiderScript_CreateInteger( -Value->Real ); break;
- default:
- AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
- ret = ERRPTR;
- break;
- }
- break;
-
- default:
- AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
- ret = ERRPTR;
- break;
- }
-
- return ret;
-}
-
-tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
-{
- tSpiderValue *preCastValue = Right;
- tSpiderValue *ret;
-
- // Convert types
- if( Left && Right && Left->Type != Right->Type )
- {
- #if 0
- // Object types
- // - Operator overload functions
- if( Left->Type == SS_DATATYPE_OBJECT )
- {
- const char *fcnname;
- switch(Operation)
- {
- case NODETYPE_ADD: fcnname = "+"; break;
- case NODETYPE_SUBTRACT: fcnname = "-"; break;
- case NODETYPE_MULTIPLY: fcnname = "*"; break;
- case NODETYPE_DIVIDE: fcnname = "/"; break;
- case NODETYPE_MODULO: fcnname = "%"; break;
- case NODETYPE_BWAND: fcnname = "&"; break;
- case NODETYPE_BWOR: fcnname = "|"; break;
- case NODETYPE_BWXOR: fcnname = "^"; break;
- case NODETYPE_BITSHIFTLEFT: fcnname = "<<"; break;
- case NODETYPE_BITSHIFTRIGHT:fcnname = ">>"; break;
- case NODETYPE_BITROTATELEFT:fcnname = "<<<"; break;
- default: fcnname = NULL; break;
- }
-
- if( fcnname )
- {
- ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
- if( ret != ERRPTR )
- return ret;
- // Fall through and try casting (which will usually fail)
- }
- }
- #endif
-
- // If implicit casts are allowed, convert Right to Left's type
- if(Script->Variant->bImplicitCasts)
- {
- Right = SpiderScript_CastValueTo(Left->Type, Right);
- if(Right == ERRPTR)
- return ERRPTR;
- }
- // If statically typed, this should never happen, but catch it anyway
- else {
- AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
- return ERRPTR;
- }
- }
-
- // NULL Check
- if( Left == NULL || Right == NULL ) {
- if(Right && Right != preCastValue) free(Right);
- return NULL;
- }
-
- // Catch comparisons
- switch(Operation)
- {
- case NODETYPE_EQUALS:
- case NODETYPE_NOTEQUALS:
- case NODETYPE_LESSTHAN:
- case NODETYPE_GREATERTHAN:
- case NODETYPE_LESSTHANEQUAL:
- case NODETYPE_GREATERTHANEQUAL: {
- int cmp;
- ret = NULL;
- // Do operation
- switch(Left->Type)
- {
- // - String Compare (does a strcmp, well memcmp)
- case SS_DATATYPE_STRING:
- // Call memcmp to do most of the work
- cmp = memcmp(
- Left->String.Data, Right->String.Data,
- (Left->String.Length < Right->String.Length) ? Left->String.Length : Right->String.Length
- );
- // Handle reaching the end of the string
- if( cmp == 0 ) {
- if( Left->String.Length == Right->String.Length )
- cmp = 0;
- else if( Left->String.Length < Right->String.Length )
- cmp = 1;
- else
- cmp = -1;
- }
- break;
-
- // - Integer Comparisons
- case SS_DATATYPE_INTEGER:
- if( Left->Integer == Right->Integer )
- cmp = 0;
- else if( Left->Integer < Right->Integer )
- cmp = -1;
- else
- cmp = 1;
- break;
- // - Real Number Comparisons
- case SS_DATATYPE_REAL:
- cmp = (Left->Real - Right->Real) / Right->Real * 10000; // < 0.1% difference is equality
- break;
- default:
- AST_RuntimeError(Node, "TODO - Comparison of type %i", Left->Type);
- ret = ERRPTR;
- break;
- }
-
- // Error check
- if( ret != ERRPTR )
- {
- if(Left->ReferenceCount == 1 && Left->Type != SS_DATATYPE_STRING)
- SpiderScript_ReferenceValue(ret = Left);
- else
- ret = SpiderScript_CreateInteger(0);
-
- // Create return
- 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 NODETYPE_GREATERTHANEQUAL: ret->Integer = (cmp >= 0); break;
- default:
- AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Operation);
- SpiderScript_DereferenceValue(ret);
- ret = ERRPTR;
- break;
- }
- }
- if(Right && Right != preCastValue) free(Right);
- return ret;
- }
-
- // Fall through and sort by type instead
- default:
- break;
- }
-
- // Do operation
- switch(Left->Type)
- {
- // String Concatenation
- case SS_DATATYPE_STRING:
- switch(Operation)
- {
- case NODETYPE_ADD: // Concatenate
- ret = SpiderScript_StringConcat(Left, Right);
- break;
- // TODO: Support python style 'i = %i' % i ?
- // Might do it via a function call
- // Implement it via % with an array, but getting past the cast will be fun
-// case NODETYPE_MODULUS:
-// break;
- // TODO: Support string repititions
-// case NODETYPE_MULTIPLY:
-// break;
-
- default:
- AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
- ret = ERRPTR;
- break;
- }
- break;
- // Integer Operations
- case SS_DATATYPE_INTEGER:
- if( Left->ReferenceCount == 1 )
- SpiderScript_ReferenceValue(ret = Left);
- else
- ret = SpiderScript_CreateInteger(0);
- switch(Operation)
- {
- case NODETYPE_ADD: ret->Integer = Left->Integer + Right->Integer; break;
- case NODETYPE_SUBTRACT: ret->Integer = Left->Integer - Right->Integer; break;
- case NODETYPE_MULTIPLY: ret->Integer = Left->Integer * Right->Integer; break;
- case NODETYPE_DIVIDE: ret->Integer = Left->Integer / Right->Integer; break;
- case NODETYPE_MODULO: ret->Integer = Left->Integer % Right->Integer; break;
- case NODETYPE_BWAND: ret->Integer = Left->Integer & Right->Integer; break;
- case NODETYPE_BWOR: ret->Integer = Left->Integer | Right->Integer; break;
- case NODETYPE_BWXOR: ret->Integer = Left->Integer ^ Right->Integer; break;
- case NODETYPE_BITSHIFTLEFT: ret->Integer = Left->Integer << Right->Integer; break;
- case NODETYPE_BITSHIFTRIGHT:ret->Integer = Left->Integer >> Right->Integer; break;
- case NODETYPE_BITROTATELEFT:
- ret->Integer = (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer));
- break;
- default:
- AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
- SpiderScript_DereferenceValue(ret);
- ret = ERRPTR;
- break;
- }
- break;
-
- // Real Numbers
- case SS_DATATYPE_REAL:
- if( Left->ReferenceCount == 1 )
- SpiderScript_ReferenceValue(ret = Left);
- else
- ret = SpiderScript_CreateReal(0);
- switch(Operation)
- {
- case NODETYPE_ADD: ret->Real = Left->Real + Right->Real; break;
- case NODETYPE_SUBTRACT: ret->Real = Left->Real - Right->Real; break;
- case NODETYPE_MULTIPLY: ret->Real = Left->Real * Right->Real; break;
- case NODETYPE_DIVIDE: ret->Real = Left->Real / Right->Real; break;
- default:
- AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
- SpiderScript_DereferenceValue(ret);
- ret = ERRPTR;
- break;
- }
- break;
-
- default:
- AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
- ret = ERRPTR;
- break;
- }
-
- if(Right && Right != preCastValue) free(Right);
-
- 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
- * \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, tSpiderValue *Value)
-{
- tAST_Variable *var, *prev = NULL;
-
- for( var = Block->FirstVar; var; prev = var, var = var->Next )
- {
- if( strcmp(var->Name, Name) == 0 ) {
- AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
- return ERRPTR;
- }
- }
-
- var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
- var->Next = NULL;
- var->Type = Type;
- var->Object = Value;
- if(Value) SpiderScript_ReferenceValue(Value);
- strcpy(var->Name, Name);
-
- if(prev) prev->Next = var;
- else Block->FirstVar = var;
-
- //printf("Defined variable %s (%i)\n", Name, Type);
-
- return var;
-}
-
-tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
-{
- tAST_Variable *var = NULL;
-
- // Speed hack
- if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
- var = VarNode->ValueCache;
- #if TRACE_VAR_LOOKUPS
- AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
- VarNode->Variable.Name, var,
- VarNode->BlockState, VarNode->BlockIdent
- );
- #endif
- }
- else
- {
- tAST_BlockState *bs;
- for( bs = Block; bs; bs = bs->Parent )
- {
- for( var = bs->FirstVar; var; var = var->Next )
- {
- if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
- break;
- }
- if(var) break;
- }
-
- if( !var )
- {
- if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
- // Define variable
- var = Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
- }
- else
- {
- AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
- return NULL;
- }
- }
-
- #if TRACE_VAR_LOOKUPS
- AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
- VarNode->Variable.Name, var,
- Block, Block->Ident);
- #endif
-
- VarNode->ValueCache = var;
- VarNode->BlockState = Block;
- VarNode->BlockIdent = Block->Ident;
- }
-
- return var;
-}
-
-/**
- * \brief Set the value of a variable
- * \return Boolean Failure
- */
-int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value)
-{
- tAST_Variable *var;
-
- var = Variable_Lookup(Block, VarNode, (Value ? Value->Type : SS_DATATYPE_UNDEF));
-
- if( !var ) return -1;
-
- if( !Block->Script->Variant->bDyamicTyped && (Value && var->Type != Value->Type) )
- {
- AST_RuntimeError(VarNode, "Type mismatch assigning to '%s'",
- VarNode->Variable.Name);
- return -2;
- }
-
-// printf("Assign %p to '%s'\n", Value, var->Name);
- SpiderScript_ReferenceValue(Value);
- SpiderScript_DereferenceValue(var->Object);
- var->Object = Value;
- return 0;
-}
-
-/**
- * \brief Get the value of a variable
- */
-tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
-{
- tAST_Variable *var = Variable_Lookup(Block, VarNode, 0);
-
- if( !var ) return ERRPTR;
-
- SpiderScript_ReferenceValue(var->Object);
- return var->Object;
-}
-
-/**
- * \brief Destorys a variable
- */
-void Variable_Destroy(tAST_Variable *Variable)
-{
-// printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
- SpiderScript_DereferenceValue(Variable->Object);
- free(Variable);
-}
-#endif
-
+++ /dev/null
-/*
- * SpiderScript Library
- * by John Hodge (thePowersGang)
- *
- * exec_bytecode.c
- * - Execute bytecode
- */
-#include <stdlib.h>
-#include <stdint.h>
-#include "common.h"
-#include "bytecode.h"
-#include <stdio.h>
-#include <string.h>
-#include "ast.h"
-#include <inttypes.h>
-
-#define TRACE 0
-
-#if TRACE
-# define DEBUG_F(v...) printf(v)
-#else
-# define DEBUG_F(v...)
-#endif
-
-// === IMPORTS ===
-extern void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
-
-// === TYPES ===
-typedef struct sBC_StackEnt tBC_StackEnt;
-typedef struct sBC_Stack tBC_Stack;
-
-enum eBC_StackEntTypes
-{
- ET_NULL, // Start of the stack
- // SS_DATATYPE_*
- ET_FUNCTION_START = NUM_SS_DATATYPES,
- ET_REFERENCE // Reference to a tSpiderValue
-};
-
-struct sBC_StackEnt
-{
- uint8_t Type;
- union {
- int64_t Integer;
- double Real;
- tSpiderValue *Reference; // Used for everything else
- tSpiderObject *Object;
- tSpiderNamespace *Namespace;
- };
-};
-
-struct sBC_Stack
-{
- int EntrySpace;
- int EntryCount;
- tBC_StackEnt Entries[];
-};
-
-// === PROTOTYPES ===
-tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args);
- int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount);
-
-// === CODE ===
-int Bytecode_int_StackPop(tBC_Stack *Stack, tBC_StackEnt *Dest)
-{
- if( Stack->EntryCount == 0 ) return 1;
- Stack->EntryCount --;
- *Dest = Stack->Entries[Stack->EntryCount];
- return 0;
-}
-
-int Bytecode_int_StackPush(tBC_Stack *Stack, tBC_StackEnt *Src)
-{
- if( Stack->EntryCount == Stack->EntrySpace ) return 1;
- Stack->Entries[Stack->EntryCount] = *Src;
- Stack->EntryCount ++;
- return 0;
-}
-
-int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
-{
- switch(Ent->Type)
- {
- case SS_DATATYPE_INTEGER:
- return !!Ent->Integer;
- case SS_DATATYPE_REAL:
- return !(-.5f < Ent->Real && Ent->Real < 0.5f);
- case SS_DATATYPE_OBJECT:
- return Ent->Object != NULL;
- case ET_FUNCTION_START:
- return -1;
- default:
- return SpiderScript_IsValueTrue(Ent->Reference);
- }
-}
-
-tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
-{
- switch(Ent->Type)
- {
- case SS_DATATYPE_INTEGER:
- case SS_DATATYPE_REAL:
- case SS_DATATYPE_OBJECT:
- if(!tmp) {
- tmp = malloc(sizeof(tSpiderValue));
- tmp->ReferenceCount = 1;
- } else {
- // Stops a stack value from having free() called on it
- tmp->ReferenceCount = 2;
- }
- break;
- default:
- break;
- }
- switch(Ent->Type)
- {
- case SS_DATATYPE_INTEGER:
- tmp->Type = SS_DATATYPE_INTEGER;
- tmp->Integer = Ent->Integer;
- return tmp;
- case SS_DATATYPE_REAL:
- tmp->Type = SS_DATATYPE_REAL;
- tmp->Real = Ent->Real;
- return tmp;
- case SS_DATATYPE_OBJECT:
- tmp->Type = SS_DATATYPE_OBJECT;
- tmp->Object = Ent->Object;
- return tmp;
- case ET_FUNCTION_START:
- AST_RuntimeError(NULL, "_GetSpiderValue on ET_FUNCTION_START");
- return NULL;
- default:
- SpiderScript_ReferenceValue(Ent->Reference);
- return Ent->Reference;
- }
-}
-
-void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
-{
- if(!Value) {
- Ent->Type = ET_REFERENCE;
- Ent->Reference = NULL;
- return ;
- }
- switch(Value->Type)
- {
- case SS_DATATYPE_INTEGER:
- Ent->Type = SS_DATATYPE_INTEGER;
- Ent->Integer = Value->Integer;
- break;
- case SS_DATATYPE_REAL:
- Ent->Type = SS_DATATYPE_REAL;
- Ent->Real = Value->Real;
- break;
- case SS_DATATYPE_OBJECT:
- Ent->Type = SS_DATATYPE_OBJECT;
- Ent->Object = Value->Object;
- Ent->Object->ReferenceCount ++;
- break;
- default:
- SpiderScript_ReferenceValue(Value);
- Ent->Type = ET_REFERENCE;
- Ent->Reference = Value;
- break;
- }
-}
-
-void Bytecode_int_DerefStackValue(tBC_StackEnt *Ent)
-{
- switch(Ent->Type)
- {
- case SS_DATATYPE_INTEGER:
- case SS_DATATYPE_REAL:
- break;
- case SS_DATATYPE_OBJECT:
- if(Ent->Object) {
- Ent->Object->ReferenceCount --;
- if(Ent->Object->ReferenceCount == 0) {
- Ent->Object->Type->Destructor( Ent->Object );
- }
-// printf("Object %p derefed (obj refcount = %i)\n", Ent->Object, Ent->Object->ReferenceCount);
- }
- Ent->Object = NULL;
- break;
- default:
- if(Ent->Reference)
- SpiderScript_DereferenceValue(Ent->Reference);
- Ent->Reference = NULL;
- break;
- }
-}
-void Bytecode_int_RefStackValue(tBC_StackEnt *Ent)
-{
- switch(Ent->Type)
- {
- case SS_DATATYPE_INTEGER:
- case SS_DATATYPE_REAL:
- break;
- case SS_DATATYPE_OBJECT:
- if(Ent->Object) {
- Ent->Object->ReferenceCount ++;
-// printf("Object %p referenced (count = %i)\n", Ent->Object, Ent->Object->ReferenceCount);
- }
- break;
- default:
- if(Ent->Reference)
- SpiderScript_ReferenceValue(Ent->Reference);
- break;
- }
-}
-
-void Bytecode_int_PrintStackValue(tBC_StackEnt *Ent)
-{
- switch(Ent->Type)
- {
- case SS_DATATYPE_INTEGER:
- printf("0x%"PRIx64, Ent->Integer);
- break;
- case SS_DATATYPE_REAL:
- printf("%lf", Ent->Real);
- break;
- case SS_DATATYPE_OBJECT:
- printf("Obj %p", Ent->Object);
- break;
- default:
- if( Ent->Reference )
- printf("*%p (%i refs)", Ent->Reference, Ent->Reference->ReferenceCount);
- else
- printf("NULL");
- break;
- }
-}
-
-#if TRACE
-# define PRINT_STACKVAL(val) Bytecode_int_PrintStackValue(&val)
-#else
-# define PRINT_STACKVAL(val)
-#endif
-
-#define GET_STACKVAL(dst) if((ret = Bytecode_int_StackPop(Stack, &dst))) { \
- AST_RuntimeError(NULL, "Stack pop failed, empty stack");\
- return ret; \
-}
-#define PUT_STACKVAL(src) if((ret = Bytecode_int_StackPush(Stack, &src))) { \
- AST_RuntimeError(NULL, "Stack push failed, full stack");\
- return ret; \
-}
-#define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
-#define OP_STRING(op_ptr) ((op_ptr)->Content.StringInt.String)
-
-tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args)
-{
- const int stack_size = 100;
- tSpiderValue *ret, tmpsval;
- tBC_Stack *stack;
- tBC_StackEnt val;
- int i;
-
- stack = malloc(sizeof(tBC_Stack) + stack_size*sizeof(tBC_StackEnt));
- stack->EntrySpace = stack_size;
- stack->EntryCount = 0;
-
- // Push arguments in order (so top is last arg)
- for( i = 0; i < NArguments; i ++ )
- {
- Bytecode_int_SetSpiderValue(&val, Args[i]);
- Bytecode_int_StackPush(stack, &val);
- }
-
- // Call
- Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
-
- // Get return value
- if( Bytecode_int_StackPop(stack, &val) ) {
- free(stack);
- return NULL;
- }
- free(stack);
-
- ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
- // Ensure it's a heap value
- if(ret == &tmpsval) {
- ret = malloc(sizeof(tSpiderValue));
- memcpy(ret, &tmpsval, sizeof(tSpiderValue));
- // Set to 2 in _GetSpiderValue, so stack doesn't have free() called
- ret->ReferenceCount = 1;
- }
-
- return ret;
-}
-
-tSpiderNamespace *Bytecode_int_ResolveNamespace(tSpiderNamespace *Start, const char *Name, const char **FinalName)
-{
- char *pos;
- tSpiderNamespace *ns = Start;
- while( (pos = strchr(Name, BC_NS_SEPARATOR)) )
- {
- int len = pos - Name;
- for( ns = ns->FirstChild; ns; ns = ns->Next )
- {
- if(memcmp(ns->Name, Name, len) == 0 && ns->Name[len] == 0)
- break;
- }
- if(!ns) {
- return NULL;
- }
- Name += len + 1;
- }
- if(FinalName) *FinalName = Name;
- return ns;
-}
-
-/**
- * \brief Call an external function (may recurse into Bytecode_ExecuteFunction, but may not)
- */
-int Bytecode_int_CallExternFunction(tSpiderScript *Script, tBC_Stack *Stack, tSpiderNamespace *DefaultNS, tBC_Op *op )
-{
- const char *name = OP_STRING(op);
- int arg_count = OP_INDX(op);
- int i, ret = 0;
- tSpiderValue *args[arg_count];
- tSpiderValue *rv;
- tBC_StackEnt val1;
- const char *namespaces[] = {NULL}; // TODO: Default/imported namespaces
-
- DEBUG_F("CALL (general) %s %i args\n", name, arg_count);
-
- // Read arguments
- for( i = arg_count; i --; )
- {
- GET_STACKVAL(val1);
- args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
- Bytecode_int_DerefStackValue(&val1);
- }
-
- // Call the function etc.
- if( op->Operation == BC_OP_CALLFUNCTION )
- {
- rv = SpiderScript_ExecuteFunction(Script, name, namespaces, arg_count, args, &op->CacheEnt);
- }
- else if( op->Operation == BC_OP_CREATEOBJ )
- {
- rv = SpiderScript_CreateObject(Script, name, namespaces, arg_count, args);
- }
- else if( op->Operation == BC_OP_CALLMETHOD )
- {
- tSpiderObject *obj;
- GET_STACKVAL(val1);
-
- if(val1.Type == SS_DATATYPE_OBJECT)
- obj = val1.Object;
- else if(val1.Type == ET_REFERENCE && val1.Reference && val1.Reference->Type == SS_DATATYPE_OBJECT)
- obj = val1.Reference->Object;
- else {
- // Error
- AST_RuntimeError(NULL, "OP_CALLMETHOD on non object");
- return -1;
- }
- rv = SpiderScript_ExecuteMethod(Script, obj, name, arg_count, args);
- Bytecode_int_DerefStackValue(&val1);
- }
- else
- {
- AST_RuntimeError(NULL, "BUG - Unknown operation for CALL/CREATEOBJ (%i)", op->Operation);
- rv = ERRPTR;
- }
- if(rv == ERRPTR) {
- AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
- return -1;
- }
- // Clean up args
- for( i = arg_count; i --; )
- SpiderScript_DereferenceValue(args[i]);
- // Get and push return
- Bytecode_int_SetSpiderValue(&val1, rv);
- PUT_STACKVAL(val1);
- // Deref return
- SpiderScript_DereferenceValue(rv);
-
- #if 0
- if(!rv) {
- printf("%s returned NULL\n", name);
- }
- if( rv && rv != ERRPTR && rv->ReferenceCount != 1 ) {
- printf("Return value from %s reference count fail (%i)\n",
- name, rv->ReferenceCount);
- }
- #endif
-
- return 0;
-}
-
-int Bytecode_int_LocalBinOp_Integer(int Operation, tBC_StackEnt *Val1, tBC_StackEnt *Val2)
-{
- switch(Operation)
- {
- case BC_OP_ADD: Val1->Integer = Val1->Integer + Val2->Integer; break;
- case BC_OP_SUBTRACT: Val1->Integer = Val1->Integer - Val2->Integer; break;
- case BC_OP_MULTIPLY: Val1->Integer = Val1->Integer * Val2->Integer; break;
- case BC_OP_DIVIDE: Val1->Integer = Val1->Integer / Val2->Integer; break;
-
- case BC_OP_EQUALS: Val1->Integer = (Val1->Integer == Val2->Integer); break;
- case BC_OP_NOTEQUALS: Val1->Integer = (Val1->Integer != Val2->Integer); break;
- case BC_OP_LESSTHAN: Val1->Integer = (Val1->Integer < Val2->Integer); break;
- case BC_OP_LESSTHANOREQUAL: Val1->Integer = (Val1->Integer <= Val2->Integer); break;
- case BC_OP_GREATERTHAN: Val1->Integer = (Val1->Integer > Val2->Integer); break;
- case BC_OP_GREATERTHANOREQUAL: Val1->Integer = (Val1->Integer >= Val2->Integer); break;
-
- case BC_OP_BITAND: Val1->Integer = Val1->Integer & Val2->Integer; break;
- case BC_OP_BITOR: Val1->Integer = Val1->Integer | Val2->Integer; break;
- case BC_OP_BITXOR: Val1->Integer = Val1->Integer ^ Val2->Integer; break;
- case BC_OP_MODULO: Val1->Integer = Val1->Integer % Val2->Integer; break;
- default: AST_RuntimeError(NULL, "Invalid operation on datatype Integer"); return -1;
- }
- return 0;
-}
-
-int Bytecode_int_LocalBinOp_Real(int Operation, tBC_StackEnt *Val1, tBC_StackEnt *Val2)
-{
- switch(Operation)
- {
- // Real = Real OP Real
- case BC_OP_ADD: Val1->Real = Val1->Real + Val2->Real; return 0;
- case BC_OP_SUBTRACT: Val1->Real = Val1->Real - Val2->Real; return 0;
- case BC_OP_MULTIPLY: Val1->Real = Val1->Real * Val2->Real; return 0;
- case BC_OP_DIVIDE: Val1->Real = Val1->Real / Val2->Real; return 0;
-
- // Bool/Integer = Real OP Real
- case BC_OP_EQUALS: Val1->Integer = (Val1->Real == Val2->Real); break;
- case BC_OP_NOTEQUALS: Val1->Integer = (Val1->Real != Val2->Real); break;
- case BC_OP_LESSTHAN: Val1->Integer = (Val1->Real < Val2->Real); break;
- case BC_OP_LESSTHANOREQUAL: Val1->Integer = (Val1->Real <= Val2->Real); break;
- case BC_OP_GREATERTHAN: Val1->Integer = (Val1->Real > Val2->Real); break;
- case BC_OP_GREATERTHANOREQUAL: Val1->Integer = (Val1->Real >= Val2->Real); break;
-
- default: AST_RuntimeError(NULL, "Invalid operation on datatype Real"); return -1;
- }
- Val1->Type = SS_DATATYPE_INTEGER; // Becomes logical
- return 0;
-}
-
-#define STATE_HDR() DEBUG_F("%p %2i ", op, Stack->EntryCount)
-
-/**
- * \brief Execute a bytecode function with a stack
- */
-int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
-{
- int ret, ast_op, i;
- tBC_Op *op;
- tBC_StackEnt val1, val2;
- int local_var_count = Fcn->BCFcn->MaxVariableCount;
- tBC_StackEnt local_vars[local_var_count]; // Includes arguments
- tSpiderValue tmpVal1, tmpVal2; // temp storage
- tSpiderValue *pval1, *pval2, *ret_val;
- tSpiderNamespace *default_namespace = &Script->Variant->RootNamespace;
-
- // Initialise local vars
- for( i = 0; i < local_var_count; i ++ )
- local_vars[i].Type = ET_NULL;
-
- // Pop off arguments
- if( ArgCount > Fcn->ArgumentCount ) return -1;
- DEBUG_F("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
- // - Handle optional arguments
- for( i = Fcn->ArgumentCount; i > ArgCount; )
- {
- i --;
- local_vars[i].Integer = 0;
- local_vars[i].Type = Fcn->Arguments[i].Type;
- }
- for( ; i --; )
- {
- GET_STACKVAL(local_vars[i]);
- // TODO: Type checks / enforcing
- }
-
- // Mark the start
- memset(&val1, 0, sizeof(val1));
- val1.Type = ET_FUNCTION_START;
- PUT_STACKVAL(val1);
-
- // Execute!
- op = Fcn->BCFcn->Operations;
- while(op)
- {
- const char *opstr = "";
- tBC_Op *nextop = op->Next, *jmp_target;
- ast_op = 0;
- switch(op->Operation)
- {
- case BC_OP_NOP:
- STATE_HDR();
- DEBUG_F("NOP\n");
- break;
- // Jumps
- case BC_OP_JUMP:
- STATE_HDR();
- jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
- DEBUG_F("JUMP #%i %p\n", OP_INDX(op), jmp_target);
- nextop = jmp_target;
- break;
- case BC_OP_JUMPIF:
- STATE_HDR();
- jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
- DEBUG_F("JUMPIF #%i %p\n", OP_INDX(op), jmp_target);
- GET_STACKVAL(val1);
- if( Bytecode_int_IsStackEntTrue(&val1) )
- nextop = jmp_target;
- break;
- case BC_OP_JUMPIFNOT:
- STATE_HDR();
- jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
- DEBUG_F("JUMPIFNOT #%i %p\n", OP_INDX(op), jmp_target);
- GET_STACKVAL(val1);
- if( !Bytecode_int_IsStackEntTrue(&val1) )
- nextop = jmp_target;
- break;
-
- // Define variables
- case BC_OP_DEFINEVAR: {
- int type, slot;
- type = OP_INDX(op) & 0xFFFF;
- slot = OP_INDX(op) >> 16;
- if(slot < 0 || slot >= local_var_count) {
- DEBUG_F("ERROR: slot %i out of range (max %i)\n", slot, local_var_count);
- return -1;
- }
- STATE_HDR();
- DEBUG_F("DEFVAR %i of type %i\n", slot, type);
- if( local_vars[slot].Type != ET_NULL ) {
- Bytecode_int_DerefStackValue( &local_vars[slot] );
- local_vars[slot].Type = ET_NULL;
- }
- memset(&local_vars[slot], 0, sizeof(local_vars[0]));
- local_vars[slot].Type = type;
- } break;
-
- // Enter/Leave context
- // - NOP now
- case BC_OP_ENTERCONTEXT:
- STATE_HDR();
- DEBUG_F("ENTERCONTEXT\n");
- break;
- case BC_OP_LEAVECONTEXT:
- STATE_HDR();
- DEBUG_F("LEAVECONTEXT\n");
- break;
-
- // Variables
- case BC_OP_LOADVAR: {
- int slot = OP_INDX(op);
- STATE_HDR();
- DEBUG_F("LOADVAR %i ", slot);
- if( slot < 0 || slot >= local_var_count ) {
- AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
- return -1;
- }
- DEBUG_F("("); PRINT_STACKVAL(local_vars[slot]); DEBUG_F(")\n");
- PUT_STACKVAL(local_vars[slot]);
- Bytecode_int_RefStackValue( &local_vars[slot] );
- } break;
- case BC_OP_SAVEVAR: {
- int slot = OP_INDX(op);
- STATE_HDR();
- DEBUG_F("SAVEVAR %i = ", slot);
- if( slot < 0 || slot >= local_var_count ) {
- AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
- return -1;
- }
- // Remove whatever was in there before
- DEBUG_F("[Deref "); PRINT_STACKVAL(local_vars[slot]); DEBUG_F("] ");
- Bytecode_int_DerefStackValue( &local_vars[slot] );
- // Place new in
- GET_STACKVAL(local_vars[slot]);
- PRINT_STACKVAL(local_vars[slot]);
- DEBUG_F("\n");
- } break;
-
- // Array index (get or set)
- case BC_OP_INDEX:
- case BC_OP_SETINDEX:
- STATE_HDR();
- GET_STACKVAL(val1); // Index
- // TODO: Check that index is an integer
- if( val1.Type != SS_DATATYPE_INTEGER ) {
- nextop = NULL;
- break;
- }
-
- // Get array as raw spider value
- GET_STACKVAL(val2); // Array
- pval1 = Bytecode_int_GetSpiderValue(&val2, &tmpVal1);
- Bytecode_int_DerefStackValue(&val2);
-
- if( op->Operation == BC_OP_SETINDEX ) {
- GET_STACKVAL(val2);
- pval2 = Bytecode_int_GetSpiderValue(&val2, NULL);
- Bytecode_int_DerefStackValue(&val2);
-
- DEBUG_F("SETINDEX %i ", val1.Integer); PRINT_STACKVAL(val2); DEBUG_F("\n");
-
- ret_val = AST_ExecuteNode_Index(Script, NULL, pval1, val1.Integer, pval2);
- if(ret_val == ERRPTR) { nextop = NULL; break; }
- SpiderScript_DereferenceValue(pval2);
- }
- else {
- DEBUG_F("INDEX %i ", val1.Integer);
- ret_val = AST_ExecuteNode_Index(Script, NULL, pval1, val1.Integer, ERRPTR);
- if(ret_val == ERRPTR) { nextop = NULL; break; }
-
- Bytecode_int_SetSpiderValue(&val1, ret_val);
- SpiderScript_DereferenceValue(ret_val);
- PUT_STACKVAL(val1);
-
- DEBUG_F("[Got "); PRINT_STACKVAL(val1); DEBUG_F("]\n");
-
- }
- // Dereference the array (or object, ...)
- if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
- break;
-
- // Object element (get or set)
- case BC_OP_ELEMENT:
- case BC_OP_SETELEMENT:
- STATE_HDR();
-
- GET_STACKVAL(val1);
- // - Integers/Reals can't have elements :)
- if( val1.Type != ET_REFERENCE ) {
- nextop = NULL;
- break;
- }
-
- pval1 = Bytecode_int_GetSpiderValue(&val1, NULL);
- Bytecode_int_DerefStackValue(&val1);
-
- if( op->Operation == BC_OP_SETELEMENT ) {
- GET_STACKVAL(val2);
- pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
- Bytecode_int_DerefStackValue(&val2);
-
- DEBUG_F("SETELEMENT %s ", OP_STRING(op)); PRINT_STACKVAL(val2); DEBUG_F("\n");
-
- ret_val = AST_ExecuteNode_Element(Script, NULL, pval1, OP_STRING(op), pval2);
- if(ret_val == ERRPTR) { nextop = NULL; break; }
-
- if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2);
- }
- else {
- DEBUG_F("ELEMENT %s ", OP_STRING(op));
-
- ret_val = AST_ExecuteNode_Element(Script, NULL, pval1, OP_STRING(op), ERRPTR);
- if(ret_val == ERRPTR) { nextop = NULL; break; }
-
- Bytecode_int_SetSpiderValue(&val2, ret_val);
- SpiderScript_DereferenceValue(ret_val);
- PUT_STACKVAL(val2);
-
- DEBUG_F("[Got "); PRINT_STACKVAL(val2); DEBUG_F("]\n");
- }
-
- SpiderScript_DereferenceValue(pval1);
- break;
-
- // Constants:
- case BC_OP_LOADINT:
- STATE_HDR();
- DEBUG_F("LOADINT 0x%lx\n", op->Content.Integer);
- val1.Type = SS_DATATYPE_INTEGER;
- val1.Integer = op->Content.Integer;
- PUT_STACKVAL(val1);
- break;
- case BC_OP_LOADREAL:
- STATE_HDR();
- DEBUG_F("LOADREAL %lf\n", op->Content.Real);
- val1.Type = SS_DATATYPE_REAL;
- val1.Real = op->Content.Real;
- PUT_STACKVAL(val1);
- break;
- case BC_OP_LOADSTR:
- STATE_HDR();
- DEBUG_F("LOADSTR %i \"%s\"\n", OP_INDX(op), OP_STRING(op));
- val1.Type = SS_DATATYPE_STRING;
- val1.Reference = SpiderScript_CreateString(OP_INDX(op), OP_STRING(op));
- PUT_STACKVAL(val1);
- break;
- case BC_OP_LOADNULL:
- STATE_HDR();
- DEBUG_F("LOADNULL\n");
- val1.Type = ET_REFERENCE;
- val1.Reference = NULL;
- PUT_STACKVAL(val1);
- break;
-
- case BC_OP_CAST:
- STATE_HDR();
- val2.Type = OP_INDX(op);
- DEBUG_F("CAST to %i\n", val2.Type);
- GET_STACKVAL(val1);
- if(val1.Type == val2.Type) {
- PUT_STACKVAL(val1);
- break;
- }
- if( val2.Type == SS_DATATYPE_INTEGER && val1.Type == SS_DATATYPE_REAL ) {
- val2.Integer = val1.Real;
- }
- else if( val2.Type == SS_DATATYPE_REAL && val2.Type == SS_DATATYPE_INTEGER ) {
- val2.Real = val1.Integer;
- }
- else {
- pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
- pval2 = SpiderScript_CastValueTo(val2.Type, pval1);
-
- Bytecode_int_SetSpiderValue(&val2, pval2);
- SpiderScript_DereferenceValue(pval2);
-
- if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
- Bytecode_int_DerefStackValue(&val1);
-// printf("CAST (%x->%x) - Original %i references remaining\n",
-// pval1->Type, OP_INDX(op),
-// pval1->ReferenceCount);
- }
- PUT_STACKVAL(val2);
- break;
-
- case BC_OP_DUPSTACK:
- STATE_HDR();
- DEBUG_F("DUPSTACK ");
- GET_STACKVAL(val1);
- PRINT_STACKVAL(val1);
- DEBUG_F("\n");
- PUT_STACKVAL(val1);
- PUT_STACKVAL(val1);
- Bytecode_int_RefStackValue(&val1);
- break;
-
- // Discard the top item from the stack
- case BC_OP_DELSTACK:
- STATE_HDR();
- DEBUG_F("DELSTACK\n");
- GET_STACKVAL(val1);
- break;
-
- // Unary Operations
- case BC_OP_LOGICNOT:
- STATE_HDR();
- DEBUG_F("LOGICNOT\n");
-
- GET_STACKVAL(val1);
- val2.Type = SS_DATATYPE_INTEGER;
- val2.Integer = !Bytecode_int_IsStackEntTrue(&val1);
- Bytecode_int_StackPush(Stack, &val2);
- Bytecode_int_DerefStackValue(&val1);
- break;
-
- case BC_OP_BITNOT:
- 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("%s\n", opstr);
-
- GET_STACKVAL(val1);
- pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
- Bytecode_int_DerefStackValue(&val1);
-
- ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1);
- if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
- Bytecode_int_SetSpiderValue(&val1, ret_val);
- if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
- Bytecode_int_StackPush(Stack, &val1);
-
- break;
-
- // Binary Operations
- case BC_OP_LOGICAND:
- if(!ast_op) ast_op = NODETYPE_LOGICALAND, opstr = "LOGICAND";
- case BC_OP_LOGICOR:
- if(!ast_op) ast_op = NODETYPE_LOGICALOR, opstr = "LOGICOR";
- case BC_OP_LOGICXOR:
- if(!ast_op) ast_op = NODETYPE_LOGICALXOR, opstr = "LOGICXOR";
-
- STATE_HDR();
- DEBUG_F("%s\n", opstr);
-
- GET_STACKVAL(val1);
- GET_STACKVAL(val2);
-
- switch(op->Operation)
- {
- case BC_OP_LOGICAND:
- i = Bytecode_int_IsStackEntTrue(&val1) && Bytecode_int_IsStackEntTrue(&val2);
- break;
- case BC_OP_LOGICOR:
- i = Bytecode_int_IsStackEntTrue(&val1) || Bytecode_int_IsStackEntTrue(&val2);
- break;
- case BC_OP_LOGICXOR:
- i = Bytecode_int_IsStackEntTrue(&val1) ^ Bytecode_int_IsStackEntTrue(&val2);
- break;
- }
- Bytecode_int_DerefStackValue(&val1);
- Bytecode_int_DerefStackValue(&val2);
-
- val1.Type = SS_DATATYPE_INTEGER;
- val1.Integer = i;
- Bytecode_int_StackPush(Stack, &val1);
- break;
-
- case BC_OP_BITAND:
- if(!ast_op) ast_op = NODETYPE_BWAND, opstr = "BITAND";
- case BC_OP_BITOR:
- if(!ast_op) ast_op = NODETYPE_BWOR, opstr = "BITOR";
- case BC_OP_BITXOR:
- if(!ast_op) ast_op = NODETYPE_BWXOR, opstr = "BITXOR";
-
- case BC_OP_BITSHIFTLEFT:
- if(!ast_op) ast_op = NODETYPE_BITSHIFTLEFT, opstr = "BITSHIFTLEFT";
- case BC_OP_BITSHIFTRIGHT:
- if(!ast_op) ast_op = NODETYPE_BITSHIFTRIGHT, opstr = "BITSHIFTRIGHT";
- case BC_OP_BITROTATELEFT:
- if(!ast_op) ast_op = NODETYPE_BITROTATELEFT, opstr = "BITROTATELEFT";
-
- case BC_OP_ADD:
- if(!ast_op) ast_op = NODETYPE_ADD, opstr = "ADD";
- case BC_OP_SUBTRACT:
- if(!ast_op) ast_op = NODETYPE_SUBTRACT, opstr = "SUBTRACT";
- case BC_OP_MULTIPLY:
- if(!ast_op) ast_op = NODETYPE_MULTIPLY, opstr = "MULTIPLY";
- case BC_OP_DIVIDE:
- if(!ast_op) ast_op = NODETYPE_DIVIDE, opstr = "DIVIDE";
- case BC_OP_MODULO:
- if(!ast_op) ast_op = NODETYPE_MODULO, opstr = "MODULO";
-
- 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:
- if(!ast_op) ast_op = NODETYPE_LESSTHANEQUAL, opstr = "LESSTHANOREQUAL";
- case BC_OP_GREATERTHAN:
- if(!ast_op) ast_op = NODETYPE_GREATERTHAN, opstr = "GREATERTHAN";
- case BC_OP_GREATERTHANOREQUAL:
- if(!ast_op) ast_op = NODETYPE_GREATERTHANEQUAL, opstr = "GREATERTHANOREQUAL";
-
- STATE_HDR();
- DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
-
- GET_STACKVAL(val2); // Right
- GET_STACKVAL(val1); // Left
-
- DEBUG_F(" ("); PRINT_STACKVAL(val1); DEBUG_F(")");
- DEBUG_F(" ("); PRINT_STACKVAL(val2); DEBUG_F(")\n");
-
- // Perform integer operations locally
- if( val1.Type == SS_DATATYPE_INTEGER && val2.Type == SS_DATATYPE_INTEGER )
- {
- if( Bytecode_int_LocalBinOp_Integer(op->Operation, &val1, &val2) ) {
- nextop = NULL;
- break;
- }
- PUT_STACKVAL(val1);
- break;
- }
-
- if(val1. Type == SS_DATATYPE_REAL && val2.Type == SS_DATATYPE_REAL )
- {
- if( Bytecode_int_LocalBinOp_Real(op->Operation, &val1, &val2) ) {
- nextop = NULL;
- break;
- }
- PUT_STACKVAL(val1);
- break;
- }
-
- pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
- pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
- Bytecode_int_DerefStackValue(&val1);
- Bytecode_int_DerefStackValue(&val2);
-
- // Hand to AST execution code
- ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
- if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
- if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2);
-
- if(ret_val == ERRPTR) {
- AST_RuntimeError(NULL, "_BinOp returned ERRPTR");
- nextop = NULL;
- break;
- }
- Bytecode_int_SetSpiderValue(&val1, ret_val);
- if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
- PUT_STACKVAL(val1);
- break;
-
- // Functions etc
- case BC_OP_CREATEOBJ:
- case BC_OP_CALLFUNCTION:
- case BC_OP_CALLMETHOD:
- STATE_HDR();
-
- if( op->Operation == BC_OP_CALLFUNCTION )
- {
- tScript_Function *fcn = NULL;
- const char *name = OP_STRING(op);
- int arg_count = OP_INDX(op);
- DEBUG_F("CALL (local) %s %i args\n", name, arg_count);
- // Check current script functions (for fast call)
- for(fcn = Script->Functions; fcn; fcn = fcn->Next)
- {
- if(strcmp(name, fcn->Name) == 0) {
- break;
- }
- }
- if(fcn && fcn->BCFcn)
- {
- DEBUG_F(" - Fast call\n");
- Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
- break;
- }
- }
-
- // Slower call
- if( Bytecode_int_CallExternFunction( Script, Stack, default_namespace, op ) ) {
- nextop = NULL;
- break;
- }
- break;
-
- case BC_OP_RETURN:
- STATE_HDR();
-
- DEBUG_F("RETURN\n");
- nextop = NULL;
- break;
-
- default:
- // TODO:
- STATE_HDR();
- AST_RuntimeError(NULL, "Unknown operation %i\n", op->Operation);
- nextop = NULL;
- break;
- }
- op = nextop;
- }
-
- // Clean up
- // - Delete local vars
- for( i = 0; i < local_var_count; i ++ )
- {
- if( local_vars[i].Type != ET_NULL )
- {
- DEBUG_F("Var %i - ", i);
- PRINT_STACKVAL(local_vars[i]);
- Bytecode_int_DerefStackValue(&local_vars[i]);
- DEBUG_F("\n");
- }
- else
- DEBUG_F("Var %i - empty\n", i);
- }
-
- // - Restore stack
- if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START )
- Stack->EntryCount --;
- else
- {
- int n_rolled = 1;
- GET_STACKVAL(val1);
- while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
- {
- Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );
- n_rolled ++;
- }
- PUT_STACKVAL(val1);
- DEBUG_F("Rolled back %i entries\n", n_rolled);
- }
-
-
- return 0;
-}
-
+++ /dev/null
-/*
- * Acess2 - SpiderScript
- * - Script Exports (Lang. Namespace)
- */
-#define _GNU_SOURCE // HACK!
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <spiderscript.h>
-
-// === PROTOTYPES ===
-tSpiderValue *Exports_sizeof(tSpiderScript *Script, int NArgs, tSpiderValue **Args);
-tSpiderValue *Exports_array(tSpiderScript *Script, int NArgs, tSpiderValue **Args);
-tSpiderValue *Exports_Lang_Strings_Split(tSpiderScript *Script, int NArgs, tSpiderValue **Args);
-tSpiderValue *Exports_Lang_Struct(tSpiderScript *Script, int NArgs, tSpiderValue **Args);
-
-// === GLOBALS ===
-tSpiderFunction gExports_Lang_Strings_Split = {
- .Name = "Split",
- .Handler = Exports_Lang_Strings_Split,
- .ReturnType = SS_MAKEARRAY(SS_DATATYPE_STRING),
- .ArgTypes = {SS_DATATYPE_STRING, SS_DATATYPE_STRING, -1}
-};
-tSpiderNamespace gExports_NS_Lang_Strings = {
- .Name = "Strings",
- .Functions = &gExports_Lang_Strings_Split
- };
-
-tSpiderFunction gExports_Lang_Struct = {
- .Name = "Struct",
- .Handler = Exports_Lang_Struct,
- .ReturnType = SS_DATATYPE_OPAQUE,
- .ArgTypes = {SS_DATATYPE_STRING, -1}
-};
-// - Lang Namespace
-tSpiderNamespace gExports_NS_Lang = {
- .Name = "Lang",
- .Functions = &gExports_Lang_Struct,
- .FirstChild = &gExports_NS_Lang_Strings
- };
-tSpiderNamespace gExportNamespaceRoot = {
- .FirstChild = &gExports_NS_Lang
-};
-
-// -- Global Functions
-tSpiderFunction gExports_array = {
- .Next = NULL,
- .Name = "array",
- .Handler = Exports_array,
- .ReturnType = SS_DATATYPE_DYNAMIC,
- .ArgTypes = {SS_DATATYPE_INTEGER, -1}
-};
-tSpiderFunction gExports_sizeof = {
- .Next = &gExports_array,
- .Name = "sizeof",
- .Handler = Exports_sizeof,
- .ReturnType = SS_DATATYPE_INTEGER,
- .ArgTypes = {SS_DATATYPE_UNDEF, -1}
-};
-tSpiderFunction *gpExports_First = &gExports_sizeof;
-
-// === CODE ===
-tSpiderValue *Exports_sizeof(tSpiderScript *Script, int NArgs, tSpiderValue **Args)
-{
- if(NArgs != 1 || !Args[0]) return NULL;
-
- switch( Args[0]->Type )
- {
- case SS_DATATYPE_STRING:
- return SpiderScript_CreateInteger(Args[0]->String.Length);
- case SS_DATATYPE_ARRAY:
- return SpiderScript_CreateInteger(Args[0]->Array.Length);
- default:
- return NULL;
- }
-}
-
-tSpiderValue *Exports_array(tSpiderScript *Script, int NArgs, tSpiderValue **Args)
-{
- if(NArgs != 2) return ERRPTR;
- if(!Args[0] || !Args[1]) return ERRPTR;
-
- if(Args[0]->Type != SS_DATATYPE_INTEGER || Args[1]->Type != SS_DATATYPE_INTEGER)
- return ERRPTR;
-
- int type = Args[1]->Integer;
- int size = Args[0]->Integer;
-
- if( type != SS_DATATYPE_ARRAY )
- {
- if( !SS_GETARRAYDEPTH(type) ) {
- // ERROR - This should never happen
- return ERRPTR;
- }
- type = SS_DOWNARRAY(type);
- }
-
- return SpiderScript_CreateArray(type, size);
-}
-
-tSpiderValue *Exports_Lang_Strings_Split(tSpiderScript *Script, int NArgs, tSpiderValue **Args)
-{
- int len, ofs, slen;
- void *haystack, *end;
- int nSubStrs = 0;
- tSpiderValue **strings = NULL;
- tSpiderValue *ret;
-
- // Error checking
- if( NArgs != 2 )
- return ERRPTR;
- if( !Args[0] || !Args[1] )
- return ERRPTR;
- if( Args[0]->Type != SS_DATATYPE_STRING )
- return ERRPTR;
- if( Args[1]->Type != SS_DATATYPE_STRING )
- return ERRPTR;
-
- // Split the string
- len = Args[0]->String.Length;
- haystack = Args[0]->String.Data;
- ofs = 0;
- do {
- end = memmem(haystack + ofs, len - ofs, Args[1]->String.Data, Args[1]->String.Length);
- if( end )
- slen = end - (haystack + ofs);
- else
- slen = len - ofs;
-
- strings = realloc(strings, (nSubStrs+1)*sizeof(tSpiderValue*));
- strings[nSubStrs] = SpiderScript_CreateString(slen, haystack + ofs);
- nSubStrs ++;
-
- ofs += slen + Args[1]->String.Length;
- } while(end);
-
- // Create output array
- ret = SpiderScript_CreateArray(SS_DATATYPE_STRING, nSubStrs);
- memcpy(ret->Array.Items, strings, nSubStrs*sizeof(tSpiderValue*));
- free(strings);
-
- return ret;
-}
-
-tSpiderValue *Exports_Lang_Struct(tSpiderScript *Script, int NArgs, tSpiderValue **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;
-}
+++ /dev/null
-/*
- * SpiderScript
- * - Script Lexer
- */
-#include "tokens.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#define DEBUG 0
-
-#define ARRAY_SIZE(x) ((sizeof(x))/(sizeof((x)[0])))
-
-// === PROTOTYPES ===
- int is_ident(char ch);
- int isdigit(int ch);
- int isspace(int ch);
- int GetToken(tParser *File);
-
-// === CONSTANTS ===
-const struct {
- const int Value;
- const char *Name;
-} csaReservedWords[] = {
- {TOK_RWD_FUNCTION, "function"},
-
- {TOK_RWD_RETURN, "return"},
- {TOK_RWD_BREAK, "break"},
- {TOK_RWD_CONTINUE, "continue"},
- {TOK_RWD_NEW, "new"},
-
- {TOK_RWD_IF, "if"},
- {TOK_RWD_ELSE, "else"},
- {TOK_RWD_DO, "do"},
- {TOK_RWD_WHILE, "while"},
- {TOK_RWD_FOR, "for"},
-
- {TOK_RWD_NULL, "null"},
- {TOK_RWD_VOID, "void"},
- {TOK_RWD_OBJECT, "Object"},
- {TOK_RWD_OPAQUE, "Opaque"},
- {TOK_RWD_INTEGER, "Integer"},
- {TOK_RWD_REAL, "Real"},
- {TOK_RWD_STRING, "String"}
-};
-
-// === CODE ===
-/**
- * \brief Read a token from a buffer
- * \param File Parser state
- */
-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 == '#' ) {
- while( *File->CurPos && *File->CurPos != '\n' )
- File->CurPos ++;
- continue ;
- }
-
- // C-Style Line Comments
- if( *File->CurPos == '/' && File->CurPos[1] == '/' ) {
- while( *File->CurPos && *File->CurPos != '\n' )
- File->CurPos ++;
- continue ;
- }
-
- // C-Style Block Comments
- if( *File->CurPos == '/' && File->CurPos[1] == '*' ) {
- 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 ;
- }
-
- // No more "whitespace"
- break;
- }
-
- // Save previous tokens (speeds up PutBack and LookAhead)
- 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 '^':
- if( *File->CurPos == '^' ) {
- File->CurPos ++;
- ret = TOK_LOGICXOR;
- break;
- }
- ret = TOK_XOR;
- break;
-
- case '|':
- if( *File->CurPos == '|' ) {
- File->CurPos ++;
- ret = TOK_LOGICOR;
- break;
- }
- ret = TOK_OR;
- break;
-
- case '&':
- if( *File->CurPos == '&' ) {
- File->CurPos ++;
- ret = TOK_LOGICAND;
- break;
- }
- ret = TOK_AND;
- break;
-
- case '/':
- if( *File->CurPos == '=' ) {
- File->CurPos ++;
- ret = TOK_ASSIGN_DIV;
- break;
- }
- ret = TOK_DIV;
- break;
- case '*':
- if( *File->CurPos == '=' ) {
- File->CurPos ++;
- ret = TOK_ASSIGN_MUL;
- break;
- }
- ret = TOK_MUL;
- break;
- case '+':
- if( *File->CurPos == '+' ) {
- File->CurPos ++;
- ret = TOK_INCREMENT;
- break;
- }
- if( *File->CurPos == '=' ) {
- File->CurPos ++;
- ret = TOK_ASSIGN_PLUS;
- break;
- }
- ret = TOK_PLUS;
- break;
- case '-':
- if( *File->CurPos == '-' ) {
- File->CurPos ++;
- ret = TOK_DECREMENT;
- break;
- }
- if( *File->CurPos == '=' ) {
- File->CurPos ++;
- ret = TOK_ASSIGN_MINUS;
- break;
- }
- if( *File->CurPos == '>' ) {
- File->CurPos ++;
- ret = TOK_ELEMENT;
- break;
- }
- ret = TOK_MINUS;
- break;
-
- // Strings
- case '"':
- while( *File->CurPos && !(*File->CurPos == '"' && *File->CurPos != '\\') )
- File->CurPos ++;
- if( *File->CurPos )
- {
- File->CurPos ++;
- ret = TOK_STR;
- }
- else
- ret = TOK_EOF;
- break;
-
- // Brackets
- case '(': ret = TOK_PAREN_OPEN; break;
- case ')': ret = TOK_PAREN_CLOSE; break;
- case '{': ret = TOK_BRACE_OPEN; break;
- case '}': ret = TOK_BRACE_CLOSE; break;
- case '[': ret = TOK_SQUARE_OPEN; break;
- case ']': ret = TOK_SQUARE_CLOSE; break;
-
- // Core symbols
- case ';': ret = TOK_SEMICOLON; break;
- case ',': ret = TOK_COMMA; break;
- #if USE_SCOPE_CHAR
- case '.': ret = TOK_SCOPE; break;
- #endif
-
- // Equals
- case '=':
- // Comparison Equals
- if( *File->CurPos == '=' ) {
- File->CurPos ++;
- ret = TOK_EQUALS;
- break;
- }
- // Assignment Equals
- ret = TOK_ASSIGN;
- break;
-
- // Less-Than
- case '<':
- // Less-Than or Equal
- if( *File->CurPos == '=' ) {
- File->CurPos ++;
- ret = TOK_LTE;
- break;
- }
- ret = TOK_LT;
- break;
-
- // Greater-Than
- case '>':
- // Greater-Than or Equal
- if( *File->CurPos == '=' ) {
- File->CurPos ++;
- ret = TOK_GTE;
- break;
- }
- ret = TOK_GT;
- break;
-
- // Logical NOT
- case '!':
- if( *File->CurPos == '=' ) {
- File->CurPos ++;
- ret = TOK_NOTEQUALS;
- break;
- }
- ret = TOK_LOGICNOT;
- break;
- // Bitwise NOT
- case '~':
- ret = TOK_BWNOT;
- break;
-
- // Variables
- // \$[0-9]+ or \$[_a-zA-Z][_a-zA-Z0-9]*
- case '$':
- // Numeric Variable
- if( isdigit( *File->CurPos ) ) {
- while( isdigit(*File->CurPos) )
- File->CurPos ++;
- }
- // Ident Variable
- else {
- while( is_ident(*File->CurPos) || isdigit(*File->CurPos) )
- File->CurPos ++;
- }
- ret = TOK_VARIABLE;
- break;
-
- // Default (Numbers and Identifiers)
- default:
- File->CurPos --;
-
- // Numbers
- if( isdigit(*File->CurPos) )
- {
- ret = TOK_INTEGER;
- if( *File->CurPos == '0' && File->CurPos[1] == 'x' )
- {
- File->CurPos += 2;
- while(('0' <= *File->CurPos && *File->CurPos <= '9')
- || ('A' <= *File->CurPos && *File->CurPos <= 'F')
- || ('a' <= *File->CurPos && *File->CurPos <= 'f') )
- {
- File->CurPos ++;
- }
- }
- else
- {
- while( isdigit(*File->CurPos) )
- File->CurPos ++;
-
-// printf("*File->CurPos = '%c'\n", *File->CurPos);
-
- // Decimal
- if( *File->CurPos == '.' )
- {
- ret = TOK_REAL;
- File->CurPos ++;
- while( isdigit(*File->CurPos) )
- File->CurPos ++;
- }
- // Exponent
- if( *File->CurPos == 'e' || *File->CurPos == 'E' )
- {
- ret = TOK_REAL;
- File->CurPos ++;
- if(*File->CurPos == '-' || *File->CurPos == '+')
- File->CurPos ++;
- while( isdigit(*File->CurPos) )
- File->CurPos ++;
- }
-
-// printf(" ret = %i\n", ret);
- }
- break;
- }
-
- // Identifier
- if( is_ident(*File->CurPos) )
- {
- ret = TOK_IDENT;
-
- // Identifier
- 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;
-
- // 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
- File->Token = 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;
-}
-
-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;
- File->CurPos = File->NextTokenStr;
- // Invalidate
- File->LastToken = -1;
-}
-
-int LookAhead(tParser *File)
-{
- // TODO: Should I save the entire state here?
- int ret = GetToken(File);
- PutBack(File);
- return ret;
-}
-
-// --- Helpers ---
-/**
- * \brief Check for ident characters
- * \note Matches Regex [a-zA-Z_]
- */
-int is_ident(char ch)
-{
- if('a' <= 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(int ch)
-{
- if('0' <= ch && ch <= '9') return 1;
- return 0;
-}
-
-int isspace(int ch)
-{
- if(' ' == ch) return 1;
- if('\t' == ch) return 1;
- if('\b' == ch) return 1;
- if('\n' == ch) return 1;
- if('\r' == ch) return 1;
- return 0;
-}
+++ /dev/null
-/*
- * Acess2 - SpiderScript
- * Interpreter Library
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <spiderscript.h>
-#include "common.h"
-#include "ast.h"
-#include "bytecode_gen.h"
-
-// === IMPORTS ===
-extern int Parse_Buffer(tSpiderScript *Script, const char *Buffer, const char *Filename);
-extern tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
-extern void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value);
-extern void Variable_Destroy(tAST_Variable *Variable);
-
-// === CODE ===
-/**
- * \brief Library Entry Point
- */
-int SoMain()
-{
- return 0;
-}
-
-/**
- * \brief Parse a script
- */
-tSpiderScript *SpiderScript_ParseFile(tSpiderVariant *Variant, const char *Filename)
-{
- char *data;
- int fLen;
- FILE *fp;
- tSpiderScript *ret;
-
- fp = fopen(Filename, "r");
- if( !fp ) {
- return NULL;
- }
-
- fseek(fp, 0, SEEK_END);
- fLen = ftell(fp);
- fseek(fp, 0, SEEK_SET);
-
- // Allocate and read data
- data = malloc(fLen + 1);
- if(!data) return NULL;
- fLen = fread(data, 1, fLen, fp);
- fclose(fp);
- if( fLen < 0 ) {
- free(data);
- return NULL;
- }
- data[fLen] = '\0';
-
-
- // Create the script
- ret = malloc(sizeof(tSpiderScript));
- ret->Variant = Variant;
- ret->Functions = NULL;
- ret->LastFunction = NULL;
-
- ret->CurNamespace = NULL;
- if( Parse_Buffer(ret, data, Filename) ) {
- free(data);
- free(ret);
- return NULL;
- }
-
- free(data);
-
-
- // HACK!!
- #if 1
- // - Save AST to a file
- {
- char cacheFilename[strlen(Filename)+6+1];
- strcpy(cacheFilename, Filename);
- strcat(cacheFilename, ".ast");
-
- SpiderScript_SaveAST(ret, cacheFilename);
- }
- #endif
- // - Save Bytecode too
- {
- char cacheFilename[strlen(Filename)+6+1];
- strcpy(cacheFilename, Filename);
- strcat(cacheFilename, ".bc");
-
- SpiderScript_SaveBytecode(ret, cacheFilename);
- }
-
- return ret;
-}
-
-int SpiderScript_SaveAST(tSpiderScript *Script, const char *Filename)
-{
- size_t size;
- FILE *fp;
- void *data;
-
- size = AST_WriteScript(NULL, Script);
-
- fp = fopen(Filename, "wb");
- if(!fp) return 1;
-
- data = malloc(size);
- if(!data) {
- fclose(fp);
- return -1;
- }
-
- size = AST_WriteScript(data, Script);
- fwrite(data, size, 1, fp);
- free(data);
-
- fclose(fp);
- return 0;
-}
-
-/**
- * \brief Free a script
- */
-void SpiderScript_Free(tSpiderScript *Script)
-{
- tScript_Function *fcn = Script->Functions;
- tScript_Function *nextFcn;
-
- // Free functions
- while(fcn)
- {
- if(fcn->ASTFcn) AST_FreeNode( fcn->ASTFcn );
- if(fcn->BCFcn) Bytecode_DeleteFunction( fcn->BCFcn );
-
- nextFcn = fcn->Next;
- free( fcn );
- fcn = nextFcn;
- }
-
- free(Script);
-}
+++ /dev/null
-/*
- * Acess2 - SpiderScript
- * - Parser
- */
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <spiderscript.h>
-#define WANT_TOKEN_STRINGS 1
-#include "tokens.h"
-#include "ast.h"
-#include "common.h"
-
-#define DEBUG 0
-#define SUPPORT_BREAK_TAGS 1
-
-// === PROTOTYPES ===
- int Parse_Buffer(tSpiderScript *Script, const char *Buffer, const char *Filename);
-void *Parse_FunctionDefinition(tSpiderScript *Script, tParser *Parser, int Type);
-tAST_Node *Parse_DoCodeBlock(tParser *Parser, tAST_Node *CodeNode);
-tAST_Node *Parse_DoBlockLine(tParser *Parser, tAST_Node *CodeNode);
-tAST_Node *Parse_VarDefList(tParser *Parser, tAST_Node *CodeNode, int Type);
-tAST_Node *Parse_GetVarDef(tParser *Parser, int Type);
-
-tAST_Node *Parse_DoExpr0(tParser *Parser); // Assignment
-tAST_Node *Parse_DoExpr1(tParser *Parser); // Boolean Operators
-tAST_Node *Parse_DoExpr2(tParser *Parser); // Comparison Operators
-tAST_Node *Parse_DoExpr3(tParser *Parser); // Bitwise Operators
-tAST_Node *Parse_DoExpr4(tParser *Parser); // Bit Shifts
-tAST_Node *Parse_DoExpr5(tParser *Parser); // Arithmatic
-tAST_Node *Parse_DoExpr6(tParser *Parser); // Mult & Div
-tAST_Node *Parse_DoExpr7(tParser *Parser); // Right Unary Operations
-tAST_Node *Parse_DoExpr8(tParser *Parser); // Left Unary Operations
-
-tAST_Node *Parse_DoParen(tParser *Parser); // Parenthesis (Always Last)
-tAST_Node *Parse_DoValue(tParser *Parser); // Values
-
-tAST_Node *Parse_GetString(tParser *Parser);
-tAST_Node *Parse_GetNumeric(tParser *Parser);
-tAST_Node *Parse_GetVariable(tParser *Parser);
-tAST_Node *Parse_GetIdent(tParser *Parser, int bObjectCreate);
-
-void SyntaxAssert(tParser *Parser, int Have, int Want);
-void SyntaxError(tParser *Parser, int bFatal, const char *Message, ...);
-
-#if 0
-#define SyntaxAssert(_parser, _have, _want) SyntaxAssertV(_parser, _have, _want, NULL)
-#define SyntaxAssertV(_parser, _have, _want, _rv) do { \
- int have = (_have), want = (_want); \
- if( (have) != (want) ) { \
- SyntaxError(Parser, 1, "Unexpected %s(%i), expecting %s(%i)\n", \
- csaTOKEN_NAMES[have], have, csaTOKEN_NAMES[want], want); \
- return _rv; \
- } \
-}while(0)
-#endif
-
-#define TODO(Parser, message...) do {\
- fprintf(stderr, "TODO: "message);\
- longjmp(Parser->JmpTarget, -1);\
-}while(0)
-
-// === CODE ===
-/**
- * \brief Parse a buffer into a syntax tree
- */
-int Parse_Buffer(tSpiderScript *Script, const char *Buffer, const char *Filename)
-{
- tParser parser = {0};
- tParser *Parser = &parser; //< Keeps code consistent
- tAST_Node *mainCode, *node;
- int type;
- tScript_Function *fcn;
-
- #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;
- // hackery to do reference counting
- parser.Filename = malloc(sizeof(int)+strlen(Filename)+1);
- strcpy(parser.Filename + sizeof(int), Filename);
- *(int*)(parser.Filename) = 0; // Set reference count
- parser.Filename += sizeof(int); // Move filename
- parser.ErrorHit = 0;
- parser.Variant = Script->Variant;
-
- mainCode = AST_NewCodeBlock(&parser);
-
- // Give us an error fallback
- if( setjmp( parser.JmpTarget ) != 0 )
- {
- AST_FreeNode( mainCode );
-
- for(fcn = Script->Functions; fcn; )
- {
- tScript_Function *nextFcn;
-
- AST_FreeNode( fcn->ASTFcn );
-
- nextFcn = fcn->Next;
- free( fcn );
- fcn = nextFcn;
- }
- return -1;
- }
-
- // Parse the file!
- while(Parser->Token != TOK_EOF)
- {
- switch( GetToken(Parser) )
- {
- case TOK_EOF:
- break;
-
- // Typed variables/functions
- case TOKEN_GROUP_TYPES:
- TOKEN_GET_DATATYPE(type, Parser->Token);
-
- switch(LookAhead(Parser))
- {
- // Define a function (pass on to the other function definition code)
- case TOK_IDENT:
- if( Parse_FunctionDefinition(Script, Parser, type) == NULL )
- longjmp(Parser->JmpTarget, -1);
- break ;
- // Define a variable (pass back to _DoBlockLine)
- case TOK_VARIABLE:
- node = Parse_VarDefList(Parser, mainCode, type);
- AST_AppendNode(mainCode, node);
- SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
- break;
- default:
- SyntaxError(Parser, 1, "Unexpected %s, expected TOK_IDENT or TOK_VARIABLE\n",
- csaTOKEN_NAMES[Parser->Token]);
- break;
- }
- break;
-
- // Define a function
- case TOK_RWD_FUNCTION:
- if( !Script->Variant->bDyamicTyped ) {
- SyntaxError(Parser, 1, "Dynamic functions are invalid in static mode");
- longjmp(Parser->JmpTarget, -1);
- }
-
- type = SS_DATATYPE_DYNAMIC;
-
- if( Parse_FunctionDefinition(Script, Parser, SS_DATATYPE_DYNAMIC) == NULL )
- longjmp(Parser->JmpTarget, -1);
-
- break;
-
- // Ordinary Statement
- default:
- PutBack(Parser);
- node = Parse_DoBlockLine(Parser, mainCode);
- if(!node) longjmp(Parser->JmpTarget, -1);
- AST_AppendNode( mainCode, node );
- break;
- }
-
- // Jump to error handler on error
- if(Parser->ErrorHit)
- longjmp(Parser->JmpTarget, -1);
- }
-
- AST_AppendFunction( Script, "", SS_DATATYPE_INTEGER, NULL, mainCode );
-
- //printf("---- %p parsed as SpiderScript ----\n", Buffer);
-
- return 0;
-}
-
-void *Parse_FunctionDefinition(tSpiderScript *Script, tParser *Parser, int Type)
-{
- char *name;
- int rv;
- tAST_Node *first_arg, *last_arg, *code;
-
- last_arg = (void*)&first_arg; // HACK
-
- SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
-
- name = strndup( Parser->TokenStr, Parser->TokenLen );
- #if DEBUG
- printf("DefFCN %s\n", name);
- #endif
-
- // Get arguments
- SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN );
- if( LookAhead(Parser) != TOK_PAREN_CLOSE )
- {
- do {
- int type = SS_DATATYPE_DYNAMIC;
- GetToken(Parser);
- // Non dynamic typed variants must use data types
- if( !Script->Variant->bDyamicTyped ) {
- TOKEN_GET_DATATYPE(type, Parser->Token);
- GetToken(Parser);
- }
- last_arg->NextSibling = Parse_GetVarDef(Parser, type);
- last_arg = last_arg->NextSibling;
- last_arg->NextSibling = NULL;
- } while(GetToken(Parser) == TOK_COMMA);
- }
- else
- GetToken(Parser);
- SyntaxAssert(Parser, Parser->Token, TOK_PAREN_CLOSE );
-
- code = Parse_DoCodeBlock(Parser, NULL);
-
- rv = AST_AppendFunction( Script, name, Type, first_arg, code );
-
- // Clean up argument definition nodes
- {
- tAST_Node *nextarg;
- for( ; first_arg; first_arg = nextarg )
- {
- nextarg = first_arg->NextSibling;
- AST_FreeNode(first_arg);
- }
- }
-
- free(name);
-
- return rv == 0 ? (void*)1 : NULL;
-}
-
-/**
- * \brief Parse a block of code surrounded by { }
- */
-tAST_Node *Parse_DoCodeBlock(tParser *Parser, tAST_Node *CodeNode)
-{
- tAST_Node *ret;
-
- // Check if we are being called for a one-liner
- if( GetToken(Parser) != TOK_BRACE_OPEN ) {
- PutBack(Parser);
- return Parse_DoBlockLine(Parser, CodeNode);
- }
-
- ret = AST_NewCodeBlock(Parser);
-
- while( LookAhead(Parser) != TOK_BRACE_CLOSE )
- {
- tAST_Node *node = Parse_DoBlockLine(Parser, ret);
- if(!node) {
- AST_FreeNode(ret);
- return NULL;
- }
- AST_AppendNode( ret, node );
- }
- GetToken(Parser); // Omnomnom
- return ret;
-}
-
-/**
- * \brief Parse a line in a block
- */
-tAST_Node *Parse_DoBlockLine(tParser *Parser, tAST_Node *CodeNode)
-{
- tAST_Node *ret;
-
- //printf("Parse_DoBlockLine: Line %i\n", Parser->CurLine);
-
- switch(LookAhead(Parser))
- {
- // New block
- case TOK_BRACE_OPEN:
- return Parse_DoCodeBlock(Parser, CodeNode);
-
- // Empty statement
- case TOK_SEMICOLON:
- GetToken(Parser);
- return NULL;
-
- // Return from a method
- case TOK_RWD_RETURN:
- GetToken(Parser);
- ret = AST_NewUniOp(Parser, NODETYPE_RETURN, Parse_DoExpr0(Parser));
- break;
-
- // Break / Continue (end a loop / go to next iteration)
- case TOK_RWD_CONTINUE:
- case TOK_RWD_BREAK:
- {
- int tok;
- char *ident = NULL;
- tok = GetToken(Parser);
- // Get the number of nesting levels to break
- if(LookAhead(Parser) == TOK_IDENT)
- {
- GetToken(Parser);
- ident = strndup(Parser->TokenStr, Parser->TokenLen);
- }
- // Get the action
- switch(tok)
- {
- case TOK_RWD_BREAK: ret = AST_NewBreakout(Parser, NODETYPE_BREAK, ident); break;
- case TOK_RWD_CONTINUE: ret = AST_NewBreakout(Parser, NODETYPE_CONTINUE, ident); break;
- default:
- SyntaxError(Parser, 1, "BUG Unhandled break/continue (%s)",
- csaTOKEN_NAMES[tok]);
- return NULL;
- }
- if(ident) free(ident);
- }
- break;
-
- // Control Statements
- 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, CodeNode);
- if( LookAhead(Parser) == TOK_RWD_ELSE ) {
- GetToken(Parser);
- false = Parse_DoCodeBlock(Parser, CodeNode);
- }
- else
- false = AST_NewNop(Parser);
- ret = AST_NewIf(Parser, cond, true, false);
- }
- return ret;
-
- case TOK_RWD_FOR:
- {
- char *tag = NULL;
- tAST_Node *init=NULL, *cond=NULL, *inc=NULL, *code;
- GetToken(Parser); // Eat 'for'
-
- #if SUPPORT_BREAK_TAGS
- if(LookAhead(Parser) == TOK_LT)
- {
- GetToken(Parser);
- SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
- tag = strndup(Parser->TokenStr, Parser->TokenLen);
- SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
- }
- #endif
-
- SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN);
-
- if(LookAhead(Parser) != TOK_SEMICOLON)
- init = Parse_DoExpr0(Parser);
-
- SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
-
- if(LookAhead(Parser) != TOK_SEMICOLON)
- cond = Parse_DoExpr0(Parser);
-
- SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
-
- if(LookAhead(Parser) != TOK_PAREN_CLOSE)
- inc = Parse_DoExpr0(Parser);
-
- SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
-
- code = Parse_DoCodeBlock(Parser, CodeNode);
- ret = AST_NewLoop(Parser, tag, init, 0, cond, inc, code);
- if(tag) free(tag);
- }
- return ret;
-
- case TOK_RWD_DO:
- {
- const char *tag = "";
- tAST_Node *code, *cond;
- GetToken(Parser); // Eat 'do'
-
- #if SUPPORT_BREAK_TAGS
- if(LookAhead(Parser) == TOK_LT)
- {
- GetToken(Parser);
- SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
- tag = strndup(Parser->TokenStr, Parser->TokenLen);
- SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
- }
- #endif
-
- code = Parse_DoCodeBlock(Parser, CodeNode);
- SyntaxAssert( Parser, GetToken(Parser), TOK_RWD_WHILE );
- SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN );
- cond = Parse_DoExpr0(Parser);
- SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_CLOSE );
- ret = AST_NewLoop(Parser, tag, AST_NewNop(Parser), 1, cond, AST_NewNop(Parser), code);
- }
- break;
- case TOK_RWD_WHILE:
- {
- const char *tag = "";
- tAST_Node *code, *cond;
- GetToken(Parser); // Eat 'while'
-
- #if SUPPORT_BREAK_TAGS
- if(LookAhead(Parser) == TOK_LT)
- {
- GetToken(Parser);
- SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
- tag = strndup(Parser->TokenStr, Parser->TokenLen);
- SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
- }
- #endif
-
- SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN );
- cond = Parse_DoExpr0(Parser);
- SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_CLOSE );
- code = Parse_DoCodeBlock(Parser, CodeNode);
- ret = AST_NewLoop(Parser, tag, AST_NewNop(Parser), 0, cond, AST_NewNop(Parser), code);
- }
- return ret;
-
- // Define Variables
- case TOKEN_GROUP_TYPES:
- {
- int type;
- GetToken(Parser);
- TOKEN_GET_DATATYPE(type, Parser->Token);
- ret = Parse_VarDefList(Parser, CodeNode, type);
- }
- break;
-
- // Default
- default:
- //printf("exp0\n");
- ret = Parse_DoExpr0(Parser);
- break;
- }
-
- SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON );
- return ret;
-}
-
-tAST_Node *Parse_VarDefList(tParser *Parser, tAST_Node *CodeNode, int Type)
-{
- tAST_Node *ret;
-
- ret = NULL;
- do {
- if(ret) AST_AppendNode( CodeNode, ret );
- SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE);
-
- ret = Parse_GetVarDef(Parser, Type);
- if(!ret) longjmp(Parser->JmpTarget, -1);
- } while(GetToken(Parser) == TOK_COMMA);
- PutBack(Parser); // Semicolon is checked by caller
-
- return ret;
-}
-
-/**
- * \brief Get a variable definition
- */
-tAST_Node *Parse_GetVarDef(tParser *Parser, int Type)
-{
- char name[Parser->TokenLen];
- tAST_Node *ret;
- int level;
-
- 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(Parser, Type, name);
- // Handle arrays
- level = 0;
- if( LookAhead(Parser) == TOK_SQUARE_OPEN )
- {
- GetToken(Parser);
- if( LookAhead(Parser) != TOK_SQUARE_CLOSE )
- {
- ret->DefVar.InitialValue = AST_NewFunctionCall(Parser, "array");
- AST_AppendFunctionCallArg(ret->DefVar.InitialValue, Parse_DoExpr0(Parser));
- }
- SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
-
- level ++;
- }
- while( LookAhead(Parser) == TOK_SQUARE_OPEN )
- {
- GetToken(Parser);
- SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
- level ++;
- }
-
- // Maul the type to denote the dereference level
- if( Parser->Variant->bDyamicTyped ) {
- ret->DefVar.DataType = SS_DATATYPE_ARRAY;
- }
- else {
- ret->DefVar.DataType |= (level << 16);
- }
-
- // Initial value
- if( LookAhead(Parser) == TOK_ASSIGN )
- {
- if( ret->DefVar.InitialValue )
- {
- SyntaxError(Parser, 1, "Cannot assign and set array size at the same time");
- }
- GetToken(Parser);
- ret->DefVar.InitialValue = Parse_DoExpr0(Parser);
- if(!ret->DefVar.InitialValue) {
- AST_FreeNode(ret);
- return NULL;
- }
- }
- else if( ret->DefVar.InitialValue )
- {
- AST_AppendFunctionCallArg(ret->DefVar.InitialValue, AST_NewInteger(Parser, ret->DefVar.DataType));
- }
-
- return ret;
-}
-
-/**
- * \brief Assignment Operations
- */
-tAST_Node *Parse_DoExpr0(tParser *Parser)
-{
- #define _next Parse_DoExpr1
- tAST_Node *ret = _next(Parser);
- int cont = 1;
-
- while( cont )
- {
- // Check Assignment
- switch(GetToken(Parser))
- {
- case TOK_ASSIGN:
- ret = AST_NewAssign(Parser, NODETYPE_NOP, ret, _next(Parser));
- break;
- case TOK_ASSIGN_DIV:
- ret = AST_NewAssign(Parser, NODETYPE_DIVIDE, ret, _next(Parser));
- break;
- case TOK_ASSIGN_MUL:
- ret = AST_NewAssign(Parser, NODETYPE_MULTIPLY, ret, _next(Parser));
- break;
- case TOK_ASSIGN_PLUS:
- ret = AST_NewAssign(Parser, NODETYPE_ADD, ret, _next(Parser));
- break;
- case TOK_ASSIGN_MINUS:
- ret = AST_NewAssign(Parser, NODETYPE_SUBTRACT, ret, _next(Parser));
- break;
- default:
- #if DEBUG >= 2
- printf("Parse_DoExpr0: Parser->Token = %i\n", Parser->Token);
- #endif
- PutBack(Parser);
- cont = 0;
- break;
- }
- }
- return ret;
- #undef _next
-}
-
-/**
- * \brief Logical/Boolean Operators
- */
-tAST_Node *Parse_DoExpr1(tParser *Parser)
-{
- #define _next Parse_DoExpr2
- tAST_Node *ret = _next(Parser);
- int cont = 1;
-
- while( cont )
- {
- switch(GetToken(Parser))
- {
- case TOK_LOGICAND:
- ret = AST_NewBinOp(Parser, NODETYPE_LOGICALAND, ret, _next(Parser));
- break;
- case TOK_LOGICOR:
- ret = AST_NewBinOp(Parser, NODETYPE_LOGICALOR, ret, _next(Parser));
- break;
- case TOK_LOGICXOR:
- ret = AST_NewBinOp(Parser, NODETYPE_LOGICALXOR, ret, _next(Parser));
- break;
- default:
- PutBack(Parser);
- cont = 0;
- break;
- }
- }
- return ret;
- #undef _next
-}
-
-// --------------------
-// Expression 2 - Comparison Operators
-// --------------------
-tAST_Node *Parse_DoExpr2(tParser *Parser)
-{
- #define _next Parse_DoExpr3
- tAST_Node *ret = _next(Parser);
- int cont = 1;
-
- while( cont )
- {
- // Check token
- switch(GetToken(Parser))
- {
- 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;
- case TOK_GT:
- ret = AST_NewBinOp(Parser, NODETYPE_GREATERTHAN, ret, _next(Parser));
- break;
- case TOK_LTE:
- ret = AST_NewBinOp(Parser, NODETYPE_LESSTHANEQUAL, ret, _next(Parser));
- break;
- case TOK_GTE:
- ret = AST_NewBinOp(Parser, NODETYPE_GREATERTHANEQUAL, ret, _next(Parser));
- break;
- default:
- PutBack(Parser);
- cont = 0;
- break;
- }
- }
- return ret;
- #undef _next
-}
-
-/**
- * \brief Bitwise Operations
- */
-tAST_Node *Parse_DoExpr3(tParser *Parser)
-{
- #define _next Parse_DoExpr4
- tAST_Node *ret = _next(Parser);
- int cont = 1;
-
- while( cont )
- {
- // Check Token
- switch(GetToken(Parser))
- {
- case TOK_OR:
- ret = AST_NewBinOp(Parser, NODETYPE_BWOR, ret, _next(Parser));
- break;
- case TOK_AND:
- ret = AST_NewBinOp(Parser, NODETYPE_BWAND, ret, _next(Parser));
- break;
- case TOK_XOR:
- ret = AST_NewBinOp(Parser, NODETYPE_BWXOR, ret, _next(Parser));
- break;
- default:
- PutBack(Parser);
- cont = 0;
- break;
- }
- }
- return ret;
- #undef _next
-}
-
-// --------------------
-// Expression 4 - Shifts
-// --------------------
-tAST_Node *Parse_DoExpr4(tParser *Parser)
-{
- #define _next Parse_DoExpr5
- tAST_Node *ret = _next(Parser);
- int cont = 1;
-
- while( cont )
- {
- switch(GetToken(Parser))
- {
- case TOK_SHL:
- ret = AST_NewBinOp(Parser, NODETYPE_BITSHIFTLEFT, ret, _next(Parser));
- break;
- case TOK_SHR:
- ret = AST_NewBinOp(Parser, NODETYPE_BITSHIFTRIGHT, ret, _next(Parser));
- break;
- default:
- PutBack(Parser);
- cont = 0;
- break;
- }
- }
-
- return ret;
- #undef _next
-}
-
-// --------------------
-// Expression 5 - Arithmatic
-// --------------------
-tAST_Node *Parse_DoExpr5(tParser *Parser)
-{
- #define _next Parse_DoExpr6
- tAST_Node *ret = _next(Parser);
- int cont = 1;
-
- // While loop is added to ensure that the evaluation order ends up as
- // right to left.
- // E.g. a + b + c + d ends up as (((a + b) + c) + d) for casting
- while( cont )
- {
- switch(GetToken(Parser))
- {
- case TOK_PLUS:
- ret = AST_NewBinOp(Parser, NODETYPE_ADD, ret, _next(Parser));
- break;
- case TOK_MINUS:
- ret = AST_NewBinOp(Parser, NODETYPE_SUBTRACT, ret, _next(Parser));
- break;
- default:
- PutBack(Parser);
- cont = 0;
- break;
- }
- }
-
- return ret;
- #undef _next
-}
-
-// --------------------
-// Expression 6 - Multiplcation & Division
-// --------------------
-tAST_Node *Parse_DoExpr6(tParser *Parser)
-{
- #define _next Parse_DoExpr7
- tAST_Node *ret = _next(Parser);
- int cont = 1;
-
- while( cont )
- {
- switch(GetToken(Parser))
- {
- case TOK_MUL:
- ret = AST_NewBinOp(Parser, NODETYPE_MULTIPLY, ret, _next(Parser));
- break;
- case TOK_DIV:
- ret = AST_NewBinOp(Parser, NODETYPE_DIVIDE, ret, _next(Parser));
- break;
- default:
- PutBack(Parser);
- cont = 0;
- break;
- }
- }
-
- return ret;
- #undef _next
-}
-
-// --------------------
-// Expression 7 - Right Unary Operations
-// --------------------
-tAST_Node *Parse_DoExpr7(tParser *Parser)
-{
- tAST_Node *ret = Parse_DoExpr8(Parser);
-
- switch(GetToken(Parser))
- {
- case TOK_INCREMENT:
- ret = AST_NewUniOp(Parser, NODETYPE_POSTINC, ret);
- break;
- case TOK_DECREMENT:
- ret = AST_NewUniOp(Parser, NODETYPE_POSTDEC, ret);
- break;
- default:
- PutBack(Parser);
- break;
- }
- return ret;
-}
-
-// --------------------
-// Expression 8 - Left Unary Operations
-// --------------------
-tAST_Node *Parse_DoExpr8(tParser *Parser)
-{
- switch(GetToken(Parser))
- {
- case TOK_INCREMENT:
- return AST_NewAssign(Parser, NODETYPE_ADD, Parse_DoExpr8(Parser), AST_NewInteger(Parser, 1));
- case TOK_DECREMENT:
- return AST_NewAssign(Parser, NODETYPE_SUBTRACT, Parse_DoExpr8(Parser), AST_NewInteger(Parser, 1));
- case TOK_MINUS:
- return AST_NewUniOp(Parser, NODETYPE_NEGATE, Parse_DoExpr8(Parser));
- case TOK_LOGICNOT:
- return AST_NewUniOp(Parser, NODETYPE_LOGICALNOT, Parse_DoExpr8(Parser));
- case TOK_BWNOT:
- return AST_NewUniOp(Parser, NODETYPE_BWNOT, Parse_DoExpr8(Parser));
- default:
- PutBack(Parser);
- return Parse_DoParen(Parser);
- }
-}
-
-// --------------------
-// 2nd Last Expression - Parens
-// --------------------
-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;
- int type;
- GetToken(Parser);
-
- // TODO: Handle casts here
- switch(LookAhead(Parser))
- {
- case TOKEN_GROUP_TYPES:
- GetToken(Parser);
- TOKEN_GET_DATATYPE(type, Parser->Token);
- SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
- ret = AST_NewCast(Parser, type, Parse_DoParen(Parser));
- break;
- default:
- ret = Parse_DoExpr0(Parser);
- SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
- break;
- }
- return ret;
- }
- else
- return Parse_DoValue(Parser);
-}
-
-// --------------------
-// Last Expression - Value
-// --------------------
-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);
- case TOK_INTEGER:
- return Parse_GetNumeric(Parser);
-
- case TOK_REAL:
- GetToken(Parser);
- return AST_NewReal( Parser, atof(Parser->TokenStr) );
-
- case TOK_IDENT:
- return Parse_GetIdent(Parser, 0);
- case TOK_VARIABLE:
- return Parse_GetVariable(Parser);
- case TOK_RWD_NULL:
- GetToken(Parser);
- return AST_NewNull(Parser); // nODETYPE_NOP returns NULL
- case TOK_RWD_NEW:
- GetToken(Parser);
- return Parse_GetIdent(Parser, 1);
-
- default:
- fprintf(stderr, "Syntax Error: Unexpected %s on line %i, Expected TOK_T_VALUE\n",
- csaTOKEN_NAMES[tok], Parser->CurLine);
- longjmp( Parser->JmpTarget, -1 );
- }
-}
-
-/**
- * \brief Get a string
- */
-tAST_Node *Parse_GetString(tParser *Parser)
-{
- tAST_Node *ret;
- int i, j;
- GetToken( Parser );
-
- {
- char data[ Parser->TokenLen - 2 ];
- j = 0;
-
- for( i = 1; i < Parser->TokenLen - 1; i++ )
- {
- if( Parser->TokenStr[i] == '\\' ) {
- i ++;
- switch( Parser->TokenStr[i] )
- {
- case 'n': data[j++] = '\n'; break;
- case 'r': data[j++] = '\r'; break;
- default:
- // TODO: Octal Codes
- // TODO: Error/Warning?
- break;
- }
- }
- else {
- data[j++] = Parser->TokenStr[i];
- }
- }
-
- // TODO: Parse Escape Codes
- ret = AST_NewString( Parser, data, j );
- }
- return ret;
-}
-
-/**
- * \brief Get a numeric value
- */
-tAST_Node *Parse_GetNumeric(tParser *Parser)
-{
- uint64_t value = 0;
- const char *pos;
- SyntaxAssert( Parser, GetToken( Parser ), TOK_INTEGER );
- pos = Parser->TokenStr;
- //printf("pos = %p, *pos = %c\n", pos, *pos);
-
- if( *pos == '0' )
- {
- pos ++;
- if(*pos == 'x') {
- pos ++;
- for( ;; pos++)
- {
- value *= 16;
- if( '0' <= *pos && *pos <= '9' ) {
- value += *pos - '0';
- continue;
- }
- if( 'A' <= *pos && *pos <= 'F' ) {
- value += *pos - 'A' + 10;
- continue;
- }
- if( 'a' <= *pos && *pos <= 'f' ) {
- value += *pos - 'a' + 10;
- continue;
- }
- break;
- }
- }
- else {
- while( '0' <= *pos && *pos <= '7' ) {
- value = value*8 + *pos - '0';
- pos ++;
- }
- }
- }
- else {
- while( '0' <= *pos && *pos <= '9' ) {
- value = value*10 + *pos - '0';
- pos ++;
- }
- }
-
- return AST_NewInteger( Parser, value );
-}
-
-/**
- * \brief Get a variable
- */
-tAST_Node *Parse_GetVariable(tParser *Parser)
-{
- tAST_Node *ret;
- 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( Parser, name );
- #if DEBUG >= 2
- printf("Parse_GetVariable: name = '%s'\n", name);
- #endif
- }
- for(;;)
- {
- GetToken(Parser);
- if( Parser->Token == TOK_SQUARE_OPEN )
- {
- ret = AST_NewBinOp(Parser, NODETYPE_INDEX, ret, Parse_DoExpr0(Parser));
- SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
- continue ;
- }
- if( Parser->Token == TOK_ELEMENT )
- {
- SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
- // Method Call
- if( LookAhead(Parser) == TOK_PAREN_OPEN )
- {
- char name[Parser->TokenLen+1];
- memcpy(name, Parser->TokenStr, Parser->TokenLen);
- name[Parser->TokenLen] = 0;
- ret = AST_NewMethodCall(Parser, ret, name);
- GetToken(Parser); // Eat the '('
- // Read arguments
- if( GetToken(Parser) != TOK_PAREN_CLOSE )
- {
- PutBack(Parser);
- do {
- AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
- } while(GetToken(Parser) == TOK_COMMA);
- SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
- }
-
- }
- // Attribute
- else
- {
- char name[Parser->TokenLen];
- memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
- name[Parser->TokenLen-1] = 0;
- ret = AST_NewClassElement(Parser, ret, name);
- }
- continue ;
- }
-
- break ;
- }
- PutBack(Parser);
- return ret;
-}
-
-/**
- * \brief Get an identifier (constant or function call)
- */
-tAST_Node *Parse_GetIdent(tParser *Parser, int bObjectCreate)
-{
- tAST_Node *ret = NULL;
- char *name;
- SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
- name = strndup( Parser->TokenStr, Parser->TokenLen );
-
- #if USE_SCOPE_CHAR
- if( GetToken(Parser) == TOK_SCOPE )
- {
- ret = AST_NewScopeDereference( Parser, name, Parse_GetIdent(Parser, bObjectCreate) );
- free(name);
- return ret;
- }
- PutBack(Parser);
- #endif
-
- if( GetToken(Parser) == TOK_PAREN_OPEN )
- {
- #if DEBUG >= 2
- printf("Parse_GetIdent: Calling '%s'\n", name);
- #endif
- // Function Call
- if( bObjectCreate )
- ret = AST_NewCreateObject( Parser, name );
- else
- ret = AST_NewFunctionCall( Parser, name );
- // Read arguments
- if( GetToken(Parser) != TOK_PAREN_CLOSE )
- {
- 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, Parser->Token, TOK_PAREN_CLOSE );
- #if DEBUG >= 2
- printf(" Parse_GetIdent: All arguments parsed\n");
- #endif
- }
- }
- else
- {
- // Runtime Constant / Variable (When implemented)
- #if DEBUG >= 2
- printf("Parse_GetIdent: Referencing '%s'\n", name);
- #endif
- PutBack(Parser);
- if( bObjectCreate ) // Void constructor (TODO: Should this be an error?)
- ret = AST_NewCreateObject( Parser, name );
- else
- ret = AST_NewConstant( Parser, name );
- }
-
- free(name);
- return ret;
-}
-
-
-void SyntaxError(tParser *Parser, int bFatal, const char *Message, ...)
-{
- va_list args;
- va_start(args, Message);
- fprintf(stderr, "%s:%i: error: ", Parser->Filename, Parser->CurLine);
- vfprintf(stderr, Message, args);
- fprintf(stderr, "\n");
- va_end(args);
-
- if( bFatal ) {
- //longjmp(Parser->JmpTarget, -1);
- Parser->ErrorHit = 1;
- }
-}
-
-void SyntaxAssert(tParser *Parser, int Have, int Want)
-{
- if( Have != Want )
- {
- SyntaxError(Parser, 1, "Unexpected %s(%i), expecting %s(%i)\n",
- csaTOKEN_NAMES[Have], Have, csaTOKEN_NAMES[Want], Want);
- }
-}
+++ /dev/null
-/*
- *
- */
-#ifndef _SPIDERSCRIPT_H_
-#define _SPIDERSCRIPT_H_
-
-#include <stdint.h>
-
-#define ERRPTR ((void*)((intptr_t)0-1))
-
-/**
- * \brief Opaque script handle
- */
-typedef struct sSpiderScript tSpiderScript;
-
-typedef struct sSpiderVariant tSpiderVariant;
-typedef struct sSpiderNamespace tSpiderNamespace;
-typedef struct sSpiderFunction tSpiderFunction;
-typedef struct sSpiderValue tSpiderValue;
-typedef struct sSpiderObjectDef tSpiderObjectDef;
-typedef struct sSpiderObject tSpiderObject;
-
-
-/**
- * \brief SpiderScript Variable Datatypes
- * \todo Expand the descriptions
- */
-enum eSpiderScript_DataTypes
-{
- /**
- * \brief Undefined data
- * \note Default type of an undefined dynamic variable
- */
- SS_DATATYPE_UNDEF,
- /**
- * \brief Dynamically typed variable
- * \note Used to dentote a non-fixed type for function parameters
- */
- SS_DATATYPE_DYNAMIC,
- /**
- * \brief Opaque Data Pointer
- *
- * Opaque data types are used for resource handles or for system buffers.
- */
- SS_DATATYPE_OPAQUE,
- /**
- * \brief Object reference
- *
- * A reference to a SpiderScript class instance. Can be accessed
- * using the -> operator.
- */
- SS_DATATYPE_OBJECT,
- /**
- * \brief Array data type (invalid when using static typing)
- */
- SS_DATATYPE_ARRAY,
- /**
- * \brief Integer datatype
- *
- * 64-bit integer
- */
- SS_DATATYPE_INTEGER,
- SS_DATATYPE_REAL, //!< Real Number (double)
- SS_DATATYPE_STRING, //!< String
- NUM_SS_DATATYPES
-};
-
-#define SS_MAKEARRAY(_type) ((_type) + 0x10000)
-#define SS_DOWNARRAY(_type) ((_type) - 0x10000)
-#define SS_GETARRAYDEPTH(_type) ((_type) >> 16)
-
-enum eSpiderValueOps
-{
- SS_VALUEOP_NOP,
-
- SS_VALUEOP_ADD,
- SS_VALUEOP_SUBTRACT,
- SS_VALUEOP_NEGATE,
- SS_VALUEOP_MULIPLY,
- SS_VALUEOP_DIVIDE,
- SS_VALUEOP_MODULO,
-
- SS_VALUEOP_BITNOT,
- SS_VALUEOP_BITAND,
- SS_VALUEOP_BITOR,
- SS_VALUEOP_BITXOR,
-
- SS_VALUEOP_SHIFTLEFT,
- SS_VALUEOP_SHIFTRIGHT,
- SS_VALUEOP_ROTATELEFT
-};
-
-/**
- * \brief Namespace definition
- */
-struct sSpiderNamespace
-{
- tSpiderNamespace *Next;
-
- tSpiderNamespace *FirstChild;
-
- tSpiderFunction *Functions;
-
- tSpiderObjectDef *Classes;
-
- int NConstants; //!< Number of constants
- tSpiderValue *Constants; //!< Number of constants
-
- const char Name[];
-};
-
-/**
- * \brief Variant of SpiderScript
- */
-struct sSpiderVariant
-{
- const char *Name; // Just for debug
-
- int bDyamicTyped; //!< Use dynamic typing
- int bImplicitCasts; //!< Allow implicit casts (casts to lefthand side)
-
- tSpiderFunction *Functions; //!< Functions (Linked List)
-
- int NConstants; //!< Number of constants
- tSpiderValue *Constants; //!< Number of constants
-
- tSpiderNamespace RootNamespace;
-};
-
-/**
- * \brief SpiderScript data object
- */
-struct sSpiderValue
-{
- enum eSpiderScript_DataTypes Type; //!< Variable type
- int ReferenceCount; //!< Reference count
-
- union {
- int64_t Integer; //!< Integer data
- double Real; //!< Real Number data
- /**
- * \brief String data
- */
- struct {
- int Length; //!< Length
- char Data[]; //!< Actual string (\a Length bytes)
- } String;
- /**
- * \brief Variable data
- */
- struct {
- int Length; //!< Length of the array
- tSpiderValue *Items[]; //!< Array elements (\a Length long)
- } Array;
-
- /**
- * \brief Opaque data
- */
- struct {
- void *Data; //!< Data (can be anywhere)
- void (*Destroy)(void *Data); //!< Called on GC
- } Opaque;
-
- /**
- * \brief Object Instance
- */
- tSpiderObject *Object;
- };
-};
-
-/**
- * \brief Object Definition
- *
- * Internal representation of an arbitary object.
- */
-struct sSpiderObjectDef
-{
- /**
- */
- struct sSpiderObjectDef *Next; //!< Internal linked list
- /**
- * \brief Object type name
- */
- const char * const Name;
- /**
- * \brief Construct an instance of the object
- * \param NArgs Number of arguments
- * \param Args Argument array
- * \return Pointer to an object instance (which must be fully valid)
- * \retval NULL Invalid parameter (usually, actually just a NULL value)
- * \retval ERRPTR Invalid parameter count
- */
- tSpiderObject *(*Constructor)(int NArgs, tSpiderValue **Args);
-
- /**
- * \brief Clean up and destroy the object
- * \param This Object instace
- * \note The object pointer (\a This) should be invalidated and freed
- * by this function.
- */
- void (*Destructor)(tSpiderObject *This);
-
-
- /**
- * \brief Get/Set an attribute's value
- */
- tSpiderValue *(*GetSetAttribute)(tSpiderObject *This, int AttibuteID, tSpiderValue *NewValue);
-
- /**
- * \brief Method Definitions (linked list)
- */
- tSpiderFunction *Methods;
-
- /**
- * \brief Number of attributes
- */
- int NAttributes;
-
- //! Attribute definitions
- struct {
- const char *Name; //!< Attribute Name
- int Type; //!< Datatype
- char bReadOnly; //!< Allow writes to the attribute?
- char bMethod; //!< IO Goes via GetSetAttribute function
- } AttributeDefs[];
-};
-
-/**
- * \brief Object Instance
- */
-struct sSpiderObject
-{
- tSpiderObjectDef *Type; //!< Object Type
- int ReferenceCount; //!< Number of references
- void *OpaqueData; //!< Pointer to the end of the \a Attributes array
- tSpiderValue *Attributes[]; //!< Attribute Array
-};
-
-/**
- * \brief Represents a function avaliable to a script
- */
-struct sSpiderFunction
-{
- /**
- * \brief Next function in list
- */
- struct sSpiderFunction *Next;
-
- /**
- * \brief Function name
- */
- const char *Name;
- /**
- * \brief Function handler
- */
- tSpiderValue *(*Handler)(tSpiderScript *Script, int nParams, tSpiderValue **Parameters);
-
- /**
- * \brief What type is returned
- */
- int ReturnType;
-
- /**
- * \brief Argument types
- *
- * Zero or -1 terminated array of \a eSpiderScript_DataTypes.
- * If the final entry is zero, the function has a fixed number of
- * parameters, if the final entry is -1, the function has a variable
- * number of arguments.
- */
- int ArgTypes[]; // Zero (or -1) terminated array of parameter types
-};
-
-
-// === FUNCTIONS ===
-/**
- * \brief Parse a file into a script
- * \param Variant Variant structure
- * \param Filename File to parse
- * \return Script suitable for execution
- */
-extern tSpiderScript *SpiderScript_ParseFile(tSpiderVariant *Variant, const char *Filename);
-/**
- * \brief Execute a function from a script
- * \param Script Script to run
- * \param Function Name of function to run ("" for the 'main')
- * \return Return value
- */
-extern tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
- const char *Function, const char *DefaultNamespaces[],
- int NArguments, tSpiderValue **Arguments,
- void **FunctionIdent
- );
-/**
- * \brief Execute an object method
- */
-extern tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
- tSpiderObject *Object, const char *MethodName,
- int NArguments, tSpiderValue **Arguments
- );
-/**
- * \brief Creates an object instance
- */
-extern tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
- const char *ClassName, const char *DefaultNamespaces[],
- int NArguments, tSpiderValue **Arguments
- );
-
-/**
- * \brief Convert a script to bytecode and save to a file
- */
-extern int SpiderScript_SaveBytecode(tSpiderScript *Script, const char *DestFile);
-/**
- * \brief Save the AST of a script to a file
- */
-extern int SpiderScript_SaveAST(tSpiderScript *Script, const char *Filename);
-
-/**
- * \brief Free a script
- * \param Script Script structure to free
- */
-extern void SpiderScript_Free(tSpiderScript *Script);
-
-extern tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes);
-
-/**
- * \name tSpiderValue Manipulation functions
- * \{
- */
-extern void SpiderScript_DereferenceValue(tSpiderValue *Object);
-extern void SpiderScript_ReferenceValue(tSpiderValue *Object);
-extern tSpiderValue *SpiderScript_CreateInteger(uint64_t Value);
-extern tSpiderValue *SpiderScript_CreateReal(double Value);
-extern tSpiderValue *SpiderScript_CreateString(int Length, const char *Data);
-extern tSpiderValue *SpiderScript_CreateArray(int InnerType, int ItemCount);
-extern tSpiderValue *SpiderScript_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2);
-extern tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
-extern int SpiderScript_IsValueTrue(tSpiderValue *Value);
-extern void SpiderScript_FreeValue(tSpiderValue *Value);
-extern char *SpiderScript_DumpValue(tSpiderValue *Value);
-
-extern tSpiderValue *SpiderScript_DoOp(tSpiderValue *Left, enum eSpiderValueOps Op, int bCanCast, tSpiderValue *Right);
-/**
- * \}
- */
-
-#endif
+++ /dev/null
-/*
- */
-#ifndef _TOKENS_H_
-#define _TOKENS_H_
-
-#include <setjmp.h>
-
-// Make the scope character ('.') be a symbol, otherwise it's just
-// a ident character
-#define USE_SCOPE_CHAR 1
-
-// === TYPES ===
-typedef struct
-{
- // Lexer State
- const char *BufStart;
- const char *CurPos;
-
- char *Filename;
-
- int LastLine;
- int LastToken, LastTokenLen;
- const char *LastTokenStr;
-
- int NextLine;
- int NextToken, NextTokenLen;
- const char *NextTokenStr;
-
- int CurLine;
- int Token, TokenLen;
- const char *TokenStr;
-
- jmp_buf JmpTarget;
- int ErrorHit;
-
- struct sSpiderVariant *Variant;
-} tParser;
-
-// === FUNCTIONS ===
- int GetToken(tParser *File);
-void PutBack(tParser *File);
- int LookAhead(tParser *File);
-
-// === CONSTANTS ===
-enum eTokens
-{
- TOK_INVAL,
- TOK_EOF,
-
- // Primitives
- TOK_STR,
- TOK_INTEGER,
- TOK_REAL,
- TOK_VARIABLE,
- TOK_IDENT,
-
- // Reserved Words
- // - Definitions
- TOK_RWD_FUNCTION,
- TOK_RWD_NAMESPACE,
- // - Control Flow
- TOK_RWD_NEW,
- TOK_RWD_RETURN,
- TOK_RWD_BREAK,
- TOK_RWD_CONTINUE,
- // - Blocks
- TOK_RWD_IF,
- TOK_RWD_ELSE,
- TOK_RWD_DO,
- TOK_RWD_WHILE,
- TOK_RWD_FOR,
- // - Value
- TOK_RWD_NULL,
- // - Types
- TOK_RWD_VOID,
- TOK_RWD_OBJECT,
- TOK_RWD_OPAQUE,
- TOK_RWD_STRING,
- TOK_RWD_INTEGER,
- TOK_RWD_REAL,
-
- //
- TOK_ASSIGN,
- TOK_SEMICOLON,
- TOK_COMMA,
- TOK_SCOPE,
- TOK_ELEMENT,
-
- // Comparisons
- TOK_EQUALS, TOK_NOTEQUALS,
- TOK_LT, TOK_LTE,
- TOK_GT, TOK_GTE,
-
- // Operations
- TOK_BWNOT, TOK_LOGICNOT,
- TOK_DIV, TOK_MUL,
- TOK_PLUS, TOK_MINUS,
- TOK_SHL, TOK_SHR,
- TOK_LOGICAND, TOK_LOGICOR, TOK_LOGICXOR,
- TOK_AND, TOK_OR, TOK_XOR,
-
- // Assignment Operations
- TOK_INCREMENT, TOK_DECREMENT,
- TOK_ASSIGN_DIV, TOK_ASSIGN_MUL,
- TOK_ASSIGN_PLUS, TOK_ASSIGN_MINUS,
- TOK_ASSIGN_SHL, TOK_ASSIGN_SHR,
- TOK_ASSIGN_LOGICAND, TOK_ASSIGN_LOGICOR, TOK_ASSIGN_LOGXICOR,
- TOK_ASSIGN_AND, TOK_ASSIGN_OR, TOK_ASSIGN_XOR,
-
- TOK_PAREN_OPEN, TOK_PAREN_CLOSE,
- TOK_BRACE_OPEN, TOK_BRACE_CLOSE,
- TOK_SQUARE_OPEN, TOK_SQUARE_CLOSE,
-
- TOK_LAST
-};
-
-#define TOKEN_GROUP_TYPES TOK_RWD_VOID:\
- case TOK_RWD_OBJECT:\
- case TOK_RWD_OPAQUE:\
- 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_OPAQUE, 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_OPAQUE: _type = SS_DATATYPE_OPAQUE; 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:_type=SS_DATATYPE_UNDEF;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_REAL",
- "TOK_VARIABLE",
- "TOK_IDENT",
-
- "TOK_RWD_FUNCTION",
- "TOK_RWD_NAMESPACE",
-
- "TOK_RWD_NEW",
- "TOK_RWD_RETURN",
- "TOK_RWD_BREAK",
- "TOK_RWD_CONTINUE",
-
- "TOK_RWD_IF",
- "TOK_RWD_ELSE",
- "TOK_RWD_DO",
- "TOK_RWD_WHILE",
- "TOK_RWD_FOR",
-
- "TOK_RWD_NULL",
- "TOK_RWD_VOID",
- "TOK_RWD_OBJECT",
- "TOK_RWD_OPAUQE",
- "TOK_RWD_STRING",
- "TOK_RWD_INTEGER",
- "TOK_RWD_REAL",
-
- "TOK_ASSIGN",
- "TOK_SEMICOLON",
- "TOK_COMMA",
- "TOK_SCOPE",
- "TOK_ELEMENT",
-
- "TOK_EQUALS", "TOK_NOTEQUALS",
- "TOK_LT", "TOK_LTE",
- "TOK_GT", "TOK_GTE",
-
- "TOK_BWNOT", "TOK_LOGICNOT",
- "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_INCREMENT", "TOK_DECREMENT",
- "TOK_ASSIGN_DIV", "TOK_ASSIGN_MUL",
- "TOK_ASSIGN_PLUS", "TOK_ASSIGN_MINUS",
- "TOK_ASSIGN_SHL", "TOK_ASSIGN_SHR",
- "TOK_ASSIGN_LOGICAND", "TOK_ASSIGN_LOGICOR", "TOK_ASSIGN_LOGICXOR",
- "TOK_ASSIGN_AND", "TOK_ASSIGN_OR", "TOK_ASSIGN_XOR",
-
- "TOK_PAREN_OPEN", "TOK_PAREN_CLOSE",
- "TOK_BRACE_OPEN", "TOK_BRACE_CLOSE",
- "TOK_SQUARE_OPEN", "TOK_SQUARE_CLOSE",
-
- "TOK_LAST"
-};
-# endif
-
-#endif
+++ /dev/null
-/*
- * SpiderScript Library
- * by John Hodge (thePowersGang)
- *
- * values.c
- * - Manage tSpiderValue objects
- */
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include "spiderscript.h"
-
-// === IMPORTS ===
-extern void AST_RuntimeError(void *Node, const char *Format, ...);
-
-// === PROTOTYPES ===
-void SpiderScript_DereferenceValue(tSpiderValue *Object);
-void SpiderScript_ReferenceValue(tSpiderValue *Object);
-tSpiderValue *SpiderScript_CreateInteger(uint64_t Value);
-tSpiderValue *SpiderScript_CreateReal(double Value);
-tSpiderValue *SpiderScript_CreateString(int Length, const char *Data);
-tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
- int SpiderScript_IsValueTrue(tSpiderValue *Value);
-void SpiderScript_FreeValue(tSpiderValue *Value);
-char *SpiderScript_DumpValue(tSpiderValue *Value);
-// --- Operations
-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 ===
-/**
- * \brief Dereference a created object
- */
-void SpiderScript_DereferenceValue(tSpiderValue *Object)
-{
- if(!Object || Object == ERRPTR) return ;
- Object->ReferenceCount --;
- if( Object->ReferenceCount == 0 )
- {
- int i;
-
- if( Object->Type == SS_DATATYPE_ARRAY || SS_GETARRAYDEPTH(Object->Type) )
- {
- for( i = 0; i < Object->Array.Length; i ++ )
- {
- if( Object->Array.Items[i] ) {
- SpiderScript_DereferenceValue(Object->Array.Items[i]);
- }
- Object->Array.Items[i] = NULL;
- }
- }
- else
- {
- switch( (enum eSpiderScript_DataTypes) Object->Type )
- {
- case SS_DATATYPE_OBJECT:
- Object->Object->ReferenceCount --;
- if(Object->Object->ReferenceCount == 0) {
- Object->Object->Type->Destructor( Object->Object );
- }
- Object->Object = NULL;
- break;
-
- case SS_DATATYPE_OPAQUE:
- Object->Opaque.Destroy( Object->Opaque.Data );
- break;
- default:
- break;
- }
- }
- free(Object);
- }
-}
-
-/**
- * \brief Reference a value
- */
-void SpiderScript_ReferenceValue(tSpiderValue *Object)
-{
- if(!Object || Object == ERRPTR) return ;
- Object->ReferenceCount ++;
-}
-
-/**
- * \brief Allocate and initialise a SpiderScript object
- */
-tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes)
-{
- int size = sizeof(tSpiderObject) + Class->NAttributes * sizeof(tSpiderValue*) + ExtraBytes;
- tSpiderObject *ret = malloc(size);
-
- ret->Type = Class;
- ret->ReferenceCount = 1;
- ret->OpaqueData = &ret->Attributes[ Class->NAttributes ];
- memset( ret->Attributes, 0, Class->NAttributes * sizeof(tSpiderValue*) );
-
- return ret;
-}
-
-/**
- * \brief Create an integer object
- */
-tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
-{
- tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
- ret->Type = SS_DATATYPE_INTEGER;
- ret->ReferenceCount = 1;
- ret->Integer = Value;
- return ret;
-}
-
-/**
- * \brief Create an real number object
- */
-tSpiderValue *SpiderScript_CreateReal(double Value)
-{
- tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
- ret->Type = SS_DATATYPE_REAL;
- ret->ReferenceCount = 1;
- ret->Real = Value;
- return ret;
-}
-
-/**
- * \brief Create an string object
- */
-tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
-{
- tSpiderValue *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
- ret->Type = SS_DATATYPE_STRING;
- ret->ReferenceCount = 1;
- ret->String.Length = Length;
- if( Data )
- memcpy(ret->String.Data, Data, Length);
- else
- memset(ret->String.Data, 0, Length);
- ret->String.Data[Length] = '\0';
- return ret;
-}
-
-tSpiderValue *SpiderScript_CreateArray(int InnerType, int ItemCount)
-{
- tSpiderValue *ret = malloc( sizeof(tSpiderValue) + ItemCount*sizeof(tSpiderValue*) );
- ret->Type = SS_MAKEARRAY(InnerType);
- ret->ReferenceCount = 1;
- ret->Array.Length = ItemCount;
- memset(ret->Array.Items, 0, ItemCount*sizeof(tSpiderValue*));
- return ret;
-}
-
-/**
- * \brief Concatenate two strings
- */
-tSpiderValue *SpiderScript_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2)
-{
- int newLen = 0;
- tSpiderValue *ret;
-
- if( Str1 && Str1->Type != SS_DATATYPE_STRING)
- return NULL;
- if( Str2 && Str2->Type != SS_DATATYPE_STRING)
- return NULL;
-
- if(Str1) newLen += Str1->String.Length;
- if(Str2) newLen += Str2->String.Length;
- ret = malloc( sizeof(tSpiderValue) + 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
- * \brief Type Destination type
- * \brief Source Input data
- */
-tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
-{
- tSpiderValue *ret = ERRPTR;
- int len = 0;
-
- if( !Source )
- {
- switch(Type)
- {
- case SS_DATATYPE_INTEGER: return SpiderScript_CreateInteger(0);
- case SS_DATATYPE_REAL: return SpiderScript_CreateReal(0);
- case SS_DATATYPE_STRING: return SpiderScript_CreateString(4, "null");
- }
- return NULL;
- }
-
- // Check if anything needs to be done
- if( Source->Type == Type ) {
- SpiderScript_ReferenceValue(Source);
- return Source;
- }
-
- // Debug
- #if 0
- {
- printf("Casting %i ", Source->Type);
- switch(Source->Type)
- {
- case SS_DATATYPE_INTEGER: printf("0x%lx", Source->Integer); break;
- case SS_DATATYPE_STRING: printf("\"%s\"", Source->String.Data); break;
- case SS_DATATYPE_REAL: printf("%f", Source->Real); break;
- default: break;
- }
- printf(" to %i\n", Type);
- }
- #endif
-
- // Object casts
- #if 0
- if( Source->Type == SS_DATATYPE_OBJECT )
- {
- const char *name = NULL;
- switch(Type)
- {
- case SS_DATATYPE_INTEGER: name = "cast Integer"; break;
- case SS_DATATYPE_REAL: name = "cast Real"; break;
- case SS_DATATYPE_STRING: name = "cast String"; break;
- case SS_DATATYPE_ARRAY: name = "cast Array"; break;
- default:
- AST_RuntimeError(NULL, "Invalid cast to %i from Object", Type);
- return ERRPTR;
- }
- if( fcnname )
- {
- ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
- if( ret != ERRPTR )
- return ret;
- // Fall through and try casting (which will usually fail)
- }
- }
- #endif
-
- switch( (enum eSpiderScript_DataTypes)Type )
- {
- case SS_DATATYPE_UNDEF:
- case SS_DATATYPE_ARRAY:
- case SS_DATATYPE_OPAQUE:
- AST_RuntimeError(NULL, "Invalid cast to %i", Type);
- return ERRPTR;
- case SS_DATATYPE_OBJECT:
- // TODO:
- AST_RuntimeError(NULL, "Invalid cast to %i", Type);
- return ERRPTR;
-
- case SS_DATATYPE_INTEGER:
- ret = malloc(sizeof(tSpiderValue));
- ret->Type = SS_DATATYPE_INTEGER;
- ret->ReferenceCount = 1;
- switch(Source->Type)
- {
- case SS_DATATYPE_INTEGER: break; // Handled above
- case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
- case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
- default:
- AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
- free(ret);
- ret = ERRPTR;
- break;
- }
- break;
-
- case SS_DATATYPE_REAL:
- ret = malloc(sizeof(tSpiderValue));
- ret->Type = SS_DATATYPE_REAL;
- ret->ReferenceCount = 1;
- switch(Source->Type)
- {
- case SS_DATATYPE_STRING: ret->Real = atof(Source->String.Data); break;
- case SS_DATATYPE_INTEGER: ret->Real = Source->Integer; break;
- default:
- AST_RuntimeError(NULL, "Invalid cast from %i to Real", Source->Type);
- free(ret);
- ret = ERRPTR;
- break;
- }
- break;
-
- case SS_DATATYPE_STRING:
- switch(Source->Type)
- {
- case SS_DATATYPE_INTEGER: len = snprintf(NULL, 0, "%li", Source->Integer); break;
- case SS_DATATYPE_REAL: len = snprintf(NULL, 0, "%g", Source->Real); break;
- default: break;
- }
- ret = malloc(sizeof(tSpiderValue) + len + 1);
- ret->Type = SS_DATATYPE_STRING;
- ret->ReferenceCount = 1;
- ret->String.Length = len;
- switch(Source->Type)
- {
- case SS_DATATYPE_INTEGER: sprintf(ret->String.Data, "%li", Source->Integer); break;
- case SS_DATATYPE_REAL:
- sprintf(ret->String.Data, "%g", Source->Real); break;
- default:
- AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
- free(ret);
- ret = ERRPTR;
- break;
- }
- break;
-
- default:
- AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target %i", Type);
- ret = ERRPTR;
- break;
- }
-
- return ret;
-}
-
-/**
- * \brief Condenses a value down to a boolean
- */
-int SpiderScript_IsValueTrue(tSpiderValue *Value)
-{
- if( Value == ERRPTR ) return 0;
- if( Value == NULL ) return 0;
-
- switch( (enum eSpiderScript_DataTypes)Value->Type )
- {
- case SS_DATATYPE_UNDEF:
- return 0;
-
- case SS_DATATYPE_INTEGER:
- return !!Value->Integer;
-
- case SS_DATATYPE_REAL:
- return (-.5f < Value->Real && Value->Real < 0.5f);
-
- case SS_DATATYPE_STRING:
- return Value->String.Length > 0;
-
- case SS_DATATYPE_OBJECT:
- return Value->Object != NULL;
-
- case SS_DATATYPE_OPAQUE:
- return Value->Opaque.Data != NULL;
-
- case SS_DATATYPE_ARRAY:
- return Value->Array.Length > 0;
- default:
- AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
- return 0;
- }
- return 0;
-}
-
-/**
- * \brief Free a value
- * \note Just calls Object_Dereference
- */
-void SpiderScript_FreeValue(tSpiderValue *Value)
-{
- SpiderScript_DereferenceValue(Value);
-}
-
-/**
- * \brief Dump a value into a string
- * \return Heap string
- */
-char *SpiderScript_DumpValue(tSpiderValue *Value)
-{
- char *ret;
- if( Value == ERRPTR )
- return strdup("ERRPTR");
- if( Value == NULL )
- return strdup("null");
-
- switch( (enum eSpiderScript_DataTypes)Value->Type )
- {
- case SS_DATATYPE_UNDEF: return strdup("undefined");
-
- case SS_DATATYPE_INTEGER:
- ret = malloc( sizeof(Value->Integer)*2 + 3 );
- sprintf(ret, "0x%lx", Value->Integer);
- return ret;
-
- case SS_DATATYPE_REAL:
- ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
- sprintf(ret, "%f", Value->Real);
- return ret;
-
- case SS_DATATYPE_STRING:
- ret = malloc( Value->String.Length + 3 );
- ret[0] = '"';
- strcpy(ret+1, Value->String.Data);
- ret[Value->String.Length+1] = '"';
- ret[Value->String.Length+2] = '\0';
- return ret;
-
- case SS_DATATYPE_OBJECT:
- ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
- sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
- return ret;
-
- case SS_DATATYPE_OPAQUE:
- ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
- sprintf(ret, "*%p", Value->Opaque.Data);
- return ret;
-
- case SS_DATATYPE_ARRAY:
- return strdup("Array");
-
- default:
- AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
- return NULL;
- }
-
-}
-
-// ---
-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, enum eSpiderValueOps Operation, int bCanCast, tSpiderValue *Right)
-{
- tSpiderValue *oldright = Right;
- tSpiderValue *ret = NULL;
- int64_t rv = 0;
-
- // Casting
- if(Right && Right->Type != SS_DATATYPE_INTEGER) {
- if(!bCanCast) return ERRPTR;
- Right = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, Right);
- }
-
- // Do the operation
- switch(Operation)
- {
- case SS_VALUEOP_NEGATE:
- if(Right) ret = ERRPTR;
- else rv = -Left->Integer;
- break;
- case SS_VALUEOP_ADD:
- 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
- if( Right != oldright )
- SpiderScript_DereferenceValue(Right);
-
- // Return error if signaled
- if(ret == ERRPTR)
- return ERRPTR;
-
- // Reuse `Left` if possible, to reduce mallocs
- if(Left->ReferenceCount == 1) {
- SpiderScript_ReferenceValue(Left);
- Left->Integer = rv;
- return Left;
- }
- else {
- return SpiderScript_CreateInteger(rv);
- }
-}
-