newrpl/lib-26-lists.c
2014-04-27 18:53:11 -04:00

370 lines
9.2 KiB
C

// LIBRARY ZERO HAS SPECIAL RUNSTREAM OPERATORS
#include "newrpl.h"
#include "libraries.h"
#include "hal.h"
// THERE'S ONLY ONE EXTERNAL FUNCTION: THE LIBRARY HANDLER
// ALL OTHER FUNCTIONS ARE LOCAL
// LIB0 PROVIDES EXIT FROM RPL, BREAKPOINTS AND RUNSTREAM MANIPULATION OPCODES
// MAIN LIBRARY NUMBER, CHANGE THIS FOR EACH LIBRARY
#define LIBRARY_NUMBER 26
#define LIB_ENUM lib26_enum
#define LIB_NAMES lib26_names
#define LIB_HANDLER lib26_handler
#define LIB_NUMBEROFCMDS LIB26_NUMBEROFCMDS
// LIST OF COMMANDS EXPORTED, CHANGE FOR EACH LIBRARY
#define CMD_LIST \
CMD(PUT), \
CMD(PUTI), \
CMD(GET), \
CMD(GETI), \
CMD(HEAD), \
CMD(TAIL)
// ADD MORE OPCODES HERE
// EXTRA LIST FOR COMMANDS WITH SYMBOLS THAT ARE DISALLOWED IN AN ENUM
// THE NAMES AND ENUM SYMBOLS ARE GIVEN SEPARATELY
#define CMD_EXTRANAME \
"}", \
"->LIST", \
"OBJ->"
#define CMD_EXTRAENUM \
ENDLIST, \
TOLIST, \
INNERCOMP
//
// INTERNAL DECLARATIONS
// CREATE AN ENUM WITH THE OPCODE NAMES FOR THE DISPATCHER
#define CMD(a) a
enum LIB_ENUM { CMD_LIST , CMD_EXTRAENUM , LIB_NUMBEROFCMDS };
#undef CMD
// AND A LIST OF STRINGS WITH THE NAMES FOR THE COMPILER
#define CMD(a) #a
char *LIB_NAMES[]= { CMD_LIST , CMD_EXTRANAME };
#undef CMD
// EXPAND A COMPOSITE IN THE STACK AND STORES THE NUMBER OF ELEMENTS AT THE END
// USES 2 SCRATCH POINTERS
BINT rplExplodeList(WORDPTR composite)
{
BINT count=0;
ScratchPointer1=composite+1;
ScratchPointer2=composite+OBJSIZE(*composite); // POINT TO THE END MARKER
while(ScratchPointer1<ScratchPointer2) {
rplPushData(ScratchPointer1);
ScratchPointer1=rplSkipOb(ScratchPointer1);
++count;
}
rplNewBINTPush(count,DECBINT);
return count;
}
// CREATE A NEW LIST. STACK LEVEL 1 = NUMBER OF ELEMENTS, LEVELS 2.. N+1 = OBJECTS
// USES 1 SCRATCH POINTER
void rplCreateList()
{
// NO ARGUMENT CHECKING
BINT64 num=rplReadNumberAsBINT(rplPeekData(1));
if(rplDepthData()<num+1) {
Exceptions|=EX_BADARGCOUNT;
ExceptionPointer=IPtr;
return;
}
BINT size=1; // 1 WORD FOR THE END MARKER
BINT count;
for(count=0;count<num;++count) {
size+=rplObjSize(rplPeekData(2+count));
}
// ALLOCATE MEMORY
WORDPTR list=rplAllocTempOb(size);
if(!list) {
Exceptions|=EX_OUTOFMEM;
ExceptionPointer=IPtr;
return;
}
// CONSTRUCT THE OBJECT
WORDPTR objptr=list+1;
*list=MKPROLOG(LIBRARY_NUMBER,size);
for(count=num;count>0;--count) {
rplCopyObject(objptr,rplPeekData(count+1));
objptr+=rplObjSize(objptr);
}
*objptr=MKOPCODE(LIBRARY_NUMBER,ENDLIST);
rplDropData(num);
rplOverwriteData(1,list);
}
void LIB_HANDLER()
{
if(ISPROLOG(CurOpcode)) {
// PROVIDE BEHAVIOR OF EXECUTING THE OBJECT HERE
rplPushData(IPtr);
return;
}
switch(OPCODE(CurOpcode))
{
case PUT:
{
// CHECK ARGUMENTS
if(rplDepthData()<3) {
Exceptions|=EX_BADARGCOUNT;
ExceptionPointer=IPtr;
return;
}
WORDPTR list=rplPeekData(3);
WORDPTR *var=0;
if(ISIDENT(*list)) {
var=rplFindLAM(list);
if(!var) {
var=rplFindGlobal(list,1);
if(!var) {
Exceptions|=EX_BADARGTYPE;
ExceptionPointer=IPtr;
return;
}
}
list=*(var+1);
}
if(!ISLIST(*list)) {
Exceptions|=EX_BADARGTYPE;
ExceptionPointer=IPtr;
return;
}
if(!ISNUMBER(*rplPeekData(2))) {
Exceptions|=EX_BADARGTYPE;
ExceptionPointer=IPtr;
return;
}
BINT nitems=rplExplodeList(list);
BINT position=rplReadNumberAsBINT(rplPeekData(nitems+3));
if(Exceptions) return;
if(position<1 || position>nitems) {
Exceptions|=EX_BADARGVALUE;
ExceptionPointer=IPtr;
return;
}
rplOverwriteData(nitems+2-position,rplPeekData(nitems+2));
rplCreateList();
rplOverwriteData(4,rplPeekData(1));
rplDropData(3);
if(var) {
*(var+1)=rplPopData();
}
}
return;
case PUTI:
return;
case GET:
{
// CHECK ARGUMENTS
if(rplDepthData()<2) {
Exceptions|=EX_BADARGCOUNT;
ExceptionPointer=IPtr;
return;
}
WORDPTR list=rplPeekData(2);
WORDPTR *var=0;
if(ISIDENT(*list)) {
var=rplFindLAM(list);
if(!var) {
var=rplFindGlobal(list,1);
if(!var) {
Exceptions|=EX_BADARGTYPE;
ExceptionPointer=IPtr;
return;
}
}
list=*(var+1);
}
if(!ISLIST(*list)) {
Exceptions|=EX_BADARGTYPE;
ExceptionPointer=IPtr;
return;
}
if(!ISNUMBER(*rplPeekData(1))) {
Exceptions|=EX_BADARGTYPE;
ExceptionPointer=IPtr;
return;
}
BINT nitems=rplExplodeList(list);
BINT position=rplReadNumberAsBINT(rplPeekData(nitems+2));
if(Exceptions) return;
if(position<1 || position>nitems) {
Exceptions|=EX_BADARGVALUE;
ExceptionPointer=IPtr;
return;
}
rplOverwriteData(nitems+3,rplPeekData(nitems+2-position));
rplDropData(nitems+2);
}
return;
case GETI:
case HEAD:
case TAIL:
return;
case ENDLIST:
return;
case TOLIST:
if(rplDepthData()<1) {
Exceptions|=EX_BADARGCOUNT;
ExceptionPointer=IPtr;
return;
}
if(!ISNUMBER(*rplPeekData(1))) {
Exceptions|=EX_BADARGTYPE;
ExceptionPointer=IPtr;
return;
}
rplCreateList();
return;
case INNERCOMP:
if(rplDepthData()<1) {
Exceptions|=EX_BADARGCOUNT;
ExceptionPointer=IPtr;
return;
}
if(!ISLIST(*rplPeekData(1))) {
Exceptions|=EX_BADARGTYPE;
ExceptionPointer=IPtr;
return;
}
rplExplodeList(rplPopData());
return;
// ADD MORE OPCODES HERE
// STANDARIZED OPCODES:
// --------------------
// LIBRARIES ARE FORCED TO ALWAYS HANDLE THE STANDARD OPCODES
case OPCODE_COMPILE:
// COMPILE RECEIVES:
// TokenStart = token string
// TokenLen = token length
// BlankStart = token blanks afterwards
// BlanksLen = blanks length
// CurrentConstruct = Opcode of current construct/WORD of current composite
// COMPILE RETURNS:
// RetNum = enum CompileErrors
// CHECK IF THE TOKEN IS THE OPEN BRACKET
if((TokenLen==1) && (!strncmp((char * )TokenStart,"{",1)))
{
rplCompileAppend((WORD) MKPROLOG(LIBRARY_NUMBER,0));
RetNum=OK_STARTCONSTRUCT;
return;
}
// CHECK IF THE TOKEN IS THE CLOSING BRACKET
if(((TokenLen==1) && (!strncmp((char *)TokenStart,"}",1))))
{
if(CurrentConstruct!=MKPROLOG(LIBRARY_NUMBER,0)) {
RetNum=ERR_SYNTAX;
return;
}
rplCompileAppend(MKOPCODE(LIBRARY_NUMBER,ENDLIST));
RetNum=OK_ENDCONSTRUCT;
return;
}
// THIS STANDARD FUNCTION WILL TAKE CARE OF COMPILATION OF STANDARD COMMANDS GIVEN IN THE LIST
// NO NEED TO CHANGE THIS UNLESS CUSTOM OPCODES
libCompileCmds(LIBRARY_NUMBER,LIB_NAMES,NULL,LIB_NUMBEROFCMDS);
// SINCE THIS IS THE LAST LIBRARY TO BE EVALUATED, DO ONE LAST PASS TO COMPILE IT AS AN IDENT
// EITHER LAM OR IN USEROB
return;
case OPCODE_DECOMPILE:
// DECOMPILE RECEIVES:
// DecompileObject = Ptr to WORD of object to decompile
// DecompStringEnd = Ptr to the end of decompile string
//DECOMPILE RETURNS
// RetNum = enum DecompileErrors
if(ISPROLOG(*DecompileObject)) {
rplDecompAppendString((BYTEPTR)" { ");
RetNum=OK_STARTCONSTRUCT;
return;
}
// THIS STANDARD FUNCTION WILL TAKE CARE OF DECOMPILING STANDARD COMMANDS GIVEN IN THE LIST
// NO NEED TO CHANGE THIS UNLESS THERE ARE CUSTOM OPCODES
libDecompileCmds(LIB_NAMES,NULL,LIB_NUMBEROFCMDS);
return;
case OPCODE_VALIDATE:
// VALIDATE RECEIVES OPCODES COMPILED BY OTHER LIBRARIES, TO BE INCLUDED WITHIN A COMPOSITE OWNED BY
// THIS LIBRARY. EVERY COMPOSITE HAS TO EVALUATE IF THE OBJECT BEING COMPILED IS ALLOWED INSIDE THIS
// COMPOSITE OR NOT. FOR EXAMPLE, A REAL MATRIX SHOULD ONLY ALLOW REAL NUMBERS INSIDE, ANY OTHER
// OPCODES SHOULD BE REJECTED AND AN ERROR THROWN.
// TokenStart = token string
// TokenLen = token length
// ArgNum2 = Opcode/WORD of object
// VALIDATE RETURNS:
// RetNum = enum CompileErrors
return;
}
// BY DEFAULT, ISSUE A BAD OPCODE ERROR
Exceptions|=EX_BADOPCODE;
ExceptionPointer=IPtr;
return;
}