2014-05-21 19:47:14 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014, Claudio Lapilli and the newRPL Team
|
|
|
|
* All rights reserved.
|
|
|
|
* This file is released under the 3-clause BSD license.
|
|
|
|
* See the file LICENSE.txt that shipped with this distribution.
|
|
|
|
*/
|
|
|
|
|
2014-04-28 00:53:11 +02:00
|
|
|
#include "newrpl.h"
|
|
|
|
#include "libraries.h"
|
|
|
|
#include "hal.h"
|
|
|
|
|
|
|
|
|
|
|
|
// THIS LIBRARY PROVIDES COMPILATION OF DIRECTORY PSEUDO-OBJECTS AND RELATED COMMANDS
|
|
|
|
|
|
|
|
|
|
|
|
// THERE'S ONLY ONE EXTERNAL FUNCTION: THE LIBRARY HANDLER
|
|
|
|
// ALL OTHER FUNCTIONS ARE LOCAL
|
|
|
|
|
|
|
|
// MAIN LIBRARY NUMBER, CHANGE THIS FOR EACH LIBRARY
|
|
|
|
#define LIBRARY_NUMBER 22
|
|
|
|
#define LIB_ENUM lib22enum
|
|
|
|
#define LIB_NAMES lib22_names
|
|
|
|
#define LIB_HANDLER lib22_handler
|
|
|
|
#define LIB_NUMBEROFCMDS LIB22_NUMBEROFCMDS
|
|
|
|
|
|
|
|
// LIST OF COMMANDS EXPORTED, CHANGE FOR EACH LIBRARY
|
|
|
|
#define CMD_LIST \
|
|
|
|
CMD(STO), \
|
|
|
|
CMD(RCL), \
|
|
|
|
CMD(INCR), \
|
|
|
|
CMD(DECR), \
|
|
|
|
CMD(PURGE), \
|
|
|
|
CMD(CRDIR), \
|
|
|
|
CMD(PGDIR), \
|
|
|
|
CMD(UPDIR), \
|
|
|
|
CMD(HOME), \
|
|
|
|
CMD(PATH)
|
|
|
|
|
|
|
|
// 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 \
|
|
|
|
"->"
|
|
|
|
#define CMD_EXTRAENUM \
|
|
|
|
NEWLOCALENV
|
|
|
|
*/
|
|
|
|
|
|
|
|
// THESE ARE SPECIAL OPCODES FOR THE COMPILER ONLY
|
|
|
|
// THE LOWER 16 BITS ARE THE NUMBER OF LAMS TO CREATE, OR THE INDEX OF LAM NUMBER TO STO/RCL
|
|
|
|
#define NEWNLOCALS 0x40000 // SPECIAL OPCODE TO CREATE NEW LOCAL VARIABLES
|
|
|
|
#define GETLAMN 0x20000 // SPECIAL OPCODE TO RCL THE CONTENT OF A LAM
|
|
|
|
#define PUTLAMN 0x10000 // SPECIAL OPCODE TO STO THE CONTENT OF A LAM
|
|
|
|
|
|
|
|
// 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
|
2014-10-17 14:22:00 +02:00
|
|
|
const char * const LIB_NAMES[]= { CMD_LIST /*, CMD_EXTRANAME*/ };
|
2014-04-28 00:53:11 +02:00
|
|
|
#undef CMD
|
|
|
|
|
|
|
|
|
|
|
|
void LIB_HANDLER()
|
|
|
|
{
|
|
|
|
if(ISPROLOG(CurOpcode)) {
|
|
|
|
// PROVIDE BEHAVIOR OF EXECUTING THE OBJECT HERE
|
2014-06-01 03:25:13 +02:00
|
|
|
// THIS SHOULD NEVER HAPPEN, AS DIRECTORY OBJECTS ARE SPECIAL HANDLES
|
|
|
|
// THEY ARE NEVER USED IN THE MIDDLE OF THE CODE
|
|
|
|
Exceptions=EX_BADOPCODE;
|
|
|
|
ExceptionPointer=IPtr;
|
2014-04-28 00:53:11 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(OPCODE(CurOpcode))
|
|
|
|
{
|
|
|
|
case STO:
|
|
|
|
{
|
|
|
|
// STORE CONTENT INSIDE A LAM OR GLOBAL VARIABLE, CREATE A NEW "GLOBAL" VARIABLE IF NEEDED
|
|
|
|
if(rplDepthData()<2) {
|
|
|
|
Exceptions=EX_BADARGCOUNT;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// ONLY ACCEPT IDENTS AS KEYS
|
|
|
|
|
|
|
|
if(!ISIDENT(*rplPeekData(1))) {
|
|
|
|
Exceptions=EX_BADARGTYPE;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-30 18:56:31 +01:00
|
|
|
WORDPTR *val=rplFindLAM(rplPeekData(1),1);
|
2014-04-28 00:53:11 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(val) {
|
|
|
|
val[1]=rplPeekData(2);
|
|
|
|
rplDropData(2);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// LAM WAS NOT FOUND, TRY A GLOBAL
|
2014-05-18 04:05:35 +02:00
|
|
|
val=rplFindGlobal(rplPeekData(1),0);
|
2014-04-28 00:53:11 +02:00
|
|
|
|
|
|
|
// HANDLE SPECIAL CASE OF STORING DIRECTORY OBJECTS
|
|
|
|
WORDPTR obj=rplPeekData(2);
|
|
|
|
if(LIBNUM(*obj)==DODIR) {
|
|
|
|
WORDPTR *sourcedir=rplFindDirbyHandle(obj);
|
|
|
|
if(sourcedir) {
|
|
|
|
WORDPTR *newdir=rplDeepCopyDir(sourcedir);
|
|
|
|
if(newdir) {
|
|
|
|
if(val) {
|
|
|
|
*(newdir+3)=*(rplGetDirfromGlobal(val)+1); // SET PARENT DIR
|
|
|
|
*(val+1)=*(newdir+1); // AND NEW HANDLE
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*(newdir+3)=*(CurrentDir+1);
|
|
|
|
rplCreateGlobal(rplPeekData(1),*(newdir+1));
|
|
|
|
}
|
|
|
|
rplDropData(2);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(val) {
|
|
|
|
val[1]=rplPeekData(2);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// CREATE A NEW GLOBAL VARIABLE
|
|
|
|
rplCreateGlobal(rplPeekData(1),rplPeekData(2));
|
|
|
|
}
|
|
|
|
rplDropData(2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
case RCL:
|
|
|
|
{
|
|
|
|
// GET CONTENT FROM LOCAL OR GLOBAL VARIABLE
|
|
|
|
if(rplDepthData()<1) {
|
|
|
|
Exceptions=EX_BADARGCOUNT;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// ONLY ACCEPT IDENTS AS KEYS (ONLY LOW-LEVEL VERSION CAN USE ARBITRARY OBJECTS)
|
|
|
|
|
|
|
|
if(!ISIDENT(*rplPeekData(1))) {
|
|
|
|
Exceptions=EX_BADARGTYPE;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
WORDPTR val=rplGetLAM(rplPeekData(1));
|
|
|
|
if(val) {
|
|
|
|
rplOverwriteData(1,val);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// NO LAM, TRY A GLOBAL
|
|
|
|
val=rplGetGlobal(rplPeekData(1));
|
|
|
|
if(val) {
|
|
|
|
rplOverwriteData(1,val);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Exceptions=EX_VARUNDEF;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case INCR:
|
|
|
|
{
|
|
|
|
if(rplDepthData()<1) {
|
|
|
|
Exceptions=EX_BADARGCOUNT;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// ONLY ACCEPT IDENTS AS KEYS (ONLY LOW-LEVEL VERSION CAN USE ARBITRARY OBJECTS)
|
|
|
|
|
|
|
|
if(!ISIDENT(*rplPeekData(1))) {
|
|
|
|
Exceptions=EX_BADARGTYPE;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// GET CONTENT FROM LOCAL OR GLOBAL VARIABLE
|
|
|
|
|
2014-05-30 20:17:07 +02:00
|
|
|
WORDPTR *var=rplFindLAM(rplPeekData(1),1);
|
2014-04-28 00:53:11 +02:00
|
|
|
if(!var) var=rplFindGlobal(rplPeekData(1),1);
|
|
|
|
if(var) {
|
|
|
|
rplOverwriteData(1,*(var+1));
|
2014-10-02 03:27:40 +02:00
|
|
|
rplPushData((WORDPTR)one_bint); // PUSH THE NUMBER ONE
|
2014-04-28 00:53:11 +02:00
|
|
|
|
|
|
|
// CALL THE OVERLOADED OPERATOR '+'
|
|
|
|
|
|
|
|
rplCallOvrOperator(OVR_ADD);
|
|
|
|
|
|
|
|
if(Exceptions) return;
|
|
|
|
|
|
|
|
|
|
|
|
*(var+1)=rplPeekData(1); // STORE THE INCREMENTED COUNTER
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Exceptions=EX_VARUNDEF;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
case DECR:
|
|
|
|
{
|
|
|
|
if(rplDepthData()<1) {
|
|
|
|
Exceptions=EX_BADARGCOUNT;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// ONLY ACCEPT IDENTS AS KEYS (ONLY LOW-LEVEL VERSION CAN USE ARBITRARY OBJECTS)
|
|
|
|
|
|
|
|
if(!ISIDENT(*rplPeekData(1))) {
|
|
|
|
Exceptions=EX_BADARGTYPE;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// GET CONTENT FROM LOCAL OR GLOBAL VARIABLE
|
|
|
|
|
2014-05-30 20:17:07 +02:00
|
|
|
WORDPTR *var=rplFindLAM(rplPeekData(1),1);
|
2014-04-28 00:53:11 +02:00
|
|
|
if(!var) var=rplFindGlobal(rplPeekData(1),1);
|
|
|
|
if(var) {
|
|
|
|
rplOverwriteData(1,*(var+1));
|
2014-10-02 03:27:40 +02:00
|
|
|
rplPushData((WORDPTR)one_bint); // PUSH THE NUMBER ONE
|
2014-04-28 00:53:11 +02:00
|
|
|
|
|
|
|
// CALL THE OVERLOADED OPERATOR '+'
|
|
|
|
|
|
|
|
rplCallOvrOperator(OVR_SUB);
|
|
|
|
|
|
|
|
if(Exceptions) return;
|
|
|
|
|
|
|
|
|
|
|
|
*(var+1)=rplPeekData(1); // STORE THE INCREMENTED COUNTER
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Exceptions=EX_VARUNDEF;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case PURGE:
|
|
|
|
// GET CONTENT FROM LOCAL OR GLOBAL VARIABLE
|
|
|
|
if(rplDepthData()<1) {
|
|
|
|
Exceptions=EX_BADARGCOUNT;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// ONLY ACCEPT IDENTS AS KEYS (ONLY LOW-LEVEL VERSION CAN USE ARBITRARY OBJECTS)
|
|
|
|
|
|
|
|
if(!ISIDENT(*rplPeekData(1))) {
|
|
|
|
Exceptions=EX_BADARGTYPE;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: ALSO ACCEPT A LIST OF VARS, WHEN WE HAVE LISTS!
|
|
|
|
|
|
|
|
rplPurgeGlobal(rplPeekData(1));
|
|
|
|
if(!Exceptions) rplDropData(1);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case CRDIR:
|
|
|
|
{
|
|
|
|
// GET CONTENT FROM LOCAL OR GLOBAL VARIABLE
|
|
|
|
if(rplDepthData()<1) {
|
|
|
|
Exceptions=EX_BADARGCOUNT;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// ONLY ACCEPT IDENTS AS KEYS (ONLY LOW-LEVEL VERSION CAN USE ARBITRARY OBJECTS)
|
|
|
|
|
|
|
|
if(!ISIDENT(*rplPeekData(1))) {
|
|
|
|
Exceptions=EX_BADARGTYPE;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
rplCreateNewDir(rplPeekData(1),CurrentDir);
|
|
|
|
|
|
|
|
rplDropData(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case PGDIR:
|
|
|
|
{
|
|
|
|
// SAME AS PURGE BUT RECURSIVELY DELETE EVERYTHING IN NON-EMPTY DIRECTORY
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case UPDIR:
|
|
|
|
{
|
|
|
|
WORDPTR *dir=rplGetParentDir(CurrentDir);
|
|
|
|
if(dir) CurrentDir=dir;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case HOME:
|
|
|
|
CurrentDir=Directories;
|
|
|
|
return;
|
|
|
|
case PATH:
|
|
|
|
|
|
|
|
// TODO: DO THIS LATER
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ADD MORE OPCODES HERE
|
|
|
|
|
|
|
|
case OVR_EVAL:
|
2014-06-01 03:25:13 +02:00
|
|
|
case OVR_XEQ:
|
2014-04-28 00:53:11 +02:00
|
|
|
// EVALUATING THE OBJECT HAS TO CHANGE THE CURRENT DIRECTORY INTO THIS ONE
|
|
|
|
{
|
|
|
|
WORDPTR *dir=rplFindDirbyHandle(rplPeekData(1));
|
|
|
|
|
2014-06-01 03:25:13 +02:00
|
|
|
if(!dir) {
|
|
|
|
Exceptions|=EX_UNDEFINED;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return; // LEAVE THE OBJECT UNEVALUATED. IT'S AN ORPHAN DIRECTORY OBJECT???
|
|
|
|
}
|
2014-04-28 00:53:11 +02:00
|
|
|
CurrentDir=dir;
|
|
|
|
rplDropData(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case OPCODE_DECOMPILE:
|
|
|
|
// DECOMPILE RECEIVES:
|
|
|
|
// DecompileObject = Ptr to prolog of object to decompile
|
|
|
|
// DecompStringEnd = Ptr to the end of decompile string
|
|
|
|
|
|
|
|
//DECOMPILE RETURNS
|
|
|
|
// RetNum = enum DecompileErrors
|
|
|
|
|
|
|
|
if(ISPROLOG(*DecompileObject)) {
|
|
|
|
rplDecompAppendString2((BYTEPTR)"DIRObject",9);
|
|
|
|
|
|
|
|
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.
|
2014-06-18 15:35:43 +02:00
|
|
|
// Library receives:
|
|
|
|
// CurrentConstruct = SET TO THE CURRENT ACTIVE CONSTRUCT TYPE
|
|
|
|
// LastCompiledObject = POINTER TO THE LAST OBJECT THAT WAS COMPILED, THAT NEEDS TO BE VERIFIED
|
2014-04-28 00:53:11 +02:00
|
|
|
|
|
|
|
// VALIDATE RETURNS:
|
2014-06-18 15:35:43 +02:00
|
|
|
// RetNum = OK_CONTINUE IF THE OBJECT IS ACCEPTED, ERR_INVALID IF NOT.
|
2014-04-28 00:53:11 +02:00
|
|
|
|
|
|
|
|
2014-06-18 15:35:43 +02:00
|
|
|
RetNum=OK_CONTINUE;
|
2014-04-28 00:53:11 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-07-08 02:43:44 +02:00
|
|
|
// UNHANDLED OPCODE...
|
|
|
|
|
|
|
|
// IF IT'S A COMPILER OPCODE, RETURN ERR_NOTMINE
|
|
|
|
if(OPCODE(CurOpcode)>=MIN_RESERVED_OPCODE) {
|
|
|
|
RetNum=ERR_NOTMINE;
|
|
|
|
return;
|
|
|
|
}
|
2014-04-28 00:53:11 +02:00
|
|
|
// BY DEFAULT, ISSUE A BAD OPCODE ERROR
|
|
|
|
Exceptions|=EX_BADOPCODE;
|
|
|
|
ExceptionPointer=IPtr;
|
|
|
|
return;
|
|
|
|
|
2014-07-08 02:43:44 +02:00
|
|
|
|
2014-04-28 00:53:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|