mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Renemed all variables to fit into a namespace
Basically, all Toy varaibles, functions, etc. are prepended with "Toy_", and macros are prepended with "TOY_". This is to reduce namespace pollution, which was an issue pointed out to be - blame @GyroVorbis. I've also bumped the minor version number - theoretically I should bump the major number, but I'm not quite ready for 1.0 yet.
This commit is contained in:
@@ -1,23 +1,23 @@
|
|||||||
#include "lib_runner.h"
|
#include "lib_runner.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
#include "repl_tools.h"
|
#include "repl_tools.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
typedef struct Runner {
|
typedef struct Toy_Runner {
|
||||||
Interpreter interpreter;
|
Toy_Interpreter interpreter;
|
||||||
unsigned char* bytecode;
|
unsigned char* bytecode;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
bool dirty;
|
bool dirty;
|
||||||
} Runner;
|
} Toy_Runner;
|
||||||
|
|
||||||
//Toy native functions
|
//Toy native functions
|
||||||
static int nativeLoadScript(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeLoadScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//arguments
|
//arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to loadScript\n");
|
interpreter->errorOutput("Incorrect number of arguments to loadScript\n");
|
||||||
@@ -25,60 +25,60 @@ static int nativeLoadScript(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the argument
|
//get the argument
|
||||||
Literal drivePathLiteral = popLiteralArray(arguments);
|
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
|
||||||
RefString* drivePath = copyRefString(AS_STRING(drivePathLiteral));
|
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral));
|
||||||
|
|
||||||
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
|
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
|
||||||
int driveLength = 0;
|
int driveLength = 0;
|
||||||
while (toCString(drivePath)[driveLength] != ':') {
|
while (Toy_toCString(drivePath)[driveLength] != ':') {
|
||||||
if (driveLength >= lengthRefString(drivePath)) {
|
if (driveLength >= Toy_lengthRefString(drivePath)) {
|
||||||
interpreter->errorOutput("Incorrect drive path format given to loadScript\n");
|
interpreter->errorOutput("Incorrect drive path format given to loadScript\n");
|
||||||
deleteRefString(drivePath);
|
Toy_deleteRefString(drivePath);
|
||||||
freeLiteral(drivePathLiteral);
|
Toy_freeLiteral(drivePathLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
driveLength++;
|
driveLength++;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefString* drive = createRefStringLength(toCString(drivePath), driveLength);
|
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
|
||||||
RefString* path = createRefStringLength( &toCString(drivePath)[driveLength + 1], lengthRefString(drivePath) - driveLength );
|
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
|
||||||
|
|
||||||
//get the real drive file path
|
//get the real drive file path
|
||||||
Literal driveLiteral = TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
|
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
|
||||||
Literal realDriveLiteral = getLiteralDictionary(getDriveDictionary(), driveLiteral);
|
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
|
||||||
|
|
||||||
if (!IS_STRING(realDriveLiteral)) {
|
if (!TOY_IS_STRING(realDriveLiteral)) {
|
||||||
interpreter->errorOutput("Incorrect literal type found for drive: ");
|
interpreter->errorOutput("Incorrect literal type found for drive: ");
|
||||||
printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
|
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
|
||||||
interpreter->errorOutput("\n");
|
interpreter->errorOutput("\n");
|
||||||
freeLiteral(realDriveLiteral);
|
Toy_freeLiteral(realDriveLiteral);
|
||||||
freeLiteral(driveLiteral);
|
Toy_freeLiteral(driveLiteral);
|
||||||
deleteRefString(path);
|
Toy_deleteRefString(path);
|
||||||
deleteRefString(drivePath);
|
Toy_deleteRefString(drivePath);
|
||||||
freeLiteral(drivePathLiteral);
|
Toy_freeLiteral(drivePathLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the final real file path (concat) TODO: move this concat to refstring library
|
//get the final real file path (concat) TODO: move this concat to refstring library
|
||||||
RefString* realDrive = copyRefString(AS_STRING(realDriveLiteral));
|
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
|
||||||
int realLength = lengthRefString(realDrive) + lengthRefString(path);
|
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
|
||||||
|
|
||||||
char* filePath = ALLOCATE(char, realLength + 1); //+1 for null
|
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
|
||||||
snprintf(filePath, realLength, "%s%s", toCString(realDrive), toCString(path));
|
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
|
||||||
|
|
||||||
//clean up the drivepath stuff
|
//clean up the drivepath stuff
|
||||||
deleteRefString(realDrive);
|
Toy_deleteRefString(realDrive);
|
||||||
freeLiteral(realDriveLiteral);
|
Toy_freeLiteral(realDriveLiteral);
|
||||||
freeLiteral(driveLiteral);
|
Toy_freeLiteral(driveLiteral);
|
||||||
deleteRefString(path);
|
Toy_deleteRefString(path);
|
||||||
deleteRefString(drivePath);
|
Toy_deleteRefString(drivePath);
|
||||||
freeLiteral(drivePathLiteral);
|
Toy_freeLiteral(drivePathLiteral);
|
||||||
|
|
||||||
//check for file extensions
|
//check for file extensions
|
||||||
if (!(filePath[realLength - 5] == '.' && filePath[realLength - 4] == 't' && filePath[realLength - 3] == 'o' && filePath[realLength - 2] == 'y')) {
|
if (!(filePath[realLength - 5] == '.' && filePath[realLength - 4] == 't' && filePath[realLength - 3] == 'o' && filePath[realLength - 2] == 'y')) {
|
||||||
interpreter->errorOutput("Bad script file extension (expected .toy)\n");
|
interpreter->errorOutput("Bad script file extension (expected .toy)\n");
|
||||||
FREE_ARRAY(char, filePath, realLength);
|
TOY_FREE_ARRAY(char, filePath, realLength);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,21 +86,21 @@ static int nativeLoadScript(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
for (int i = 0; i < realLength - 1; i++) {
|
for (int i = 0; i < realLength - 1; i++) {
|
||||||
if (filePath[i] == '.' && filePath[i + 1] == '.') {
|
if (filePath[i] == '.' && filePath[i + 1] == '.') {
|
||||||
interpreter->errorOutput("Parent directory access not allowed\n");
|
interpreter->errorOutput("Parent directory access not allowed\n");
|
||||||
FREE_ARRAY(char, filePath, realLength);
|
TOY_FREE_ARRAY(char, filePath, realLength);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//load and compile the bytecode
|
//load and compile the bytecode
|
||||||
size_t fileSize = 0;
|
size_t fileSize = 0;
|
||||||
char* source = readFile(filePath, &fileSize);
|
char* source = Toy_readFile(filePath, &fileSize);
|
||||||
|
|
||||||
if (!source) {
|
if (!source) {
|
||||||
interpreter->errorOutput("Failed to load source file\n");
|
interpreter->errorOutput("Failed to load source file\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* bytecode = compileString(source, &fileSize);
|
unsigned char* bytecode = Toy_compileString(source, &fileSize);
|
||||||
free((void*)source);
|
free((void*)source);
|
||||||
|
|
||||||
if (!bytecode) {
|
if (!bytecode) {
|
||||||
@@ -109,27 +109,27 @@ static int nativeLoadScript(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//build the runner object
|
//build the runner object
|
||||||
Runner* runner = ALLOCATE(Runner, 1);
|
Toy_Runner* runner = TOY_ALLOCATE(Toy_Runner, 1);
|
||||||
setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
|
Toy_setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
|
||||||
setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
|
Toy_setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
|
||||||
setInterpreterError(&runner->interpreter, interpreter->errorOutput);
|
Toy_setInterpreterError(&runner->interpreter, interpreter->errorOutput);
|
||||||
runner->interpreter.hooks = interpreter->hooks;
|
runner->interpreter.hooks = interpreter->hooks;
|
||||||
runner->interpreter.scope = NULL;
|
runner->interpreter.scope = NULL;
|
||||||
resetInterpreter(&runner->interpreter);
|
Toy_resetInterpreter(&runner->interpreter);
|
||||||
runner->bytecode = bytecode;
|
runner->bytecode = bytecode;
|
||||||
runner->size = fileSize;
|
runner->size = fileSize;
|
||||||
runner->dirty = false;
|
runner->dirty = false;
|
||||||
|
|
||||||
//build the opaque object, and push it to the stack
|
//build the opaque object, and push it to the stack
|
||||||
Literal runnerLiteral = TO_OPAQUE_LITERAL(runner, OPAQUE_TAG_RUNNER);
|
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
|
||||||
pushLiteralArray(&interpreter->stack, runnerLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
|
||||||
|
|
||||||
FREE_ARRAY(char, filePath, realLength);
|
TOY_FREE_ARRAY(char, filePath, realLength);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeLoadScriptBytecode(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeLoadScriptBytecode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//arguments
|
//arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to loadScriptBytecode\n");
|
interpreter->errorOutput("Incorrect number of arguments to loadScriptBytecode\n");
|
||||||
@@ -137,60 +137,60 @@ static int nativeLoadScriptBytecode(Interpreter* interpreter, LiteralArray* argu
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the argument
|
//get the argument
|
||||||
Literal drivePathLiteral = popLiteralArray(arguments);
|
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
|
||||||
RefString* drivePath = copyRefString(AS_STRING(drivePathLiteral));
|
Toy_RefString* drivePath = Toy_copyRefString(TOY_AS_STRING(drivePathLiteral));
|
||||||
|
|
||||||
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
|
//get the drive and path as a string (can't trust that pesky strtok - custom split) TODO: move this to refstring library
|
||||||
int driveLength = 0;
|
int driveLength = 0;
|
||||||
while (toCString(drivePath)[driveLength] != ':') {
|
while (Toy_toCString(drivePath)[driveLength] != ':') {
|
||||||
if (driveLength >= lengthRefString(drivePath)) {
|
if (driveLength >= Toy_lengthRefString(drivePath)) {
|
||||||
interpreter->errorOutput("Incorrect drive path format given to loadScriptBytecode\n");
|
interpreter->errorOutput("Incorrect drive path format given to loadScriptBytecode\n");
|
||||||
deleteRefString(drivePath);
|
Toy_deleteRefString(drivePath);
|
||||||
freeLiteral(drivePathLiteral);
|
Toy_freeLiteral(drivePathLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
driveLength++;
|
driveLength++;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefString* drive = createRefStringLength(toCString(drivePath), driveLength);
|
Toy_RefString* drive = Toy_createRefStringLength(Toy_toCString(drivePath), driveLength);
|
||||||
RefString* path = createRefStringLength( &toCString(drivePath)[driveLength + 1], lengthRefString(drivePath) - driveLength );
|
Toy_RefString* path = Toy_createRefStringLength( &Toy_toCString(drivePath)[driveLength + 1], Toy_lengthRefString(drivePath) - driveLength );
|
||||||
|
|
||||||
//get the real drive file path
|
//get the real drive file path
|
||||||
Literal driveLiteral = TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
|
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(drive); //NOTE: driveLiteral takes ownership of the refString
|
||||||
Literal realDriveLiteral = getLiteralDictionary(getDriveDictionary(), driveLiteral);
|
Toy_Literal realDriveLiteral = Toy_getLiteralDictionary(Toy_getDriveDictionary(), driveLiteral);
|
||||||
|
|
||||||
if (!IS_STRING(realDriveLiteral)) {
|
if (!TOY_IS_STRING(realDriveLiteral)) {
|
||||||
interpreter->errorOutput("Incorrect literal type found for drive: ");
|
interpreter->errorOutput("Incorrect literal type found for drive: ");
|
||||||
printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
|
Toy_printLiteralCustom(realDriveLiteral, interpreter->errorOutput);
|
||||||
interpreter->errorOutput("\n");
|
interpreter->errorOutput("\n");
|
||||||
freeLiteral(realDriveLiteral);
|
Toy_freeLiteral(realDriveLiteral);
|
||||||
freeLiteral(driveLiteral);
|
Toy_freeLiteral(driveLiteral);
|
||||||
deleteRefString(path);
|
Toy_deleteRefString(path);
|
||||||
deleteRefString(drivePath);
|
Toy_deleteRefString(drivePath);
|
||||||
freeLiteral(drivePathLiteral);
|
Toy_freeLiteral(drivePathLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the final real file path (concat) TODO: move this concat to refstring library
|
//get the final real file path (concat) TODO: move this concat to refstring library
|
||||||
RefString* realDrive = copyRefString(AS_STRING(realDriveLiteral));
|
Toy_RefString* realDrive = Toy_copyRefString(TOY_AS_STRING(realDriveLiteral));
|
||||||
int realLength = lengthRefString(realDrive) + lengthRefString(path);
|
int realLength = Toy_lengthRefString(realDrive) + Toy_lengthRefString(path);
|
||||||
|
|
||||||
char* filePath = ALLOCATE(char, realLength + 1); //+1 for null
|
char* filePath = TOY_ALLOCATE(char, realLength + 1); //+1 for null
|
||||||
snprintf(filePath, realLength, "%s%s", toCString(realDrive), toCString(path));
|
snprintf(filePath, realLength, "%s%s", Toy_toCString(realDrive), Toy_toCString(path));
|
||||||
|
|
||||||
//clean up the drivepath stuff
|
//clean up the drivepath stuff
|
||||||
deleteRefString(realDrive);
|
Toy_deleteRefString(realDrive);
|
||||||
freeLiteral(realDriveLiteral);
|
Toy_freeLiteral(realDriveLiteral);
|
||||||
freeLiteral(driveLiteral);
|
Toy_freeLiteral(driveLiteral);
|
||||||
deleteRefString(path);
|
Toy_deleteRefString(path);
|
||||||
deleteRefString(drivePath);
|
Toy_deleteRefString(drivePath);
|
||||||
freeLiteral(drivePathLiteral);
|
Toy_freeLiteral(drivePathLiteral);
|
||||||
|
|
||||||
//check for file extensions
|
//check for file extensions
|
||||||
if (!(filePath[realLength - 4] == '.' && filePath[realLength - 3] == 't' && filePath[realLength - 2] == 'b')) {
|
if (!(filePath[realLength - 4] == '.' && filePath[realLength - 3] == 't' && filePath[realLength - 2] == 'b')) {
|
||||||
interpreter->errorOutput("Bad binary file extension (expected .tb)\n");
|
interpreter->errorOutput("Bad binary file extension (expected .tb)\n");
|
||||||
FREE_ARRAY(char, filePath, realLength);
|
TOY_FREE_ARRAY(char, filePath, realLength);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,14 +198,14 @@ static int nativeLoadScriptBytecode(Interpreter* interpreter, LiteralArray* argu
|
|||||||
for (int i = 0; i < realLength - 1; i++) {
|
for (int i = 0; i < realLength - 1; i++) {
|
||||||
if (filePath[i] == '.' && filePath[i + 1] == '.') {
|
if (filePath[i] == '.' && filePath[i + 1] == '.') {
|
||||||
interpreter->errorOutput("Parent directory access not allowed\n");
|
interpreter->errorOutput("Parent directory access not allowed\n");
|
||||||
FREE_ARRAY(char, filePath, realLength);
|
TOY_FREE_ARRAY(char, filePath, realLength);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//load the bytecode
|
//load the bytecode
|
||||||
size_t fileSize = 0;
|
size_t fileSize = 0;
|
||||||
unsigned char* bytecode = (unsigned char*)readFile(filePath, &fileSize);
|
unsigned char* bytecode = (unsigned char*)Toy_readFile(filePath, &fileSize);
|
||||||
|
|
||||||
if (!bytecode) {
|
if (!bytecode) {
|
||||||
interpreter->errorOutput("Failed to load bytecode file\n");
|
interpreter->errorOutput("Failed to load bytecode file\n");
|
||||||
@@ -213,27 +213,27 @@ static int nativeLoadScriptBytecode(Interpreter* interpreter, LiteralArray* argu
|
|||||||
}
|
}
|
||||||
|
|
||||||
//build the runner object
|
//build the runner object
|
||||||
Runner* runner = ALLOCATE(Runner, 1);
|
Toy_Runner* runner = TOY_ALLOCATE(Toy_Runner, 1);
|
||||||
setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
|
Toy_setInterpreterPrint(&runner->interpreter, interpreter->printOutput);
|
||||||
setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
|
Toy_setInterpreterAssert(&runner->interpreter, interpreter->assertOutput);
|
||||||
setInterpreterError(&runner->interpreter, interpreter->errorOutput);
|
Toy_setInterpreterError(&runner->interpreter, interpreter->errorOutput);
|
||||||
runner->interpreter.hooks = interpreter->hooks;
|
runner->interpreter.hooks = interpreter->hooks;
|
||||||
runner->interpreter.scope = NULL;
|
runner->interpreter.scope = NULL;
|
||||||
resetInterpreter(&runner->interpreter);
|
Toy_resetInterpreter(&runner->interpreter);
|
||||||
runner->bytecode = bytecode;
|
runner->bytecode = bytecode;
|
||||||
runner->size = fileSize;
|
runner->size = fileSize;
|
||||||
runner->dirty = false;
|
runner->dirty = false;
|
||||||
|
|
||||||
//build the opaque object, and push it to the stack
|
//build the opaque object, and push it to the stack
|
||||||
Literal runnerLiteral = TO_OPAQUE_LITERAL(runner, OPAQUE_TAG_RUNNER);
|
Toy_Literal runnerLiteral = TOY_TO_OPAQUE_LITERAL(runner, TOY_OPAQUE_TAG_RUNNER);
|
||||||
pushLiteralArray(&interpreter->stack, runnerLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, runnerLiteral);
|
||||||
|
|
||||||
FREE_ARRAY(char, filePath, realLength);
|
TOY_FREE_ARRAY(char, filePath, realLength);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeRunScript(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeRunScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
|
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
|
||||||
@@ -241,40 +241,40 @@ static int nativeRunScript(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the runner object
|
//get the runner object
|
||||||
Literal runnerLiteral = popLiteralArray(arguments);
|
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal runnerIdn = runnerLiteral;
|
Toy_Literal runnerIdn = runnerLiteral;
|
||||||
if (IS_IDENTIFIER(runnerLiteral) && parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
||||||
freeLiteral(runnerIdn);
|
Toy_freeLiteral(runnerIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
|
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
|
||||||
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Runner* runner = AS_OPAQUE(runnerLiteral);
|
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
if (runner->dirty) {
|
if (runner->dirty) {
|
||||||
interpreter->errorOutput("Can't re-run a dirty script (try resetting it first)\n");
|
interpreter->errorOutput("Can't re-run a dirty script (try resetting it first)\n");
|
||||||
freeLiteral(runnerLiteral);
|
Toy_freeLiteral(runnerLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* bytecodeCopy = ALLOCATE(unsigned char, runner->size);
|
unsigned char* bytecodeCopy = TOY_ALLOCATE(unsigned char, runner->size);
|
||||||
memcpy(bytecodeCopy, runner->bytecode, runner->size); //need a COPY of the bytecode, because the interpreter eats it
|
memcpy(bytecodeCopy, runner->bytecode, runner->size); //need a COPY of the bytecode, because the interpreter eats it
|
||||||
|
|
||||||
runInterpreter(&runner->interpreter, bytecodeCopy, runner->size);
|
Toy_runInterpreter(&runner->interpreter, bytecodeCopy, runner->size);
|
||||||
runner->dirty = true;
|
runner->dirty = true;
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(runnerLiteral);
|
Toy_freeLiteral(runnerLiteral);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeGetScriptVar(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeGetScriptVar(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 2) {
|
if (arguments->count != 2) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _getScriptVar\n");
|
interpreter->errorOutput("Incorrect number of arguments to _getScriptVar\n");
|
||||||
@@ -282,50 +282,50 @@ static int nativeGetScriptVar(Interpreter* interpreter, LiteralArray* arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the runner object
|
//get the runner object
|
||||||
Literal varName = popLiteralArray(arguments);
|
Toy_Literal varName = Toy_popLiteralArray(arguments);
|
||||||
Literal runnerLiteral = popLiteralArray(arguments);
|
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal varNameIdn = varName;
|
Toy_Literal varNameIdn = varName;
|
||||||
if (IS_IDENTIFIER(varName) && parseIdentifierToValue(interpreter, &varName)) {
|
if (TOY_IS_IDENTIFIER(varName) && Toy_parseIdentifierToValue(interpreter, &varName)) {
|
||||||
freeLiteral(varNameIdn);
|
Toy_freeLiteral(varNameIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal runnerIdn = runnerLiteral;
|
Toy_Literal runnerIdn = runnerLiteral;
|
||||||
if (IS_IDENTIFIER(runnerLiteral) && parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
||||||
freeLiteral(runnerIdn);
|
Toy_freeLiteral(runnerIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
|
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
|
||||||
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Runner* runner = AS_OPAQUE(runnerLiteral);
|
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
|
||||||
|
|
||||||
//dirty check
|
//dirty check
|
||||||
if (!runner->dirty) {
|
if (!runner->dirty) {
|
||||||
interpreter->errorOutput("Can't access variable from a non-dirty script (try running it first)\n");
|
interpreter->errorOutput("Can't access variable from a non-dirty script (try running it first)\n");
|
||||||
freeLiteral(runnerLiteral);
|
Toy_freeLiteral(runnerLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the desired variable
|
//get the desired variable
|
||||||
Literal varIdn = TO_IDENTIFIER_LITERAL(copyRefString(AS_STRING(varName)));
|
Toy_Literal varIdn = TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_STRING(varName)));
|
||||||
Literal result = TO_NULL_LITERAL;
|
Toy_Literal result = TOY_TO_NULL_LITERAL;
|
||||||
getScopeVariable(runner->interpreter.scope, varIdn, &result);
|
Toy_getScopeVariable(runner->interpreter.scope, varIdn, &result);
|
||||||
|
|
||||||
pushLiteralArray(&interpreter->stack, result);
|
Toy_pushLiteralArray(&interpreter->stack, result);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(result);
|
Toy_freeLiteral(result);
|
||||||
freeLiteral(varIdn);
|
Toy_freeLiteral(varIdn);
|
||||||
freeLiteral(varName);
|
Toy_freeLiteral(varName);
|
||||||
freeLiteral(runnerLiteral);
|
Toy_freeLiteral(runnerLiteral);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeCallScriptFn(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeCallScriptFn(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count < 2) {
|
if (arguments->count < 2) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _callScriptFn\n");
|
interpreter->errorOutput("Incorrect number of arguments to _callScriptFn\n");
|
||||||
@@ -333,96 +333,96 @@ static int nativeCallScriptFn(Interpreter* interpreter, LiteralArray* arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the rest args
|
//get the rest args
|
||||||
LiteralArray tmp;
|
Toy_LiteralArray tmp;
|
||||||
initLiteralArray(&tmp);
|
Toy_initLiteralArray(&tmp);
|
||||||
|
|
||||||
while (arguments->count > 2) {
|
while (arguments->count > 2) {
|
||||||
Literal lit = popLiteralArray(arguments);
|
Toy_Literal lit = Toy_popLiteralArray(arguments);
|
||||||
pushLiteralArray(&tmp, lit);
|
Toy_pushLiteralArray(&tmp, lit);
|
||||||
freeLiteral(lit);
|
Toy_freeLiteral(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
LiteralArray rest;
|
Toy_LiteralArray rest;
|
||||||
initLiteralArray(&rest);
|
Toy_initLiteralArray(&rest);
|
||||||
|
|
||||||
while (tmp.count) { //correct the order of the rest args
|
while (tmp.count) { //correct the order of the rest args
|
||||||
Literal lit = popLiteralArray(&tmp);
|
Toy_Literal lit = Toy_popLiteralArray(&tmp);
|
||||||
pushLiteralArray(&rest, lit);
|
Toy_pushLiteralArray(&rest, lit);
|
||||||
freeLiteral(lit);
|
Toy_freeLiteral(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
freeLiteralArray(&tmp);
|
Toy_freeLiteralArray(&tmp);
|
||||||
|
|
||||||
|
|
||||||
//get the runner object
|
//get the runner object
|
||||||
Literal varName = popLiteralArray(arguments);
|
Toy_Literal varName = Toy_popLiteralArray(arguments);
|
||||||
Literal runnerLiteral = popLiteralArray(arguments);
|
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal varNameIdn = varName;
|
Toy_Literal varNameIdn = varName;
|
||||||
if (IS_IDENTIFIER(varName) && parseIdentifierToValue(interpreter, &varName)) {
|
if (TOY_IS_IDENTIFIER(varName) && Toy_parseIdentifierToValue(interpreter, &varName)) {
|
||||||
freeLiteral(varNameIdn);
|
Toy_freeLiteral(varNameIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal runnerIdn = runnerLiteral;
|
Toy_Literal runnerIdn = runnerLiteral;
|
||||||
if (IS_IDENTIFIER(runnerLiteral) && parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
||||||
freeLiteral(runnerIdn);
|
Toy_freeLiteral(runnerIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
|
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
|
||||||
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Runner* runner = AS_OPAQUE(runnerLiteral);
|
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
|
||||||
|
|
||||||
//dirty check
|
//dirty check
|
||||||
if (!runner->dirty) {
|
if (!runner->dirty) {
|
||||||
interpreter->errorOutput("Can't access fn from a non-dirty script (try running it first)\n");
|
interpreter->errorOutput("Can't access fn from a non-dirty script (try running it first)\n");
|
||||||
freeLiteral(runnerLiteral);
|
Toy_freeLiteral(runnerLiteral);
|
||||||
freeLiteralArray(&rest);
|
Toy_freeLiteralArray(&rest);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the desired variable
|
//get the desired variable
|
||||||
Literal varIdn = TO_IDENTIFIER_LITERAL(copyRefString(AS_STRING(varName)));
|
Toy_Literal varIdn = TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_STRING(varName)));
|
||||||
Literal fn = TO_NULL_LITERAL;
|
Toy_Literal fn = TOY_TO_NULL_LITERAL;
|
||||||
getScopeVariable(runner->interpreter.scope, varIdn, &fn);
|
Toy_getScopeVariable(runner->interpreter.scope, varIdn, &fn);
|
||||||
|
|
||||||
if (!IS_FUNCTION(fn)) {
|
if (!TOY_IS_FUNCTION(fn)) {
|
||||||
interpreter->errorOutput("Can't run a non-function literal\n");
|
interpreter->errorOutput("Can't run a non-function literal\n");
|
||||||
freeLiteral(fn);
|
Toy_freeLiteral(fn);
|
||||||
freeLiteral(varIdn);
|
Toy_freeLiteral(varIdn);
|
||||||
freeLiteral(varName);
|
Toy_freeLiteral(varName);
|
||||||
freeLiteral(runnerLiteral);
|
Toy_freeLiteral(runnerLiteral);
|
||||||
freeLiteralArray(&rest);
|
Toy_freeLiteralArray(&rest);
|
||||||
}
|
}
|
||||||
|
|
||||||
//call
|
//call
|
||||||
LiteralArray resultArray;
|
Toy_LiteralArray resultArray;
|
||||||
initLiteralArray(&resultArray);
|
Toy_initLiteralArray(&resultArray);
|
||||||
|
|
||||||
callLiteralFn(interpreter, fn, &rest, &resultArray);
|
Toy_callLiteralFn(interpreter, fn, &rest, &resultArray);
|
||||||
|
|
||||||
Literal result = TO_NULL_LITERAL;
|
Toy_Literal result = TOY_TO_NULL_LITERAL;
|
||||||
if (resultArray.count > 0) {
|
if (resultArray.count > 0) {
|
||||||
result = popLiteralArray(&resultArray);
|
result = Toy_popLiteralArray(&resultArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
pushLiteralArray(&interpreter->stack, result);
|
Toy_pushLiteralArray(&interpreter->stack, result);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteralArray(&resultArray);
|
Toy_freeLiteralArray(&resultArray);
|
||||||
freeLiteral(result);
|
Toy_freeLiteral(result);
|
||||||
freeLiteral(fn);
|
Toy_freeLiteral(fn);
|
||||||
freeLiteral(varIdn);
|
Toy_freeLiteral(varIdn);
|
||||||
freeLiteral(varName);
|
Toy_freeLiteral(varName);
|
||||||
freeLiteral(runnerLiteral);
|
Toy_freeLiteral(runnerLiteral);
|
||||||
freeLiteralArray(&rest);
|
Toy_freeLiteralArray(&rest);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeResetScript(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeResetScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _resetScript\n");
|
interpreter->errorOutput("Incorrect number of arguments to _resetScript\n");
|
||||||
@@ -430,35 +430,35 @@ static int nativeResetScript(Interpreter* interpreter, LiteralArray* arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the runner object
|
//get the runner object
|
||||||
Literal runnerLiteral = popLiteralArray(arguments);
|
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal runnerIdn = runnerLiteral;
|
Toy_Literal runnerIdn = runnerLiteral;
|
||||||
if (IS_IDENTIFIER(runnerLiteral) && parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
||||||
freeLiteral(runnerIdn);
|
Toy_freeLiteral(runnerIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
|
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
|
||||||
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Runner* runner = AS_OPAQUE(runnerLiteral);
|
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
|
||||||
|
|
||||||
//reset
|
//reset
|
||||||
if (!runner->dirty) {
|
if (!runner->dirty) {
|
||||||
interpreter->errorOutput("Can't reset a non-dirty script (try running it first)\n");
|
interpreter->errorOutput("Can't reset a non-dirty script (try running it first)\n");
|
||||||
freeLiteral(runnerLiteral);
|
Toy_freeLiteral(runnerLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
resetInterpreter(&runner->interpreter);
|
Toy_resetInterpreter(&runner->interpreter);
|
||||||
runner->dirty = false;
|
runner->dirty = false;
|
||||||
freeLiteral(runnerLiteral);
|
Toy_freeLiteral(runnerLiteral);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeFreeScript(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeFreeScript(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _freeScript\n");
|
interpreter->errorOutput("Incorrect number of arguments to _freeScript\n");
|
||||||
@@ -466,33 +466,33 @@ static int nativeFreeScript(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the runner object
|
//get the runner object
|
||||||
Literal runnerLiteral = popLiteralArray(arguments);
|
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal runnerIdn = runnerLiteral;
|
Toy_Literal runnerIdn = runnerLiteral;
|
||||||
if (IS_IDENTIFIER(runnerLiteral) && parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
||||||
freeLiteral(runnerIdn);
|
Toy_freeLiteral(runnerIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
|
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
|
||||||
interpreter->errorOutput("Unrecognized opaque literal in _freeScript\n");
|
interpreter->errorOutput("Unrecognized opaque literal in _freeScript\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Runner* runner = AS_OPAQUE(runnerLiteral);
|
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
|
||||||
|
|
||||||
//clear out the runner object
|
//clear out the runner object
|
||||||
runner->interpreter.hooks = NULL;
|
runner->interpreter.hooks = NULL;
|
||||||
freeInterpreter(&runner->interpreter);
|
Toy_freeInterpreter(&runner->interpreter);
|
||||||
FREE_ARRAY(unsigned char, runner->bytecode, runner->size);
|
TOY_FREE_ARRAY(unsigned char, runner->bytecode, runner->size);
|
||||||
|
|
||||||
FREE(Runner, runner);
|
TOY_FREE(Toy_Runner, runner);
|
||||||
|
|
||||||
freeLiteral(runnerLiteral);
|
Toy_freeLiteral(runnerLiteral);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeCheckScriptDirty(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeCheckScriptDirty(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
|
interpreter->errorOutput("Incorrect number of arguments to _runScript\n");
|
||||||
@@ -500,28 +500,28 @@ static int nativeCheckScriptDirty(Interpreter* interpreter, LiteralArray* argume
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the runner object
|
//get the runner object
|
||||||
Literal runnerLiteral = popLiteralArray(arguments);
|
Toy_Literal runnerLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal runnerIdn = runnerLiteral;
|
Toy_Literal runnerIdn = runnerLiteral;
|
||||||
if (IS_IDENTIFIER(runnerLiteral) && parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
if (TOY_IS_IDENTIFIER(runnerLiteral) && Toy_parseIdentifierToValue(interpreter, &runnerLiteral)) {
|
||||||
freeLiteral(runnerIdn);
|
Toy_freeLiteral(runnerIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OPAQUE_TAG(runnerLiteral) != OPAQUE_TAG_RUNNER) {
|
if (TOY_GET_OPAQUE_TAG(runnerLiteral) != TOY_OPAQUE_TAG_RUNNER) {
|
||||||
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
interpreter->errorOutput("Unrecognized opaque literal in _runScript\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Runner* runner = AS_OPAQUE(runnerLiteral);
|
Toy_Runner* runner = TOY_AS_OPAQUE(runnerLiteral);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
Literal result = TO_BOOLEAN_LITERAL(runner->dirty);
|
Toy_Literal result = TOY_TO_BOOLEAN_LITERAL(runner->dirty);
|
||||||
|
|
||||||
pushLiteralArray(&interpreter->stack, result);
|
Toy_pushLiteralArray(&interpreter->stack, result);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(result);
|
Toy_freeLiteral(result);
|
||||||
freeLiteral(runnerLiteral);
|
Toy_freeLiteral(runnerLiteral);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -529,10 +529,10 @@ static int nativeCheckScriptDirty(Interpreter* interpreter, LiteralArray* argume
|
|||||||
//call the hook
|
//call the hook
|
||||||
typedef struct Natives {
|
typedef struct Natives {
|
||||||
char* name;
|
char* name;
|
||||||
NativeFn fn;
|
Toy_NativeFn fn;
|
||||||
} Natives;
|
} Natives;
|
||||||
|
|
||||||
int hookRunner(Interpreter* interpreter, Literal identifier, Literal alias) {
|
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
|
||||||
//build the natives list
|
//build the natives list
|
||||||
Natives natives[] = {
|
Natives natives[] = {
|
||||||
{"loadScript", nativeLoadScript},
|
{"loadScript", nativeLoadScript},
|
||||||
@@ -547,67 +547,67 @@ int hookRunner(Interpreter* interpreter, Literal identifier, Literal alias) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//store the library in an aliased dictionary
|
//store the library in an aliased dictionary
|
||||||
if (!IS_NULL(alias)) {
|
if (!TOY_IS_NULL(alias)) {
|
||||||
//make sure the name isn't taken
|
//make sure the name isn't taken
|
||||||
if (isDelcaredScopeVariable(interpreter->scope, alias)) {
|
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
|
||||||
interpreter->errorOutput("Can't override an existing variable\n");
|
interpreter->errorOutput("Can't override an existing variable\n");
|
||||||
freeLiteral(alias);
|
Toy_freeLiteral(alias);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//create the dictionary to load up with functions
|
//create the dictionary to load up with functions
|
||||||
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
|
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
|
||||||
initLiteralDictionary(dictionary);
|
Toy_initLiteralDictionary(dictionary);
|
||||||
|
|
||||||
//load the dict with functions
|
//load the dict with functions
|
||||||
for (int i = 0; natives[i].name; i++) {
|
for (int i = 0; natives[i].name; i++) {
|
||||||
Literal name = TO_STRING_LITERAL(createRefString(natives[i].name));
|
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
|
||||||
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
||||||
func.type = LITERAL_FUNCTION_NATIVE;
|
func.type = TOY_LITERAL_FUNCTION_NATIVE;
|
||||||
|
|
||||||
setLiteralDictionary(dictionary, name, func);
|
Toy_setLiteralDictionary(dictionary, name, func);
|
||||||
|
|
||||||
freeLiteral(name);
|
Toy_freeLiteral(name);
|
||||||
freeLiteral(func);
|
Toy_freeLiteral(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
//build the type
|
//build the type
|
||||||
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, true);
|
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
|
||||||
Literal strType = TO_TYPE_LITERAL(LITERAL_STRING, true);
|
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
|
||||||
Literal fnType = TO_TYPE_LITERAL(LITERAL_FUNCTION_NATIVE, true);
|
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
|
||||||
TYPE_PUSH_SUBTYPE(&type, strType);
|
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
|
||||||
TYPE_PUSH_SUBTYPE(&type, fnType);
|
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
|
||||||
|
|
||||||
//set scope
|
//set scope
|
||||||
Literal dict = TO_DICTIONARY_LITERAL(dictionary);
|
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
|
||||||
declareScopeVariable(interpreter->scope, alias, type);
|
Toy_declareScopeVariable(interpreter->scope, alias, type);
|
||||||
setScopeVariable(interpreter->scope, alias, dict, false);
|
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(dict);
|
Toy_freeLiteral(dict);
|
||||||
freeLiteral(type);
|
Toy_freeLiteral(type);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//default
|
//default
|
||||||
for (int i = 0; natives[i].name; i++) {
|
for (int i = 0; natives[i].name; i++) {
|
||||||
injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//file system API
|
//file system API
|
||||||
static LiteralDictionary driveDictionary;
|
static Toy_LiteralDictionary Toy_driveDictionary;
|
||||||
|
|
||||||
void initDriveDictionary() {
|
void Toy_initDriveDictionary() {
|
||||||
initLiteralDictionary(&driveDictionary);
|
Toy_initLiteralDictionary(&Toy_driveDictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeDriveDictionary() {
|
void Toy_freeDriveDictionary() {
|
||||||
freeLiteralDictionary(&driveDictionary);
|
Toy_freeLiteralDictionary(&Toy_driveDictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
LiteralDictionary* getDriveDictionary() {
|
Toy_LiteralDictionary* Toy_getDriveDictionary() {
|
||||||
return &driveDictionary;
|
return &Toy_driveDictionary;
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
int hookRunner(Interpreter* interpreter, Literal identifier, Literal alias);
|
int Toy_hookRunner(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||||
|
|
||||||
//file system API - these need to be set by the host
|
//file system API - these need to be set by the host
|
||||||
void initDriveDictionary();
|
void Toy_initDriveDictionary();
|
||||||
void freeDriveDictionary();
|
void Toy_freeDriveDictionary();
|
||||||
LiteralDictionary* getDriveDictionary();
|
Toy_LiteralDictionary* Toy_getDriveDictionary();
|
||||||
|
|
||||||
#define OPAQUE_TAG_RUNNER 100
|
#define TOY_OPAQUE_TAG_RUNNER 100
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "lib_standard.h"
|
#include "lib_standard.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 0) {
|
if (arguments->count != 0) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to clock\n");
|
interpreter->errorOutput("Incorrect number of arguments to clock\n");
|
||||||
@@ -19,13 +19,13 @@ static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
|
|
||||||
//push to the stack
|
//push to the stack
|
||||||
int len = strlen(timestr) - 1; //-1 for the newline
|
int len = strlen(timestr) - 1; //-1 for the newline
|
||||||
Literal timeLiteral = TO_STRING_LITERAL(createRefStringLength(timestr, len));
|
Toy_Literal timeLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(timestr, len));
|
||||||
|
|
||||||
//push to the stack
|
//push to the stack
|
||||||
pushLiteralArray(&interpreter->stack, timeLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -33,10 +33,10 @@ static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
//call the hook
|
//call the hook
|
||||||
typedef struct Natives {
|
typedef struct Natives {
|
||||||
char* name;
|
char* name;
|
||||||
NativeFn fn;
|
Toy_NativeFn fn;
|
||||||
} Natives;
|
} Natives;
|
||||||
|
|
||||||
int hookStandard(Interpreter* interpreter, Literal identifier, Literal alias) {
|
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
|
||||||
//build the natives list
|
//build the natives list
|
||||||
Natives natives[] = {
|
Natives natives[] = {
|
||||||
{"clock", nativeClock},
|
{"clock", nativeClock},
|
||||||
@@ -44,51 +44,51 @@ int hookStandard(Interpreter* interpreter, Literal identifier, Literal alias) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//store the library in an aliased dictionary
|
//store the library in an aliased dictionary
|
||||||
if (!IS_NULL(alias)) {
|
if (!TOY_IS_NULL(alias)) {
|
||||||
//make sure the name isn't taken
|
//make sure the name isn't taken
|
||||||
if (isDelcaredScopeVariable(interpreter->scope, alias)) {
|
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
|
||||||
interpreter->errorOutput("Can't override an existing variable\n");
|
interpreter->errorOutput("Can't override an existing variable\n");
|
||||||
freeLiteral(alias);
|
Toy_freeLiteral(alias);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//create the dictionary to load up with functions
|
//create the dictionary to load up with functions
|
||||||
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
|
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
|
||||||
initLiteralDictionary(dictionary);
|
Toy_initLiteralDictionary(dictionary);
|
||||||
|
|
||||||
//load the dict with functions
|
//load the dict with functions
|
||||||
for (int i = 0; natives[i].name; i++) {
|
for (int i = 0; natives[i].name; i++) {
|
||||||
Literal name = TO_STRING_LITERAL(createRefString(natives[i].name));
|
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
|
||||||
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
||||||
func.type = LITERAL_FUNCTION_NATIVE;
|
func.type = TOY_LITERAL_FUNCTION_NATIVE;
|
||||||
|
|
||||||
setLiteralDictionary(dictionary, name, func);
|
Toy_setLiteralDictionary(dictionary, name, func);
|
||||||
|
|
||||||
freeLiteral(name);
|
Toy_freeLiteral(name);
|
||||||
freeLiteral(func);
|
Toy_freeLiteral(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
//build the type
|
//build the type
|
||||||
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, true);
|
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
|
||||||
Literal strType = TO_TYPE_LITERAL(LITERAL_STRING, true);
|
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
|
||||||
Literal fnType = TO_TYPE_LITERAL(LITERAL_FUNCTION_NATIVE, true);
|
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
|
||||||
TYPE_PUSH_SUBTYPE(&type, strType);
|
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
|
||||||
TYPE_PUSH_SUBTYPE(&type, fnType);
|
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
|
||||||
|
|
||||||
//set scope
|
//set scope
|
||||||
Literal dict = TO_DICTIONARY_LITERAL(dictionary);
|
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
|
||||||
declareScopeVariable(interpreter->scope, alias, type);
|
Toy_declareScopeVariable(interpreter->scope, alias, type);
|
||||||
setScopeVariable(interpreter->scope, alias, dict, false);
|
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(dict);
|
Toy_freeLiteral(dict);
|
||||||
freeLiteral(type);
|
Toy_freeLiteral(type);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//default
|
//default
|
||||||
for (int i = 0; natives[i].name; i++) {
|
for (int i = 0; natives[i].name; i++) {
|
||||||
injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
int hookStandard(Interpreter* interpreter, Literal identifier, Literal alias);
|
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||||
|
|
||||||
|
|||||||
268
repl/lib_timer.c
268
repl/lib_timer.c
@@ -1,13 +1,13 @@
|
|||||||
#include "lib_timer.h"
|
#include "lib_timer.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
//GOD DAMN IT: https://stackoverflow.com/questions/15846762/timeval-subtract-explanation
|
//GOD DAMN IT: https://stackoverflow.com/questions/15846762/timeval-subtract-explanation
|
||||||
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) {
|
static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) {
|
||||||
//normallize
|
//normallize
|
||||||
if (x->tv_usec > 999999) {
|
if (x->tv_usec > 999999) {
|
||||||
x->tv_sec += x->tv_usec / 1000000;
|
x->tv_sec += x->tv_usec / 1000000;
|
||||||
@@ -34,7 +34,7 @@ int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *
|
|||||||
|
|
||||||
//god damn it
|
//god damn it
|
||||||
static struct timeval* diff(struct timeval* lhs, struct timeval* rhs) {
|
static struct timeval* diff(struct timeval* lhs, struct timeval* rhs) {
|
||||||
struct timeval* d = ALLOCATE(struct timeval, 1);
|
struct timeval* d = TOY_ALLOCATE(struct timeval, 1);
|
||||||
|
|
||||||
//I gave up, copied from SO
|
//I gave up, copied from SO
|
||||||
timeval_subtract(d, rhs, lhs);
|
timeval_subtract(d, rhs, lhs);
|
||||||
@@ -43,7 +43,7 @@ static struct timeval* diff(struct timeval* lhs, struct timeval* rhs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//callbacks
|
//callbacks
|
||||||
static int nativeStartTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeStartTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 0) {
|
if (arguments->count != 0) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to startTimer\n");
|
interpreter->errorOutput("Incorrect number of arguments to startTimer\n");
|
||||||
@@ -51,19 +51,19 @@ static int nativeStartTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the timeinfo from C
|
//get the timeinfo from C
|
||||||
struct timeval* timeinfo = ALLOCATE(struct timeval, 1);
|
struct timeval* timeinfo = TOY_ALLOCATE(struct timeval, 1);
|
||||||
gettimeofday(timeinfo, NULL);
|
gettimeofday(timeinfo, NULL);
|
||||||
|
|
||||||
//wrap in an opaque literal for Toy
|
//wrap in an opaque literal for Toy
|
||||||
Literal timeLiteral = TO_OPAQUE_LITERAL(timeinfo, -1);
|
Toy_Literal timeLiteral = TOY_TO_OPAQUE_LITERAL(timeinfo, -1);
|
||||||
pushLiteralArray(&interpreter->stack, timeLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
|
||||||
|
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeStopTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeStopTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _stopTimer\n");
|
interpreter->errorOutput("Incorrect number of arguments to _stopTimer\n");
|
||||||
@@ -75,34 +75,34 @@ static int nativeStopTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
gettimeofday(&timerStop, NULL);
|
gettimeofday(&timerStop, NULL);
|
||||||
|
|
||||||
//unwrap the opaque literal
|
//unwrap the opaque literal
|
||||||
Literal timeLiteral = popLiteralArray(arguments);
|
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal timeLiteralIdn = timeLiteral;
|
Toy_Literal timeLiteralIdn = timeLiteral;
|
||||||
if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) {
|
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
|
||||||
freeLiteral(timeLiteralIdn);
|
Toy_freeLiteral(timeLiteralIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(timeLiteral)) {
|
if (!TOY_IS_OPAQUE(timeLiteral)) {
|
||||||
interpreter->errorOutput("Incorrect argument type passed to _stopTimer\n");
|
interpreter->errorOutput("Incorrect argument type passed to _stopTimer\n");
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval* timerStart = AS_OPAQUE(timeLiteral);
|
struct timeval* timerStart = TOY_AS_OPAQUE(timeLiteral);
|
||||||
|
|
||||||
//determine the difference, and wrap it
|
//determine the difference, and wrap it
|
||||||
struct timeval* d = diff(timerStart, &timerStop);
|
struct timeval* d = diff(timerStart, &timerStop);
|
||||||
Literal diffLiteral = TO_OPAQUE_LITERAL(d, -1);
|
Toy_Literal diffLiteral = TOY_TO_OPAQUE_LITERAL(d, -1);
|
||||||
pushLiteralArray(&interpreter->stack, diffLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, diffLiteral);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
freeLiteral(diffLiteral);
|
Toy_freeLiteral(diffLiteral);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeCreateTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeCreateTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 2) {
|
if (arguments->count != 2) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to createTimer\n");
|
interpreter->errorOutput("Incorrect number of arguments to createTimer\n");
|
||||||
@@ -110,50 +110,50 @@ static int nativeCreateTimer(Interpreter* interpreter, LiteralArray* arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get the args
|
//get the args
|
||||||
Literal microsecondLiteral = popLiteralArray(arguments);
|
Toy_Literal microsecondLiteral = Toy_popLiteralArray(arguments);
|
||||||
Literal secondLiteral = popLiteralArray(arguments);
|
Toy_Literal secondLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal secondLiteralIdn = secondLiteral;
|
Toy_Literal secondLiteralIdn = secondLiteral;
|
||||||
if (IS_IDENTIFIER(secondLiteral) && parseIdentifierToValue(interpreter, &secondLiteral)) {
|
if (TOY_IS_IDENTIFIER(secondLiteral) && Toy_parseIdentifierToValue(interpreter, &secondLiteral)) {
|
||||||
freeLiteral(secondLiteralIdn);
|
Toy_freeLiteral(secondLiteralIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal microsecondLiteralIdn = microsecondLiteral;
|
Toy_Literal microsecondLiteralIdn = microsecondLiteral;
|
||||||
if (IS_IDENTIFIER(microsecondLiteral) && parseIdentifierToValue(interpreter, µsecondLiteral)) {
|
if (TOY_IS_IDENTIFIER(microsecondLiteral) && Toy_parseIdentifierToValue(interpreter, µsecondLiteral)) {
|
||||||
freeLiteral(microsecondLiteralIdn);
|
Toy_freeLiteral(microsecondLiteralIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_INTEGER(secondLiteral) || !IS_INTEGER(microsecondLiteral)) {
|
if (!TOY_IS_INTEGER(secondLiteral) || !TOY_IS_INTEGER(microsecondLiteral)) {
|
||||||
interpreter->errorOutput("Incorrect argument type passed to createTimer\n");
|
interpreter->errorOutput("Incorrect argument type passed to createTimer\n");
|
||||||
freeLiteral(secondLiteral);
|
Toy_freeLiteral(secondLiteral);
|
||||||
freeLiteral(microsecondLiteral);
|
Toy_freeLiteral(microsecondLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AS_INTEGER(microsecondLiteral) <= -1000 * 1000 || AS_INTEGER(microsecondLiteral) >= 1000 * 1000 || (AS_INTEGER(secondLiteral) != 0 && AS_INTEGER(microsecondLiteral) < 0) ) {
|
if (TOY_AS_INTEGER(microsecondLiteral) <= -1000 * 1000 || TOY_AS_INTEGER(microsecondLiteral) >= 1000 * 1000 || (TOY_AS_INTEGER(secondLiteral) != 0 && TOY_AS_INTEGER(microsecondLiteral) < 0) ) {
|
||||||
interpreter->errorOutput("Microseconds out of range in createTimer\n");
|
interpreter->errorOutput("Microseconds out of range in createTimer\n");
|
||||||
freeLiteral(secondLiteral);
|
Toy_freeLiteral(secondLiteral);
|
||||||
freeLiteral(microsecondLiteral);
|
Toy_freeLiteral(microsecondLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the timeinfo from toy
|
//get the timeinfo from toy
|
||||||
struct timeval* timeinfo = ALLOCATE(struct timeval, 1);
|
struct timeval* timeinfo = TOY_ALLOCATE(struct timeval, 1);
|
||||||
timeinfo->tv_sec = AS_INTEGER(secondLiteral);
|
timeinfo->tv_sec = TOY_AS_INTEGER(secondLiteral);
|
||||||
timeinfo->tv_usec = AS_INTEGER(microsecondLiteral);
|
timeinfo->tv_usec = TOY_AS_INTEGER(microsecondLiteral);
|
||||||
|
|
||||||
//wrap in an opaque literal for Toy
|
//wrap in an opaque literal for Toy
|
||||||
Literal timeLiteral = TO_OPAQUE_LITERAL(timeinfo, -1);
|
Toy_Literal timeLiteral = TOY_TO_OPAQUE_LITERAL(timeinfo, -1);
|
||||||
pushLiteralArray(&interpreter->stack, timeLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
|
||||||
|
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
freeLiteral(secondLiteral);
|
Toy_freeLiteral(secondLiteral);
|
||||||
freeLiteral(microsecondLiteral);
|
Toy_freeLiteral(microsecondLiteral);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeGetTimerSeconds(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeGetTimerSeconds(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _getTimerSeconds\n");
|
interpreter->errorOutput("Incorrect number of arguments to _getTimerSeconds\n");
|
||||||
@@ -161,33 +161,33 @@ static int nativeGetTimerSeconds(Interpreter* interpreter, LiteralArray* argumen
|
|||||||
}
|
}
|
||||||
|
|
||||||
//unwrap the opaque literal
|
//unwrap the opaque literal
|
||||||
Literal timeLiteral = popLiteralArray(arguments);
|
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal timeLiteralIdn = timeLiteral;
|
Toy_Literal timeLiteralIdn = timeLiteral;
|
||||||
if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) {
|
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
|
||||||
freeLiteral(timeLiteralIdn);
|
Toy_freeLiteral(timeLiteralIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(timeLiteral)) {
|
if (!TOY_IS_OPAQUE(timeLiteral)) {
|
||||||
interpreter->errorOutput("Incorrect argument type passed to _getTimerSeconds\n");
|
interpreter->errorOutput("Incorrect argument type passed to _getTimerSeconds\n");
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval* timer = AS_OPAQUE(timeLiteral);
|
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
|
||||||
|
|
||||||
//create the result literal
|
//create the result literal
|
||||||
Literal result = TO_INTEGER_LITERAL(timer->tv_sec);
|
Toy_Literal result = TOY_TO_INTEGER_LITERAL(timer->tv_sec);
|
||||||
pushLiteralArray(&interpreter->stack, result);
|
Toy_pushLiteralArray(&interpreter->stack, result);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
freeLiteral(result);
|
Toy_freeLiteral(result);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeGetTimerMicroseconds(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeGetTimerMicroseconds(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _getTimerMicroseconds\n");
|
interpreter->errorOutput("Incorrect number of arguments to _getTimerMicroseconds\n");
|
||||||
@@ -195,33 +195,33 @@ static int nativeGetTimerMicroseconds(Interpreter* interpreter, LiteralArray* ar
|
|||||||
}
|
}
|
||||||
|
|
||||||
//unwrap the opaque literal
|
//unwrap the opaque literal
|
||||||
Literal timeLiteral = popLiteralArray(arguments);
|
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal timeLiteralIdn = timeLiteral;
|
Toy_Literal timeLiteralIdn = timeLiteral;
|
||||||
if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) {
|
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
|
||||||
freeLiteral(timeLiteralIdn);
|
Toy_freeLiteral(timeLiteralIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(timeLiteral)) {
|
if (!TOY_IS_OPAQUE(timeLiteral)) {
|
||||||
interpreter->errorOutput("Incorrect argument type passed to _getTimerMicroseconds\n");
|
interpreter->errorOutput("Incorrect argument type passed to _getTimerMicroseconds\n");
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval* timer = AS_OPAQUE(timeLiteral);
|
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
|
||||||
|
|
||||||
//create the result literal
|
//create the result literal
|
||||||
Literal result = TO_INTEGER_LITERAL(timer->tv_usec);
|
Toy_Literal result = TOY_TO_INTEGER_LITERAL(timer->tv_usec);
|
||||||
pushLiteralArray(&interpreter->stack, result);
|
Toy_pushLiteralArray(&interpreter->stack, result);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
freeLiteral(result);
|
Toy_freeLiteral(result);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeCompareTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeCompareTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 2) {
|
if (arguments->count != 2) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _compareTimer\n");
|
interpreter->errorOutput("Incorrect number of arguments to _compareTimer\n");
|
||||||
@@ -229,43 +229,43 @@ static int nativeCompareTimer(Interpreter* interpreter, LiteralArray* arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//unwrap the opaque literals
|
//unwrap the opaque literals
|
||||||
Literal rhsLiteral = popLiteralArray(arguments);
|
Toy_Literal rhsLiteral = Toy_popLiteralArray(arguments);
|
||||||
Literal lhsLiteral = popLiteralArray(arguments);
|
Toy_Literal lhsLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal lhsLiteralIdn = lhsLiteral;
|
Toy_Literal lhsLiteralIdn = lhsLiteral;
|
||||||
if (IS_IDENTIFIER(lhsLiteral) && parseIdentifierToValue(interpreter, &lhsLiteral)) {
|
if (TOY_IS_IDENTIFIER(lhsLiteral) && Toy_parseIdentifierToValue(interpreter, &lhsLiteral)) {
|
||||||
freeLiteral(lhsLiteralIdn);
|
Toy_freeLiteral(lhsLiteralIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal rhsLiteralIdn = rhsLiteral;
|
Toy_Literal rhsLiteralIdn = rhsLiteral;
|
||||||
if (IS_IDENTIFIER(rhsLiteral) && parseIdentifierToValue(interpreter, &rhsLiteral)) {
|
if (TOY_IS_IDENTIFIER(rhsLiteral) && Toy_parseIdentifierToValue(interpreter, &rhsLiteral)) {
|
||||||
freeLiteral(rhsLiteralIdn);
|
Toy_freeLiteral(rhsLiteralIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(lhsLiteral) || !IS_OPAQUE(rhsLiteral)) {
|
if (!TOY_IS_OPAQUE(lhsLiteral) || !TOY_IS_OPAQUE(rhsLiteral)) {
|
||||||
interpreter->errorOutput("Incorrect argument type passed to _compareTimer\n");
|
interpreter->errorOutput("Incorrect argument type passed to _compareTimer\n");
|
||||||
freeLiteral(lhsLiteral);
|
Toy_freeLiteral(lhsLiteral);
|
||||||
freeLiteral(rhsLiteral);
|
Toy_freeLiteral(rhsLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval* lhsTimer = AS_OPAQUE(lhsLiteral);
|
struct timeval* lhsTimer = TOY_AS_OPAQUE(lhsLiteral);
|
||||||
struct timeval* rhsTimer = AS_OPAQUE(rhsLiteral);
|
struct timeval* rhsTimer = TOY_AS_OPAQUE(rhsLiteral);
|
||||||
|
|
||||||
//determine the difference, and wrap it
|
//determine the difference, and wrap it
|
||||||
struct timeval* d = diff(lhsTimer, rhsTimer);
|
struct timeval* d = diff(lhsTimer, rhsTimer);
|
||||||
Literal diffLiteral = TO_OPAQUE_LITERAL(d, -1);
|
Toy_Literal diffLiteral = TOY_TO_OPAQUE_LITERAL(d, -1);
|
||||||
pushLiteralArray(&interpreter->stack, diffLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, diffLiteral);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(lhsLiteral);
|
Toy_freeLiteral(lhsLiteral);
|
||||||
freeLiteral(rhsLiteral);
|
Toy_freeLiteral(rhsLiteral);
|
||||||
freeLiteral(diffLiteral);
|
Toy_freeLiteral(diffLiteral);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeTimerToString(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeTimerToString(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _timerToString\n");
|
interpreter->errorOutput("Incorrect number of arguments to _timerToString\n");
|
||||||
@@ -273,44 +273,44 @@ static int nativeTimerToString(Interpreter* interpreter, LiteralArray* arguments
|
|||||||
}
|
}
|
||||||
|
|
||||||
//unwrap in an opaque literal
|
//unwrap in an opaque literal
|
||||||
Literal timeLiteral = popLiteralArray(arguments);
|
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal timeLiteralIdn = timeLiteral;
|
Toy_Literal timeLiteralIdn = timeLiteral;
|
||||||
if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) {
|
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
|
||||||
freeLiteral(timeLiteralIdn);
|
Toy_freeLiteral(timeLiteralIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(timeLiteral)) {
|
if (!TOY_IS_OPAQUE(timeLiteral)) {
|
||||||
interpreter->errorOutput("Incorrect argument type passed to _timerToString\n");
|
interpreter->errorOutput("Incorrect argument type passed to _timerToString\n");
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval* timer = AS_OPAQUE(timeLiteral);
|
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
|
||||||
|
|
||||||
//create the string literal
|
//create the string literal
|
||||||
Literal resultLiteral = TO_NULL_LITERAL;
|
Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL;
|
||||||
if (timer->tv_sec == 0 && timer->tv_usec < 0) { //special case, for when the negative sign is encoded in the usec
|
if (timer->tv_sec == 0 && timer->tv_usec < 0) { //special case, for when the negative sign is encoded in the usec
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
snprintf(buffer, 128, "-%ld.%06ld", timer->tv_sec, -timer->tv_usec);
|
snprintf(buffer, 128, "-%ld.%06ld", timer->tv_sec, -timer->tv_usec);
|
||||||
resultLiteral = TO_STRING_LITERAL(createRefStringLength(buffer, strlen(buffer)));
|
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strlen(buffer)));
|
||||||
}
|
}
|
||||||
else { //normal case
|
else { //normal case
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
|
snprintf(buffer, 128, "%ld.%06ld", timer->tv_sec, timer->tv_usec);
|
||||||
resultLiteral = TO_STRING_LITERAL(createRefStringLength(buffer, strlen(buffer)));
|
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, strlen(buffer)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pushLiteralArray(&interpreter->stack, resultLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
freeLiteral(resultLiteral);
|
Toy_freeLiteral(resultLiteral);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeDestroyTimer(Interpreter* interpreter, LiteralArray* arguments) {
|
static int nativeDestroyTimer(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to _destroyTimer\n");
|
interpreter->errorOutput("Incorrect number of arguments to _destroyTimer\n");
|
||||||
@@ -318,24 +318,24 @@ static int nativeDestroyTimer(Interpreter* interpreter, LiteralArray* arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//unwrap in an opaque literal
|
//unwrap in an opaque literal
|
||||||
Literal timeLiteral = popLiteralArray(arguments);
|
Toy_Literal timeLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal timeLiteralIdn = timeLiteral;
|
Toy_Literal timeLiteralIdn = timeLiteral;
|
||||||
if (IS_IDENTIFIER(timeLiteral) && parseIdentifierToValue(interpreter, &timeLiteral)) {
|
if (TOY_IS_IDENTIFIER(timeLiteral) && Toy_parseIdentifierToValue(interpreter, &timeLiteral)) {
|
||||||
freeLiteral(timeLiteralIdn);
|
Toy_freeLiteral(timeLiteralIdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_OPAQUE(timeLiteral)) {
|
if (!TOY_IS_OPAQUE(timeLiteral)) {
|
||||||
interpreter->errorOutput("Incorrect argument type passed to _destroyTimer\n");
|
interpreter->errorOutput("Incorrect argument type passed to _destroyTimer\n");
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval* timer = AS_OPAQUE(timeLiteral);
|
struct timeval* timer = TOY_AS_OPAQUE(timeLiteral);
|
||||||
|
|
||||||
FREE(struct timeval, timer);
|
TOY_FREE(struct timeval, timer);
|
||||||
|
|
||||||
freeLiteral(timeLiteral);
|
Toy_freeLiteral(timeLiteral);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -343,10 +343,10 @@ static int nativeDestroyTimer(Interpreter* interpreter, LiteralArray* arguments)
|
|||||||
//call the hook
|
//call the hook
|
||||||
typedef struct Natives {
|
typedef struct Natives {
|
||||||
char* name;
|
char* name;
|
||||||
NativeFn fn;
|
Toy_NativeFn fn;
|
||||||
} Natives;
|
} Natives;
|
||||||
|
|
||||||
int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias) {
|
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
|
||||||
//build the natives list
|
//build the natives list
|
||||||
Natives natives[] = {
|
Natives natives[] = {
|
||||||
{"startTimer", nativeStartTimer},
|
{"startTimer", nativeStartTimer},
|
||||||
@@ -361,51 +361,51 @@ int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//store the library in an aliased dictionary
|
//store the library in an aliased dictionary
|
||||||
if (!IS_NULL(alias)) {
|
if (!TOY_IS_NULL(alias)) {
|
||||||
//make sure the name isn't taken
|
//make sure the name isn't taken
|
||||||
if (isDelcaredScopeVariable(interpreter->scope, alias)) {
|
if (Toy_isDelcaredScopeVariable(interpreter->scope, alias)) {
|
||||||
interpreter->errorOutput("Can't override an existing variable\n");
|
interpreter->errorOutput("Can't override an existing variable\n");
|
||||||
freeLiteral(alias);
|
Toy_freeLiteral(alias);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//create the dictionary to load up with functions
|
//create the dictionary to load up with functions
|
||||||
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
|
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
|
||||||
initLiteralDictionary(dictionary);
|
Toy_initLiteralDictionary(dictionary);
|
||||||
|
|
||||||
//load the dict with functions
|
//load the dict with functions
|
||||||
for (int i = 0; natives[i].name; i++) {
|
for (int i = 0; natives[i].name; i++) {
|
||||||
Literal name = TO_STRING_LITERAL(createRefString(natives[i].name));
|
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
|
||||||
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
Toy_Literal func = TOY_TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
|
||||||
func.type = LITERAL_FUNCTION_NATIVE;
|
func.type = TOY_LITERAL_FUNCTION_NATIVE;
|
||||||
|
|
||||||
setLiteralDictionary(dictionary, name, func);
|
Toy_setLiteralDictionary(dictionary, name, func);
|
||||||
|
|
||||||
freeLiteral(name);
|
Toy_freeLiteral(name);
|
||||||
freeLiteral(func);
|
Toy_freeLiteral(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
//build the type
|
//build the type
|
||||||
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, true);
|
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
|
||||||
Literal strType = TO_TYPE_LITERAL(LITERAL_STRING, true);
|
Toy_Literal strType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, true);
|
||||||
Literal fnType = TO_TYPE_LITERAL(LITERAL_FUNCTION_NATIVE, true);
|
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
|
||||||
TYPE_PUSH_SUBTYPE(&type, strType);
|
TOY_TYPE_PUSH_SUBTYPE(&type, strType);
|
||||||
TYPE_PUSH_SUBTYPE(&type, fnType);
|
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
|
||||||
|
|
||||||
//set scope
|
//set scope
|
||||||
Literal dict = TO_DICTIONARY_LITERAL(dictionary);
|
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
|
||||||
declareScopeVariable(interpreter->scope, alias, type);
|
Toy_declareScopeVariable(interpreter->scope, alias, type);
|
||||||
setScopeVariable(interpreter->scope, alias, dict, false);
|
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(dict);
|
Toy_freeLiteral(dict);
|
||||||
freeLiteral(type);
|
Toy_freeLiteral(type);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//default
|
//default
|
||||||
for (int i = 0; natives[i].name; i++) {
|
for (int i = 0; natives[i].name; i++) {
|
||||||
injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias);
|
int Toy_hookTimer(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
#include "lib_timer.h"
|
#include "lib_timer.h"
|
||||||
#include "lib_runner.h"
|
#include "lib_runner.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "lexer.h"
|
#include "toy_lexer.h"
|
||||||
#include "parser.h"
|
#include "toy_parser.h"
|
||||||
#include "compiler.h"
|
#include "toy_compiler.h"
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -22,13 +22,13 @@ void repl() {
|
|||||||
char input[size];
|
char input[size];
|
||||||
memset(input, 0, size);
|
memset(input, 0, size);
|
||||||
|
|
||||||
Interpreter interpreter; //persist the interpreter for the scopes
|
Toy_Interpreter interpreter; //persist the interpreter for the scopes
|
||||||
initInterpreter(&interpreter);
|
Toy_initInterpreter(&interpreter);
|
||||||
|
|
||||||
//inject the libs
|
//inject the libs
|
||||||
injectNativeHook(&interpreter, "standard", hookStandard);
|
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
|
||||||
injectNativeHook(&interpreter, "timer", hookTimer);
|
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
|
||||||
injectNativeHook(&interpreter, "runner", hookRunner);
|
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
printf("> ");
|
printf("> ");
|
||||||
@@ -44,100 +44,100 @@ void repl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//setup this iteration
|
//setup this iteration
|
||||||
Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
Parser parser;
|
Toy_Parser parser;
|
||||||
Compiler compiler;
|
Toy_Compiler compiler;
|
||||||
|
|
||||||
initLexer(&lexer, input);
|
Toy_initLexer(&lexer, input);
|
||||||
initParser(&parser, &lexer);
|
Toy_initParser(&parser, &lexer);
|
||||||
initCompiler(&compiler);
|
Toy_initCompiler(&compiler);
|
||||||
|
|
||||||
//run this iteration
|
//run this iteration
|
||||||
ASTNode* node = scanParser(&parser);
|
Toy_ASTNode* node = Toy_scanParser(&parser);
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
//pack up and restart
|
//pack up and restart
|
||||||
if (node->type == AST_NODE_ERROR) {
|
if (node->type == TOY_AST_NODE_ERROR) {
|
||||||
printf(ERROR "error node detected\n" RESET);
|
printf(TOY_CC_ERROR "error node detected\n" TOY_CC_RESET);
|
||||||
error = true;
|
error = true;
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCompiler(&compiler, node);
|
Toy_writeCompiler(&compiler, node);
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
node = scanParser(&parser);
|
node = Toy_scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
//get the bytecode dump
|
//get the bytecode dump
|
||||||
int size = 0;
|
int size = 0;
|
||||||
unsigned char* tb = collateCompiler(&compiler, &size);
|
unsigned char* tb = Toy_collateCompiler(&compiler, &size);
|
||||||
|
|
||||||
//run the bytecode
|
//run the bytecode
|
||||||
runInterpreter(&interpreter, tb, size);
|
Toy_runInterpreter(&interpreter, tb, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
//clean up this iteration
|
//clean up this iteration
|
||||||
freeCompiler(&compiler);
|
Toy_freeCompiler(&compiler);
|
||||||
freeParser(&parser);
|
Toy_freeParser(&parser);
|
||||||
error = false;
|
error = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeInterpreter(&interpreter);
|
Toy_freeInterpreter(&interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
//entry point
|
//entry point
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
initCommand(argc, argv);
|
Toy_initCommand(argc, argv);
|
||||||
|
|
||||||
//lib setup (hacky - only really for this program)
|
//lib setup (hacky - only really for this program)
|
||||||
initDriveDictionary();
|
Toy_initDriveDictionary();
|
||||||
|
|
||||||
Literal driveLiteral = TO_STRING_LITERAL(createRefString("scripts"));
|
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
|
||||||
Literal pathLiteral = TO_STRING_LITERAL(createRefString("scripts"));
|
Toy_Literal pathLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
|
||||||
|
|
||||||
setLiteralDictionary(getDriveDictionary(), driveLiteral, pathLiteral);
|
Toy_setLiteralDictionary(Toy_getDriveDictionary(), driveLiteral, pathLiteral);
|
||||||
|
|
||||||
freeLiteral(driveLiteral);
|
Toy_freeLiteral(driveLiteral);
|
||||||
freeLiteral(pathLiteral);
|
Toy_freeLiteral(pathLiteral);
|
||||||
|
|
||||||
//command specific actions
|
//command specific actions
|
||||||
if (command.error) {
|
if (command.error) {
|
||||||
usageCommand(argc, argv);
|
Toy_usageCommand(argc, argv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.help) {
|
if (command.help) {
|
||||||
helpCommand(argc, argv);
|
Toy_helpCommand(argc, argv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.version) {
|
if (command.version) {
|
||||||
copyrightCommand(argc, argv);
|
Toy_copyrightCommand(argc, argv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//version
|
//version
|
||||||
if (command.verbose) {
|
if (command.verbose) {
|
||||||
printf(NOTICE "Toy Programming Language Version %d.%d.%d\n" RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH);
|
printf(TOY_CC_NOTICE "Toy Programming Language Version %d.%d.%d\n" TOY_CC_RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
//run source file
|
//run source file
|
||||||
if (command.sourcefile) {
|
if (command.sourcefile) {
|
||||||
runSourceFile(command.sourcefile);
|
Toy_runSourceFile(command.sourcefile);
|
||||||
|
|
||||||
//lib cleanup
|
//lib cleanup
|
||||||
freeDriveDictionary();
|
Toy_freeDriveDictionary();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//run from stdin
|
//run from stdin
|
||||||
if (command.source) {
|
if (command.source) {
|
||||||
runSource(command.source);
|
Toy_runSource(command.source);
|
||||||
|
|
||||||
//lib cleanup
|
//lib cleanup
|
||||||
freeDriveDictionary();
|
Toy_freeDriveDictionary();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -145,21 +145,21 @@ int main(int argc, const char* argv[]) {
|
|||||||
//compile source file
|
//compile source file
|
||||||
if (command.compilefile && command.outfile) {
|
if (command.compilefile && command.outfile) {
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
char* source = readFile(command.compilefile, &size);
|
char* source = Toy_readFile(command.compilefile, &size);
|
||||||
unsigned char* tb = compileString(source, &size);
|
unsigned char* tb = Toy_compileString(source, &size);
|
||||||
if (!tb) {
|
if (!tb) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
writeFile(command.outfile, tb, size);
|
Toy_writeFile(command.outfile, tb, size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//run binary
|
//run binary
|
||||||
if (command.binaryfile) {
|
if (command.binaryfile) {
|
||||||
runBinaryFile(command.binaryfile);
|
Toy_runBinaryFile(command.binaryfile);
|
||||||
|
|
||||||
//lib cleanup
|
//lib cleanup
|
||||||
freeDriveDictionary();
|
Toy_freeDriveDictionary();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -167,7 +167,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
repl();
|
repl();
|
||||||
|
|
||||||
//lib cleanup
|
//lib cleanup
|
||||||
freeDriveDictionary();
|
Toy_freeDriveDictionary();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,22 +3,22 @@
|
|||||||
#include "lib_timer.h"
|
#include "lib_timer.h"
|
||||||
#include "lib_runner.h"
|
#include "lib_runner.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "lexer.h"
|
#include "toy_lexer.h"
|
||||||
#include "parser.h"
|
#include "toy_parser.h"
|
||||||
#include "compiler.h"
|
#include "toy_compiler.h"
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
//IO functions
|
//IO functions
|
||||||
char* readFile(char* path, size_t* fileSize) {
|
char* Toy_readFile(char* path, size_t* fileSize) {
|
||||||
FILE* file = fopen(path, "rb");
|
FILE* file = fopen(path, "rb");
|
||||||
|
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
fprintf(stderr, ERROR "Could not open file \"%s\"\n" RESET, path);
|
fprintf(stderr, TOY_CC_ERROR "Could not open file \"%s\"\n" TOY_CC_RESET, path);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ char* readFile(char* path, size_t* fileSize) {
|
|||||||
char* buffer = (char*)malloc(*fileSize + 1);
|
char* buffer = (char*)malloc(*fileSize + 1);
|
||||||
|
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
fprintf(stderr, ERROR "Not enough memory to read \"%s\"\n" RESET, path);
|
fprintf(stderr, TOY_CC_ERROR "Not enough memory to read \"%s\"\n" TOY_CC_RESET, path);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ char* readFile(char* path, size_t* fileSize) {
|
|||||||
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
|
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
|
||||||
|
|
||||||
if (bytesRead < *fileSize) {
|
if (bytesRead < *fileSize) {
|
||||||
fprintf(stderr, ERROR "Could not read file \"%s\"\n" RESET, path);
|
fprintf(stderr, TOY_CC_ERROR "Could not read file \"%s\"\n" TOY_CC_RESET, path);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,18 +47,18 @@ char* readFile(char* path, size_t* fileSize) {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
int writeFile(char* path, unsigned char* bytes, size_t size) {
|
int Toy_writeFile(char* path, unsigned char* bytes, size_t size) {
|
||||||
FILE* file = fopen(path, "wb");
|
FILE* file = fopen(path, "wb");
|
||||||
|
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
fprintf(stderr, ERROR "Could not open file \"%s\"\n" RESET, path);
|
fprintf(stderr, TOY_CC_ERROR "Could not open file \"%s\"\n" TOY_CC_RESET, path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int written = fwrite(bytes, size, 1, file);
|
int written = fwrite(bytes, size, 1, file);
|
||||||
|
|
||||||
if (written != 1) {
|
if (written != 1) {
|
||||||
fprintf(stderr, ERROR "Could not write file \"%s\"\n" RESET, path);
|
fprintf(stderr, TOY_CC_ERROR "Could not write file \"%s\"\n" TOY_CC_RESET, path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,79 +68,79 @@ int writeFile(char* path, unsigned char* bytes, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//repl functions
|
//repl functions
|
||||||
unsigned char* compileString(char* source, size_t* size) {
|
unsigned char* Toy_compileString(char* source, size_t* size) {
|
||||||
Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
Parser parser;
|
Toy_Parser parser;
|
||||||
Compiler compiler;
|
Toy_Compiler compiler;
|
||||||
|
|
||||||
initLexer(&lexer, source);
|
Toy_initLexer(&lexer, source);
|
||||||
initParser(&parser, &lexer);
|
Toy_initParser(&parser, &lexer);
|
||||||
initCompiler(&compiler);
|
Toy_initCompiler(&compiler);
|
||||||
|
|
||||||
//run the parser until the end of the source
|
//run the parser until the end of the source
|
||||||
ASTNode* node = scanParser(&parser);
|
Toy_ASTNode* node = Toy_scanParser(&parser);
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
//pack up and leave
|
//pack up and leave
|
||||||
if (node->type == AST_NODE_ERROR) {
|
if (node->type == TOY_AST_NODE_ERROR) {
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
freeCompiler(&compiler);
|
Toy_freeCompiler(&compiler);
|
||||||
freeParser(&parser);
|
Toy_freeParser(&parser);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCompiler(&compiler, node);
|
Toy_writeCompiler(&compiler, node);
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
node = scanParser(&parser);
|
node = Toy_scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the bytecode dump
|
//get the bytecode dump
|
||||||
unsigned char* tb = collateCompiler(&compiler, (int*)(size));
|
unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size));
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeCompiler(&compiler);
|
Toy_freeCompiler(&compiler);
|
||||||
freeParser(&parser);
|
Toy_freeParser(&parser);
|
||||||
//no lexer to clean up
|
//no lexer to clean up
|
||||||
|
|
||||||
//finally
|
//finally
|
||||||
return tb;
|
return tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void runBinary(unsigned char* tb, size_t size) {
|
void Toy_runBinary(unsigned char* tb, size_t size) {
|
||||||
Interpreter interpreter;
|
Toy_Interpreter interpreter;
|
||||||
initInterpreter(&interpreter);
|
Toy_initInterpreter(&interpreter);
|
||||||
|
|
||||||
//inject the libs
|
//inject the libs
|
||||||
injectNativeHook(&interpreter, "standard", hookStandard);
|
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
|
||||||
injectNativeHook(&interpreter, "timer", hookTimer);
|
Toy_injectNativeHook(&interpreter, "timer", Toy_hookTimer);
|
||||||
injectNativeHook(&interpreter, "runner", hookRunner);
|
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
|
||||||
|
|
||||||
runInterpreter(&interpreter, tb, size);
|
Toy_runInterpreter(&interpreter, tb, size);
|
||||||
freeInterpreter(&interpreter);
|
Toy_freeInterpreter(&interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void runBinaryFile(char* fname) {
|
void Toy_runBinaryFile(char* fname) {
|
||||||
size_t size = 0; //not used
|
size_t size = 0; //not used
|
||||||
unsigned char* tb = (unsigned char*)readFile(fname, &size);
|
unsigned char* tb = (unsigned char*)Toy_readFile(fname, &size);
|
||||||
if (!tb) {
|
if (!tb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
runBinary(tb, size);
|
Toy_runBinary(tb, size);
|
||||||
//interpreter takes ownership of the binary data
|
//interpreter takes ownership of the binary data
|
||||||
}
|
}
|
||||||
|
|
||||||
void runSource(char* source) {
|
void Toy_runSource(char* source) {
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
unsigned char* tb = compileString(source, &size);
|
unsigned char* tb = Toy_compileString(source, &size);
|
||||||
if (!tb) {
|
if (!tb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
runBinary(tb, size);
|
Toy_runBinary(tb, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void runSourceFile(char* fname) {
|
void Toy_runSourceFile(char* fname) {
|
||||||
size_t size = 0; //not used
|
size_t size = 0; //not used
|
||||||
char* source = readFile(fname, &size);
|
char* source = Toy_readFile(fname, &size);
|
||||||
runSource(source);
|
Toy_runSource(source);
|
||||||
free((void*)source);
|
free((void*)source);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
|
|
||||||
char* readFile(char* path, size_t* fileSize);
|
char* Toy_readFile(char* path, size_t* fileSize);
|
||||||
int writeFile(char* path, unsigned char* bytes, size_t size);
|
int Toy_writeFile(char* path, unsigned char* bytes, size_t size);
|
||||||
|
|
||||||
unsigned char* compileString(char* source, size_t* size);
|
unsigned char* Toy_compileString(char* source, size_t* size);
|
||||||
|
|
||||||
void runBinary(unsigned char* tb, size_t size);
|
void Toy_runBinary(unsigned char* tb, size_t size);
|
||||||
void runBinaryFile(char* fname);
|
void Toy_runBinaryFile(char* fname);
|
||||||
void runSource(char* source);
|
void Toy_runSource(char* source);
|
||||||
void runSourceFile(char* fname);
|
void Toy_runSourceFile(char* fname);
|
||||||
|
|
||||||
|
|||||||
@@ -1,173 +1,173 @@
|
|||||||
#include "ast_node.h"
|
#include "toy_ast_node.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
void freeASTNodeCustom(ASTNode* node, bool freeSelf) {
|
static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
|
||||||
//don't free a NULL node
|
//don't free a NULL node
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(node->type) {
|
switch(node->type) {
|
||||||
case AST_NODE_ERROR:
|
case TOY_AST_NODE_ERROR:
|
||||||
//NO-OP
|
//NO-OP
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_LITERAL:
|
case TOY_AST_NODE_LITERAL:
|
||||||
freeLiteral(node->atomic.literal);
|
Toy_freeLiteral(node->atomic.literal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_UNARY:
|
case TOY_AST_NODE_UNARY:
|
||||||
freeASTNode(node->unary.child);
|
Toy_freeASTNode(node->unary.child);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_BINARY:
|
case TOY_AST_NODE_BINARY:
|
||||||
freeASTNode(node->binary.left);
|
Toy_freeASTNode(node->binary.left);
|
||||||
freeASTNode(node->binary.right);
|
Toy_freeASTNode(node->binary.right);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_TERNARY:
|
case TOY_AST_NODE_TERNARY:
|
||||||
freeASTNode(node->ternary.condition);
|
Toy_freeASTNode(node->ternary.condition);
|
||||||
freeASTNode(node->ternary.thenPath);
|
Toy_freeASTNode(node->ternary.thenPath);
|
||||||
freeASTNode(node->ternary.elsePath);
|
Toy_freeASTNode(node->ternary.elsePath);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_GROUPING:
|
case TOY_AST_NODE_GROUPING:
|
||||||
freeASTNode(node->grouping.child);
|
Toy_freeASTNode(node->grouping.child);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_BLOCK:
|
case TOY_AST_NODE_BLOCK:
|
||||||
for (int i = 0; i < node->block.count; i++) {
|
for (int i = 0; i < node->block.count; i++) {
|
||||||
freeASTNodeCustom(node->block.nodes + i, false);
|
freeASTNodeCustom(node->block.nodes + i, false);
|
||||||
}
|
}
|
||||||
FREE_ARRAY(ASTNode, node->block.nodes, node->block.capacity);
|
TOY_FREE_ARRAY(Toy_ASTNode, node->block.nodes, node->block.capacity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_COMPOUND:
|
case TOY_AST_NODE_COMPOUND:
|
||||||
for (int i = 0; i < node->compound.count; i++) {
|
for (int i = 0; i < node->compound.count; i++) {
|
||||||
freeASTNodeCustom(node->compound.nodes + i, false);
|
freeASTNodeCustom(node->compound.nodes + i, false);
|
||||||
}
|
}
|
||||||
FREE_ARRAY(ASTNode, node->compound.nodes, node->compound.capacity);
|
TOY_FREE_ARRAY(Toy_ASTNode, node->compound.nodes, node->compound.capacity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_PAIR:
|
case TOY_AST_NODE_PAIR:
|
||||||
freeASTNode(node->pair.left);
|
Toy_freeASTNode(node->pair.left);
|
||||||
freeASTNode(node->pair.right);
|
Toy_freeASTNode(node->pair.right);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_INDEX:
|
case TOY_AST_NODE_INDEX:
|
||||||
freeASTNode(node->index.first);
|
Toy_freeASTNode(node->index.first);
|
||||||
freeASTNode(node->index.second);
|
Toy_freeASTNode(node->index.second);
|
||||||
freeASTNode(node->index.third);
|
Toy_freeASTNode(node->index.third);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_VAR_DECL:
|
case TOY_AST_NODE_VAR_DECL:
|
||||||
freeLiteral(node->varDecl.identifier);
|
Toy_freeLiteral(node->varDecl.identifier);
|
||||||
freeLiteral(node->varDecl.typeLiteral);
|
Toy_freeLiteral(node->varDecl.typeLiteral);
|
||||||
freeASTNode(node->varDecl.expression);
|
Toy_freeASTNode(node->varDecl.expression);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_FN_COLLECTION:
|
case TOY_AST_NODE_FN_COLLECTION:
|
||||||
for (int i = 0; i < node->fnCollection.count; i++) {
|
for (int i = 0; i < node->fnCollection.count; i++) {
|
||||||
freeASTNodeCustom(node->fnCollection.nodes + i, false);
|
freeASTNodeCustom(node->fnCollection.nodes + i, false);
|
||||||
}
|
}
|
||||||
FREE_ARRAY(ASTNode, node->fnCollection.nodes, node->fnCollection.capacity);
|
TOY_FREE_ARRAY(Toy_ASTNode, node->fnCollection.nodes, node->fnCollection.capacity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_FN_DECL:
|
case TOY_AST_NODE_FN_DECL:
|
||||||
freeLiteral(node->fnDecl.identifier);
|
Toy_freeLiteral(node->fnDecl.identifier);
|
||||||
freeASTNode(node->fnDecl.arguments);
|
Toy_freeASTNode(node->fnDecl.arguments);
|
||||||
freeASTNode(node->fnDecl.returns);
|
Toy_freeASTNode(node->fnDecl.returns);
|
||||||
freeASTNode(node->fnDecl.block);
|
Toy_freeASTNode(node->fnDecl.block);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_FN_CALL:
|
case TOY_AST_NODE_FN_CALL:
|
||||||
freeASTNode(node->fnCall.arguments);
|
Toy_freeASTNode(node->fnCall.arguments);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_FN_RETURN:
|
case TOY_AST_NODE_FN_RETURN:
|
||||||
freeASTNode(node->returns.returns);
|
Toy_freeASTNode(node->returns.returns);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_IF:
|
case TOY_AST_NODE_IF:
|
||||||
freeASTNode(node->pathIf.condition);
|
Toy_freeASTNode(node->pathIf.condition);
|
||||||
freeASTNode(node->pathIf.thenPath);
|
Toy_freeASTNode(node->pathIf.thenPath);
|
||||||
freeASTNode(node->pathIf.elsePath);
|
Toy_freeASTNode(node->pathIf.elsePath);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_WHILE:
|
case TOY_AST_NODE_WHILE:
|
||||||
freeASTNode(node->pathWhile.condition);
|
Toy_freeASTNode(node->pathWhile.condition);
|
||||||
freeASTNode(node->pathWhile.thenPath);
|
Toy_freeASTNode(node->pathWhile.thenPath);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_FOR:
|
case TOY_AST_NODE_FOR:
|
||||||
freeASTNode(node->pathFor.preClause);
|
Toy_freeASTNode(node->pathFor.preClause);
|
||||||
freeASTNode(node->pathFor.postClause);
|
Toy_freeASTNode(node->pathFor.postClause);
|
||||||
freeASTNode(node->pathFor.condition);
|
Toy_freeASTNode(node->pathFor.condition);
|
||||||
freeASTNode(node->pathFor.thenPath);
|
Toy_freeASTNode(node->pathFor.thenPath);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_BREAK:
|
case TOY_AST_NODE_BREAK:
|
||||||
//NO-OP
|
//NO-OP
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_CONTINUE:
|
case TOY_AST_NODE_CONTINUE:
|
||||||
//NO-OP
|
//NO-OP
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_PREFIX_INCREMENT:
|
case TOY_AST_NODE_PREFIX_INCREMENT:
|
||||||
freeLiteral(node->prefixIncrement.identifier);
|
Toy_freeLiteral(node->prefixIncrement.identifier);
|
||||||
break;
|
break;
|
||||||
case AST_NODE_PREFIX_DECREMENT:
|
case TOY_AST_NODE_PREFIX_DECREMENT:
|
||||||
freeLiteral(node->prefixDecrement.identifier);
|
Toy_freeLiteral(node->prefixDecrement.identifier);
|
||||||
break;
|
break;
|
||||||
case AST_NODE_POSTFIX_INCREMENT:
|
case TOY_AST_NODE_POSTFIX_INCREMENT:
|
||||||
freeLiteral(node->postfixIncrement.identifier);
|
Toy_freeLiteral(node->postfixIncrement.identifier);
|
||||||
break;
|
break;
|
||||||
case AST_NODE_POSTFIX_DECREMENT:
|
case TOY_AST_NODE_POSTFIX_DECREMENT:
|
||||||
freeLiteral(node->postfixDecrement.identifier);
|
Toy_freeLiteral(node->postfixDecrement.identifier);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_NODE_IMPORT:
|
case TOY_AST_NODE_IMPORT:
|
||||||
freeLiteral(node->import.identifier);
|
Toy_freeLiteral(node->import.identifier);
|
||||||
freeLiteral(node->import.alias);
|
Toy_freeLiteral(node->import.alias);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (freeSelf) {
|
if (freeSelf) {
|
||||||
FREE(ASTNode, node);
|
TOY_FREE(Toy_ASTNode, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeASTNode(ASTNode* node) {
|
void Toy_freeASTNode(Toy_ASTNode* node) {
|
||||||
freeASTNodeCustom(node, true);
|
freeASTNodeCustom(node, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//various emitters
|
//various emitters
|
||||||
void emitASTNodeLiteral(ASTNode** nodeHandle, Literal literal) {
|
void Toy_emitASTNodeLiteral(Toy_ASTNode** nodeHandle, Toy_Literal literal) {
|
||||||
//allocate a new node
|
//allocate a new node
|
||||||
*nodeHandle = ALLOCATE(ASTNode, 1);
|
*nodeHandle = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
(*nodeHandle)->type = AST_NODE_LITERAL;
|
(*nodeHandle)->type = TOY_AST_NODE_LITERAL;
|
||||||
(*nodeHandle)->atomic.literal = copyLiteral(literal);
|
(*nodeHandle)->atomic.literal = Toy_copyLiteral(literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child) {
|
void Toy_emitASTNodeUnary(Toy_ASTNode** nodeHandle, Toy_Opcode opcode, Toy_ASTNode* child) {
|
||||||
//allocate a new node
|
//allocate a new node
|
||||||
*nodeHandle = ALLOCATE(ASTNode, 1);
|
*nodeHandle = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
(*nodeHandle)->type = AST_NODE_UNARY;
|
(*nodeHandle)->type = TOY_AST_NODE_UNARY;
|
||||||
(*nodeHandle)->unary.opcode = opcode;
|
(*nodeHandle)->unary.opcode = opcode;
|
||||||
(*nodeHandle)->unary.child = child;
|
(*nodeHandle)->unary.child = child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode) {
|
void Toy_emitASTNodeBinary(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs, Toy_Opcode opcode) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_BINARY;
|
tmp->type = TOY_AST_NODE_BINARY;
|
||||||
tmp->binary.opcode = opcode;
|
tmp->binary.opcode = opcode;
|
||||||
tmp->binary.left = *nodeHandle;
|
tmp->binary.left = *nodeHandle;
|
||||||
tmp->binary.right = rhs;
|
tmp->binary.right = rhs;
|
||||||
@@ -175,10 +175,10 @@ void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode) {
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeTernary(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath) {
|
void Toy_emitASTNodeTernary(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath, Toy_ASTNode* elsePath) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_TERNARY;
|
tmp->type = TOY_AST_NODE_TERNARY;
|
||||||
tmp->ternary.condition = condition;
|
tmp->ternary.condition = condition;
|
||||||
tmp->ternary.thenPath = thenPath;
|
tmp->ternary.thenPath = thenPath;
|
||||||
tmp->ternary.elsePath = elsePath;
|
tmp->ternary.elsePath = elsePath;
|
||||||
@@ -186,19 +186,19 @@ void emitASTNodeTernary(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenP
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeGrouping(ASTNode** nodeHandle) {
|
void Toy_emitASTNodeGrouping(Toy_ASTNode** nodeHandle) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_GROUPING;
|
tmp->type = TOY_AST_NODE_GROUPING;
|
||||||
tmp->grouping.child = *nodeHandle;
|
tmp->grouping.child = *nodeHandle;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeBlock(ASTNode** nodeHandle) {
|
void Toy_emitASTNodeBlock(Toy_ASTNode** nodeHandle) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_BLOCK;
|
tmp->type = TOY_AST_NODE_BLOCK;
|
||||||
tmp->block.nodes = NULL; //NOTE: appended by the parser
|
tmp->block.nodes = NULL; //NOTE: appended by the parser
|
||||||
tmp->block.capacity = 0;
|
tmp->block.capacity = 0;
|
||||||
tmp->block.count = 0;
|
tmp->block.count = 0;
|
||||||
@@ -206,10 +206,10 @@ void emitASTNodeBlock(ASTNode** nodeHandle) {
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType) {
|
void Toy_emitASTNodeCompound(Toy_ASTNode** nodeHandle, Toy_LiteralType literalType) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_COMPOUND;
|
tmp->type = TOY_AST_NODE_COMPOUND;
|
||||||
tmp->compound.literalType = literalType;
|
tmp->compound.literalType = literalType;
|
||||||
tmp->compound.nodes = NULL;
|
tmp->compound.nodes = NULL;
|
||||||
tmp->compound.capacity = 0;
|
tmp->compound.capacity = 0;
|
||||||
@@ -218,17 +218,17 @@ void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType) {
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setASTNodePair(ASTNode* node, ASTNode* left, ASTNode* right) {
|
void Toy_setASTNodePair(Toy_ASTNode* node, Toy_ASTNode* left, Toy_ASTNode* right) {
|
||||||
//set - assume the node has already been allocated
|
//set - assume the node has already been allocated
|
||||||
node->type = AST_NODE_PAIR;
|
node->type = TOY_AST_NODE_PAIR;
|
||||||
node->pair.left = left;
|
node->pair.left = left;
|
||||||
node->pair.right = right;
|
node->pair.right = right;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, ASTNode* third) {
|
void Toy_emitASTNodeIndex(Toy_ASTNode** nodeHandle, Toy_ASTNode* first, Toy_ASTNode* second, Toy_ASTNode* third) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_INDEX;
|
tmp->type = TOY_AST_NODE_INDEX;
|
||||||
tmp->index.first = first;
|
tmp->index.first = first;
|
||||||
tmp->index.second = second;
|
tmp->index.second = second;
|
||||||
tmp->index.third = third;
|
tmp->index.third = third;
|
||||||
@@ -236,10 +236,10 @@ void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, AST
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal typeLiteral, ASTNode* expression) {
|
void Toy_emitASTNodeVarDecl(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_Literal typeLiteral, Toy_ASTNode* expression) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_VAR_DECL;
|
tmp->type = TOY_AST_NODE_VAR_DECL;
|
||||||
tmp->varDecl.identifier = identifier;
|
tmp->varDecl.identifier = identifier;
|
||||||
tmp->varDecl.typeLiteral = typeLiteral;
|
tmp->varDecl.typeLiteral = typeLiteral;
|
||||||
tmp->varDecl.expression = expression;
|
tmp->varDecl.expression = expression;
|
||||||
@@ -247,10 +247,10 @@ void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal typeLi
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeFnCollection(ASTNode** nodeHandle) { //a collection of nodes, intended for use with functions
|
void Toy_emitASTNodeFnCollection(Toy_ASTNode** nodeHandle) { //a collection of nodes, intended for use with functions
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_FN_COLLECTION;
|
tmp->type = TOY_AST_NODE_FN_COLLECTION;
|
||||||
tmp->fnCollection.nodes = NULL;
|
tmp->fnCollection.nodes = NULL;
|
||||||
tmp->fnCollection.capacity = 0;
|
tmp->fnCollection.capacity = 0;
|
||||||
tmp->fnCollection.count = 0;
|
tmp->fnCollection.count = 0;
|
||||||
@@ -258,10 +258,10 @@ void emitASTNodeFnCollection(ASTNode** nodeHandle) { //a collection of nodes, in
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* arguments, ASTNode* returns, ASTNode* block) {
|
void Toy_emitASTNodeFnDecl(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_ASTNode* arguments, Toy_ASTNode* returns, Toy_ASTNode* block) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_FN_DECL;
|
tmp->type = TOY_AST_NODE_FN_DECL;
|
||||||
tmp->fnDecl.identifier = identifier;
|
tmp->fnDecl.identifier = identifier;
|
||||||
tmp->fnDecl.arguments = arguments;
|
tmp->fnDecl.arguments = arguments;
|
||||||
tmp->fnDecl.returns = returns;
|
tmp->fnDecl.returns = returns;
|
||||||
@@ -270,29 +270,29 @@ void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* argume
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeFnCall(ASTNode** nodeHandle, ASTNode* arguments) {
|
void Toy_emitASTNodeFnCall(Toy_ASTNode** nodeHandle, Toy_ASTNode* arguments) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_FN_CALL;
|
tmp->type = TOY_AST_NODE_FN_CALL;
|
||||||
tmp->fnCall.arguments = arguments;
|
tmp->fnCall.arguments = arguments;
|
||||||
tmp->fnCall.argumentCount = arguments->fnCollection.count;
|
tmp->fnCall.argumentCount = arguments->fnCollection.count;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeFnReturn(ASTNode** nodeHandle, ASTNode* returns) {
|
void Toy_emitASTNodeFnReturn(Toy_ASTNode** nodeHandle, Toy_ASTNode* returns) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_FN_RETURN;
|
tmp->type = TOY_AST_NODE_FN_RETURN;
|
||||||
tmp->returns.returns = returns;
|
tmp->returns.returns = returns;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeIf(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath) {
|
void Toy_emitASTNodeIf(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath, Toy_ASTNode* elsePath) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_IF;
|
tmp->type = TOY_AST_NODE_IF;
|
||||||
tmp->pathIf.condition = condition;
|
tmp->pathIf.condition = condition;
|
||||||
tmp->pathIf.thenPath = thenPath;
|
tmp->pathIf.thenPath = thenPath;
|
||||||
tmp->pathIf.elsePath = elsePath;
|
tmp->pathIf.elsePath = elsePath;
|
||||||
@@ -300,20 +300,20 @@ void emitASTNodeIf(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath,
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeWhile(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath) {
|
void Toy_emitASTNodeWhile(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_WHILE;
|
tmp->type = TOY_AST_NODE_WHILE;
|
||||||
tmp->pathWhile.condition = condition;
|
tmp->pathWhile.condition = condition;
|
||||||
tmp->pathWhile.thenPath = thenPath;
|
tmp->pathWhile.thenPath = thenPath;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeFor(ASTNode** nodeHandle, ASTNode* preClause, ASTNode* condition, ASTNode* postClause, ASTNode* thenPath) {
|
void Toy_emitASTNodeFor(Toy_ASTNode** nodeHandle, Toy_ASTNode* preClause, Toy_ASTNode* condition, Toy_ASTNode* postClause, Toy_ASTNode* thenPath) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_FOR;
|
tmp->type = TOY_AST_NODE_FOR;
|
||||||
tmp->pathFor.preClause = preClause;
|
tmp->pathFor.preClause = preClause;
|
||||||
tmp->pathFor.condition = condition;
|
tmp->pathFor.condition = condition;
|
||||||
tmp->pathFor.postClause = postClause;
|
tmp->pathFor.postClause = postClause;
|
||||||
@@ -322,64 +322,64 @@ void emitASTNodeFor(ASTNode** nodeHandle, ASTNode* preClause, ASTNode* condition
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeBreak(ASTNode** nodeHandle) {
|
void Toy_emitASTNodeBreak(Toy_ASTNode** nodeHandle) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_BREAK;
|
tmp->type = TOY_AST_NODE_BREAK;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeContinue(ASTNode** nodeHandle) {
|
void Toy_emitASTNodeContinue(Toy_ASTNode** nodeHandle) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_CONTINUE;
|
tmp->type = TOY_AST_NODE_CONTINUE;
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodePrefixIncrement(ASTNode** nodeHandle, Literal identifier) {
|
void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_PREFIX_INCREMENT;
|
tmp->type = TOY_AST_NODE_PREFIX_INCREMENT;
|
||||||
tmp->prefixIncrement.identifier = copyLiteral(identifier);
|
tmp->prefixIncrement.identifier = Toy_copyLiteral(identifier);
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodePrefixDecrement(ASTNode** nodeHandle, Literal identifier) {
|
void Toy_emitASTNodePrefixDecrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_PREFIX_DECREMENT;
|
tmp->type = TOY_AST_NODE_PREFIX_DECREMENT;
|
||||||
tmp->prefixDecrement.identifier = copyLiteral(identifier);
|
tmp->prefixDecrement.identifier = Toy_copyLiteral(identifier);
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodePostfixIncrement(ASTNode** nodeHandle, Literal identifier) {
|
void Toy_emitASTNodePostfixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_POSTFIX_INCREMENT;
|
tmp->type = TOY_AST_NODE_POSTFIX_INCREMENT;
|
||||||
tmp->postfixIncrement.identifier = copyLiteral(identifier);
|
tmp->postfixIncrement.identifier = Toy_copyLiteral(identifier);
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodePostfixDecrement(ASTNode** nodeHandle, Literal identifier) {
|
void Toy_emitASTNodePostfixDecrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_POSTFIX_DECREMENT;
|
tmp->type = TOY_AST_NODE_POSTFIX_DECREMENT;
|
||||||
tmp->postfixDecrement.identifier = copyLiteral(identifier);
|
tmp->postfixDecrement.identifier = Toy_copyLiteral(identifier);
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitASTNodeImport(ASTNode** nodeHandle, Literal identifier, Literal alias) {
|
void Toy_emitASTNodeImport(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_Literal alias) {
|
||||||
ASTNode* tmp = ALLOCATE(ASTNode, 1);
|
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||||
|
|
||||||
tmp->type = AST_NODE_IMPORT;
|
tmp->type = TOY_AST_NODE_IMPORT;
|
||||||
tmp->import.identifier = copyLiteral(identifier);
|
tmp->import.identifier = Toy_copyLiteral(identifier);
|
||||||
tmp->import.alias = copyLiteral(alias);
|
tmp->import.alias = Toy_copyLiteral(alias);
|
||||||
|
|
||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,269 +1,269 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
#include "literal.h"
|
#include "toy_literal.h"
|
||||||
#include "opcodes.h"
|
#include "toy_opcodes.h"
|
||||||
#include "token_types.h"
|
#include "toy_token_types.h"
|
||||||
|
|
||||||
//nodes are the intermediaries between parsers and compilers
|
//nodes are the intermediaries between parsers and compilers
|
||||||
typedef union _node ASTNode;
|
typedef union Toy_private_node Toy_ASTNode;
|
||||||
|
|
||||||
typedef enum ASTNodeType {
|
typedef enum Toy_ASTNodeType {
|
||||||
AST_NODE_ERROR,
|
TOY_AST_NODE_ERROR,
|
||||||
AST_NODE_LITERAL, //a simple value
|
TOY_AST_NODE_LITERAL, //a simple value
|
||||||
AST_NODE_UNARY, //one child + opcode
|
TOY_AST_NODE_UNARY, //one child + opcode
|
||||||
AST_NODE_BINARY, //two children, left and right + opcode
|
TOY_AST_NODE_BINARY, //two children, left and right + opcode
|
||||||
AST_NODE_TERNARY, //three children, condition, then path & else path
|
TOY_AST_NODE_TERNARY, //three children, condition, then path & else path
|
||||||
AST_NODE_GROUPING, //one child
|
TOY_AST_NODE_GROUPING, //one child
|
||||||
AST_NODE_BLOCK, //contains a sub-node array
|
TOY_AST_NODE_BLOCK, //contains a sub-node array
|
||||||
AST_NODE_COMPOUND, //contains a sub-node array
|
TOY_AST_NODE_COMPOUND, //contains a sub-node array
|
||||||
AST_NODE_PAIR, //contains a left and right
|
TOY_AST_NODE_PAIR, //contains a left and right
|
||||||
AST_NODE_INDEX, //index a variable
|
TOY_AST_NODE_INDEX, //index a variable
|
||||||
AST_NODE_VAR_DECL, //contains identifier literal, typenode, expression definition
|
TOY_AST_NODE_VAR_DECL, //contains identifier literal, typenode, expression definition
|
||||||
AST_NODE_FN_DECL, //containd identifier literal, arguments node, returns node, block node
|
TOY_AST_NODE_FN_DECL, //containd identifier literal, arguments node, returns node, block node
|
||||||
AST_NODE_FN_COLLECTION, //parts of a function
|
TOY_AST_NODE_FN_COLLECTION, //parts of a function
|
||||||
AST_NODE_FN_CALL, //call a function
|
TOY_AST_NODE_FN_CALL, //call a function
|
||||||
AST_NODE_FN_RETURN, //for control flow
|
TOY_AST_NODE_FN_RETURN, //for control flow
|
||||||
AST_NODE_IF, //for control flow
|
TOY_AST_NODE_IF, //for control flow
|
||||||
AST_NODE_WHILE, //for control flow
|
TOY_AST_NODE_WHILE, //for control flow
|
||||||
AST_NODE_FOR, //for control flow
|
TOY_AST_NODE_FOR, //for control flow
|
||||||
AST_NODE_BREAK, //for control flow
|
TOY_AST_NODE_BREAK, //for control flow
|
||||||
AST_NODE_CONTINUE, //for control flow
|
TOY_AST_NODE_CONTINUE, //for control flow
|
||||||
AST_NODE_PREFIX_INCREMENT, //increment a variable
|
TOY_AST_NODE_PREFIX_INCREMENT, //increment a variable
|
||||||
AST_NODE_POSTFIX_INCREMENT, //increment a variable
|
TOY_AST_NODE_POSTFIX_INCREMENT, //increment a variable
|
||||||
AST_NODE_PREFIX_DECREMENT, //decrement a variable
|
TOY_AST_NODE_PREFIX_DECREMENT, //decrement a variable
|
||||||
AST_NODE_POSTFIX_DECREMENT, //decrement a variable
|
TOY_AST_NODE_POSTFIX_DECREMENT, //decrement a variable
|
||||||
AST_NODE_IMPORT, //import a library
|
TOY_AST_NODE_IMPORT, //import a library
|
||||||
} ASTNodeType;
|
} Toy_ASTNodeType;
|
||||||
|
|
||||||
//literals
|
//literals
|
||||||
void emitASTNodeLiteral(ASTNode** nodeHandle, Literal literal);
|
void Toy_emitASTNodeLiteral(Toy_ASTNode** nodeHandle, Toy_Literal literal);
|
||||||
|
|
||||||
typedef struct NodeLiteral {
|
typedef struct Toy_NodeLiteral {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
Literal literal;
|
Toy_Literal literal;
|
||||||
} NodeLiteral;
|
} Toy_NodeLiteral;
|
||||||
|
|
||||||
//unary operator
|
//unary operator
|
||||||
void emitASTNodeUnary(ASTNode** nodeHandle, Opcode opcode, ASTNode* child);
|
void Toy_emitASTNodeUnary(Toy_ASTNode** nodeHandle, Toy_Opcode opcode, Toy_ASTNode* child);
|
||||||
|
|
||||||
typedef struct NodeUnary {
|
typedef struct Toy_NodeUnary {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
Opcode opcode;
|
Toy_Opcode opcode;
|
||||||
ASTNode* child;
|
Toy_ASTNode* child;
|
||||||
} NodeUnary;
|
} Toy_NodeUnary;
|
||||||
|
|
||||||
//binary operator
|
//binary operator
|
||||||
void emitASTNodeBinary(ASTNode** nodeHandle, ASTNode* rhs, Opcode opcode); //handled node becomes lhs
|
void Toy_emitASTNodeBinary(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs, Toy_Opcode opcode); //handled node becomes lhs
|
||||||
|
|
||||||
typedef struct NodeBinary {
|
typedef struct Toy_NodeBinary {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
Opcode opcode;
|
Toy_Opcode opcode;
|
||||||
ASTNode* left;
|
Toy_ASTNode* left;
|
||||||
ASTNode* right;
|
Toy_ASTNode* right;
|
||||||
} NodeBinary;
|
} Toy_NodeBinary;
|
||||||
|
|
||||||
//ternary operator
|
//ternary operator
|
||||||
void emitASTNodeTernary(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath);
|
void Toy_emitASTNodeTernary(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath, Toy_ASTNode* elsePath);
|
||||||
|
|
||||||
typedef struct NodeTernary {
|
typedef struct Toy_NodeTernary {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
ASTNode* condition;
|
Toy_ASTNode* condition;
|
||||||
ASTNode* thenPath;
|
Toy_ASTNode* thenPath;
|
||||||
ASTNode* elsePath;
|
Toy_ASTNode* elsePath;
|
||||||
} NodeTernary;
|
} Toy_NodeTernary;
|
||||||
|
|
||||||
//grouping of other AST nodes
|
//grouping of other AST nodes
|
||||||
void emitASTNodeGrouping(ASTNode** nodeHandle);
|
void Toy_emitASTNodeGrouping(Toy_ASTNode** nodeHandle);
|
||||||
|
|
||||||
typedef struct NodeGrouping {
|
typedef struct Toy_NodeGrouping {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
ASTNode* child;
|
Toy_ASTNode* child;
|
||||||
} NodeGrouping;
|
} Toy_NodeGrouping;
|
||||||
|
|
||||||
//block of statement nodes
|
//block of statement nodes
|
||||||
void emitASTNodeBlock(ASTNode** nodeHandle);
|
void Toy_emitASTNodeBlock(Toy_ASTNode** nodeHandle);
|
||||||
|
|
||||||
typedef struct NodeBlock {
|
typedef struct Toy_NodeBlock {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
ASTNode* nodes;
|
Toy_ASTNode* nodes;
|
||||||
int capacity;
|
int capacity;
|
||||||
int count;
|
int count;
|
||||||
} NodeBlock;
|
} Toy_NodeBlock;
|
||||||
|
|
||||||
//compound literals (array, dictionary)
|
//compound literals (array, dictionary)
|
||||||
void emitASTNodeCompound(ASTNode** nodeHandle, LiteralType literalType);
|
void Toy_emitASTNodeCompound(Toy_ASTNode** nodeHandle, Toy_LiteralType literalType);
|
||||||
|
|
||||||
typedef struct NodeCompound {
|
typedef struct Toy_NodeCompound {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
LiteralType literalType;
|
Toy_LiteralType literalType;
|
||||||
ASTNode* nodes;
|
Toy_ASTNode* nodes;
|
||||||
int capacity;
|
int capacity;
|
||||||
int count;
|
int count;
|
||||||
} NodeCompound;
|
} Toy_NodeCompound;
|
||||||
|
|
||||||
void setASTNodePair(ASTNode* node, ASTNode* left, ASTNode* right); //NOTE: this is a set function, not an emit function
|
void Toy_setASTNodePair(Toy_ASTNode* node, Toy_ASTNode* left, Toy_ASTNode* right); //NOTE: this is a set function, not an emit function
|
||||||
|
|
||||||
typedef struct NodePair {
|
typedef struct Toy_NodePair {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
ASTNode* left;
|
Toy_ASTNode* left;
|
||||||
ASTNode* right;
|
Toy_ASTNode* right;
|
||||||
} NodePair;
|
} Toy_NodePair;
|
||||||
|
|
||||||
void emitASTNodeIndex(ASTNode** nodeHandle, ASTNode* first, ASTNode* second, ASTNode* third);
|
void Toy_emitASTNodeIndex(Toy_ASTNode** nodeHandle, Toy_ASTNode* first, Toy_ASTNode* second, Toy_ASTNode* third);
|
||||||
|
|
||||||
typedef struct NodeIndex {
|
typedef struct Toy_NodeIndex {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
ASTNode* first;
|
Toy_ASTNode* first;
|
||||||
ASTNode* second;
|
Toy_ASTNode* second;
|
||||||
ASTNode* third;
|
Toy_ASTNode* third;
|
||||||
} NodeIndex;
|
} Toy_NodeIndex;
|
||||||
|
|
||||||
//variable declaration
|
//variable declaration
|
||||||
void emitASTNodeVarDecl(ASTNode** nodeHandle, Literal identifier, Literal type, ASTNode* expression);
|
void Toy_emitASTNodeVarDecl(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_Literal type, Toy_ASTNode* expression);
|
||||||
|
|
||||||
typedef struct NodeVarDecl {
|
typedef struct Toy_NodeVarDecl {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
Literal identifier;
|
Toy_Literal identifier;
|
||||||
Literal typeLiteral;
|
Toy_Literal typeLiteral;
|
||||||
ASTNode* expression;
|
Toy_ASTNode* expression;
|
||||||
} NodeVarDecl;
|
} Toy_NodeVarDecl;
|
||||||
|
|
||||||
//NOTE: fnCollection is used by fnDecl, fnCall and fnReturn
|
//NOTE: fnCollection is used by fnDecl, fnCall and fnReturn
|
||||||
void emitASTNodeFnCollection(ASTNode** nodeHandle);
|
void Toy_emitASTNodeFnCollection(Toy_ASTNode** nodeHandle);
|
||||||
|
|
||||||
typedef struct NodeFnCollection {
|
typedef struct Toy_NodeFnCollection {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
ASTNode* nodes;
|
Toy_ASTNode* nodes;
|
||||||
int capacity;
|
int capacity;
|
||||||
int count;
|
int count;
|
||||||
} NodeFnCollection;
|
} Toy_NodeFnCollection;
|
||||||
|
|
||||||
//function declaration
|
//function declaration
|
||||||
void emitASTNodeFnDecl(ASTNode** nodeHandle, Literal identifier, ASTNode* arguments, ASTNode* returns, ASTNode* block);
|
void Toy_emitASTNodeFnDecl(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_ASTNode* arguments, Toy_ASTNode* returns, Toy_ASTNode* block);
|
||||||
|
|
||||||
typedef struct NodeFnDecl {
|
typedef struct Toy_NodeFnDecl {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
Literal identifier;
|
Toy_Literal identifier;
|
||||||
ASTNode* arguments;
|
Toy_ASTNode* arguments;
|
||||||
ASTNode* returns;
|
Toy_ASTNode* returns;
|
||||||
ASTNode* block;
|
Toy_ASTNode* block;
|
||||||
} NodeFnDecl;
|
} Toy_NodeFnDecl;
|
||||||
|
|
||||||
//function call
|
//function call
|
||||||
void emitASTNodeFnCall(ASTNode** nodeHandle, ASTNode* arguments);
|
void Toy_emitASTNodeFnCall(Toy_ASTNode** nodeHandle, Toy_ASTNode* arguments);
|
||||||
|
|
||||||
typedef struct NodeFnCall {
|
typedef struct Toy_NodeFnCall {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
ASTNode* arguments;
|
Toy_ASTNode* arguments;
|
||||||
int argumentCount; //NOTE: leave this, so it can be hacked by dottify()
|
int argumentCount; //NOTE: leave this, so it can be hacked by dottify()
|
||||||
} NodeFnCall;
|
} Toy_NodeFnCall;
|
||||||
|
|
||||||
//function return
|
//function return
|
||||||
void emitASTNodeFnReturn(ASTNode** nodeHandle, ASTNode* returns);
|
void Toy_emitASTNodeFnReturn(Toy_ASTNode** nodeHandle, Toy_ASTNode* returns);
|
||||||
|
|
||||||
typedef struct NodeFnReturn {
|
typedef struct Toy_NodeFnReturn {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
ASTNode* returns;
|
Toy_ASTNode* returns;
|
||||||
} NodeFnReturn;
|
} Toy_NodeFnReturn;
|
||||||
|
|
||||||
//control flow path - if-else, while, for, break, continue, return
|
//control flow path - if-else, while, for, break, continue, return
|
||||||
void emitASTNodeIf(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath, ASTNode* elsePath);
|
void Toy_emitASTNodeIf(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath, Toy_ASTNode* elsePath);
|
||||||
void emitASTNodeWhile(ASTNode** nodeHandle, ASTNode* condition, ASTNode* thenPath);
|
void Toy_emitASTNodeWhile(Toy_ASTNode** nodeHandle, Toy_ASTNode* condition, Toy_ASTNode* thenPath);
|
||||||
void emitASTNodeFor(ASTNode** nodeHandle, ASTNode* preClause, ASTNode* condition, ASTNode* postClause, ASTNode* thenPath);
|
void Toy_emitASTNodeFor(Toy_ASTNode** nodeHandle, Toy_ASTNode* preClause, Toy_ASTNode* condition, Toy_ASTNode* postClause, Toy_ASTNode* thenPath);
|
||||||
void emitASTNodeBreak(ASTNode** nodeHandle);
|
void Toy_emitASTNodeBreak(Toy_ASTNode** nodeHandle);
|
||||||
void emitASTNodeContinue(ASTNode** nodeHandle);
|
void Toy_emitASTNodeContinue(Toy_ASTNode** nodeHandle);
|
||||||
|
|
||||||
typedef struct NodeIf {
|
typedef struct Toy_NodeIf {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
ASTNode* condition;
|
Toy_ASTNode* condition;
|
||||||
ASTNode* thenPath;
|
Toy_ASTNode* thenPath;
|
||||||
ASTNode* elsePath;
|
Toy_ASTNode* elsePath;
|
||||||
} NodeIf;
|
} Toy_NodeIf;
|
||||||
|
|
||||||
typedef struct NodeWhile {
|
typedef struct Toy_NodeWhile {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
ASTNode* condition;
|
Toy_ASTNode* condition;
|
||||||
ASTNode* thenPath;
|
Toy_ASTNode* thenPath;
|
||||||
} NodeWhile;
|
} Toy_NodeWhile;
|
||||||
|
|
||||||
typedef struct NodeFor {
|
typedef struct Toy_NodeFor {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
ASTNode* preClause;
|
Toy_ASTNode* preClause;
|
||||||
ASTNode* condition;
|
Toy_ASTNode* condition;
|
||||||
ASTNode* postClause;
|
Toy_ASTNode* postClause;
|
||||||
ASTNode* thenPath;
|
Toy_ASTNode* thenPath;
|
||||||
} NodeFor;
|
} Toy_NodeFor;
|
||||||
|
|
||||||
typedef struct NodeBreak {
|
typedef struct Toy_NodeBreak {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
} NodeBreak;
|
} Toy_NodeBreak;
|
||||||
|
|
||||||
typedef struct NodeContinue {
|
typedef struct Toy_NodeContinue {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
} NodeContinue;
|
} Toy_NodeContinue;
|
||||||
|
|
||||||
//pre-post increment/decrement
|
//pre-post increment/decrement
|
||||||
void emitASTNodePrefixIncrement(ASTNode** nodeHandle, Literal identifier);
|
void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
|
||||||
void emitASTNodePrefixDecrement(ASTNode** nodeHandle, Literal identifier);
|
void Toy_emitASTNodePrefixDecrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
|
||||||
void emitASTNodePostfixIncrement(ASTNode** nodeHandle, Literal identifier);
|
void Toy_emitASTNodePostfixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
|
||||||
void emitASTNodePostfixDecrement(ASTNode** nodeHandle, Literal identifier);
|
void Toy_emitASTNodePostfixDecrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
|
||||||
|
|
||||||
typedef struct NodePrefixIncrement {
|
typedef struct Toy_NodePrefixIncrement {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
Literal identifier;
|
Toy_Literal identifier;
|
||||||
} NodePrefixIncrement;
|
} Toy_NodePrefixIncrement;
|
||||||
|
|
||||||
typedef struct NodePrefixDecrement {
|
typedef struct Toy_NodePrefixDecrement {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
Literal identifier;
|
Toy_Literal identifier;
|
||||||
} NodePrefixDecrement;
|
} Toy_NodePrefixDecrement;
|
||||||
|
|
||||||
typedef struct NodePostfixIncrement {
|
typedef struct Toy_NodePostfixIncrement {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
Literal identifier;
|
Toy_Literal identifier;
|
||||||
} NodePostfixIncrement;
|
} Toy_NodePostfixIncrement;
|
||||||
|
|
||||||
typedef struct NodePostfixDecrement {
|
typedef struct Toy_NodePostfixDecrement {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
Literal identifier;
|
Toy_Literal identifier;
|
||||||
} NodePostfixDecrement;
|
} Toy_NodePostfixDecrement;
|
||||||
|
|
||||||
//import a library
|
//import a library
|
||||||
void emitASTNodeImport(ASTNode** nodeHandle, Literal identifier, Literal alias);
|
void Toy_emitASTNodeImport(Toy_ASTNode** nodeHandle, Toy_Literal identifier, Toy_Literal alias);
|
||||||
|
|
||||||
typedef struct NodeImport {
|
typedef struct Toy_NodeImport {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
Literal identifier;
|
Toy_Literal identifier;
|
||||||
Literal alias;
|
Toy_Literal alias;
|
||||||
} NodeImport;
|
} Toy_NodeImport;
|
||||||
|
|
||||||
union _node {
|
union Toy_private_node {
|
||||||
ASTNodeType type;
|
Toy_ASTNodeType type;
|
||||||
NodeLiteral atomic;
|
Toy_NodeLiteral atomic;
|
||||||
NodeUnary unary;
|
Toy_NodeUnary unary;
|
||||||
NodeBinary binary;
|
Toy_NodeBinary binary;
|
||||||
NodeTernary ternary;
|
Toy_NodeTernary ternary;
|
||||||
NodeGrouping grouping;
|
Toy_NodeGrouping grouping;
|
||||||
NodeBlock block;
|
Toy_NodeBlock block;
|
||||||
NodeCompound compound;
|
Toy_NodeCompound compound;
|
||||||
NodePair pair;
|
Toy_NodePair pair;
|
||||||
NodeIndex index;
|
Toy_NodeIndex index;
|
||||||
NodeVarDecl varDecl;
|
Toy_NodeVarDecl varDecl;
|
||||||
NodeFnCollection fnCollection;
|
Toy_NodeFnCollection fnCollection;
|
||||||
NodeFnDecl fnDecl;
|
Toy_NodeFnDecl fnDecl;
|
||||||
NodeFnCall fnCall;
|
Toy_NodeFnCall fnCall;
|
||||||
NodeFnReturn returns;
|
Toy_NodeFnReturn returns;
|
||||||
NodeIf pathIf;
|
Toy_NodeIf pathIf;
|
||||||
NodeWhile pathWhile;
|
Toy_NodeWhile pathWhile;
|
||||||
NodeFor pathFor;
|
Toy_NodeFor pathFor;
|
||||||
NodeBreak pathBreak;
|
Toy_NodeBreak pathBreak;
|
||||||
NodeContinue pathContinue;
|
Toy_NodeContinue pathContinue;
|
||||||
NodePrefixIncrement prefixIncrement;
|
Toy_NodePrefixIncrement prefixIncrement;
|
||||||
NodePrefixDecrement prefixDecrement;
|
Toy_NodePrefixDecrement prefixDecrement;
|
||||||
NodePostfixIncrement postfixIncrement;
|
Toy_NodePostfixIncrement postfixIncrement;
|
||||||
NodePostfixDecrement postfixDecrement;
|
Toy_NodePostfixDecrement postfixDecrement;
|
||||||
NodeImport import;
|
Toy_NodeImport import;
|
||||||
};
|
};
|
||||||
|
|
||||||
TOY_API void freeASTNode(ASTNode* node);
|
TOY_API void Toy_freeASTNode(Toy_ASTNode* node);
|
||||||
|
|||||||
1246
source/toy_builtin.c
1246
source/toy_builtin.c
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
//the _index function is a historical oddity - it's used whenever a compound is indexed
|
//the _index function is a historical oddity - it's used whenever a compound is indexed
|
||||||
int _index(Interpreter* interpreter, LiteralArray* arguments);
|
int _index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
|
||||||
|
|
||||||
//globally available native functions
|
//globally available native functions
|
||||||
int _set(Interpreter* interpreter, LiteralArray* arguments);
|
int _set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
|
||||||
int _get(Interpreter* interpreter, LiteralArray* arguments);
|
int _get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
|
||||||
int _push(Interpreter* interpreter, LiteralArray* arguments);
|
int _push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
|
||||||
int _pop(Interpreter* interpreter, LiteralArray* arguments);
|
int _pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
|
||||||
int _length(Interpreter* interpreter, LiteralArray* arguments);
|
int _length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
|
||||||
int _clear(Interpreter* interpreter, LiteralArray* arguments);
|
int _clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ STATIC_ASSERT(sizeof(unsigned int) == 4);
|
|||||||
//declare the singleton
|
//declare the singleton
|
||||||
Command command;
|
Command command;
|
||||||
|
|
||||||
void initCommand(int argc, const char* argv[]) {
|
void Toy_initCommand(int argc, const char* argv[]) {
|
||||||
//default values
|
//default values
|
||||||
command.error = false;
|
command.error = false;
|
||||||
command.help = false;
|
command.help = false;
|
||||||
@@ -95,12 +95,12 @@ void initCommand(int argc, const char* argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void usageCommand(int argc, const char* argv[]) {
|
void Toy_usageCommand(int argc, const char* argv[]) {
|
||||||
printf("Usage: %s [<file.tb> | -h | -v | [-d][-f file | -i source | -c file [-o outfile]]]\n\n", argv[0]);
|
printf("Usage: %s [<file.tb> | -h | -v | [-d][-f file | -i source | -c file [-o outfile]]]\n\n", argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void helpCommand(int argc, const char* argv[]) {
|
void Toy_helpCommand(int argc, const char* argv[]) {
|
||||||
usageCommand(argc, argv);
|
Toy_usageCommand(argc, argv);
|
||||||
|
|
||||||
printf("<file.tb>\t\t\tBinary input file in tb format, must be version %d.%d.%d.\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH);
|
printf("<file.tb>\t\t\tBinary input file in tb format, must be version %d.%d.%d.\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH);
|
||||||
printf("-h\t| --help\t\tShow this help then exit.\n\n");
|
printf("-h\t| --help\t\tShow this help then exit.\n\n");
|
||||||
@@ -112,7 +112,7 @@ void helpCommand(int argc, const char* argv[]) {
|
|||||||
printf("-o\t| --output outfile\tName of the output file built with --compile (default: out.tb).\n\n");
|
printf("-o\t| --output outfile\tName of the output file built with --compile (default: out.tb).\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyrightCommand(int argc, const char* argv[]) {
|
void Toy_copyrightCommand(int argc, const char* argv[]) {
|
||||||
printf("Toy Programming Language Interpreter Version %d.%d.%d (built on %s)\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD);
|
printf("Toy Programming Language Interpreter Version %d.%d.%d (built on %s)\n\n", TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH, TOY_VERSION_BUILD);
|
||||||
printf("Copyright (c) 2020-2022 Kayne Ruse, KR Game Studios\n\n");
|
printf("Copyright (c) 2020-2022 Kayne Ruse, KR Game Studios\n\n");
|
||||||
printf("This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.\n\n");
|
printf("This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.\n\n");
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define TOY_VERSION_MAJOR 0
|
#define TOY_VERSION_MAJOR 0
|
||||||
#define TOY_VERSION_MINOR 7
|
#define TOY_VERSION_MINOR 8
|
||||||
#define TOY_VERSION_PATCH 1
|
#define TOY_VERSION_PATCH 0
|
||||||
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
|
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
|
||||||
|
|
||||||
//platform-specific specifications
|
//platform-specific specifications
|
||||||
@@ -37,9 +37,9 @@ typedef struct {
|
|||||||
|
|
||||||
extern Command command;
|
extern Command command;
|
||||||
|
|
||||||
void initCommand(int argc, const char* argv[]);
|
void Toy_initCommand(int argc, const char* argv[]);
|
||||||
|
|
||||||
void usageCommand(int argc, const char* argv[]);
|
void Toy_usageCommand(int argc, const char* argv[]);
|
||||||
void helpCommand(int argc, const char* argv[]);
|
void Toy_helpCommand(int argc, const char* argv[]);
|
||||||
void copyrightCommand(int argc, const char* argv[]);
|
void Toy_copyrightCommand(int argc, const char* argv[]);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
#include "opcodes.h"
|
#include "toy_opcodes.h"
|
||||||
#include "ast_node.h"
|
#include "toy_ast_node.h"
|
||||||
#include "literal_array.h"
|
#include "toy_literal_array.h"
|
||||||
|
|
||||||
//the compiler takes the nodes, and turns them into sequential chunks of bytecode, saving literals to an external array
|
//the compiler takes the nodes, and turns them into sequential chunks of bytecode, saving literals to an external array
|
||||||
typedef struct Compiler {
|
typedef struct Toy_Compiler {
|
||||||
LiteralArray literalCache;
|
Toy_LiteralArray literalCache;
|
||||||
unsigned char* bytecode;
|
unsigned char* bytecode;
|
||||||
int capacity;
|
int capacity;
|
||||||
int count;
|
int count;
|
||||||
} Compiler;
|
} Toy_Compiler;
|
||||||
|
|
||||||
TOY_API void initCompiler(Compiler* compiler);
|
TOY_API void Toy_initCompiler(Toy_Compiler* compiler);
|
||||||
TOY_API void writeCompiler(Compiler* compiler, ASTNode* node);
|
TOY_API void Toy_writeCompiler(Toy_Compiler* compiler, Toy_ASTNode* node);
|
||||||
TOY_API void freeCompiler(Compiler* compiler);
|
TOY_API void Toy_freeCompiler(Toy_Compiler* compiler);
|
||||||
|
|
||||||
//embed the header, data section, code section, function section, etc.
|
//embed the header, data section, code section, function section, etc.
|
||||||
TOY_API unsigned char* collateCompiler(Compiler* compiler, int* size);
|
TOY_API unsigned char* Toy_collateCompiler(Toy_Compiler* compiler, int* size);
|
||||||
|
|||||||
@@ -3,28 +3,28 @@
|
|||||||
//NOTE: you need both font AND background for these to work
|
//NOTE: you need both font AND background for these to work
|
||||||
|
|
||||||
//fonts color
|
//fonts color
|
||||||
#define FONT_BLACK "\033[30;"
|
#define TOY_CC_FONT_BLACK "\033[30;"
|
||||||
#define FONT_RED "\033[31;"
|
#define TOY_CC_FONT_RED "\033[31;"
|
||||||
#define FONT_GREEN "\033[32;"
|
#define TOY_CC_FONT_GREEN "\033[32;"
|
||||||
#define FONT_YELLOW "\033[33;"
|
#define TOY_CC_FONT_YELLOW "\033[33;"
|
||||||
#define FONT_BLUE "\033[34;"
|
#define TOY_CC_FONT_BLUE "\033[34;"
|
||||||
#define FONT_PURPLE "\033[35;"
|
#define TOY_CC_FONT_PURPLE "\033[35;"
|
||||||
#define FONT_DGREEN "\033[6;"
|
#define TOY_CC_FONT_DGREEN "\033[6;"
|
||||||
#define FONT_WHITE "\033[7;"
|
#define TOY_CC_FONT_WHITE "\033[7;"
|
||||||
#define FONT_CYAN "\x1b[36m"
|
#define TOY_CC_FONT_CYAN "\x1b[36m"
|
||||||
|
|
||||||
//background color
|
//background color
|
||||||
#define BACK_BLACK "40m"
|
#define TOY_CC_BACK_BLACK "40m"
|
||||||
#define BACK_RED "41m"
|
#define TOY_CC_BACK_RED "41m"
|
||||||
#define BACK_GREEN "42m"
|
#define TOY_CC_BACK_GREEN "42m"
|
||||||
#define BACK_YELLOW "43m"
|
#define TOY_CC_BACK_YELLOW "43m"
|
||||||
#define BACK_BLUE "44m"
|
#define TOY_CC_BACK_BLUE "44m"
|
||||||
#define BACK_PURPLE "45m"
|
#define TOY_CC_BACK_PURPLE "45m"
|
||||||
#define BACK_DGREEN "46m"
|
#define TOY_CC_BACK_DGREEN "46m"
|
||||||
#define BACK_WHITE "47m"
|
#define TOY_CC_BACK_WHITE "47m"
|
||||||
|
|
||||||
//useful
|
//useful
|
||||||
#define NOTICE FONT_GREEN BACK_BLACK
|
#define TOY_CC_NOTICE TOY_CC_FONT_GREEN TOY_CC_BACK_BLACK
|
||||||
#define WARN FONT_YELLOW BACK_BLACK
|
#define TOY_CC_WARN TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK
|
||||||
#define ERROR FONT_RED BACK_BLACK
|
#define TOY_CC_ERROR TOY_CC_FONT_RED TOY_CC_BACK_BLACK
|
||||||
#define RESET "\033[0m"
|
#define TOY_CC_RESET "\033[0m"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,56 +1,56 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
#include "literal.h"
|
#include "toy_literal.h"
|
||||||
#include "literal_array.h"
|
#include "toy_literal_array.h"
|
||||||
#include "literal_dictionary.h"
|
#include "toy_literal_dictionary.h"
|
||||||
#include "scope.h"
|
#include "toy_scope.h"
|
||||||
|
|
||||||
typedef void (*PrintFn)(const char*);
|
typedef void (*Toy_PrintFn)(const char*);
|
||||||
|
|
||||||
//the interpreter acts depending on the bytecode instructions
|
//the interpreter acts depending on the bytecode instructions
|
||||||
typedef struct Interpreter {
|
typedef struct Toy_Interpreter {
|
||||||
//input
|
//input
|
||||||
unsigned char* bytecode;
|
unsigned char* bytecode;
|
||||||
int length;
|
int length;
|
||||||
int count;
|
int count;
|
||||||
int codeStart; //BUGFIX: for jumps, must be initialized to -1
|
int codeStart; //BUGFIX: for jumps, must be initialized to -1
|
||||||
LiteralArray literalCache; //read-only - built from the bytecode, refreshed each time new bytecode is provided
|
Toy_LiteralArray literalCache; //read-only - built from the bytecode, refreshed each time new bytecode is provided
|
||||||
|
|
||||||
//operation
|
//operation
|
||||||
Scope* scope;
|
Toy_Scope* scope;
|
||||||
LiteralArray stack;
|
Toy_LiteralArray stack;
|
||||||
|
|
||||||
//Library APIs
|
//Library APIs
|
||||||
LiteralDictionary* hooks;
|
Toy_LiteralDictionary* hooks;
|
||||||
|
|
||||||
//debug outputs
|
//debug outputs
|
||||||
PrintFn printOutput;
|
Toy_PrintFn printOutput;
|
||||||
PrintFn assertOutput;
|
Toy_PrintFn assertOutput;
|
||||||
PrintFn errorOutput;
|
Toy_PrintFn errorOutput;
|
||||||
|
|
||||||
int depth; //don't overflow
|
int depth; //don't overflow
|
||||||
bool panic;
|
bool panic;
|
||||||
} Interpreter;
|
} Toy_Interpreter;
|
||||||
|
|
||||||
//native API
|
//native API
|
||||||
typedef int (*NativeFn)(Interpreter* interpreter, LiteralArray* arguments);
|
typedef int (*Toy_NativeFn)(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments);
|
||||||
TOY_API bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func);
|
TOY_API bool Toy_injectNativeFn(Toy_Interpreter* interpreter, char* name, Toy_NativeFn func);
|
||||||
|
|
||||||
typedef int (*HookFn)(Interpreter* interpreter, Literal identifier, Literal alias);
|
typedef int (*Toy_HookFn)(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
|
||||||
TOY_API bool injectNativeHook(Interpreter* interpreter, char* name, HookFn hook);
|
TOY_API bool Toy_injectNativeHook(Toy_Interpreter* interpreter, char* name, Toy_HookFn hook);
|
||||||
|
|
||||||
TOY_API bool callLiteralFn(Interpreter* interpreter, Literal func, LiteralArray* arguments, LiteralArray* returns);
|
TOY_API bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_LiteralArray* arguments, Toy_LiteralArray* returns);
|
||||||
TOY_API bool callFn(Interpreter* interpreter, char* name, LiteralArray* arguments, LiteralArray* returns);
|
TOY_API bool Toy_callFn(Toy_Interpreter* interpreter, char* name, Toy_LiteralArray* arguments, Toy_LiteralArray* returns);
|
||||||
|
|
||||||
//utilities for the host program
|
//utilities for the host program
|
||||||
TOY_API bool parseIdentifierToValue(Interpreter* interpreter, Literal* literalPtr);
|
TOY_API bool Toy_parseIdentifierToValue(Toy_Interpreter* interpreter, Toy_Literal* literalPtr);
|
||||||
TOY_API void setInterpreterPrint(Interpreter* interpreter, PrintFn printOutput);
|
TOY_API void Toy_setInterpreterPrint(Toy_Interpreter* interpreter, Toy_PrintFn printOutput);
|
||||||
TOY_API void setInterpreterAssert(Interpreter* interpreter, PrintFn assertOutput);
|
TOY_API void Toy_setInterpreterAssert(Toy_Interpreter* interpreter, Toy_PrintFn assertOutput);
|
||||||
TOY_API void setInterpreterError(Interpreter* interpreter, PrintFn errorOutput);
|
TOY_API void Toy_setInterpreterError(Toy_Interpreter* interpreter, Toy_PrintFn errorOutput);
|
||||||
|
|
||||||
//main access
|
//main access
|
||||||
TOY_API void initInterpreter(Interpreter* interpreter); //start of program
|
TOY_API void Toy_initInterpreter(Toy_Interpreter* interpreter); //start of program
|
||||||
TOY_API void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length); //run the code
|
TOY_API void Toy_runInterpreter(Toy_Interpreter* interpreter, unsigned char* bytecode, int length); //run the code
|
||||||
TOY_API void resetInterpreter(Interpreter* interpreter); //use this to reset the interpreter's environment between runs
|
TOY_API void Toy_resetInterpreter(Toy_Interpreter* interpreter); //use this to reset the interpreter's environment between runs
|
||||||
TOY_API void freeInterpreter(Interpreter* interpreter); //end of program
|
TOY_API void Toy_freeInterpreter(Toy_Interpreter* interpreter); //end of program
|
||||||
|
|||||||
@@ -1,77 +1,77 @@
|
|||||||
#include "keyword_types.h"
|
#include "toy_keyword_types.h"
|
||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
KeywordType keywordTypes[] = {
|
Toy_KeywordType Toy_keywordTypes[] = {
|
||||||
//type keywords
|
//type keywords
|
||||||
{TOKEN_NULL, "null"},
|
{TOY_TOKEN_NULL, "null"},
|
||||||
{TOKEN_BOOLEAN, "bool"},
|
{TOY_TOKEN_BOOLEAN, "bool"},
|
||||||
{TOKEN_INTEGER, "int"},
|
{TOY_TOKEN_INTEGER, "int"},
|
||||||
{TOKEN_FLOAT, "float"},
|
{TOY_TOKEN_FLOAT, "float"},
|
||||||
{TOKEN_STRING, "string"},
|
{TOY_TOKEN_STRING, "string"},
|
||||||
{TOKEN_FUNCTION, "fn"},
|
{TOY_TOKEN_FUNCTION, "fn"},
|
||||||
{TOKEN_OPAQUE, "opaque"},
|
{TOY_TOKEN_OPAQUE, "opaque"},
|
||||||
{TOKEN_ANY, "any"},
|
{TOY_TOKEN_ANY, "any"},
|
||||||
|
|
||||||
//other keywords
|
//other keywords
|
||||||
{TOKEN_AS, "as"},
|
{TOY_TOKEN_AS, "as"},
|
||||||
{TOKEN_ASSERT, "assert"},
|
{TOY_TOKEN_ASSERT, "assert"},
|
||||||
{TOKEN_BREAK, "break"},
|
{TOY_TOKEN_BREAK, "break"},
|
||||||
{TOKEN_CLASS, "class"},
|
{TOY_TOKEN_CLASS, "class"},
|
||||||
{TOKEN_CONST, "const"},
|
{TOY_TOKEN_CONST, "const"},
|
||||||
{TOKEN_CONTINUE, "continue"},
|
{TOY_TOKEN_CONTINUE, "continue"},
|
||||||
{TOKEN_DO, "do"},
|
{TOY_TOKEN_DO, "do"},
|
||||||
{TOKEN_ELSE, "else"},
|
{TOY_TOKEN_ELSE, "else"},
|
||||||
{TOKEN_EXPORT, "export"},
|
{TOY_TOKEN_EXPORT, "export"},
|
||||||
{TOKEN_FOR, "for"},
|
{TOY_TOKEN_FOR, "for"},
|
||||||
{TOKEN_FOREACH, "foreach"},
|
{TOY_TOKEN_FOREACH, "foreach"},
|
||||||
{TOKEN_IF, "if"},
|
{TOY_TOKEN_IF, "if"},
|
||||||
{TOKEN_IMPORT, "import"},
|
{TOY_TOKEN_IMPORT, "import"},
|
||||||
{TOKEN_IN, "in"},
|
{TOY_TOKEN_IN, "in"},
|
||||||
{TOKEN_OF, "of"},
|
{TOY_TOKEN_OF, "of"},
|
||||||
{TOKEN_PRINT, "print"},
|
{TOY_TOKEN_PRINT, "print"},
|
||||||
{TOKEN_RETURN, "return"},
|
{TOY_TOKEN_RETURN, "return"},
|
||||||
{TOKEN_TYPE, "type"},
|
{TOY_TOKEN_TYPE, "type"},
|
||||||
{TOKEN_ASTYPE, "astype"},
|
{TOY_TOKEN_ASTYPE, "astype"},
|
||||||
{TOKEN_TYPEOF, "typeof"},
|
{TOY_TOKEN_TYPEOF, "typeof"},
|
||||||
{TOKEN_VAR, "var"},
|
{TOY_TOKEN_VAR, "var"},
|
||||||
{TOKEN_WHILE, "while"},
|
{TOY_TOKEN_WHILE, "while"},
|
||||||
|
|
||||||
//literal values
|
//literal values
|
||||||
{TOKEN_LITERAL_TRUE, "true"},
|
{TOY_TOKEN_LITERAL_TRUE, "true"},
|
||||||
{TOKEN_LITERAL_FALSE, "false"},
|
{TOY_TOKEN_LITERAL_FALSE, "false"},
|
||||||
|
|
||||||
//meta tokens
|
//meta tokens
|
||||||
{TOKEN_PASS, NULL},
|
{TOY_TOKEN_PASS, NULL},
|
||||||
{TOKEN_ERROR, NULL},
|
{TOY_TOKEN_ERROR, NULL},
|
||||||
|
|
||||||
{TOKEN_EOF, NULL},
|
{TOY_TOKEN_EOF, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
char* findKeywordByType(TokenType type) {
|
char* Toy_findKeywordByType(Toy_TokenType type) {
|
||||||
if (type == TOKEN_EOF) {
|
if (type == TOY_TOKEN_EOF) {
|
||||||
return "EOF";
|
return "EOF";
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; keywordTypes[i].keyword; i++) {
|
for(int i = 0; Toy_keywordTypes[i].keyword; i++) {
|
||||||
if (keywordTypes[i].type == type) {
|
if (Toy_keywordTypes[i].type == type) {
|
||||||
return keywordTypes[i].keyword;
|
return Toy_keywordTypes[i].keyword;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenType findTypeByKeyword(const char* keyword) {
|
Toy_TokenType Toy_findTypeByKeyword(const char* keyword) {
|
||||||
const int length = strlen(keyword);
|
const int length = strlen(keyword);
|
||||||
|
|
||||||
for (int i = 0; keywordTypes[i].keyword; i++) {
|
for (int i = 0; Toy_keywordTypes[i].keyword; i++) {
|
||||||
if (!strncmp(keyword, keywordTypes[i].keyword, length)) {
|
if (!strncmp(keyword, Toy_keywordTypes[i].keyword, length)) {
|
||||||
return keywordTypes[i].type;
|
return Toy_keywordTypes[i].type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TOKEN_EOF;
|
return TOY_TOKEN_EOF;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "token_types.h"
|
#include "toy_token_types.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TokenType type;
|
Toy_TokenType type;
|
||||||
char* keyword;
|
char* keyword;
|
||||||
} KeywordType;
|
} Toy_KeywordType;
|
||||||
|
|
||||||
extern KeywordType keywordTypes[];
|
extern Toy_KeywordType Toy_keywordTypes[];
|
||||||
|
|
||||||
char* findKeywordByType(TokenType type);
|
char* Toy_findKeywordByType(Toy_TokenType type);
|
||||||
|
|
||||||
TokenType findTypeByKeyword(const char* keyword);
|
Toy_TokenType Toy_findTypeByKeyword(const char* keyword);
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
#include "lexer.h"
|
#include "toy_lexer.h"
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
#include "keyword_types.h"
|
#include "toy_keyword_types.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
//static generic utility functions
|
//static generic utility functions
|
||||||
static void cleanLexer(Lexer* lexer) {
|
static void cleanLexer(Toy_Lexer* lexer) {
|
||||||
lexer->source = NULL;
|
lexer->source = NULL;
|
||||||
lexer->start = 0;
|
lexer->start = 0;
|
||||||
lexer->current = 0;
|
lexer->current = 0;
|
||||||
lexer->line = 1;
|
lexer->line = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isAtEnd(Lexer* lexer) {
|
static bool isAtEnd(Toy_Lexer* lexer) {
|
||||||
return lexer->source[lexer->current] == '\0';
|
return lexer->source[lexer->current] == '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static char peek(Lexer* lexer) {
|
static char peek(Toy_Lexer* lexer) {
|
||||||
return lexer->source[lexer->current];
|
return lexer->source[lexer->current];
|
||||||
}
|
}
|
||||||
|
|
||||||
static char peekNext(Lexer* lexer) {
|
static char peekNext(Toy_Lexer* lexer) {
|
||||||
if (isAtEnd(lexer)) return '\0';
|
if (isAtEnd(lexer)) return '\0';
|
||||||
return lexer->source[lexer->current + 1];
|
return lexer->source[lexer->current + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static char advance(Lexer* lexer) {
|
static char advance(Toy_Lexer* lexer) {
|
||||||
if (isAtEnd(lexer)) {
|
if (isAtEnd(lexer)) {
|
||||||
return '\0';
|
return '\0';
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ static char advance(Lexer* lexer) {
|
|||||||
return lexer->source[lexer->current - 1];
|
return lexer->source[lexer->current - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eatWhitespace(Lexer* lexer) {
|
static void eatWhitespace(Toy_Lexer* lexer) {
|
||||||
const char c = peek(lexer);
|
const char c = peek(lexer);
|
||||||
|
|
||||||
switch(c) {
|
switch(c) {
|
||||||
@@ -79,11 +79,11 @@ static void eatWhitespace(Lexer* lexer) {
|
|||||||
eatWhitespace(lexer);
|
eatWhitespace(lexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isDigit(Lexer* lexer) {
|
static bool isDigit(Toy_Lexer* lexer) {
|
||||||
return peek(lexer) >= '0' && peek(lexer) <= '9';
|
return peek(lexer) >= '0' && peek(lexer) <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isAlpha(Lexer* lexer) {
|
static bool isAlpha(Toy_Lexer* lexer) {
|
||||||
return
|
return
|
||||||
(peek(lexer) >= 'A' && peek(lexer) <= 'Z') ||
|
(peek(lexer) >= 'A' && peek(lexer) <= 'Z') ||
|
||||||
(peek(lexer) >= 'a' && peek(lexer) <= 'z') ||
|
(peek(lexer) >= 'a' && peek(lexer) <= 'z') ||
|
||||||
@@ -91,7 +91,7 @@ static bool isAlpha(Lexer* lexer) {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool match(Lexer* lexer, char c) {
|
static bool match(Toy_Lexer* lexer, char c) {
|
||||||
if (peek(lexer) == c) {
|
if (peek(lexer) == c) {
|
||||||
advance(lexer);
|
advance(lexer);
|
||||||
return true;
|
return true;
|
||||||
@@ -101,10 +101,10 @@ static bool match(Lexer* lexer, char c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//token generators
|
//token generators
|
||||||
static Token makeErrorToken(Lexer* lexer, char* msg) {
|
static Toy_Token makeErrorToken(Toy_Lexer* lexer, char* msg) {
|
||||||
Token token;
|
Toy_Token token;
|
||||||
|
|
||||||
token.type = TOKEN_ERROR;
|
token.type = TOY_TOKEN_ERROR;
|
||||||
token.lexeme = msg;
|
token.lexeme = msg;
|
||||||
token.length = strlen(msg);
|
token.length = strlen(msg);
|
||||||
token.line = lexer->line;
|
token.line = lexer->line;
|
||||||
@@ -112,15 +112,15 @@ static Token makeErrorToken(Lexer* lexer, char* msg) {
|
|||||||
#ifndef TOY_EXPORT
|
#ifndef TOY_EXPORT
|
||||||
if (command.verbose) {
|
if (command.verbose) {
|
||||||
printf("err:");
|
printf("err:");
|
||||||
printToken(&token);
|
Toy_printToken(&token);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token makeToken(Lexer* lexer, TokenType type) {
|
static Toy_Token makeToken(Toy_Lexer* lexer, Toy_TokenType type) {
|
||||||
Token token;
|
Toy_Token token;
|
||||||
|
|
||||||
token.type = type;
|
token.type = type;
|
||||||
token.length = lexer->current - lexer->start;
|
token.length = lexer->current - lexer->start;
|
||||||
@@ -131,25 +131,25 @@ static Token makeToken(Lexer* lexer, TokenType type) {
|
|||||||
//BUG #10: this shows TOKEN_EOF twice due to the overarching structure of the program - can't be fixed
|
//BUG #10: this shows TOKEN_EOF twice due to the overarching structure of the program - can't be fixed
|
||||||
if (command.verbose) {
|
if (command.verbose) {
|
||||||
printf("tok:");
|
printf("tok:");
|
||||||
printToken(&token);
|
Toy_printToken(&token);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token makeIntegerOrFloat(Lexer* lexer) {
|
static Toy_Token makeIntegerOrFloat(Toy_Lexer* lexer) {
|
||||||
TokenType type = TOKEN_LITERAL_INTEGER; //what am I making?
|
Toy_TokenType type = TOY_TOKEN_LITERAL_INTEGER; //what am I making?
|
||||||
|
|
||||||
while(isDigit(lexer)) advance(lexer);
|
while(isDigit(lexer)) advance(lexer);
|
||||||
|
|
||||||
if (peek(lexer) == '.' && (peekNext(lexer) >= '0' && peekNext(lexer) <= '9')) { //BUGFIX: peekNext == digit
|
if (peek(lexer) == '.' && (peekNext(lexer) >= '0' && peekNext(lexer) <= '9')) { //BUGFIX: peekNext == digit
|
||||||
type = TOKEN_LITERAL_FLOAT;
|
type = TOY_TOKEN_LITERAL_FLOAT;
|
||||||
advance(lexer);
|
advance(lexer);
|
||||||
while(isDigit(lexer)) advance(lexer);
|
while(isDigit(lexer)) advance(lexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Token token;
|
Toy_Token token;
|
||||||
|
|
||||||
token.type = type;
|
token.type = type;
|
||||||
token.lexeme = &lexer->source[lexer->start];
|
token.lexeme = &lexer->source[lexer->start];
|
||||||
@@ -158,19 +158,19 @@ static Token makeIntegerOrFloat(Lexer* lexer) {
|
|||||||
|
|
||||||
#ifndef TOY_EXPORT
|
#ifndef TOY_EXPORT
|
||||||
if (command.verbose) {
|
if (command.verbose) {
|
||||||
if (type == TOKEN_LITERAL_INTEGER) {
|
if (type == TOY_TOKEN_LITERAL_INTEGER) {
|
||||||
printf("int:");
|
printf("int:");
|
||||||
} else {
|
} else {
|
||||||
printf("flt:");
|
printf("flt:");
|
||||||
}
|
}
|
||||||
printToken(&token);
|
Toy_printToken(&token);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token makeString(Lexer* lexer, char terminator) {
|
static Toy_Token makeString(Toy_Lexer* lexer, char terminator) {
|
||||||
while (!isAtEnd(lexer) && peek(lexer) != terminator) {
|
while (!isAtEnd(lexer) && peek(lexer) != terminator) {
|
||||||
advance(lexer);
|
advance(lexer);
|
||||||
}
|
}
|
||||||
@@ -181,9 +181,9 @@ static Token makeString(Lexer* lexer, char terminator) {
|
|||||||
return makeErrorToken(lexer, "Unterminated string");
|
return makeErrorToken(lexer, "Unterminated string");
|
||||||
}
|
}
|
||||||
|
|
||||||
Token token;
|
Toy_Token token;
|
||||||
|
|
||||||
token.type = TOKEN_LITERAL_STRING;
|
token.type = TOY_TOKEN_LITERAL_STRING;
|
||||||
token.lexeme = &lexer->source[lexer->start + 1];
|
token.lexeme = &lexer->source[lexer->start + 1];
|
||||||
token.length = lexer->current - lexer->start - 2;
|
token.length = lexer->current - lexer->start - 2;
|
||||||
token.line = lexer->line;
|
token.line = lexer->line;
|
||||||
@@ -191,14 +191,14 @@ static Token makeString(Lexer* lexer, char terminator) {
|
|||||||
#ifndef TOY_EXPORT
|
#ifndef TOY_EXPORT
|
||||||
if (command.verbose) {
|
if (command.verbose) {
|
||||||
printf("str:");
|
printf("str:");
|
||||||
printToken(&token);
|
Toy_printToken(&token);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token makeKeywordOrIdentifier(Lexer* lexer) {
|
static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
|
||||||
advance(lexer); //first letter can only be alpha
|
advance(lexer); //first letter can only be alpha
|
||||||
|
|
||||||
while(isDigit(lexer) || isAlpha(lexer)) {
|
while(isDigit(lexer) || isAlpha(lexer)) {
|
||||||
@@ -206,11 +206,11 @@ static Token makeKeywordOrIdentifier(Lexer* lexer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//scan for a keyword
|
//scan for a keyword
|
||||||
for (int i = 0; keywordTypes[i].keyword; i++) {
|
for (int i = 0; Toy_keywordTypes[i].keyword; i++) {
|
||||||
if (strlen(keywordTypes[i].keyword) == (long unsigned int)(lexer->current - lexer->start) && !strncmp(keywordTypes[i].keyword, &lexer->source[lexer->start], lexer->current - lexer->start)) {
|
if (strlen(Toy_keywordTypes[i].keyword) == (long unsigned int)(lexer->current - lexer->start) && !strncmp(Toy_keywordTypes[i].keyword, &lexer->source[lexer->start], lexer->current - lexer->start)) {
|
||||||
Token token;
|
Toy_Token token;
|
||||||
|
|
||||||
token.type = keywordTypes[i].type;
|
token.type = Toy_keywordTypes[i].type;
|
||||||
token.lexeme = &lexer->source[lexer->start];
|
token.lexeme = &lexer->source[lexer->start];
|
||||||
token.length = lexer->current - lexer->start;
|
token.length = lexer->current - lexer->start;
|
||||||
token.line = lexer->line;
|
token.line = lexer->line;
|
||||||
@@ -218,7 +218,7 @@ static Token makeKeywordOrIdentifier(Lexer* lexer) {
|
|||||||
#ifndef TOY_EXPORT
|
#ifndef TOY_EXPORT
|
||||||
if (command.verbose) {
|
if (command.verbose) {
|
||||||
printf("kwd:");
|
printf("kwd:");
|
||||||
printToken(&token);
|
Toy_printToken(&token);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -227,9 +227,9 @@ static Token makeKeywordOrIdentifier(Lexer* lexer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//return an identifier
|
//return an identifier
|
||||||
Token token;
|
Toy_Token token;
|
||||||
|
|
||||||
token.type = TOKEN_IDENTIFIER;
|
token.type = TOY_TOKEN_IDENTIFIER;
|
||||||
token.lexeme = &lexer->source[lexer->start];
|
token.lexeme = &lexer->source[lexer->start];
|
||||||
token.length = lexer->current - lexer->start;
|
token.length = lexer->current - lexer->start;
|
||||||
token.line = lexer->line;
|
token.line = lexer->line;
|
||||||
@@ -237,7 +237,7 @@ static Token makeKeywordOrIdentifier(Lexer* lexer) {
|
|||||||
#ifndef TOY_EXPORT
|
#ifndef TOY_EXPORT
|
||||||
if (command.verbose) {
|
if (command.verbose) {
|
||||||
printf("idf:");
|
printf("idf:");
|
||||||
printToken(&token);
|
Toy_printToken(&token);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -245,18 +245,18 @@ static Token makeKeywordOrIdentifier(Lexer* lexer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
void initLexer(Lexer* lexer, char* source) {
|
void Toy_initLexer(Toy_Lexer* lexer, char* source) {
|
||||||
cleanLexer(lexer);
|
cleanLexer(lexer);
|
||||||
|
|
||||||
lexer->source = source;
|
lexer->source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token scanLexer(Lexer* lexer) {
|
Toy_Token Toy_scanLexer(Toy_Lexer* lexer) {
|
||||||
eatWhitespace(lexer);
|
eatWhitespace(lexer);
|
||||||
|
|
||||||
lexer->start = lexer->current;
|
lexer->start = lexer->current;
|
||||||
|
|
||||||
if (isAtEnd(lexer)) return makeToken(lexer, TOKEN_EOF);
|
if (isAtEnd(lexer)) return makeToken(lexer, TOY_TOKEN_EOF);
|
||||||
|
|
||||||
if (isDigit(lexer)) return makeIntegerOrFloat(lexer);
|
if (isDigit(lexer)) return makeIntegerOrFloat(lexer);
|
||||||
if (isAlpha(lexer)) return makeKeywordOrIdentifier(lexer);
|
if (isAlpha(lexer)) return makeKeywordOrIdentifier(lexer);
|
||||||
@@ -264,45 +264,45 @@ Token scanLexer(Lexer* lexer) {
|
|||||||
char c = advance(lexer);
|
char c = advance(lexer);
|
||||||
|
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '(': return makeToken(lexer, TOKEN_PAREN_LEFT);
|
case '(': return makeToken(lexer, TOY_TOKEN_PAREN_LEFT);
|
||||||
case ')': return makeToken(lexer, TOKEN_PAREN_RIGHT);
|
case ')': return makeToken(lexer, TOY_TOKEN_PAREN_RIGHT);
|
||||||
case '{': return makeToken(lexer, TOKEN_BRACE_LEFT);
|
case '{': return makeToken(lexer, TOY_TOKEN_BRACE_LEFT);
|
||||||
case '}': return makeToken(lexer, TOKEN_BRACE_RIGHT);
|
case '}': return makeToken(lexer, TOY_TOKEN_BRACE_RIGHT);
|
||||||
case '[': return makeToken(lexer, TOKEN_BRACKET_LEFT);
|
case '[': return makeToken(lexer, TOY_TOKEN_BRACKET_LEFT);
|
||||||
case ']': return makeToken(lexer, TOKEN_BRACKET_RIGHT);
|
case ']': return makeToken(lexer, TOY_TOKEN_BRACKET_RIGHT);
|
||||||
|
|
||||||
case '+': return makeToken(lexer, match(lexer, '=') ? TOKEN_PLUS_ASSIGN : match(lexer, '+') ? TOKEN_PLUS_PLUS: TOKEN_PLUS);
|
case '+': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_PLUS_ASSIGN : match(lexer, '+') ? TOY_TOKEN_PLUS_PLUS: TOY_TOKEN_PLUS);
|
||||||
case '-': return makeToken(lexer, match(lexer, '=') ? TOKEN_MINUS_ASSIGN : match(lexer, '-') ? TOKEN_MINUS_MINUS: TOKEN_MINUS);
|
case '-': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_MINUS_ASSIGN : match(lexer, '-') ? TOY_TOKEN_MINUS_MINUS: TOY_TOKEN_MINUS);
|
||||||
case '*': return makeToken(lexer, match(lexer, '=') ? TOKEN_MULTIPLY_ASSIGN : TOKEN_MULTIPLY);
|
case '*': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_MULTIPLY_ASSIGN : TOY_TOKEN_MULTIPLY);
|
||||||
case '/': return makeToken(lexer, match(lexer, '=') ? TOKEN_DIVIDE_ASSIGN : TOKEN_DIVIDE);
|
case '/': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_DIVIDE_ASSIGN : TOY_TOKEN_DIVIDE);
|
||||||
case '%': return makeToken(lexer, match(lexer, '=') ? TOKEN_MODULO_ASSIGN : TOKEN_MODULO);
|
case '%': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_MODULO_ASSIGN : TOY_TOKEN_MODULO);
|
||||||
|
|
||||||
case '!': return makeToken(lexer, match(lexer, '=') ? TOKEN_NOT_EQUAL : TOKEN_NOT);
|
case '!': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_NOT_EQUAL : TOY_TOKEN_NOT);
|
||||||
case '=': return makeToken(lexer, match(lexer, '=') ? TOKEN_EQUAL : TOKEN_ASSIGN);
|
case '=': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_EQUAL : TOY_TOKEN_ASSIGN);
|
||||||
|
|
||||||
case '<': return makeToken(lexer, match(lexer, '=') ? TOKEN_LESS_EQUAL : TOKEN_LESS);
|
case '<': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_LESS_EQUAL : TOY_TOKEN_LESS);
|
||||||
case '>': return makeToken(lexer, match(lexer, '=') ? TOKEN_GREATER_EQUAL : TOKEN_GREATER);
|
case '>': return makeToken(lexer, match(lexer, '=') ? TOY_TOKEN_GREATER_EQUAL : TOY_TOKEN_GREATER);
|
||||||
|
|
||||||
case '&': //TOKEN_AND not used
|
case '&': //TOKEN_AND not used
|
||||||
if (advance(lexer) != '&') {
|
if (advance(lexer) != '&') {
|
||||||
return makeErrorToken(lexer, "Unexpected '&'");
|
return makeErrorToken(lexer, "Unexpected '&'");
|
||||||
} else {
|
} else {
|
||||||
return makeToken(lexer, TOKEN_AND);
|
return makeToken(lexer, TOY_TOKEN_AND);
|
||||||
}
|
}
|
||||||
|
|
||||||
case '|': return makeToken(lexer, match(lexer, '|') ? TOKEN_OR : TOKEN_PIPE);
|
case '|': return makeToken(lexer, match(lexer, '|') ? TOY_TOKEN_OR : TOY_TOKEN_PIPE);
|
||||||
|
|
||||||
case '?': return makeToken(lexer, TOKEN_QUESTION);
|
case '?': return makeToken(lexer, TOY_TOKEN_QUESTION);
|
||||||
case ':': return makeToken(lexer, TOKEN_COLON);
|
case ':': return makeToken(lexer, TOY_TOKEN_COLON);
|
||||||
case ';': return makeToken(lexer, TOKEN_SEMICOLON);
|
case ';': return makeToken(lexer, TOY_TOKEN_SEMICOLON);
|
||||||
case ',': return makeToken(lexer, TOKEN_COMMA);
|
case ',': return makeToken(lexer, TOY_TOKEN_COMMA);
|
||||||
case '.':
|
case '.':
|
||||||
if (peek(lexer) == '.' && peekNext(lexer) == '.') {
|
if (peek(lexer) == '.' && peekNext(lexer) == '.') {
|
||||||
advance(lexer);
|
advance(lexer);
|
||||||
advance(lexer);
|
advance(lexer);
|
||||||
return makeToken(lexer, TOKEN_REST);
|
return makeToken(lexer, TOY_TOKEN_REST);
|
||||||
}
|
}
|
||||||
return makeToken(lexer, TOKEN_DOT);
|
return makeToken(lexer, TOY_TOKEN_DOT);
|
||||||
|
|
||||||
case '"':
|
case '"':
|
||||||
return makeString(lexer, c);
|
return makeString(lexer, c);
|
||||||
@@ -322,18 +322,18 @@ static void trim(char** s, int* l) { //all this to remove a newline?
|
|||||||
}
|
}
|
||||||
|
|
||||||
//for debugging
|
//for debugging
|
||||||
void printToken(Token* token) {
|
void Toy_printToken(Toy_Token* token) {
|
||||||
if (token->type == TOKEN_ERROR) {
|
if (token->type == TOY_TOKEN_ERROR) {
|
||||||
printf(ERROR "Error\t%d\t%.*s\n" RESET, token->line, token->length, token->lexeme);
|
printf(TOY_CC_ERROR "Error\t%d\t%.*s\n" TOY_CC_RESET, token->line, token->length, token->lexeme);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\t%d\t%d\t", token->type, token->line);
|
printf("\t%d\t%d\t", token->type, token->line);
|
||||||
|
|
||||||
if (token->type == TOKEN_IDENTIFIER || token->type == TOKEN_LITERAL_INTEGER || token->type == TOKEN_LITERAL_FLOAT || token->type == TOKEN_LITERAL_STRING) {
|
if (token->type == TOY_TOKEN_IDENTIFIER || token->type == TOY_TOKEN_LITERAL_INTEGER || token->type == TOY_TOKEN_LITERAL_FLOAT || token->type == TOY_TOKEN_LITERAL_STRING) {
|
||||||
printf("%.*s\t", token->length, token->lexeme);
|
printf("%.*s\t", token->length, token->lexeme);
|
||||||
} else {
|
} else {
|
||||||
char* keyword = findKeywordByType(token->type);
|
char* keyword = Toy_findKeywordByType(token->type);
|
||||||
|
|
||||||
if (keyword != NULL) {
|
if (keyword != NULL) {
|
||||||
printf("%s", keyword);
|
printf("%s", keyword);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
#include "token_types.h"
|
#include "toy_token_types.h"
|
||||||
|
|
||||||
//lexers are bound to a string of code, and return a single token every time scan is called
|
//lexers are bound to a string of code, and return a single token every time scan is called
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -9,18 +9,18 @@ typedef struct {
|
|||||||
int start; //start of the token
|
int start; //start of the token
|
||||||
int current; //current position of the lexer
|
int current; //current position of the lexer
|
||||||
int line; //track this for error handling
|
int line; //track this for error handling
|
||||||
} Lexer;
|
} Toy_Lexer;
|
||||||
|
|
||||||
//tokens are intermediaries between lexers and parsers
|
//tokens are intermediaries between lexers and parsers
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TokenType type;
|
Toy_TokenType type;
|
||||||
char* lexeme;
|
char* lexeme;
|
||||||
int length;
|
int length;
|
||||||
int line;
|
int line;
|
||||||
} Token;
|
} Toy_Token;
|
||||||
|
|
||||||
TOY_API void initLexer(Lexer* lexer, char* source);
|
TOY_API void Toy_initLexer(Toy_Lexer* lexer, char* source);
|
||||||
Token scanLexer(Lexer* lexer);
|
Toy_Token Toy_scanLexer(Toy_Lexer* lexer);
|
||||||
|
|
||||||
//for debugging
|
//for debugging
|
||||||
void printToken(Token* token);
|
void Toy_printToken(Toy_Token* token);
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "literal.h"
|
#include "toy_literal.h"
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include "literal_array.h"
|
#include "toy_literal_array.h"
|
||||||
#include "literal_dictionary.h"
|
#include "toy_literal_dictionary.h"
|
||||||
#include "scope.h"
|
#include "toy_scope.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@@ -29,203 +29,203 @@ static unsigned int hashUInt(unsigned int x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
void freeLiteral(Literal literal) {
|
void Toy_freeLiteral(Toy_Literal literal) {
|
||||||
//refstrings
|
//refstrings
|
||||||
if (IS_STRING(literal)) {
|
if (TOY_IS_STRING(literal)) {
|
||||||
deleteRefString(AS_STRING(literal));
|
Toy_deleteRefString(TOY_AS_STRING(literal));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_IDENTIFIER(literal)) {
|
if (TOY_IS_IDENTIFIER(literal)) {
|
||||||
deleteRefString(AS_IDENTIFIER(literal));
|
Toy_deleteRefString(TOY_AS_IDENTIFIER(literal));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//compounds
|
//compounds
|
||||||
if (IS_ARRAY(literal) || literal.type == LITERAL_DICTIONARY_INTERMEDIATE || literal.type == LITERAL_TYPE_INTERMEDIATE) {
|
if (TOY_IS_ARRAY(literal) || literal.type == TOY_LITERAL_DICTIONARY_INTERMEDIATE || literal.type == TOY_LITERAL_TYPE_INTERMEDIATE) {
|
||||||
freeLiteralArray(AS_ARRAY(literal));
|
Toy_freeLiteralArray(TOY_AS_ARRAY(literal));
|
||||||
FREE(LiteralArray, AS_ARRAY(literal));
|
TOY_FREE(Toy_LiteralArray, TOY_AS_ARRAY(literal));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_DICTIONARY(literal)) {
|
if (TOY_IS_DICTIONARY(literal)) {
|
||||||
freeLiteralDictionary(AS_DICTIONARY(literal));
|
Toy_freeLiteralDictionary(TOY_AS_DICTIONARY(literal));
|
||||||
FREE(LiteralDictionary, AS_DICTIONARY(literal));
|
TOY_FREE(Toy_LiteralDictionary, TOY_AS_DICTIONARY(literal));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//complex literals
|
//complex literals
|
||||||
if (IS_FUNCTION(literal)) {
|
if (TOY_IS_FUNCTION(literal)) {
|
||||||
popScope(AS_FUNCTION(literal).scope);
|
Toy_popScope(TOY_AS_FUNCTION(literal).scope);
|
||||||
AS_FUNCTION(literal).scope = NULL;
|
TOY_AS_FUNCTION(literal).scope = NULL;
|
||||||
FREE_ARRAY(unsigned char, AS_FUNCTION(literal).bytecode, AS_FUNCTION(literal).length);
|
TOY_FREE_ARRAY(unsigned char, TOY_AS_FUNCTION(literal).bytecode, TOY_AS_FUNCTION(literal).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_TYPE(literal)) {
|
if (TOY_IS_TYPE(literal)) {
|
||||||
for (int i = 0; i < AS_TYPE(literal).count; i++) {
|
for (int i = 0; i < TOY_AS_TYPE(literal).count; i++) {
|
||||||
freeLiteral(((Literal*)(AS_TYPE(literal).subtypes))[i]);
|
Toy_freeLiteral(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i]);
|
||||||
}
|
}
|
||||||
FREE_ARRAY(Literal, AS_TYPE(literal).subtypes, AS_TYPE(literal).capacity);
|
TOY_FREE_ARRAY(Toy_Literal, TOY_AS_TYPE(literal).subtypes, TOY_AS_TYPE(literal).capacity);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _isTruthy(Literal x) {
|
bool Toy_private_isTruthy(Toy_Literal x) {
|
||||||
if (IS_NULL(x)) {
|
if (TOY_IS_NULL(x)) {
|
||||||
fprintf(stderr, ERROR "ERROR: Null is neither true nor false\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Null is neither true nor false\n" TOY_CC_RESET);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_BOOLEAN(x)) {
|
if (TOY_IS_BOOLEAN(x)) {
|
||||||
return AS_BOOLEAN(x);
|
return TOY_AS_BOOLEAN(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal _toStringLiteral(RefString* ptr) {
|
Toy_Literal Toy_private_toStringLiteral(Toy_RefString* ptr) {
|
||||||
return ((Literal){LITERAL_STRING, { .string.ptr = ptr }});
|
return ((Toy_Literal){TOY_LITERAL_STRING, { .string.ptr = ptr }});
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal _toIdentifierLiteral(RefString* ptr) {
|
Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr) {
|
||||||
return ((Literal){LITERAL_IDENTIFIER,{ .identifier.ptr = ptr, .identifier.hash = hashString(toCString(ptr), lengthRefString(ptr)) }});
|
return ((Toy_Literal){TOY_LITERAL_IDENTIFIER,{ .identifier.ptr = ptr, .identifier.hash = hashString(Toy_toCString(ptr), Toy_lengthRefString(ptr)) }});
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal* _typePushSubtype(Literal* lit, Literal subtype) {
|
Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype) {
|
||||||
//grow the subtype array
|
//grow the subtype array
|
||||||
if (AS_TYPE(*lit).count + 1 > AS_TYPE(*lit).capacity) {
|
if (TOY_AS_TYPE(*lit).count + 1 > TOY_AS_TYPE(*lit).capacity) {
|
||||||
int oldCapacity = AS_TYPE(*lit).capacity;
|
int oldCapacity = TOY_AS_TYPE(*lit).capacity;
|
||||||
|
|
||||||
AS_TYPE(*lit).capacity = GROW_CAPACITY(oldCapacity);
|
TOY_AS_TYPE(*lit).capacity = TOY_GROW_CAPACITY(oldCapacity);
|
||||||
AS_TYPE(*lit).subtypes = GROW_ARRAY(Literal, AS_TYPE(*lit).subtypes, oldCapacity, AS_TYPE(*lit).capacity);
|
TOY_AS_TYPE(*lit).subtypes = TOY_GROW_ARRAY(Toy_Literal, TOY_AS_TYPE(*lit).subtypes, oldCapacity, TOY_AS_TYPE(*lit).capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
//actually push
|
//actually push
|
||||||
((Literal*)(AS_TYPE(*lit).subtypes))[ AS_TYPE(*lit).count++ ] = subtype;
|
((Toy_Literal*)(TOY_AS_TYPE(*lit).subtypes))[ TOY_AS_TYPE(*lit).count++ ] = subtype;
|
||||||
return &((Literal*)(AS_TYPE(*lit).subtypes))[ AS_TYPE(*lit).count - 1 ];
|
return &((Toy_Literal*)(TOY_AS_TYPE(*lit).subtypes))[ TOY_AS_TYPE(*lit).count - 1 ];
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal copyLiteral(Literal original) {
|
Toy_Literal Toy_copyLiteral(Toy_Literal original) {
|
||||||
switch(original.type) {
|
switch(original.type) {
|
||||||
case LITERAL_NULL:
|
case TOY_LITERAL_NULL:
|
||||||
case LITERAL_BOOLEAN:
|
case TOY_LITERAL_BOOLEAN:
|
||||||
case LITERAL_INTEGER:
|
case TOY_LITERAL_INTEGER:
|
||||||
case LITERAL_FLOAT:
|
case TOY_LITERAL_FLOAT:
|
||||||
//no copying needed
|
//no copying needed
|
||||||
return original;
|
return original;
|
||||||
|
|
||||||
case LITERAL_STRING: {
|
case TOY_LITERAL_STRING: {
|
||||||
return TO_STRING_LITERAL(copyRefString(AS_STRING(original)));
|
return TOY_TO_STRING_LITERAL(Toy_copyRefString(TOY_AS_STRING(original)));
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_ARRAY: {
|
case TOY_LITERAL_ARRAY: {
|
||||||
LiteralArray* array = ALLOCATE(LiteralArray, 1);
|
Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1);
|
||||||
initLiteralArray(array);
|
Toy_initLiteralArray(array);
|
||||||
|
|
||||||
//copy each element
|
//copy each element
|
||||||
for (int i = 0; i < AS_ARRAY(original)->count; i++) {
|
for (int i = 0; i < TOY_AS_ARRAY(original)->count; i++) {
|
||||||
pushLiteralArray(array, AS_ARRAY(original)->literals[i]);
|
Toy_pushLiteralArray(array, TOY_AS_ARRAY(original)->literals[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TO_ARRAY_LITERAL(array);
|
return TOY_TO_ARRAY_LITERAL(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_DICTIONARY: {
|
case TOY_LITERAL_DICTIONARY: {
|
||||||
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
|
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
|
||||||
initLiteralDictionary(dictionary);
|
Toy_initLiteralDictionary(dictionary);
|
||||||
|
|
||||||
//copy each entry
|
//copy each entry
|
||||||
for (int i = 0; i < AS_DICTIONARY(original)->capacity; i++) {
|
for (int i = 0; i < TOY_AS_DICTIONARY(original)->capacity; i++) {
|
||||||
if ( !IS_NULL(AS_DICTIONARY(original)->entries[i].key) ) {
|
if ( !TOY_IS_NULL(TOY_AS_DICTIONARY(original)->entries[i].key) ) {
|
||||||
setLiteralDictionary(dictionary, AS_DICTIONARY(original)->entries[i].key, AS_DICTIONARY(original)->entries[i].value);
|
Toy_setLiteralDictionary(dictionary, TOY_AS_DICTIONARY(original)->entries[i].key, TOY_AS_DICTIONARY(original)->entries[i].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TO_DICTIONARY_LITERAL(dictionary);
|
return TOY_TO_DICTIONARY_LITERAL(dictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_FUNCTION: {
|
case TOY_LITERAL_FUNCTION: {
|
||||||
unsigned char* buffer = ALLOCATE(unsigned char, AS_FUNCTION(original).length);
|
unsigned char* buffer = TOY_ALLOCATE(unsigned char, TOY_AS_FUNCTION(original).length);
|
||||||
memcpy(buffer, AS_FUNCTION(original).bytecode, AS_FUNCTION(original).length);
|
memcpy(buffer, TOY_AS_FUNCTION(original).bytecode, TOY_AS_FUNCTION(original).length);
|
||||||
|
|
||||||
Literal literal = TO_FUNCTION_LITERAL(buffer, AS_FUNCTION(original).length);
|
Toy_Literal literal = TOY_TO_FUNCTION_LITERAL(buffer, TOY_AS_FUNCTION(original).length);
|
||||||
AS_FUNCTION(literal).scope = copyScope(AS_FUNCTION(original).scope);
|
TOY_AS_FUNCTION(literal).scope = Toy_copyScope(TOY_AS_FUNCTION(original).scope);
|
||||||
|
|
||||||
return literal;
|
return literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_IDENTIFIER: {
|
case TOY_LITERAL_IDENTIFIER: {
|
||||||
return TO_IDENTIFIER_LITERAL(copyRefString(AS_IDENTIFIER(original)));
|
return TOY_TO_IDENTIFIER_LITERAL(Toy_copyRefString(TOY_AS_IDENTIFIER(original)));
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_TYPE: {
|
case TOY_LITERAL_TYPE: {
|
||||||
Literal lit = TO_TYPE_LITERAL(AS_TYPE(original).typeOf, AS_TYPE(original).constant);
|
Toy_Literal lit = TOY_TO_TYPE_LITERAL(TOY_AS_TYPE(original).typeOf, TOY_AS_TYPE(original).constant);
|
||||||
|
|
||||||
for (int i = 0; i < AS_TYPE(original).count; i++) {
|
for (int i = 0; i < TOY_AS_TYPE(original).count; i++) {
|
||||||
TYPE_PUSH_SUBTYPE(&lit, copyLiteral( ((Literal*)(AS_TYPE(original).subtypes))[i] ));
|
TOY_TYPE_PUSH_SUBTYPE(&lit, Toy_copyLiteral( ((Toy_Literal*)(TOY_AS_TYPE(original).subtypes))[i] ));
|
||||||
}
|
}
|
||||||
|
|
||||||
return lit;
|
return lit;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_OPAQUE: {
|
case TOY_LITERAL_OPAQUE: {
|
||||||
return original; //literally a shallow copy
|
return original; //literally a shallow copy
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_DICTIONARY_INTERMEDIATE: {
|
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: {
|
||||||
LiteralArray* array = ALLOCATE(LiteralArray, 1);
|
Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1);
|
||||||
initLiteralArray(array);
|
Toy_initLiteralArray(array);
|
||||||
|
|
||||||
//copy each element
|
//copy each element
|
||||||
for (int i = 0; i < AS_ARRAY(original)->count; i++) {
|
for (int i = 0; i < TOY_AS_ARRAY(original)->count; i++) {
|
||||||
Literal literal = copyLiteral(AS_ARRAY(original)->literals[i]);
|
Toy_Literal literal = Toy_copyLiteral(TOY_AS_ARRAY(original)->literals[i]);
|
||||||
pushLiteralArray(array, literal);
|
Toy_pushLiteralArray(array, literal);
|
||||||
freeLiteral(literal);
|
Toy_freeLiteral(literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal ret = TO_ARRAY_LITERAL(array);
|
Toy_Literal ret = TOY_TO_ARRAY_LITERAL(array);
|
||||||
ret.type = LITERAL_DICTIONARY_INTERMEDIATE;
|
ret.type = TOY_LITERAL_DICTIONARY_INTERMEDIATE;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_TYPE_INTERMEDIATE: {
|
case TOY_LITERAL_TYPE_INTERMEDIATE: {
|
||||||
LiteralArray* array = ALLOCATE(LiteralArray, 1);
|
Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1);
|
||||||
initLiteralArray(array);
|
Toy_initLiteralArray(array);
|
||||||
|
|
||||||
//copy each element
|
//copy each element
|
||||||
for (int i = 0; i < AS_ARRAY(original)->count; i++) {
|
for (int i = 0; i < TOY_AS_ARRAY(original)->count; i++) {
|
||||||
Literal literal = copyLiteral(AS_ARRAY(original)->literals[i]);
|
Toy_Literal literal = Toy_copyLiteral(TOY_AS_ARRAY(original)->literals[i]);
|
||||||
pushLiteralArray(array, literal);
|
Toy_pushLiteralArray(array, literal);
|
||||||
freeLiteral(literal);
|
Toy_freeLiteral(literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal ret = TO_ARRAY_LITERAL(array);
|
Toy_Literal ret = TOY_TO_ARRAY_LITERAL(array);
|
||||||
ret.type = LITERAL_TYPE_INTERMEDIATE;
|
ret.type = TOY_LITERAL_TYPE_INTERMEDIATE;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_FUNCTION_INTERMEDIATE: //caries a compiler
|
case TOY_LITERAL_FUNCTION_INTERMEDIATE: //caries a compiler
|
||||||
case LITERAL_FUNCTION_NATIVE:
|
case TOY_LITERAL_FUNCTION_NATIVE:
|
||||||
case LITERAL_INDEX_BLANK:
|
case TOY_LITERAL_INDEX_BLANK:
|
||||||
//no copying possible
|
//no copying possible
|
||||||
return original;
|
return original;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, ERROR "ERROR: Can't copy that literal type: %d\n" RESET, original.type);
|
fprintf(stderr, TOY_CC_ERROR "TOY_CC_ERROR: Can't copy that literal type: %d\n" TOY_CC_RESET, original.type);
|
||||||
return TO_NULL_LITERAL;
|
return TOY_TO_NULL_LITERAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool literalsAreEqual(Literal lhs, Literal rhs) {
|
bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs) {
|
||||||
//utility for other things
|
//utility for other things
|
||||||
if (lhs.type != rhs.type) {
|
if (lhs.type != rhs.type) {
|
||||||
// ints and floats are compatible
|
// ints and floats are compatible
|
||||||
if ((IS_INTEGER(lhs) || IS_FLOAT(lhs)) && (IS_INTEGER(rhs) || IS_FLOAT(rhs))) {
|
if ((TOY_IS_INTEGER(lhs) || TOY_IS_FLOAT(lhs)) && (TOY_IS_INTEGER(rhs) || TOY_IS_FLOAT(rhs))) {
|
||||||
if (IS_INTEGER(lhs)) {
|
if (TOY_IS_INTEGER(lhs)) {
|
||||||
return AS_INTEGER(lhs) + AS_FLOAT(rhs);
|
return TOY_AS_INTEGER(lhs) + TOY_AS_FLOAT(rhs);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return AS_FLOAT(lhs) + AS_INTEGER(rhs);
|
return TOY_AS_FLOAT(lhs) + TOY_AS_INTEGER(rhs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,172 +233,172 @@ bool literalsAreEqual(Literal lhs, Literal rhs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch(lhs.type) {
|
switch(lhs.type) {
|
||||||
case LITERAL_NULL:
|
case TOY_LITERAL_NULL:
|
||||||
return true; //can only be true because of the check above
|
return true; //can only be true because of the check above
|
||||||
|
|
||||||
case LITERAL_BOOLEAN:
|
case TOY_LITERAL_BOOLEAN:
|
||||||
return AS_BOOLEAN(lhs) == AS_BOOLEAN(rhs);
|
return TOY_AS_BOOLEAN(lhs) == TOY_AS_BOOLEAN(rhs);
|
||||||
|
|
||||||
case LITERAL_INTEGER:
|
case TOY_LITERAL_INTEGER:
|
||||||
return AS_INTEGER(lhs) == AS_INTEGER(rhs);
|
return TOY_AS_INTEGER(lhs) == TOY_AS_INTEGER(rhs);
|
||||||
|
|
||||||
case LITERAL_FLOAT:
|
case TOY_LITERAL_FLOAT:
|
||||||
return AS_FLOAT(lhs) == AS_FLOAT(rhs);
|
return TOY_AS_FLOAT(lhs) == TOY_AS_FLOAT(rhs);
|
||||||
|
|
||||||
case LITERAL_STRING:
|
case TOY_LITERAL_STRING:
|
||||||
return equalsRefString(AS_STRING(lhs), AS_STRING(rhs));
|
return Toy_equalsRefString(TOY_AS_STRING(lhs), TOY_AS_STRING(rhs));
|
||||||
|
|
||||||
case LITERAL_ARRAY:
|
case TOY_LITERAL_ARRAY:
|
||||||
case LITERAL_DICTIONARY_INTERMEDIATE: //BUGFIX
|
case TOY_LITERAL_DICTIONARY_INTERMEDIATE: //BUGFIX
|
||||||
case LITERAL_TYPE_INTERMEDIATE: //BUGFIX: used for storing types as an array
|
case TOY_LITERAL_TYPE_INTERMEDIATE: //BUGFIX: used for storing types as an array
|
||||||
//mismatched sizes
|
//mismatched sizes
|
||||||
if (AS_ARRAY(lhs)->count != AS_ARRAY(rhs)->count) {
|
if (TOY_AS_ARRAY(lhs)->count != TOY_AS_ARRAY(rhs)->count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//mismatched elements (in order)
|
//mismatched elements (in order)
|
||||||
for (int i = 0; i < AS_ARRAY(lhs)->count; i++) {
|
for (int i = 0; i < TOY_AS_ARRAY(lhs)->count; i++) {
|
||||||
if (!literalsAreEqual( AS_ARRAY(lhs)->literals[i], AS_ARRAY(rhs)->literals[i] )) {
|
if (!Toy_literalsAreEqual( TOY_AS_ARRAY(lhs)->literals[i], TOY_AS_ARRAY(rhs)->literals[i] )) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case LITERAL_DICTIONARY:
|
case TOY_LITERAL_DICTIONARY:
|
||||||
//relatively slow, especially when nested
|
//relatively slow, especially when nested
|
||||||
for (int i = 0; i < AS_DICTIONARY(lhs)->capacity; i++) {
|
for (int i = 0; i < TOY_AS_DICTIONARY(lhs)->capacity; i++) {
|
||||||
if (!IS_NULL(AS_DICTIONARY(lhs)->entries[i].key)) { //only compare non-null keys
|
if (!TOY_IS_NULL(TOY_AS_DICTIONARY(lhs)->entries[i].key)) { //only compare non-null keys
|
||||||
//check it exists in rhs
|
//check it exists in rhs
|
||||||
if (!existsLiteralDictionary(AS_DICTIONARY(rhs), AS_DICTIONARY(lhs)->entries[i].key)) {
|
if (!Toy_existsLiteralDictionary(TOY_AS_DICTIONARY(rhs), TOY_AS_DICTIONARY(lhs)->entries[i].key)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//compare the values
|
//compare the values
|
||||||
Literal val = getLiteralDictionary(AS_DICTIONARY(rhs), AS_DICTIONARY(lhs)->entries[i].key); //TODO: could be more efficient
|
Toy_Literal val = Toy_getLiteralDictionary(TOY_AS_DICTIONARY(rhs), TOY_AS_DICTIONARY(lhs)->entries[i].key); //TODO: could be more efficient
|
||||||
if (!literalsAreEqual(AS_DICTIONARY(lhs)->entries[i].value, val)) {
|
if (!Toy_literalsAreEqual(TOY_AS_DICTIONARY(lhs)->entries[i].value, val)) {
|
||||||
freeLiteral(val);
|
Toy_freeLiteral(val);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
freeLiteral(val);
|
Toy_freeLiteral(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case LITERAL_FUNCTION:
|
case TOY_LITERAL_FUNCTION:
|
||||||
case LITERAL_FUNCTION_NATIVE:
|
case TOY_LITERAL_FUNCTION_NATIVE:
|
||||||
return false; //functions are never equal
|
return false; //functions are never equal
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_IDENTIFIER:
|
case TOY_LITERAL_IDENTIFIER:
|
||||||
//check shortcuts
|
//check shortcuts
|
||||||
if (HASH_I(lhs) != HASH_I(rhs)) {
|
if (TOY_HASH_I(lhs) != TOY_HASH_I(rhs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return equalsRefString(AS_IDENTIFIER(lhs), AS_IDENTIFIER(rhs));
|
return Toy_equalsRefString(TOY_AS_IDENTIFIER(lhs), TOY_AS_IDENTIFIER(rhs));
|
||||||
|
|
||||||
case LITERAL_TYPE:
|
case TOY_LITERAL_TYPE:
|
||||||
//check types
|
//check types
|
||||||
if (AS_TYPE(lhs).typeOf != AS_TYPE(rhs).typeOf) {
|
if (TOY_AS_TYPE(lhs).typeOf != TOY_AS_TYPE(rhs).typeOf) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//const don't match
|
//const don't match
|
||||||
if (AS_TYPE(lhs).constant != AS_TYPE(rhs).constant) {
|
if (TOY_AS_TYPE(lhs).constant != TOY_AS_TYPE(rhs).constant) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check subtypes
|
//check subtypes
|
||||||
if (AS_TYPE(lhs).count != AS_TYPE(rhs).count) {
|
if (TOY_AS_TYPE(lhs).count != TOY_AS_TYPE(rhs).count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check array|dictionary signatures are the same (in order)
|
//check array|dictionary signatures are the same (in order)
|
||||||
if (AS_TYPE(lhs).typeOf == LITERAL_ARRAY || AS_TYPE(lhs).typeOf == LITERAL_DICTIONARY) {
|
if (TOY_AS_TYPE(lhs).typeOf == TOY_LITERAL_ARRAY || TOY_AS_TYPE(lhs).typeOf == TOY_LITERAL_DICTIONARY) {
|
||||||
for (int i = 0; i < AS_TYPE(lhs).count; i++) {
|
for (int i = 0; i < TOY_AS_TYPE(lhs).count; i++) {
|
||||||
if (!literalsAreEqual(((Literal*)(AS_TYPE(lhs).subtypes))[i], ((Literal*)(AS_TYPE(rhs).subtypes))[i])) {
|
if (!Toy_literalsAreEqual(((Toy_Literal*)(TOY_AS_TYPE(lhs).subtypes))[i], ((Toy_Literal*)(TOY_AS_TYPE(rhs).subtypes))[i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case LITERAL_OPAQUE:
|
case TOY_LITERAL_OPAQUE:
|
||||||
return false; //IDK what this is!
|
return false; //IDK what this is!
|
||||||
|
|
||||||
case LITERAL_ANY:
|
case TOY_LITERAL_ANY:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case LITERAL_FUNCTION_INTERMEDIATE:
|
case TOY_LITERAL_FUNCTION_INTERMEDIATE:
|
||||||
fprintf(stderr, ERROR "[internal] Can't compare intermediate functions\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "[internal] Can't compare intermediate functions\n" TOY_CC_RESET);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case LITERAL_INDEX_BLANK:
|
case TOY_LITERAL_INDEX_BLANK:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//should never be seen
|
//should never be seen
|
||||||
fprintf(stderr, ERROR "[internal] Unrecognized literal type in equality: %d\n" RESET, lhs.type);
|
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in equality: %d\n" TOY_CC_RESET, lhs.type);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashLiteral(Literal lit) {
|
int Toy_hashLiteral(Toy_Literal lit) {
|
||||||
switch(lit.type) {
|
switch(lit.type) {
|
||||||
case LITERAL_NULL:
|
case TOY_LITERAL_NULL:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LITERAL_BOOLEAN:
|
case TOY_LITERAL_BOOLEAN:
|
||||||
return AS_BOOLEAN(lit) ? 1 : 0;
|
return TOY_AS_BOOLEAN(lit) ? 1 : 0;
|
||||||
|
|
||||||
case LITERAL_INTEGER:
|
case TOY_LITERAL_INTEGER:
|
||||||
return hashUInt((unsigned int)AS_INTEGER(lit));
|
return hashUInt((unsigned int)TOY_AS_INTEGER(lit));
|
||||||
|
|
||||||
case LITERAL_FLOAT:
|
case TOY_LITERAL_FLOAT:
|
||||||
return hashUInt(*(unsigned int*)(&AS_FLOAT(lit)));
|
return hashUInt(*(unsigned int*)(&TOY_AS_FLOAT(lit)));
|
||||||
|
|
||||||
case LITERAL_STRING:
|
case TOY_LITERAL_STRING:
|
||||||
return hashString(toCString(AS_STRING(lit)), lengthRefString(AS_STRING(lit)));
|
return hashString(Toy_toCString(TOY_AS_STRING(lit)), Toy_lengthRefString(TOY_AS_STRING(lit)));
|
||||||
|
|
||||||
case LITERAL_ARRAY: {
|
case TOY_LITERAL_ARRAY: {
|
||||||
unsigned int res = 0;
|
unsigned int res = 0;
|
||||||
for (int i = 0; i < AS_ARRAY(lit)->count; i++) {
|
for (int i = 0; i < TOY_AS_ARRAY(lit)->count; i++) {
|
||||||
res += hashLiteral(AS_ARRAY(lit)->literals[i]);
|
res += Toy_hashLiteral(TOY_AS_ARRAY(lit)->literals[i]);
|
||||||
}
|
}
|
||||||
return hashUInt(res);
|
return hashUInt(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_DICTIONARY: {
|
case TOY_LITERAL_DICTIONARY: {
|
||||||
unsigned int res = 0;
|
unsigned int res = 0;
|
||||||
for (int i = 0; i < AS_DICTIONARY(lit)->capacity; i++) {
|
for (int i = 0; i < TOY_AS_DICTIONARY(lit)->capacity; i++) {
|
||||||
if (!IS_NULL(AS_DICTIONARY(lit)->entries[i].key)) { //only hash non-null keys
|
if (!TOY_IS_NULL(TOY_AS_DICTIONARY(lit)->entries[i].key)) { //only hash non-null keys
|
||||||
res += hashLiteral(AS_DICTIONARY(lit)->entries[i].key);
|
res += Toy_hashLiteral(TOY_AS_DICTIONARY(lit)->entries[i].key);
|
||||||
res += hashLiteral(AS_DICTIONARY(lit)->entries[i].value);
|
res += Toy_hashLiteral(TOY_AS_DICTIONARY(lit)->entries[i].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hashUInt(res);
|
return hashUInt(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
case LITERAL_FUNCTION:
|
case TOY_LITERAL_FUNCTION:
|
||||||
case LITERAL_FUNCTION_NATIVE:
|
case TOY_LITERAL_FUNCTION_NATIVE:
|
||||||
return 0; //can't hash these
|
return 0; //can't hash these
|
||||||
|
|
||||||
case LITERAL_IDENTIFIER:
|
case TOY_LITERAL_IDENTIFIER:
|
||||||
return HASH_I(lit); //pre-computed
|
return TOY_HASH_I(lit); //pre-computed
|
||||||
|
|
||||||
case LITERAL_TYPE:
|
case TOY_LITERAL_TYPE:
|
||||||
return AS_TYPE(lit).typeOf; //nothing else I can do
|
return TOY_AS_TYPE(lit).typeOf; //nothing else I can do
|
||||||
|
|
||||||
case LITERAL_OPAQUE:
|
case TOY_LITERAL_OPAQUE:
|
||||||
case LITERAL_ANY:
|
case TOY_LITERAL_ANY:
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//should never bee seen
|
//should never bee seen
|
||||||
fprintf(stderr, ERROR "[internal] Unrecognized literal type in hash: %d\n" RESET, lit.type);
|
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in hash: %d\n" TOY_CC_RESET, lit.type);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -420,8 +420,8 @@ static void printToBuffer(const char* str) {
|
|||||||
while (strlen(str) + globalPrintCount + 1 > globalPrintCapacity) {
|
while (strlen(str) + globalPrintCount + 1 > globalPrintCapacity) {
|
||||||
int oldCapacity = globalPrintCapacity;
|
int oldCapacity = globalPrintCapacity;
|
||||||
|
|
||||||
globalPrintCapacity = GROW_CAPACITY(globalPrintCapacity);
|
globalPrintCapacity = TOY_GROW_CAPACITY(globalPrintCapacity);
|
||||||
globalPrintBuffer = GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity);
|
globalPrintBuffer = TOY_GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str);
|
snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str);
|
||||||
@@ -429,55 +429,55 @@ static void printToBuffer(const char* str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
void printLiteral(Literal literal) {
|
void Toy_printLiteral(Toy_Literal literal) {
|
||||||
printLiteralCustom(literal, stdoutWrapper);
|
Toy_printLiteralCustom(literal, stdoutWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*)) {
|
||||||
switch(literal.type) {
|
switch(literal.type) {
|
||||||
case LITERAL_NULL:
|
case TOY_LITERAL_NULL:
|
||||||
printFn("null");
|
printFn("null");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_BOOLEAN:
|
case TOY_LITERAL_BOOLEAN:
|
||||||
printFn(AS_BOOLEAN(literal) ? "true" : "false");
|
printFn(TOY_AS_BOOLEAN(literal) ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_INTEGER: {
|
case TOY_LITERAL_INTEGER: {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
snprintf(buffer, 256, "%d", AS_INTEGER(literal));
|
snprintf(buffer, 256, "%d", TOY_AS_INTEGER(literal));
|
||||||
printFn(buffer);
|
printFn(buffer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_FLOAT: {
|
case TOY_LITERAL_FLOAT: {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
|
|
||||||
if (AS_FLOAT(literal) - (int)AS_FLOAT(literal)) {
|
if (TOY_AS_FLOAT(literal) - (int)TOY_AS_FLOAT(literal)) {
|
||||||
snprintf(buffer, 256, "%g", AS_FLOAT(literal));
|
snprintf(buffer, 256, "%g", TOY_AS_FLOAT(literal));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
snprintf(buffer, 256, "%.1f", AS_FLOAT(literal));
|
snprintf(buffer, 256, "%.1f", TOY_AS_FLOAT(literal));
|
||||||
}
|
}
|
||||||
|
|
||||||
printFn(buffer);
|
printFn(buffer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_STRING: {
|
case TOY_LITERAL_STRING: {
|
||||||
char buffer[MAX_STRING_LENGTH];
|
char buffer[TOY_MAX_STRING_LENGTH];
|
||||||
if (!quotes) {
|
if (!quotes) {
|
||||||
snprintf(buffer, MAX_STRING_LENGTH, "%.*s", lengthRefString(AS_STRING(literal)), toCString(AS_STRING(literal)));
|
snprintf(buffer, TOY_MAX_STRING_LENGTH, "%.*s", Toy_lengthRefString(TOY_AS_STRING(literal)), Toy_toCString(TOY_AS_STRING(literal)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
snprintf(buffer, MAX_STRING_LENGTH, "%c%.*s%c", quotes, lengthRefString(AS_STRING(literal)), toCString(AS_STRING(literal)), quotes);
|
snprintf(buffer, TOY_MAX_STRING_LENGTH, "%c%.*s%c", quotes, Toy_lengthRefString(TOY_AS_STRING(literal)), Toy_toCString(TOY_AS_STRING(literal)), quotes);
|
||||||
}
|
}
|
||||||
printFn(buffer);
|
printFn(buffer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_ARRAY: {
|
case TOY_LITERAL_ARRAY: {
|
||||||
LiteralArray* ptr = AS_ARRAY(literal);
|
Toy_LiteralArray* ptr = TOY_AS_ARRAY(literal);
|
||||||
|
|
||||||
//hold potential parent-call buffers on the C stack
|
//hold potential parent-call buffers on the C stack
|
||||||
char* cacheBuffer = globalPrintBuffer;
|
char* cacheBuffer = globalPrintBuffer;
|
||||||
@@ -491,7 +491,7 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
printToBuffer("[");
|
printToBuffer("[");
|
||||||
for (int i = 0; i < ptr->count; i++) {
|
for (int i = 0; i < ptr->count; i++) {
|
||||||
quotes = '"';
|
quotes = '"';
|
||||||
printLiteralCustom(ptr->literals[i], printToBuffer);
|
Toy_printLiteralCustom(ptr->literals[i], printToBuffer);
|
||||||
|
|
||||||
if (i + 1 < ptr->count) {
|
if (i + 1 < ptr->count) {
|
||||||
printToBuffer(",");
|
printToBuffer(",");
|
||||||
@@ -510,13 +510,13 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
|
|
||||||
//finally, output and cleanup
|
//finally, output and cleanup
|
||||||
printFn(printBuffer);
|
printFn(printBuffer);
|
||||||
FREE_ARRAY(char, printBuffer, printCapacity);
|
TOY_FREE_ARRAY(char, printBuffer, printCapacity);
|
||||||
quotes = 0;
|
quotes = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_DICTIONARY: {
|
case TOY_LITERAL_DICTIONARY: {
|
||||||
LiteralDictionary* ptr = AS_DICTIONARY(literal);
|
Toy_LiteralDictionary* ptr = TOY_AS_DICTIONARY(literal);
|
||||||
|
|
||||||
//hold potential parent-call buffers on the C stack
|
//hold potential parent-call buffers on the C stack
|
||||||
char* cacheBuffer = globalPrintBuffer;
|
char* cacheBuffer = globalPrintBuffer;
|
||||||
@@ -530,7 +530,7 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
int delimCount = 0;
|
int delimCount = 0;
|
||||||
printToBuffer("[");
|
printToBuffer("[");
|
||||||
for (int i = 0; i < ptr->capacity; i++) {
|
for (int i = 0; i < ptr->capacity; i++) {
|
||||||
if (IS_NULL(ptr->entries[i].key)) {
|
if (TOY_IS_NULL(ptr->entries[i].key)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,10 +539,10 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
quotes = '"';
|
quotes = '"';
|
||||||
printLiteralCustom(ptr->entries[i].key, printToBuffer);
|
Toy_printLiteralCustom(ptr->entries[i].key, printToBuffer);
|
||||||
printToBuffer(":");
|
printToBuffer(":");
|
||||||
quotes = '"';
|
quotes = '"';
|
||||||
printLiteralCustom(ptr->entries[i].value, printToBuffer);
|
Toy_printLiteralCustom(ptr->entries[i].value, printToBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//empty dicts MUST have a ":" printed
|
//empty dicts MUST have a ":" printed
|
||||||
@@ -563,24 +563,24 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
|
|
||||||
//finally, output and cleanup
|
//finally, output and cleanup
|
||||||
printFn(printBuffer);
|
printFn(printBuffer);
|
||||||
FREE_ARRAY(char, printBuffer, printCapacity);
|
TOY_FREE_ARRAY(char, printBuffer, printCapacity);
|
||||||
quotes = 0;
|
quotes = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_FUNCTION:
|
case TOY_LITERAL_FUNCTION:
|
||||||
case LITERAL_FUNCTION_NATIVE:
|
case TOY_LITERAL_FUNCTION_NATIVE:
|
||||||
printFn("(function)");
|
printFn("(function)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_IDENTIFIER: {
|
case TOY_LITERAL_IDENTIFIER: {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
snprintf(buffer, 256, "%.*s", lengthRefString(AS_IDENTIFIER(literal)), toCString(AS_IDENTIFIER(literal)));
|
snprintf(buffer, 256, "%.*s", Toy_lengthRefString(TOY_AS_IDENTIFIER(literal)), Toy_toCString(TOY_AS_IDENTIFIER(literal)));
|
||||||
printFn(buffer);
|
printFn(buffer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_TYPE: {
|
case TOY_LITERAL_TYPE: {
|
||||||
//hold potential parent-call buffers on the C stack
|
//hold potential parent-call buffers on the C stack
|
||||||
char* cacheBuffer = globalPrintBuffer;
|
char* cacheBuffer = globalPrintBuffer;
|
||||||
globalPrintBuffer = NULL;
|
globalPrintBuffer = NULL;
|
||||||
@@ -592,78 +592,78 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
//print the type correctly
|
//print the type correctly
|
||||||
printToBuffer("<");
|
printToBuffer("<");
|
||||||
|
|
||||||
switch(AS_TYPE(literal).typeOf) {
|
switch(TOY_AS_TYPE(literal).typeOf) {
|
||||||
case LITERAL_NULL:
|
case TOY_LITERAL_NULL:
|
||||||
printToBuffer("null");
|
printToBuffer("null");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_BOOLEAN:
|
case TOY_LITERAL_BOOLEAN:
|
||||||
printToBuffer("bool");
|
printToBuffer("bool");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_INTEGER:
|
case TOY_LITERAL_INTEGER:
|
||||||
printToBuffer("int");
|
printToBuffer("int");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_FLOAT:
|
case TOY_LITERAL_FLOAT:
|
||||||
printToBuffer("float");
|
printToBuffer("float");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_STRING:
|
case TOY_LITERAL_STRING:
|
||||||
printToBuffer("string");
|
printToBuffer("string");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_ARRAY:
|
case TOY_LITERAL_ARRAY:
|
||||||
//print all in the array
|
//print all in the array
|
||||||
printToBuffer("[");
|
printToBuffer("[");
|
||||||
for (int i = 0; i < AS_TYPE(literal).count; i++) {
|
for (int i = 0; i < TOY_AS_TYPE(literal).count; i++) {
|
||||||
printLiteralCustom(((Literal*)(AS_TYPE(literal).subtypes))[i], printToBuffer);
|
Toy_printLiteralCustom(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i], printToBuffer);
|
||||||
}
|
}
|
||||||
printToBuffer("]");
|
printToBuffer("]");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_DICTIONARY:
|
case TOY_LITERAL_DICTIONARY:
|
||||||
printToBuffer("[");
|
printToBuffer("[");
|
||||||
|
|
||||||
for (int i = 0; i < AS_TYPE(literal).count; i += 2) {
|
for (int i = 0; i < TOY_AS_TYPE(literal).count; i += 2) {
|
||||||
printLiteralCustom(((Literal*)(AS_TYPE(literal).subtypes))[i], printToBuffer);
|
Toy_printLiteralCustom(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i], printToBuffer);
|
||||||
printToBuffer(":");
|
printToBuffer(":");
|
||||||
printLiteralCustom(((Literal*)(AS_TYPE(literal).subtypes))[i + 1], printToBuffer);
|
Toy_printLiteralCustom(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i + 1], printToBuffer);
|
||||||
}
|
}
|
||||||
printToBuffer("]");
|
printToBuffer("]");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_FUNCTION:
|
case TOY_LITERAL_FUNCTION:
|
||||||
printToBuffer("function");
|
printToBuffer("function");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_FUNCTION_NATIVE:
|
case TOY_LITERAL_FUNCTION_NATIVE:
|
||||||
printToBuffer("native");
|
printToBuffer("native");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_IDENTIFIER:
|
case TOY_LITERAL_IDENTIFIER:
|
||||||
printToBuffer("identifier");
|
printToBuffer("identifier");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_TYPE:
|
case TOY_LITERAL_TYPE:
|
||||||
printToBuffer("type");
|
printToBuffer("type");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_OPAQUE:
|
case TOY_LITERAL_OPAQUE:
|
||||||
printToBuffer("opaque");
|
printToBuffer("opaque");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_ANY:
|
case TOY_LITERAL_ANY:
|
||||||
printToBuffer("any");
|
printToBuffer("any");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//should never be seen
|
//should never be seen
|
||||||
fprintf(stderr, ERROR "[internal] Unrecognized literal type in print type: %d\n" RESET, AS_TYPE(literal).typeOf);
|
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in print type: %d\n" TOY_CC_RESET, TOY_AS_TYPE(literal).typeOf);
|
||||||
}
|
}
|
||||||
|
|
||||||
//const (printed last)
|
//const (printed last)
|
||||||
if (AS_TYPE(literal).constant) {
|
if (TOY_AS_TYPE(literal).constant) {
|
||||||
printToBuffer(" const");
|
printToBuffer(" const");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,26 +680,26 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
|
|||||||
|
|
||||||
//finally, output and cleanup
|
//finally, output and cleanup
|
||||||
printFn(printBuffer);
|
printFn(printBuffer);
|
||||||
FREE_ARRAY(char, printBuffer, printCapacity);
|
TOY_FREE_ARRAY(char, printBuffer, printCapacity);
|
||||||
quotes = 0;
|
quotes = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_TYPE_INTERMEDIATE:
|
case TOY_LITERAL_TYPE_INTERMEDIATE:
|
||||||
case LITERAL_FUNCTION_INTERMEDIATE:
|
case TOY_LITERAL_FUNCTION_INTERMEDIATE:
|
||||||
printFn("Unprintable literal found");
|
printFn("Unprintable literal found");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_OPAQUE:
|
case TOY_LITERAL_OPAQUE:
|
||||||
printFn("(opaque)");
|
printFn("(opaque)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_ANY:
|
case TOY_LITERAL_ANY:
|
||||||
printFn("(any)");
|
printFn("(any)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//should never be seen
|
//should never be seen
|
||||||
fprintf(stderr, ERROR "[internal] Unrecognized literal type in print: %d\n" RESET, literal.type);
|
fprintf(stderr, TOY_CC_ERROR "[internal] Unrecognized literal type in print: %d\n" TOY_CC_RESET, literal.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,41 +2,41 @@
|
|||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
|
|
||||||
#include "refstring.h"
|
#include "toy_refstring.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LITERAL_NULL,
|
TOY_LITERAL_NULL,
|
||||||
LITERAL_BOOLEAN,
|
TOY_LITERAL_BOOLEAN,
|
||||||
LITERAL_INTEGER,
|
TOY_LITERAL_INTEGER,
|
||||||
LITERAL_FLOAT,
|
TOY_LITERAL_FLOAT,
|
||||||
LITERAL_STRING,
|
TOY_LITERAL_STRING,
|
||||||
LITERAL_ARRAY,
|
TOY_LITERAL_ARRAY,
|
||||||
LITERAL_DICTIONARY,
|
TOY_LITERAL_DICTIONARY,
|
||||||
LITERAL_FUNCTION,
|
TOY_LITERAL_FUNCTION,
|
||||||
LITERAL_IDENTIFIER,
|
TOY_LITERAL_IDENTIFIER,
|
||||||
LITERAL_TYPE,
|
TOY_LITERAL_TYPE,
|
||||||
LITERAL_OPAQUE,
|
TOY_LITERAL_OPAQUE,
|
||||||
LITERAL_ANY,
|
TOY_LITERAL_ANY,
|
||||||
|
|
||||||
//these are meta-level types - not for general use
|
//these are meta-level types - not for general use
|
||||||
LITERAL_TYPE_INTERMEDIATE, //used to process types in the compiler only
|
TOY_LITERAL_TYPE_INTERMEDIATE, //used to process types in the compiler only
|
||||||
LITERAL_DICTIONARY_INTERMEDIATE, //used to process dictionaries in the compiler only
|
TOY_LITERAL_DICTIONARY_INTERMEDIATE, //used to process dictionaries in the compiler only
|
||||||
LITERAL_FUNCTION_INTERMEDIATE, //used to process functions in the compiler only
|
TOY_LITERAL_FUNCTION_INTERMEDIATE, //used to process functions in the compiler only
|
||||||
LITERAL_FUNCTION_ARG_REST, //used to process function rest parameters only
|
TOY_LITERAL_FUNCTION_ARG_REST, //used to process function rest parameters only
|
||||||
LITERAL_FUNCTION_NATIVE, //for handling native functions only
|
TOY_LITERAL_FUNCTION_NATIVE, //for handling native functions only
|
||||||
LITERAL_INDEX_BLANK, //for blank indexing i.e. arr[:]
|
TOY_LITERAL_INDEX_BLANK, //for blank indexing i.e. arr[:]
|
||||||
} LiteralType;
|
} Toy_LiteralType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
LiteralType type;
|
Toy_LiteralType type;
|
||||||
union {
|
union {
|
||||||
bool boolean;
|
bool boolean;
|
||||||
int integer;
|
int integer;
|
||||||
float number;
|
float number;
|
||||||
struct {
|
struct {
|
||||||
RefString* ptr;
|
Toy_RefString* ptr;
|
||||||
//string hash?
|
//string hash?
|
||||||
} string;
|
} string;
|
||||||
|
|
||||||
@@ -50,12 +50,12 @@ typedef struct {
|
|||||||
} function;
|
} function;
|
||||||
|
|
||||||
struct { //for variable names
|
struct { //for variable names
|
||||||
RefString* ptr;
|
Toy_RefString* ptr;
|
||||||
int hash;
|
int hash;
|
||||||
} identifier;
|
} identifier;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
LiteralType typeOf; //no longer a mask
|
Toy_LiteralType typeOf; //no longer a mask
|
||||||
bool constant;
|
bool constant;
|
||||||
void* subtypes; //for nested types caused by compounds
|
void* subtypes; //for nested types caused by compounds
|
||||||
int capacity;
|
int capacity;
|
||||||
@@ -67,67 +67,67 @@ typedef struct {
|
|||||||
int tag; //TODO: remove tags?
|
int tag; //TODO: remove tags?
|
||||||
} opaque;
|
} opaque;
|
||||||
} as;
|
} as;
|
||||||
} Literal;
|
} Toy_Literal;
|
||||||
|
|
||||||
#define IS_NULL(value) ((value).type == LITERAL_NULL)
|
#define TOY_IS_NULL(value) ((value).type == TOY_LITERAL_NULL)
|
||||||
#define IS_BOOLEAN(value) ((value).type == LITERAL_BOOLEAN)
|
#define TOY_IS_BOOLEAN(value) ((value).type == TOY_LITERAL_BOOLEAN)
|
||||||
#define IS_INTEGER(value) ((value).type == LITERAL_INTEGER)
|
#define TOY_IS_INTEGER(value) ((value).type == TOY_LITERAL_INTEGER)
|
||||||
#define IS_FLOAT(value) ((value).type == LITERAL_FLOAT)
|
#define TOY_IS_FLOAT(value) ((value).type == TOY_LITERAL_FLOAT)
|
||||||
#define IS_STRING(value) ((value).type == LITERAL_STRING)
|
#define TOY_IS_STRING(value) ((value).type == TOY_LITERAL_STRING)
|
||||||
#define IS_ARRAY(value) ((value).type == LITERAL_ARRAY)
|
#define TOY_IS_ARRAY(value) ((value).type == TOY_LITERAL_ARRAY)
|
||||||
#define IS_DICTIONARY(value) ((value).type == LITERAL_DICTIONARY)
|
#define TOY_IS_DICTIONARY(value) ((value).type == TOY_LITERAL_DICTIONARY)
|
||||||
#define IS_FUNCTION(value) ((value).type == LITERAL_FUNCTION)
|
#define TOY_IS_FUNCTION(value) ((value).type == TOY_LITERAL_FUNCTION)
|
||||||
#define IS_FUNCTION_NATIVE(value) ((value).type == LITERAL_FUNCTION_NATIVE)
|
#define TOY_IS_FUNCTION_NATIVE(value) ((value).type == TOY_LITERAL_FUNCTION_NATIVE)
|
||||||
#define IS_IDENTIFIER(value) ((value).type == LITERAL_IDENTIFIER)
|
#define TOY_IS_IDENTIFIER(value) ((value).type == TOY_LITERAL_IDENTIFIER)
|
||||||
#define IS_TYPE(value) ((value).type == LITERAL_TYPE)
|
#define TOY_IS_TYPE(value) ((value).type == TOY_LITERAL_TYPE)
|
||||||
#define IS_OPAQUE(value) ((value).type == LITERAL_OPAQUE)
|
#define TOY_IS_OPAQUE(value) ((value).type == TOY_LITERAL_OPAQUE)
|
||||||
|
|
||||||
#define AS_BOOLEAN(value) ((value).as.boolean)
|
#define TOY_AS_BOOLEAN(value) ((value).as.boolean)
|
||||||
#define AS_INTEGER(value) ((value).as.integer)
|
#define TOY_AS_INTEGER(value) ((value).as.integer)
|
||||||
#define AS_FLOAT(value) ((value).as.number)
|
#define TOY_AS_FLOAT(value) ((value).as.number)
|
||||||
#define AS_STRING(value) ((value).as.string.ptr)
|
#define TOY_AS_STRING(value) ((value).as.string.ptr)
|
||||||
#define AS_ARRAY(value) ((LiteralArray*)((value).as.array))
|
#define TOY_AS_ARRAY(value) ((Toy_LiteralArray*)((value).as.array))
|
||||||
#define AS_DICTIONARY(value) ((LiteralDictionary*)((value).as.dictionary))
|
#define TOY_AS_DICTIONARY(value) ((Toy_LiteralDictionary*)((value).as.dictionary))
|
||||||
#define AS_FUNCTION(value) ((value).as.function)
|
#define TOY_AS_FUNCTION(value) ((value).as.function)
|
||||||
#define AS_IDENTIFIER(value) ((value).as.identifier.ptr)
|
#define TOY_AS_IDENTIFIER(value) ((value).as.identifier.ptr)
|
||||||
#define AS_TYPE(value) ((value).as.type)
|
#define TOY_AS_TYPE(value) ((value).as.type)
|
||||||
#define AS_OPAQUE(value) ((value).as.opaque.ptr)
|
#define TOY_AS_OPAQUE(value) ((value).as.opaque.ptr)
|
||||||
|
|
||||||
#define TO_NULL_LITERAL ((Literal){LITERAL_NULL, { .integer = 0 }})
|
#define TOY_TO_NULL_LITERAL ((Toy_Literal){TOY_LITERAL_NULL, { .integer = 0 }})
|
||||||
#define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }})
|
#define TOY_TO_BOOLEAN_LITERAL(value) ((Toy_Literal){TOY_LITERAL_BOOLEAN, { .boolean = value }})
|
||||||
#define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }})
|
#define TOY_TO_INTEGER_LITERAL(value) ((Toy_Literal){TOY_LITERAL_INTEGER, { .integer = value }})
|
||||||
#define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }})
|
#define TOY_TO_FLOAT_LITERAL(value) ((Toy_Literal){TOY_LITERAL_FLOAT, { .number = value }})
|
||||||
#define TO_STRING_LITERAL(value) _toStringLiteral(value)
|
#define TOY_TO_STRING_LITERAL(value) Toy_private_toStringLiteral(value)
|
||||||
#define TO_ARRAY_LITERAL(value) ((Literal){LITERAL_ARRAY, { .array = value }})
|
#define TOY_TO_ARRAY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_ARRAY, { .array = value }})
|
||||||
#define TO_DICTIONARY_LITERAL(value) ((Literal){LITERAL_DICTIONARY, { .dictionary = value }})
|
#define TOY_TO_DICTIONARY_LITERAL(value) ((Toy_Literal){TOY_LITERAL_DICTIONARY, { .dictionary = value }})
|
||||||
#define TO_FUNCTION_LITERAL(value, l) ((Literal){LITERAL_FUNCTION, { .function.bytecode = value, .function.scope = NULL, .function.length = l }})
|
#define TOY_TO_FUNCTION_LITERAL(value, l) ((Toy_Literal){TOY_LITERAL_FUNCTION, { .function.bytecode = value, .function.scope = NULL, .function.length = l }})
|
||||||
#define TO_IDENTIFIER_LITERAL(value) _toIdentifierLiteral(value)
|
#define TOY_TO_IDENTIFIER_LITERAL(value) Toy_private_toIdentifierLiteral(value)
|
||||||
#define TO_TYPE_LITERAL(value, c) ((Literal){ LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
|
#define TOY_TO_TYPE_LITERAL(value, c) ((Toy_Literal){ TOY_LITERAL_TYPE, { .type.typeOf = value, .type.constant = c, .type.subtypes = NULL, .type.capacity = 0, .type.count = 0 }})
|
||||||
#define TO_OPAQUE_LITERAL(value, t) ((Literal){ LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }})
|
#define TOY_TO_OPAQUE_LITERAL(value, t) ((Toy_Literal){ TOY_LITERAL_OPAQUE, { .opaque.ptr = value, .opaque.tag = t }})
|
||||||
|
|
||||||
//BUGFIX: For blank indexing
|
//BUGFIX: For blank indexing
|
||||||
#define IS_INDEX_BLANK(value) ((value).type == LITERAL_INDEX_BLANK)
|
#define TOY_IS_INDEX_BLANK(value) ((value).type == TOY_LITERAL_INDEX_BLANK)
|
||||||
#define TO_INDEX_BLANK_LITERAL ((Literal){LITERAL_INDEX_BLANK, { .integer = 0 }})
|
#define TOY_TO_INDEX_BLANK_LITERAL ((Toy_Literal){TOY_LITERAL_INDEX_BLANK, { .integer = 0 }})
|
||||||
|
|
||||||
TOY_API void freeLiteral(Literal literal);
|
TOY_API void Toy_freeLiteral(Toy_Literal literal);
|
||||||
|
|
||||||
#define IS_TRUTHY(x) _isTruthy(x)
|
#define TOY_IS_TRUTHY(x) Toy_private_isTruthy(x)
|
||||||
|
|
||||||
#define MAX_STRING_LENGTH 4096
|
#define TOY_MAX_STRING_LENGTH 4096
|
||||||
#define HASH_I(lit) ((lit).as.identifier.hash)
|
#define TOY_HASH_I(lit) ((lit).as.identifier.hash)
|
||||||
#define TYPE_PUSH_SUBTYPE(lit, subtype) _typePushSubtype(lit, subtype)
|
#define TOY_TYPE_PUSH_SUBTYPE(lit, subtype) Toy_private_typePushSubtype(lit, subtype)
|
||||||
#define OPAQUE_TAG(o) o.as.opaque.tag
|
#define TOY_GET_OPAQUE_TAG(o) o.as.opaque.tag
|
||||||
|
|
||||||
//BUGFIX: macros are not functions
|
//BUGFIX: macros are not functions
|
||||||
TOY_API bool _isTruthy(Literal x);
|
TOY_API bool Toy_private_isTruthy(Toy_Literal x);
|
||||||
TOY_API Literal _toStringLiteral(RefString* ptr);
|
TOY_API Toy_Literal Toy_private_toStringLiteral(Toy_RefString* ptr);
|
||||||
TOY_API Literal _toIdentifierLiteral(RefString* ptr);
|
TOY_API Toy_Literal Toy_private_toIdentifierLiteral(Toy_RefString* ptr);
|
||||||
TOY_API Literal* _typePushSubtype(Literal* lit, Literal subtype);
|
TOY_API Toy_Literal* Toy_private_typePushSubtype(Toy_Literal* lit, Toy_Literal subtype);
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
TOY_API Literal copyLiteral(Literal original);
|
TOY_API Toy_Literal Toy_copyLiteral(Toy_Literal original);
|
||||||
TOY_API bool literalsAreEqual(Literal lhs, Literal rhs);
|
TOY_API bool Toy_literalsAreEqual(Toy_Literal lhs, Toy_Literal rhs);
|
||||||
TOY_API int hashLiteral(Literal lit);
|
TOY_API int Toy_hashLiteral(Toy_Literal lit);
|
||||||
|
|
||||||
TOY_API void printLiteral(Literal literal);
|
TOY_API void Toy_printLiteral(Toy_Literal literal);
|
||||||
TOY_API void printLiteralCustom(Literal literal, void (printFn)(const char*));
|
TOY_API void Toy_printLiteralCustom(Toy_Literal literal, void (printFn)(const char*));
|
||||||
|
|||||||
@@ -1,56 +1,56 @@
|
|||||||
#include "literal_array.h"
|
#include "toy_literal_array.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
void initLiteralArray(LiteralArray* array) {
|
void Toy_initLiteralArray(Toy_LiteralArray* array) {
|
||||||
array->capacity = 0;
|
array->capacity = 0;
|
||||||
array->count = 0;
|
array->count = 0;
|
||||||
array->literals = NULL;
|
array->literals = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeLiteralArray(LiteralArray* array) {
|
void Toy_freeLiteralArray(Toy_LiteralArray* array) {
|
||||||
//clean up memory
|
//clean up memory
|
||||||
for(int i = 0; i < array->count; i++) {
|
for(int i = 0; i < array->count; i++) {
|
||||||
freeLiteral(array->literals[i]);
|
Toy_freeLiteral(array->literals[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
FREE_ARRAY(Literal, array->literals, array->capacity);
|
TOY_FREE_ARRAY(Toy_Literal, array->literals, array->capacity);
|
||||||
initLiteralArray(array);
|
Toy_initLiteralArray(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pushLiteralArray(LiteralArray* array, Literal literal) {
|
int Toy_pushLiteralArray(Toy_LiteralArray* array, Toy_Literal literal) {
|
||||||
if (array->capacity < array->count + 1) {
|
if (array->capacity < array->count + 1) {
|
||||||
int oldCapacity = array->capacity;
|
int oldCapacity = array->capacity;
|
||||||
|
|
||||||
array->capacity = GROW_CAPACITY(oldCapacity);
|
array->capacity = TOY_GROW_CAPACITY(oldCapacity);
|
||||||
array->literals = GROW_ARRAY(Literal, array->literals, oldCapacity, array->capacity);
|
array->literals = TOY_GROW_ARRAY(Toy_Literal, array->literals, oldCapacity, array->capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
array->literals[array->count] = copyLiteral(literal);
|
array->literals[array->count] = Toy_copyLiteral(literal);
|
||||||
return array->count++;
|
return array->count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal popLiteralArray(LiteralArray* array) {
|
Toy_Literal Toy_popLiteralArray(Toy_LiteralArray* array) {
|
||||||
if (array->count <= 0) {
|
if (array->count <= 0) {
|
||||||
return TO_NULL_LITERAL;
|
return TOY_TO_NULL_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the return
|
//get the return
|
||||||
Literal ret = array->literals[array->count-1];
|
Toy_Literal ret = array->literals[array->count-1];
|
||||||
|
|
||||||
//null the existing data
|
//null the existing data
|
||||||
array->literals[array->count-1] = TO_NULL_LITERAL;
|
array->literals[array->count-1] = TOY_TO_NULL_LITERAL;
|
||||||
|
|
||||||
array->count--;
|
array->count--;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//find a literal in the array that matches the "literal" argument
|
//find a literal in the array that matches the "literal" argument
|
||||||
int findLiteralIndex(LiteralArray* array, Literal literal) {
|
int Toy_findLiteralIndex(Toy_LiteralArray* array, Toy_Literal literal) {
|
||||||
for (int i = 0; i < array->count; i++) {
|
for (int i = 0; i < array->count; i++) {
|
||||||
//not the same type
|
//not the same type
|
||||||
if (array->literals[i].type != literal.type) {
|
if (array->literals[i].type != literal.type) {
|
||||||
@@ -58,7 +58,7 @@ int findLiteralIndex(LiteralArray* array, Literal literal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//types match?
|
//types match?
|
||||||
if (literalsAreEqual(array->literals[i], literal)) {
|
if (Toy_literalsAreEqual(array->literals[i], literal)) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,33 +66,33 @@ int findLiteralIndex(LiteralArray* array, Literal literal) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setLiteralArray(LiteralArray* array, Literal index, Literal value) {
|
bool Toy_setLiteralArray(Toy_LiteralArray* array, Toy_Literal index, Toy_Literal value) {
|
||||||
if (!IS_INTEGER(index)) {
|
if (!TOY_IS_INTEGER(index)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = AS_INTEGER(index);
|
int idx = TOY_AS_INTEGER(index);
|
||||||
|
|
||||||
if (idx < 0 || idx >= array->count) {
|
if (idx < 0 || idx >= array->count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeLiteral(array->literals[idx]);
|
Toy_freeLiteral(array->literals[idx]);
|
||||||
array->literals[idx] = copyLiteral(value);
|
array->literals[idx] = Toy_copyLiteral(value);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal getLiteralArray(LiteralArray* array, Literal index) {
|
Toy_Literal Toy_getLiteralArray(Toy_LiteralArray* array, Toy_Literal index) {
|
||||||
if (!IS_INTEGER(index)) {
|
if (!TOY_IS_INTEGER(index)) {
|
||||||
return TO_NULL_LITERAL;
|
return TOY_TO_NULL_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = AS_INTEGER(index);
|
int idx = TOY_AS_INTEGER(index);
|
||||||
|
|
||||||
if (idx < 0 || idx >= array->count) {
|
if (idx < 0 || idx >= array->count) {
|
||||||
return TO_NULL_LITERAL;
|
return TOY_TO_NULL_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return copyLiteral(array->literals[idx]);
|
return Toy_copyLiteral(array->literals[idx]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,19 @@
|
|||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
|
|
||||||
#include "literal.h"
|
#include "toy_literal.h"
|
||||||
|
|
||||||
typedef struct LiteralArray {
|
typedef struct Toy_LiteralArray {
|
||||||
Literal* literals;
|
Toy_Literal* literals;
|
||||||
int capacity;
|
int capacity;
|
||||||
int count;
|
int count;
|
||||||
} LiteralArray;
|
} Toy_LiteralArray;
|
||||||
|
|
||||||
TOY_API void initLiteralArray(LiteralArray* array);
|
TOY_API void Toy_initLiteralArray(Toy_LiteralArray* array);
|
||||||
TOY_API void freeLiteralArray(LiteralArray* array);
|
TOY_API void Toy_freeLiteralArray(Toy_LiteralArray* array);
|
||||||
TOY_API int pushLiteralArray(LiteralArray* array, Literal literal);
|
TOY_API int Toy_pushLiteralArray(Toy_LiteralArray* array, Toy_Literal literal);
|
||||||
TOY_API Literal popLiteralArray(LiteralArray* array);
|
TOY_API Toy_Literal Toy_popLiteralArray(Toy_LiteralArray* array);
|
||||||
TOY_API bool setLiteralArray(LiteralArray* array, Literal index, Literal value);
|
TOY_API bool Toy_setLiteralArray(Toy_LiteralArray* array, Toy_Literal index, Toy_Literal value);
|
||||||
TOY_API Literal getLiteralArray(LiteralArray* array, Literal index);
|
TOY_API Toy_Literal Toy_getLiteralArray(Toy_LiteralArray* array, Toy_Literal index);
|
||||||
|
|
||||||
int findLiteralIndex(LiteralArray* array, Literal literal);
|
int Toy_findLiteralIndex(Toy_LiteralArray* array, Toy_Literal literal);
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
#include "literal_dictionary.h"
|
#include "toy_literal_dictionary.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
//util functions
|
//util functions
|
||||||
static void setEntryValues(_entry* entry, Literal key, Literal value) {
|
static void setEntryValues(Toy_private_entry* entry, Toy_Literal key, Toy_Literal value) {
|
||||||
//much simpler now
|
//much simpler now
|
||||||
freeLiteral(entry->key);
|
Toy_freeLiteral(entry->key);
|
||||||
entry->key = copyLiteral(key);
|
entry->key = Toy_copyLiteral(key);
|
||||||
|
|
||||||
freeLiteral(entry->value);
|
Toy_freeLiteral(entry->value);
|
||||||
entry->value = copyLiteral(value);
|
entry->value = Toy_copyLiteral(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _entry* getEntryArray(_entry* array, int capacity, Literal key, unsigned int hash, bool mustExist) {
|
static Toy_private_entry* getEntryArray(Toy_private_entry* array, int capacity, Toy_Literal key, unsigned int hash, bool mustExist) {
|
||||||
//find "key", starting at index
|
//find "key", starting at index
|
||||||
unsigned int index = hash % capacity;
|
unsigned int index = hash % capacity;
|
||||||
unsigned int start = index;
|
unsigned int start = index;
|
||||||
@@ -26,16 +26,16 @@ static _entry* getEntryArray(_entry* array, int capacity, Literal key, unsigned
|
|||||||
|
|
||||||
//literal probing and collision checking
|
//literal probing and collision checking
|
||||||
while (index != start) { //WARNING: this is the only function allowed to retrieve an entry from the array
|
while (index != start) { //WARNING: this is the only function allowed to retrieve an entry from the array
|
||||||
_entry* entry = &array[index];
|
Toy_private_entry* entry = &array[index];
|
||||||
|
|
||||||
if (IS_NULL(entry->key)) { //if key is empty, it's either empty or tombstone
|
if (TOY_IS_NULL(entry->key)) { //if key is empty, it's either empty or tombstone
|
||||||
if (IS_NULL(entry->value) && !mustExist) {
|
if (TOY_IS_NULL(entry->value) && !mustExist) {
|
||||||
//found a truly empty bucket
|
//found a truly empty bucket
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
//else it's a tombstone - ignore
|
//else it's a tombstone - ignore
|
||||||
} else {
|
} else {
|
||||||
if (literalsAreEqual(key, entry->key)) {
|
if (Toy_literalsAreEqual(key, entry->key)) {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,46 +46,46 @@ static _entry* getEntryArray(_entry* array, int capacity, Literal key, unsigned
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void adjustEntryCapacity(_entry** dictionaryHandle, int oldCapacity, int capacity) {
|
static void adjustEntryCapacity(Toy_private_entry** dictionaryHandle, int oldCapacity, int capacity) {
|
||||||
//new entry space
|
//new entry space
|
||||||
_entry* newEntries = ALLOCATE(_entry, capacity);
|
Toy_private_entry* newEntries = TOY_ALLOCATE(Toy_private_entry, capacity);
|
||||||
|
|
||||||
for (int i = 0; i < capacity; i++) {
|
for (int i = 0; i < capacity; i++) {
|
||||||
newEntries[i].key = TO_NULL_LITERAL;
|
newEntries[i].key = TOY_TO_NULL_LITERAL;
|
||||||
newEntries[i].value = TO_NULL_LITERAL;
|
newEntries[i].value = TOY_TO_NULL_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//move the old array into the new one
|
//move the old array into the new one
|
||||||
for (int i = 0; i < oldCapacity; i++) {
|
for (int i = 0; i < oldCapacity; i++) {
|
||||||
if (IS_NULL((*dictionaryHandle)[i].key)) {
|
if (TOY_IS_NULL((*dictionaryHandle)[i].key)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//place the key and value in the new array (reusing string memory)
|
//place the key and value in the new array (reusing string memory)
|
||||||
_entry* entry = getEntryArray(newEntries, capacity, TO_NULL_LITERAL, hashLiteral((*dictionaryHandle)[i].key), false);
|
Toy_private_entry* entry = getEntryArray(newEntries, capacity, TOY_TO_NULL_LITERAL, Toy_hashLiteral((*dictionaryHandle)[i].key), false);
|
||||||
|
|
||||||
entry->key = (*dictionaryHandle)[i].key;
|
entry->key = (*dictionaryHandle)[i].key;
|
||||||
entry->value = (*dictionaryHandle)[i].value;
|
entry->value = (*dictionaryHandle)[i].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
//clear the old array
|
//clear the old array
|
||||||
FREE_ARRAY(_entry, *dictionaryHandle, oldCapacity);
|
TOY_FREE_ARRAY(Toy_private_entry, *dictionaryHandle, oldCapacity);
|
||||||
|
|
||||||
*dictionaryHandle = newEntries;
|
*dictionaryHandle = newEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool setEntryArray(_entry** dictionaryHandle, int* capacityPtr, int contains, Literal key, Literal value, int hash) {
|
static bool setEntryArray(Toy_private_entry** dictionaryHandle, int* capacityPtr, int contains, Toy_Literal key, Toy_Literal value, int hash) {
|
||||||
//expand array if needed
|
//expand array if needed
|
||||||
if (contains + 1 > *capacityPtr * DICTIONARY_MAX_LOAD) {
|
if (contains + 1 > *capacityPtr * TOY_DICTIONARY_MAX_LOAD) {
|
||||||
int oldCapacity = *capacityPtr;
|
int oldCapacity = *capacityPtr;
|
||||||
*capacityPtr = GROW_CAPACITY(*capacityPtr);
|
*capacityPtr = TOY_GROW_CAPACITY(*capacityPtr);
|
||||||
adjustEntryCapacity(dictionaryHandle, oldCapacity, *capacityPtr); //custom rather than automatic reallocation
|
adjustEntryCapacity(dictionaryHandle, oldCapacity, *capacityPtr); //custom rather than automatic reallocation
|
||||||
}
|
}
|
||||||
|
|
||||||
_entry* entry = getEntryArray(*dictionaryHandle, *capacityPtr, key, hash, false);
|
Toy_private_entry* entry = getEntryArray(*dictionaryHandle, *capacityPtr, key, hash, false);
|
||||||
|
|
||||||
//true = contains increase
|
//true = contains increase
|
||||||
if (IS_NULL(entry->key)) {
|
if (TOY_IS_NULL(entry->key)) {
|
||||||
setEntryValues(entry, key, value);
|
setEntryValues(entry, key, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -97,61 +97,61 @@ static bool setEntryArray(_entry** dictionaryHandle, int* capacityPtr, int conta
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeEntry(_entry* entry) {
|
static void freeEntry(Toy_private_entry* entry) {
|
||||||
freeLiteral(entry->key);
|
Toy_freeLiteral(entry->key);
|
||||||
freeLiteral(entry->value);
|
Toy_freeLiteral(entry->value);
|
||||||
entry->key = TO_NULL_LITERAL;
|
entry->key = TOY_TO_NULL_LITERAL;
|
||||||
entry->value = TO_NULL_LITERAL;
|
entry->value = TOY_TO_NULL_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeEntryArray(_entry* array, int capacity) {
|
static void freeEntryArray(Toy_private_entry* array, int capacity) {
|
||||||
if (array == NULL) {
|
if (array == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < capacity; i++) {
|
for (int i = 0; i < capacity; i++) {
|
||||||
if (!IS_NULL(array[i].key)) {
|
if (!TOY_IS_NULL(array[i].key)) {
|
||||||
freeEntry(&array[i]);
|
freeEntry(&array[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FREE_ARRAY(_entry, array, capacity);
|
TOY_FREE_ARRAY(Toy_private_entry, array, capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
void initLiteralDictionary(LiteralDictionary* dictionary) {
|
void Toy_initLiteralDictionary(Toy_LiteralDictionary* dictionary) {
|
||||||
//HACK: because modulo by 0 is undefined, set the capacity to a non-zero value (and allocate the arrays)
|
//HACK: because modulo by 0 is undefined, set the capacity to a non-zero value (and allocate the arrays)
|
||||||
dictionary->entries = NULL;
|
dictionary->entries = NULL;
|
||||||
dictionary->capacity = GROW_CAPACITY(0);
|
dictionary->capacity = TOY_GROW_CAPACITY(0);
|
||||||
dictionary->contains = 0;
|
dictionary->contains = 0;
|
||||||
dictionary->count = 0;
|
dictionary->count = 0;
|
||||||
adjustEntryCapacity(&dictionary->entries, 0, dictionary->capacity);
|
adjustEntryCapacity(&dictionary->entries, 0, dictionary->capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeLiteralDictionary(LiteralDictionary* dictionary) {
|
void Toy_freeLiteralDictionary(Toy_LiteralDictionary* dictionary) {
|
||||||
freeEntryArray(dictionary->entries, dictionary->capacity);
|
freeEntryArray(dictionary->entries, dictionary->capacity);
|
||||||
dictionary->capacity = 0;
|
dictionary->capacity = 0;
|
||||||
dictionary->contains = 0;
|
dictionary->contains = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLiteralDictionary(LiteralDictionary* dictionary, Literal key, Literal value) {
|
void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key, Toy_Literal value) {
|
||||||
if (IS_NULL(key)) {
|
if (TOY_IS_NULL(key)) {
|
||||||
fprintf(stderr, ERROR "Dictionaries can't have null keys (set)\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have null keys (set)\n" TOY_CC_RESET);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BUGFIX: Can't hash a function
|
//BUGFIX: Can't hash a function
|
||||||
if (IS_FUNCTION(key) || IS_FUNCTION_NATIVE(key)) {
|
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
|
||||||
fprintf(stderr, ERROR "Dictionaries can't have function keys (set)\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (set)\n" TOY_CC_RESET);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_OPAQUE(key)) {
|
if (TOY_IS_OPAQUE(key)) {
|
||||||
fprintf(stderr, ERROR "Dictionaries can't have opaque keys (set)\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have opaque keys (set)\n" TOY_CC_RESET);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int increment = setEntryArray(&dictionary->entries, &dictionary->capacity, dictionary->contains, key, value, hashLiteral(key));
|
const int increment = setEntryArray(&dictionary->entries, &dictionary->capacity, dictionary->contains, key, value, Toy_hashLiteral(key));
|
||||||
|
|
||||||
if (increment) {
|
if (increment) {
|
||||||
dictionary->contains++;
|
dictionary->contains++;
|
||||||
@@ -159,61 +159,61 @@ void setLiteralDictionary(LiteralDictionary* dictionary, Literal key, Literal va
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal getLiteralDictionary(LiteralDictionary* dictionary, Literal key) {
|
Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key) {
|
||||||
if (IS_NULL(key)) {
|
if (TOY_IS_NULL(key)) {
|
||||||
fprintf(stderr, ERROR "Dictionaries can't have null keys (get)\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have null keys (get)\n" TOY_CC_RESET);
|
||||||
return TO_NULL_LITERAL;
|
return TOY_TO_NULL_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BUGFIX: Can't hash a function
|
//BUGFIX: Can't hash a function
|
||||||
if (IS_FUNCTION(key) || IS_FUNCTION_NATIVE(key)) {
|
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
|
||||||
fprintf(stderr, ERROR "Dictionaries can't have function keys (get)\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (get)\n" TOY_CC_RESET);
|
||||||
return TO_NULL_LITERAL;
|
return TOY_TO_NULL_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_OPAQUE(key)) {
|
if (TOY_IS_OPAQUE(key)) {
|
||||||
fprintf(stderr, ERROR "Dictionaries can't have opaque keys (get)\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have opaque keys (get)\n" TOY_CC_RESET);
|
||||||
return TO_NULL_LITERAL;
|
return TOY_TO_NULL_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, hashLiteral(key), true);
|
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
|
||||||
|
|
||||||
if (entry != NULL) {
|
if (entry != NULL) {
|
||||||
return copyLiteral(entry->value);
|
return Toy_copyLiteral(entry->value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return TO_NULL_LITERAL;
|
return TOY_TO_NULL_LITERAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeLiteralDictionary(LiteralDictionary* dictionary, Literal key) {
|
void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key) {
|
||||||
if (IS_NULL(key)) {
|
if (TOY_IS_NULL(key)) {
|
||||||
fprintf(stderr, ERROR "Dictionaries can't have null keys (remove)\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have null keys (remove)\n" TOY_CC_RESET);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//BUGFIX: Can't hash a function
|
//BUGFIX: Can't hash a function
|
||||||
if (IS_FUNCTION(key) || IS_FUNCTION_NATIVE(key)) {
|
if (TOY_IS_FUNCTION(key) || TOY_IS_FUNCTION_NATIVE(key)) {
|
||||||
fprintf(stderr, ERROR "Dictionaries can't have function keys (remove)\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have function keys (remove)\n" TOY_CC_RESET);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_OPAQUE(key)) {
|
if (TOY_IS_OPAQUE(key)) {
|
||||||
fprintf(stderr, ERROR "Dictionaries can't have opaque keys (remove)\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "Dictionaries can't have opaque keys (remove)\n" TOY_CC_RESET);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, hashLiteral(key), true);
|
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), true);
|
||||||
|
|
||||||
if (entry != NULL) {
|
if (entry != NULL) {
|
||||||
freeEntry(entry);
|
freeEntry(entry);
|
||||||
entry->value = TO_BOOLEAN_LITERAL(true); //tombstone
|
entry->value = TOY_TO_BOOLEAN_LITERAL(true); //tombstone
|
||||||
dictionary->count--;
|
dictionary->count--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool existsLiteralDictionary(LiteralDictionary* dictionary, Literal key) {
|
bool Toy_existsLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key) {
|
||||||
//null & not tombstoned
|
//null & not tombstoned
|
||||||
_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, hashLiteral(key), false);
|
Toy_private_entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, Toy_hashLiteral(key), false);
|
||||||
return !(IS_NULL(entry->key) && IS_NULL(entry->value));
|
return !(TOY_IS_NULL(entry->key) && TOY_IS_NULL(entry->value));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,28 +2,28 @@
|
|||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
|
|
||||||
#include "literal.h"
|
#include "toy_literal.h"
|
||||||
|
|
||||||
//TODO: benchmark this
|
//TODO: benchmark this
|
||||||
#define DICTIONARY_MAX_LOAD 0.75
|
#define TOY_DICTIONARY_MAX_LOAD 0.75
|
||||||
|
|
||||||
typedef struct _entry {
|
typedef struct Toy_private_entry {
|
||||||
Literal key;
|
Toy_Literal key;
|
||||||
Literal value;
|
Toy_Literal value;
|
||||||
} _entry;
|
} Toy_private_entry;
|
||||||
|
|
||||||
typedef struct LiteralDictionary {
|
typedef struct Toy_LiteralDictionary {
|
||||||
_entry* entries;
|
Toy_private_entry* entries;
|
||||||
int capacity;
|
int capacity;
|
||||||
int count;
|
int count;
|
||||||
int contains; //count + tombstones, for internal use
|
int contains; //count + tombstones, for internal use
|
||||||
} LiteralDictionary;
|
} Toy_LiteralDictionary;
|
||||||
|
|
||||||
TOY_API void initLiteralDictionary(LiteralDictionary* dictionary);
|
TOY_API void Toy_initLiteralDictionary(Toy_LiteralDictionary* dictionary);
|
||||||
TOY_API void freeLiteralDictionary(LiteralDictionary* dictionary);
|
TOY_API void Toy_freeLiteralDictionary(Toy_LiteralDictionary* dictionary);
|
||||||
|
|
||||||
TOY_API void setLiteralDictionary(LiteralDictionary* dictionary, Literal key, Literal value);
|
TOY_API void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key, Toy_Literal value);
|
||||||
TOY_API Literal getLiteralDictionary(LiteralDictionary* dictionary, Literal key);
|
TOY_API Toy_Literal Toy_getLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key);
|
||||||
TOY_API void removeLiteralDictionary(LiteralDictionary* dictionary, Literal key);
|
TOY_API void Toy_removeLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key);
|
||||||
|
|
||||||
TOY_API bool existsLiteralDictionary(LiteralDictionary* dictionary, Literal key);
|
TOY_API bool Toy_existsLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key);
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
#include "refstring.h"
|
#include "toy_refstring.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
//default allocator
|
//default allocator
|
||||||
void* defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
static void* defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
||||||
if (newSize == 0 && oldSize == 0) {
|
if (newSize == 0 && oldSize == 0) {
|
||||||
//causes issues, so just skip out with a NO-OP
|
//causes issues, so just skip out with a NO-OP
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -22,7 +22,7 @@ void* defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
|||||||
void* mem = realloc(pointer, newSize);
|
void* mem = realloc(pointer, newSize);
|
||||||
|
|
||||||
if (mem == NULL) {
|
if (mem == NULL) {
|
||||||
fprintf(stderr, ERROR "[internal] Memory allocation error (requested %d for %ld, replacing %d)\n" RESET, (int)newSize, (long int)pointer, (int)oldSize);
|
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %d for %ld, replacing %d)\n" TOY_CC_RESET, (int)newSize, (long int)pointer, (int)oldSize);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,29 +30,29 @@ void* defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//static variables
|
//static variables
|
||||||
static MemoryAllocatorFn allocator;
|
static Toy_MemoryAllocatorFn allocator;
|
||||||
|
|
||||||
//preload
|
//preload
|
||||||
static void __attribute__((constructor)) preloadMemoryAllocator() {
|
static void __attribute__((constructor)) preloadMemoryAllocator() {
|
||||||
setMemoryAllocator(defaultMemoryAllocator);
|
Toy_setMemoryAllocator(defaultMemoryAllocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
//exposed API
|
//exposed API
|
||||||
void* reallocate(void* pointer, size_t oldSize, size_t newSize) {
|
void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize) {
|
||||||
return allocator(pointer, oldSize, newSize);
|
return allocator(pointer, oldSize, newSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMemoryAllocator(MemoryAllocatorFn fn) {
|
void Toy_setMemoryAllocator(Toy_MemoryAllocatorFn fn) {
|
||||||
if (fn == NULL) {
|
if (fn == NULL) {
|
||||||
fprintf(stderr, ERROR "[internal] Memory allocator error (can't be null)\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocator error (can't be null)\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fn == reallocate) {
|
if (fn == Toy_reallocate) {
|
||||||
fprintf(stderr, ERROR "[internal] Memory allocator error (can't loop the reallocate function)\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocator error (can't loop the Toy_reallocate function)\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
allocator = fn;
|
allocator = fn;
|
||||||
setRefStringAllocatorFn(fn);
|
Toy_setRefStringAllocatorFn(fn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
|
|
||||||
#define ALLOCATE(type, count) ((type*)reallocate(NULL, 0, sizeof(type) * (count)))
|
#define TOY_ALLOCATE(type, count) ((type*)Toy_reallocate(NULL, 0, sizeof(type) * (count)))
|
||||||
#define FREE(type, pointer) reallocate(pointer, sizeof(type), 0)
|
#define TOY_FREE(type, pointer) Toy_reallocate(pointer, sizeof(type), 0)
|
||||||
#define GROW_CAPACITY(capacity) ((capacity) < 8 ? 8 : (capacity) * 2)
|
#define TOY_GROW_CAPACITY(capacity) ((capacity) < 8 ? 8 : (capacity) * 2)
|
||||||
#define GROW_CAPACITY_FAST(capacity) ((capacity) < 32 ? 32 : (capacity) * 2)
|
#define TOY_GROW_CAPACITY_FAST(capacity) ((capacity) < 32 ? 32 : (capacity) * 2)
|
||||||
#define GROW_ARRAY(type, pointer, oldCount, count) (type*)reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
|
#define TOY_GROW_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
|
||||||
#define SHRINK_ARRAY(type, pointer, oldCount, count) (type*)reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
|
#define TOY_SHRINK_ARRAY(type, pointer, oldCount, count) (type*)Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), sizeof(type) * (count))
|
||||||
#define FREE_ARRAY(type, pointer, oldCount) reallocate((type*)pointer, sizeof(type) * (oldCount), 0)
|
#define TOY_FREE_ARRAY(type, pointer, oldCount) Toy_reallocate((type*)pointer, sizeof(type) * (oldCount), 0)
|
||||||
|
|
||||||
//implementation details
|
//implementation details
|
||||||
void* reallocate(void* pointer, size_t oldSize, size_t newSize);
|
void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize);
|
||||||
|
|
||||||
//assign the memory allocator
|
//assign the memory allocator
|
||||||
typedef void* (*MemoryAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
|
typedef void* (*Toy_MemoryAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
|
||||||
TOY_API void setMemoryAllocator(MemoryAllocatorFn);
|
TOY_API void Toy_setMemoryAllocator(Toy_MemoryAllocatorFn);
|
||||||
|
|||||||
@@ -1,87 +1,87 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
typedef enum Opcode {
|
typedef enum Toy_Opcode {
|
||||||
OP_EOF,
|
TOY_OP_EOF,
|
||||||
|
|
||||||
//basic statements
|
//basic statements
|
||||||
OP_ASSERT,
|
TOY_OP_ASSERT,
|
||||||
OP_PRINT,
|
TOY_OP_PRINT,
|
||||||
|
|
||||||
//data
|
//data
|
||||||
OP_LITERAL,
|
TOY_OP_LITERAL,
|
||||||
OP_LITERAL_LONG, //for more than 256 literals in a chunk
|
TOY_OP_LITERAL_LONG, //for more than 256 literals in a chunk
|
||||||
OP_LITERAL_RAW, //forcibly get the raw value of the literal
|
TOY_OP_LITERAL_RAW, //forcibly get the raw value of the literal
|
||||||
|
|
||||||
//arithmetic operators
|
//arithmetic operators
|
||||||
OP_NEGATE,
|
TOY_OP_NEGATE,
|
||||||
OP_ADDITION,
|
TOY_OP_ADDITION,
|
||||||
OP_SUBTRACTION,
|
TOY_OP_SUBTRACTION,
|
||||||
OP_MULTIPLICATION,
|
TOY_OP_MULTIPLICATION,
|
||||||
OP_DIVISION,
|
TOY_OP_DIVISION,
|
||||||
OP_MODULO,
|
TOY_OP_MODULO,
|
||||||
OP_GROUPING_BEGIN,
|
TOY_OP_GROUPING_BEGIN,
|
||||||
OP_GROUPING_END,
|
TOY_OP_GROUPING_END,
|
||||||
|
|
||||||
//variable stuff
|
//variable stuff
|
||||||
OP_SCOPE_BEGIN,
|
TOY_OP_SCOPE_BEGIN,
|
||||||
OP_SCOPE_END,
|
TOY_OP_SCOPE_END,
|
||||||
|
|
||||||
OP_TYPE_DECL, //declare a type to be used (as a literal)
|
TOY_OP_TYPE_DECL, //declare a type to be used (as a literal)
|
||||||
OP_TYPE_DECL_LONG, //declare a type to be used (as a long literal)
|
TOY_OP_TYPE_DECL_LONG, //declare a type to be used (as a long literal)
|
||||||
|
|
||||||
OP_VAR_DECL, //declare a variable to be used (as a literal)
|
TOY_OP_VAR_DECL, //declare a variable to be used (as a literal)
|
||||||
OP_VAR_DECL_LONG, //declare a variable to be used (as a long literal)
|
TOY_OP_VAR_DECL_LONG, //declare a variable to be used (as a long literal)
|
||||||
|
|
||||||
OP_FN_DECL, //declare a function to be used (as a literal)
|
TOY_OP_FN_DECL, //declare a function to be used (as a literal)
|
||||||
OP_FN_DECL_LONG, //declare a function to be used (as a long literal)
|
TOY_OP_FN_DECL_LONG, //declare a function to be used (as a long literal)
|
||||||
|
|
||||||
OP_VAR_ASSIGN, //assign to a literal
|
TOY_OP_VAR_ASSIGN, //assign to a literal
|
||||||
OP_VAR_ADDITION_ASSIGN,
|
TOY_OP_VAR_ADDITION_ASSIGN,
|
||||||
OP_VAR_SUBTRACTION_ASSIGN,
|
TOY_OP_VAR_SUBTRACTION_ASSIGN,
|
||||||
OP_VAR_MULTIPLICATION_ASSIGN,
|
TOY_OP_VAR_MULTIPLICATION_ASSIGN,
|
||||||
OP_VAR_DIVISION_ASSIGN,
|
TOY_OP_VAR_DIVISION_ASSIGN,
|
||||||
OP_VAR_MODULO_ASSIGN,
|
TOY_OP_VAR_MODULO_ASSIGN,
|
||||||
|
|
||||||
OP_TYPE_CAST, //temporarily change a type of an atomic value
|
TOY_OP_TYPE_CAST, //temporarily change a type of an atomic value
|
||||||
OP_TYPE_OF, //get the type of a variable
|
TOY_OP_TYPE_OF, //get the type of a variable
|
||||||
|
|
||||||
OP_IMPORT,
|
TOY_OP_IMPORT,
|
||||||
OP_EXPORT_removed,
|
TOY_OP_EXPORT_removed,
|
||||||
|
|
||||||
//for indexing
|
//for indexing
|
||||||
OP_INDEX,
|
TOY_OP_INDEX,
|
||||||
OP_INDEX_ASSIGN,
|
TOY_OP_INDEX_ASSIGN,
|
||||||
OP_INDEX_ASSIGN_INTERMEDIATE,
|
TOY_OP_INDEX_ASSIGN_INTERMEDIATE,
|
||||||
OP_DOT,
|
TOY_OP_DOT,
|
||||||
|
|
||||||
//comparison of values
|
//comparison of values
|
||||||
OP_COMPARE_EQUAL,
|
TOY_OP_COMPARE_EQUAL,
|
||||||
OP_COMPARE_NOT_EQUAL,
|
TOY_OP_COMPARE_NOT_EQUAL,
|
||||||
OP_COMPARE_LESS,
|
TOY_OP_COMPARE_LESS,
|
||||||
OP_COMPARE_LESS_EQUAL,
|
TOY_OP_COMPARE_LESS_EQUAL,
|
||||||
OP_COMPARE_GREATER,
|
TOY_OP_COMPARE_GREATER,
|
||||||
OP_COMPARE_GREATER_EQUAL,
|
TOY_OP_COMPARE_GREATER_EQUAL,
|
||||||
OP_INVERT, //for booleans
|
TOY_OP_INVERT, //for booleans
|
||||||
|
|
||||||
//logical operators
|
//logical operators
|
||||||
OP_AND,
|
TOY_OP_AND,
|
||||||
OP_OR,
|
TOY_OP_OR,
|
||||||
|
|
||||||
//jumps, and conditional jumps (absolute)
|
//jumps, and conditional jumps (absolute)
|
||||||
OP_JUMP,
|
TOY_OP_JUMP,
|
||||||
OP_IF_FALSE_JUMP,
|
TOY_OP_IF_FALSE_JUMP,
|
||||||
OP_FN_CALL,
|
TOY_OP_FN_CALL,
|
||||||
OP_FN_RETURN,
|
TOY_OP_FN_RETURN,
|
||||||
|
|
||||||
//pop the stack at the end of a complex statement
|
//pop the stack at the end of a complex statement
|
||||||
OP_POP_STACK,
|
TOY_OP_POP_STACK,
|
||||||
|
|
||||||
//ternary shorthand
|
//ternary shorthand
|
||||||
OP_TERNARY,
|
TOY_OP_TERNARY,
|
||||||
|
|
||||||
//meta
|
//meta
|
||||||
OP_FN_END, //different from SECTION_END
|
TOY_OP_FN_END, //different from SECTION_END
|
||||||
OP_SECTION_END = 255,
|
TOY_OP_SECTION_END = 255,
|
||||||
//TODO: add more
|
//TODO: add more
|
||||||
} Opcode;
|
} Toy_Opcode;
|
||||||
|
|
||||||
|
|||||||
1126
source/toy_parser.c
1126
source/toy_parser.c
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
#include "lexer.h"
|
#include "toy_lexer.h"
|
||||||
#include "ast_node.h"
|
#include "toy_ast_node.h"
|
||||||
|
|
||||||
//DOCS: parsers are bound to a lexer, and turn the outputted tokens into AST nodes
|
//DOCS: parsers are bound to a lexer, and turn the outputted tokens into AST nodes
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Lexer* lexer;
|
Toy_Lexer* lexer;
|
||||||
bool error; //I've had an error
|
bool error; //I've had an error
|
||||||
bool panic; //I am processing an error
|
bool panic; //I am processing an error
|
||||||
|
|
||||||
//track the last two outputs from the lexer
|
//track the last two outputs from the lexer
|
||||||
Token current;
|
Toy_Token current;
|
||||||
Token previous;
|
Toy_Token previous;
|
||||||
} Parser;
|
} Toy_Parser;
|
||||||
|
|
||||||
TOY_API void initParser(Parser* parser, Lexer* lexer);
|
TOY_API void Toy_initParser(Toy_Parser* parser, Toy_Lexer* lexer);
|
||||||
TOY_API void freeParser(Parser* parser);
|
TOY_API void Toy_freeParser(Toy_Parser* parser);
|
||||||
TOY_API ASTNode* scanParser(Parser* parser);
|
TOY_API Toy_ASTNode* Toy_scanParser(Toy_Parser* parser);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "refstring.h"
|
#include "toy_refstring.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@@ -6,27 +6,27 @@
|
|||||||
//test variable sizes based on platform (safety)
|
//test variable sizes based on platform (safety)
|
||||||
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")
|
#define STATIC_ASSERT(test_for_true) static_assert((test_for_true), "(" #test_for_true ") failed")
|
||||||
|
|
||||||
STATIC_ASSERT(sizeof(RefString) == 12);
|
STATIC_ASSERT(sizeof(Toy_RefString) == 12);
|
||||||
STATIC_ASSERT(sizeof(int) == 4);
|
STATIC_ASSERT(sizeof(int) == 4);
|
||||||
STATIC_ASSERT(sizeof(char) == 1);
|
STATIC_ASSERT(sizeof(char) == 1);
|
||||||
|
|
||||||
//memory allocation
|
//memory allocation
|
||||||
static RefStringAllocatorFn allocate;
|
static Toy_RefStringAllocatorFn allocate;
|
||||||
|
|
||||||
void setRefStringAllocatorFn(RefStringAllocatorFn allocator) {
|
void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn allocator) {
|
||||||
allocate = allocator;
|
allocate = allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
//API
|
//API
|
||||||
RefString* createRefString(char* cstring) {
|
Toy_RefString* Toy_createRefString(char* cstring) {
|
||||||
int length = strnlen(cstring, 4096);
|
int length = strnlen(cstring, 4096);
|
||||||
|
|
||||||
return createRefStringLength(cstring, length);
|
return Toy_createRefStringLength(cstring, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefString* createRefStringLength(char* cstring, int length) {
|
Toy_RefString* Toy_createRefStringLength(char* cstring, int length) {
|
||||||
//allocate the memory area (including metadata space)
|
//allocate the memory area (including metadata space)
|
||||||
RefString* refString = (RefString*)allocate(NULL, 0, sizeof(int) * 2 + sizeof(char) * length + 1);
|
Toy_RefString* refString = (Toy_RefString*)allocate(NULL, 0, sizeof(int) * 2 + sizeof(char) * length + 1);
|
||||||
|
|
||||||
//set the data
|
//set the data
|
||||||
refString->refcount = 1;
|
refString->refcount = 1;
|
||||||
@@ -38,7 +38,7 @@ RefString* createRefStringLength(char* cstring, int length) {
|
|||||||
return refString;
|
return refString;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteRefString(RefString* refString) {
|
void Toy_deleteRefString(Toy_RefString* refString) {
|
||||||
//decrement, then check
|
//decrement, then check
|
||||||
refString->refcount--;
|
refString->refcount--;
|
||||||
if (refString->refcount <= 0) {
|
if (refString->refcount <= 0) {
|
||||||
@@ -46,30 +46,30 @@ void deleteRefString(RefString* refString) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int countRefString(RefString* refString) {
|
int Toy_countRefString(Toy_RefString* refString) {
|
||||||
return refString->refcount;
|
return refString->refcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lengthRefString(RefString* refString) {
|
int Toy_lengthRefString(Toy_RefString* refString) {
|
||||||
return refString->length;
|
return refString->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefString* copyRefString(RefString* refString) {
|
Toy_RefString* Toy_copyRefString(Toy_RefString* refString) {
|
||||||
//Cheaty McCheater Face
|
//Cheaty McCheater Face
|
||||||
refString->refcount++;
|
refString->refcount++;
|
||||||
return refString;
|
return refString;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefString* deepCopyRefString(RefString* refString) {
|
Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString) {
|
||||||
//create a new string, with a new refcount
|
//create a new string, with a new refcount
|
||||||
return createRefStringLength(refString->data, refString->length);
|
return Toy_createRefStringLength(refString->data, refString->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* toCString(RefString* refString) {
|
char* Toy_toCString(Toy_RefString* refString) {
|
||||||
return refString->data;
|
return refString->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool equalsRefString(RefString* lhs, RefString* rhs) {
|
bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs) {
|
||||||
//same pointer
|
//same pointer
|
||||||
if (lhs == rhs) {
|
if (lhs == rhs) {
|
||||||
return true;
|
return true;
|
||||||
@@ -84,7 +84,7 @@ bool equalsRefString(RefString* lhs, RefString* rhs) {
|
|||||||
return strncmp(lhs->data, rhs->data, lhs->length) == 0;
|
return strncmp(lhs->data, rhs->data, lhs->length) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool equalsRefStringCString(RefString* lhs, char* cstring) {
|
bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring) {
|
||||||
//get the rhs length
|
//get the rhs length
|
||||||
int length = strnlen(cstring, 4096);
|
int length = strnlen(cstring, 4096);
|
||||||
|
|
||||||
|
|||||||
@@ -4,24 +4,24 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
//memory allocation hook
|
//memory allocation hook
|
||||||
typedef void* (*RefStringAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
|
typedef void* (*Toy_RefStringAllocatorFn)(void* pointer, size_t oldSize, size_t newSize);
|
||||||
void setRefStringAllocatorFn(RefStringAllocatorFn);
|
void Toy_setRefStringAllocatorFn(Toy_RefStringAllocatorFn);
|
||||||
|
|
||||||
//the RefString structure
|
//the RefString structure
|
||||||
typedef struct RefString {
|
typedef struct Toy_RefString {
|
||||||
int refcount;
|
int refcount;
|
||||||
int length;
|
int length;
|
||||||
char data[1];
|
char data[1];
|
||||||
} RefString;
|
} Toy_RefString;
|
||||||
|
|
||||||
//API
|
//API
|
||||||
RefString* createRefString(char* cstring);
|
Toy_RefString* Toy_createRefString(char* cstring);
|
||||||
RefString* createRefStringLength(char* cstring, int length);
|
Toy_RefString* Toy_createRefStringLength(char* cstring, int length);
|
||||||
void deleteRefString(RefString* refString);
|
void Toy_deleteRefString(Toy_RefString* refString);
|
||||||
int countRefString(RefString* refString);
|
int Toy_countRefString(Toy_RefString* refString);
|
||||||
int lengthRefString(RefString* refString);
|
int Toy_lengthRefString(Toy_RefString* refString);
|
||||||
RefString* copyRefString(RefString* refString);
|
Toy_RefString* Toy_copyRefString(Toy_RefString* refString);
|
||||||
RefString* deepCopyRefString(RefString* refString);
|
Toy_RefString* Toy_deepCopyRefString(Toy_RefString* refString);
|
||||||
char* toCString(RefString* refString);
|
char* Toy_toCString(Toy_RefString* refString);
|
||||||
bool equalsRefString(RefString* lhs, RefString* rhs);
|
bool Toy_equalsRefString(Toy_RefString* lhs, Toy_RefString* rhs);
|
||||||
bool equalsRefStringCString(RefString* lhs, char* cstring);
|
bool Toy_equalsRefStringCString(Toy_RefString* lhs, char* cstring);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#include "scope.h"
|
#include "toy_scope.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
//run up the ancestor chain, freeing anything with 0 references left
|
//run up the ancestor chain, freeing anything with 0 references left
|
||||||
static void freeAncestorChain(Scope* scope) {
|
static void freeAncestorChain(Toy_Scope* scope) {
|
||||||
scope->references--;
|
scope->references--;
|
||||||
|
|
||||||
//free scope chain
|
//free scope chain
|
||||||
@@ -15,65 +15,65 @@ static void freeAncestorChain(Scope* scope) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeLiteralDictionary(&scope->variables);
|
Toy_freeLiteralDictionary(&scope->variables);
|
||||||
freeLiteralDictionary(&scope->types);
|
Toy_freeLiteralDictionary(&scope->types);
|
||||||
|
|
||||||
FREE(Scope, scope);
|
TOY_FREE(Toy_Scope, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
//return false if invalid type
|
//return false if invalid type
|
||||||
static bool checkType(Literal typeLiteral, Literal original, Literal value, bool constCheck) {
|
static bool checkType(Toy_Literal typeLiteral, Toy_Literal original, Toy_Literal value, bool constCheck) {
|
||||||
//for constants, fail if original != value
|
//for constants, fail if original != value
|
||||||
if (constCheck && AS_TYPE(typeLiteral).constant && !literalsAreEqual(original, value)) {
|
if (constCheck && TOY_AS_TYPE(typeLiteral).constant && !Toy_literalsAreEqual(original, value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//for any types
|
//for any types
|
||||||
if (AS_TYPE(typeLiteral).typeOf == LITERAL_ANY) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_ANY) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//don't allow null types
|
//don't allow null types
|
||||||
if (AS_TYPE(typeLiteral).typeOf == LITERAL_NULL) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//always allow null values
|
//always allow null values
|
||||||
if (IS_NULL(value)) {
|
if (TOY_IS_NULL(value)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//for each type, if a mismatch is found, return false
|
//for each type, if a mismatch is found, return false
|
||||||
if (AS_TYPE(typeLiteral).typeOf == LITERAL_BOOLEAN && !IS_BOOLEAN(value)) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_BOOLEAN && !TOY_IS_BOOLEAN(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AS_TYPE(typeLiteral).typeOf == LITERAL_INTEGER && !IS_INTEGER(value)) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_INTEGER && !TOY_IS_INTEGER(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AS_TYPE(typeLiteral).typeOf == LITERAL_FLOAT && !IS_FLOAT(value)) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_FLOAT && !TOY_IS_FLOAT(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AS_TYPE(typeLiteral).typeOf == LITERAL_STRING && !IS_STRING(value)) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_STRING && !TOY_IS_STRING(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AS_TYPE(typeLiteral).typeOf == LITERAL_ARRAY && !IS_ARRAY(value)) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_ARRAY && !TOY_IS_ARRAY(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ARRAY(value)) {
|
if (TOY_IS_ARRAY(value)) {
|
||||||
//check value's type
|
//check value's type
|
||||||
if (AS_TYPE(typeLiteral).typeOf != LITERAL_ARRAY) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf != TOY_LITERAL_ARRAY) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if null, assume it's a new array variable that needs checking
|
//if null, assume it's a new array variable that needs checking
|
||||||
if (IS_NULL(original)) {
|
if (TOY_IS_NULL(original)) {
|
||||||
for (int i = 0; i < AS_ARRAY(value)->count; i++) {
|
for (int i = 0; i < TOY_AS_ARRAY(value)->count; i++) {
|
||||||
if (!checkType( ((Literal*)(AS_TYPE(typeLiteral).subtypes))[0], TO_NULL_LITERAL, AS_ARRAY(value)->literals[i], constCheck)) {
|
if (!checkType( ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0], TOY_TO_NULL_LITERAL, TOY_AS_ARRAY(value)->literals[i], constCheck)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,36 +82,36 @@ static bool checkType(Literal typeLiteral, Literal original, Literal value, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
//check children
|
//check children
|
||||||
for (int i = 0; i < AS_ARRAY(value)->count; i++) {
|
for (int i = 0; i < TOY_AS_ARRAY(value)->count; i++) {
|
||||||
if (AS_ARRAY(original)->count <= i) {
|
if (TOY_AS_ARRAY(original)->count <= i) {
|
||||||
return true; //assume new entry pushed
|
return true; //assume new entry pushed
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[0], AS_ARRAY(original)->literals[i], AS_ARRAY(value)->literals[i], constCheck)) {
|
if (!checkType(((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0], TOY_AS_ARRAY(original)->literals[i], TOY_AS_ARRAY(value)->literals[i], constCheck)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AS_TYPE(typeLiteral).typeOf == LITERAL_DICTIONARY && !IS_DICTIONARY(value)) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_DICTIONARY && !TOY_IS_DICTIONARY(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_DICTIONARY(value)) {
|
if (TOY_IS_DICTIONARY(value)) {
|
||||||
//check value's type
|
//check value's type
|
||||||
if (AS_TYPE(typeLiteral).typeOf != LITERAL_DICTIONARY) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf != TOY_LITERAL_DICTIONARY) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if null, assume it's a new dictionary variable that needs checking
|
//if null, assume it's a new dictionary variable that needs checking
|
||||||
if (IS_NULL(original)) {
|
if (TOY_IS_NULL(original)) {
|
||||||
for (int i = 0; i < AS_DICTIONARY(value)->capacity; i++) {
|
for (int i = 0; i < TOY_AS_DICTIONARY(value)->capacity; i++) {
|
||||||
//check the type of key and value
|
//check the type of key and value
|
||||||
if (!checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[0], TO_NULL_LITERAL, AS_DICTIONARY(value)->entries[i].key, constCheck)) {
|
if (!checkType(((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0], TOY_TO_NULL_LITERAL, TOY_AS_DICTIONARY(value)->entries[i].key, constCheck)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[1], TO_NULL_LITERAL, AS_DICTIONARY(value)->entries[i].value, constCheck)) {
|
if (!checkType(((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[1], TOY_TO_NULL_LITERAL, TOY_AS_DICTIONARY(value)->entries[i].value, constCheck)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,17 +120,17 @@ static bool checkType(Literal typeLiteral, Literal original, Literal value, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
//check each child of value against the child of original
|
//check each child of value against the child of original
|
||||||
for (int i = 0; i < AS_DICTIONARY(value)->capacity; i++) {
|
for (int i = 0; i < TOY_AS_DICTIONARY(value)->capacity; i++) {
|
||||||
if (IS_NULL(AS_DICTIONARY(value)->entries[i].key)) { //only non-tombstones
|
if (TOY_IS_NULL(TOY_AS_DICTIONARY(value)->entries[i].key)) { //only non-tombstones
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//find the internal child of original that matches this child of value
|
//find the internal child of original that matches this child of value
|
||||||
_entry* ptr = NULL;
|
Toy_private_entry* ptr = NULL;
|
||||||
|
|
||||||
for (int j = 0; j < AS_DICTIONARY(original)->capacity; j++) {
|
for (int j = 0; j < TOY_AS_DICTIONARY(original)->capacity; j++) {
|
||||||
if (literalsAreEqual(AS_DICTIONARY(original)->entries[j].key, AS_DICTIONARY(value)->entries[i].key)) {
|
if (Toy_literalsAreEqual(TOY_AS_DICTIONARY(original)->entries[j].key, TOY_AS_DICTIONARY(value)->entries[i].key)) {
|
||||||
ptr = &AS_DICTIONARY(original)->entries[j];
|
ptr = &TOY_AS_DICTIONARY(original)->entries[j];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,21 +141,21 @@ static bool checkType(Literal typeLiteral, Literal original, Literal value, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
//check the type of key and value
|
//check the type of key and value
|
||||||
if (!checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[0], ptr->key, AS_DICTIONARY(value)->entries[i].key, constCheck)) {
|
if (!checkType(((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0], ptr->key, TOY_AS_DICTIONARY(value)->entries[i].key, constCheck)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[1], ptr->value, AS_DICTIONARY(value)->entries[i].value, constCheck)) {
|
if (!checkType(((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[1], ptr->value, TOY_AS_DICTIONARY(value)->entries[i].value, constCheck)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AS_TYPE(typeLiteral).typeOf == LITERAL_FUNCTION && !IS_FUNCTION(value)) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_FUNCTION && !TOY_IS_FUNCTION(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AS_TYPE(typeLiteral).typeOf == LITERAL_TYPE && !IS_TYPE(value)) {
|
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_TYPE && !TOY_IS_TYPE(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,39 +163,39 @@ static bool checkType(Literal typeLiteral, Literal original, Literal value, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
Scope* pushScope(Scope* ancestor) {
|
Toy_Scope* Toy_pushScope(Toy_Scope* ancestor) {
|
||||||
Scope* scope = ALLOCATE(Scope, 1);
|
Toy_Scope* scope = TOY_ALLOCATE(Toy_Scope, 1);
|
||||||
scope->ancestor = ancestor;
|
scope->ancestor = ancestor;
|
||||||
initLiteralDictionary(&scope->variables);
|
Toy_initLiteralDictionary(&scope->variables);
|
||||||
initLiteralDictionary(&scope->types);
|
Toy_initLiteralDictionary(&scope->types);
|
||||||
|
|
||||||
//tick up all scope reference counts
|
//tick up all scope reference counts
|
||||||
scope->references = 0;
|
scope->references = 0;
|
||||||
for (Scope* ptr = scope; ptr != NULL; ptr = ptr->ancestor) {
|
for (Toy_Scope* ptr = scope; ptr != NULL; ptr = ptr->ancestor) {
|
||||||
ptr->references++;
|
ptr->references++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope* popScope(Scope* scope) {
|
Toy_Scope* Toy_popScope(Toy_Scope* scope) {
|
||||||
if (scope == NULL) { //CAN pop a null
|
if (scope == NULL) { //CAN pop a null
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope* ret = scope->ancestor;
|
Toy_Scope* ret = scope->ancestor;
|
||||||
|
|
||||||
//BUGFIX: when freeing a scope, free the function's scopes manually
|
//BUGFIX: when freeing a scope, free the function's scopes manually
|
||||||
for (int i = 0; i < scope->variables.capacity; i++) {
|
for (int i = 0; i < scope->variables.capacity; i++) {
|
||||||
//handle keys, just in case
|
//handle keys, just in case
|
||||||
if (IS_FUNCTION(scope->variables.entries[i].key)) {
|
if (TOY_IS_FUNCTION(scope->variables.entries[i].key)) {
|
||||||
popScope(AS_FUNCTION(scope->variables.entries[i].key).scope);
|
Toy_popScope(TOY_AS_FUNCTION(scope->variables.entries[i].key).scope);
|
||||||
AS_FUNCTION(scope->variables.entries[i].key).scope = NULL;
|
TOY_AS_FUNCTION(scope->variables.entries[i].key).scope = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_FUNCTION(scope->variables.entries[i].value)) {
|
if (TOY_IS_FUNCTION(scope->variables.entries[i].value)) {
|
||||||
popScope(AS_FUNCTION(scope->variables.entries[i].value).scope);
|
Toy_popScope(TOY_AS_FUNCTION(scope->variables.entries[i].value).scope);
|
||||||
AS_FUNCTION(scope->variables.entries[i].value).scope = NULL;
|
TOY_AS_FUNCTION(scope->variables.entries[i].value).scope = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,28 +204,28 @@ Scope* popScope(Scope* scope) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope* copyScope(Scope* original) {
|
Toy_Scope* Toy_copyScope(Toy_Scope* original) {
|
||||||
Scope* scope = ALLOCATE(Scope, 1);
|
Toy_Scope* scope = TOY_ALLOCATE(Toy_Scope, 1);
|
||||||
scope->ancestor = original->ancestor;
|
scope->ancestor = original->ancestor;
|
||||||
initLiteralDictionary(&scope->variables);
|
Toy_initLiteralDictionary(&scope->variables);
|
||||||
initLiteralDictionary(&scope->types);
|
Toy_initLiteralDictionary(&scope->types);
|
||||||
|
|
||||||
//tick up all scope reference counts
|
//tick up all scope reference counts
|
||||||
scope->references = 0;
|
scope->references = 0;
|
||||||
for (Scope* ptr = scope; ptr != NULL; ptr = ptr->ancestor) {
|
for (Toy_Scope* ptr = scope; ptr != NULL; ptr = ptr->ancestor) {
|
||||||
ptr->references++;
|
ptr->references++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//copy the contents of the dictionaries
|
//copy the contents of the dictionaries
|
||||||
for (int i = 0; i < original->variables.capacity; i++) {
|
for (int i = 0; i < original->variables.capacity; i++) {
|
||||||
if (!IS_NULL(original->variables.entries[i].key)) {
|
if (!TOY_IS_NULL(original->variables.entries[i].key)) {
|
||||||
setLiteralDictionary(&scope->variables, original->variables.entries[i].key, original->variables.entries[i].value);
|
Toy_setLiteralDictionary(&scope->variables, original->variables.entries[i].key, original->variables.entries[i].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < original->types.capacity; i++) {
|
for (int i = 0; i < original->types.capacity; i++) {
|
||||||
if (!IS_NULL(original->types.entries[i].key)) {
|
if (!TOY_IS_NULL(original->types.entries[i].key)) {
|
||||||
setLiteralDictionary(&scope->types, original->types.entries[i].key, original->types.entries[i].value);
|
Toy_setLiteralDictionary(&scope->types, original->types.entries[i].key, original->types.entries[i].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,92 +233,92 @@ Scope* copyScope(Scope* original) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//returns false if error
|
//returns false if error
|
||||||
bool declareScopeVariable(Scope* scope, Literal key, Literal type) {
|
bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal type) {
|
||||||
//don't redefine a variable within this scope
|
//don't redefine a variable within this scope
|
||||||
if (existsLiteralDictionary(&scope->variables, key)) {
|
if (Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_TYPE(type)) {
|
if (!TOY_IS_TYPE(type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//store the type, for later checking on assignment
|
//store the type, for later checking on assignment
|
||||||
setLiteralDictionary(&scope->types, key, type);
|
Toy_setLiteralDictionary(&scope->types, key, type);
|
||||||
|
|
||||||
setLiteralDictionary(&scope->variables, key, TO_NULL_LITERAL);
|
Toy_setLiteralDictionary(&scope->variables, key, TOY_TO_NULL_LITERAL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDelcaredScopeVariable(Scope* scope, Literal key) {
|
bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key) {
|
||||||
if (scope == NULL) {
|
if (scope == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if it's not in this scope, keep searching up the chain
|
//if it's not in this scope, keep searching up the chain
|
||||||
if (!existsLiteralDictionary(&scope->variables, key)) {
|
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||||
return isDelcaredScopeVariable(scope->ancestor, key);
|
return Toy_isDelcaredScopeVariable(scope->ancestor, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//return false if undefined, or can't be assigned
|
//return false if undefined, or can't be assigned
|
||||||
bool setScopeVariable(Scope* scope, Literal key, Literal value, bool constCheck) {
|
bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck) {
|
||||||
//dead end
|
//dead end
|
||||||
if (scope == NULL) {
|
if (scope == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if it's not in this scope, keep searching up the chain
|
//if it's not in this scope, keep searching up the chain
|
||||||
if (!existsLiteralDictionary(&scope->variables, key)) {
|
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||||
return setScopeVariable(scope->ancestor, key, value, constCheck);
|
return Toy_setScopeVariable(scope->ancestor, key, value, constCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
//type checking
|
//type checking
|
||||||
Literal typeLiteral = getLiteralDictionary(&scope->types, key);
|
Toy_Literal typeLiteral = Toy_getLiteralDictionary(&scope->types, key);
|
||||||
Literal original = getLiteralDictionary(&scope->variables, key);
|
Toy_Literal original = Toy_getLiteralDictionary(&scope->variables, key);
|
||||||
|
|
||||||
if (!checkType(typeLiteral, original, value, constCheck)) {
|
if (!checkType(typeLiteral, original, value, constCheck)) {
|
||||||
freeLiteral(typeLiteral);
|
Toy_freeLiteral(typeLiteral);
|
||||||
freeLiteral(original);
|
Toy_freeLiteral(original);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//actually assign
|
//actually assign
|
||||||
setLiteralDictionary(&scope->variables, key, value);
|
Toy_setLiteralDictionary(&scope->variables, key, value);
|
||||||
|
|
||||||
freeLiteral(typeLiteral);
|
Toy_freeLiteral(typeLiteral);
|
||||||
freeLiteral(original);
|
Toy_freeLiteral(original);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getScopeVariable(Scope* scope, Literal key, Literal* valueHandle) {
|
bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* valueHandle) {
|
||||||
//dead end
|
//dead end
|
||||||
if (scope == NULL) {
|
if (scope == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if it's not in this scope, keep searching up the chain
|
//if it's not in this scope, keep searching up the chain
|
||||||
if (!existsLiteralDictionary(&scope->variables, key)) {
|
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||||
return getScopeVariable(scope->ancestor, key, valueHandle);
|
return Toy_getScopeVariable(scope->ancestor, key, valueHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
*valueHandle = getLiteralDictionary(&scope->variables, key);
|
*valueHandle = Toy_getLiteralDictionary(&scope->variables, key);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal getScopeType(Scope* scope, Literal key) {
|
Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key) {
|
||||||
//dead end
|
//dead end
|
||||||
if (scope == NULL) {
|
if (scope == NULL) {
|
||||||
return TO_NULL_LITERAL;
|
return TOY_TO_NULL_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if it's not in this scope, keep searching up the chain
|
//if it's not in this scope, keep searching up the chain
|
||||||
if (!existsLiteralDictionary(&scope->types, key)) {
|
if (!Toy_existsLiteralDictionary(&scope->types, key)) {
|
||||||
return getScopeType(scope->ancestor, key);
|
return Toy_getScopeType(scope->ancestor, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getLiteralDictionary(&scope->types, key);
|
return Toy_getLiteralDictionary(&scope->types, key);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "literal_array.h"
|
#include "toy_literal_array.h"
|
||||||
#include "literal_dictionary.h"
|
#include "toy_literal_dictionary.h"
|
||||||
|
|
||||||
typedef struct Scope {
|
typedef struct Toy_Scope {
|
||||||
LiteralDictionary variables; //only allow identifiers as the keys
|
Toy_LiteralDictionary variables; //only allow identifiers as the keys
|
||||||
LiteralDictionary types; //the types, indexed by identifiers
|
Toy_LiteralDictionary types; //the types, indexed by identifiers
|
||||||
struct Scope* ancestor;
|
struct Toy_Scope* ancestor;
|
||||||
int references; //how many scopes point here
|
int references; //how many scopes point here
|
||||||
} Scope;
|
} Toy_Scope;
|
||||||
|
|
||||||
Scope* pushScope(Scope* scope);
|
Toy_Scope* Toy_pushScope(Toy_Scope* scope);
|
||||||
Scope* popScope(Scope* scope);
|
Toy_Scope* Toy_popScope(Toy_Scope* scope);
|
||||||
Scope* copyScope(Scope* original);
|
Toy_Scope* Toy_copyScope(Toy_Scope* original);
|
||||||
|
|
||||||
//returns false if error
|
//returns false if error
|
||||||
bool declareScopeVariable(Scope* scope, Literal key, Literal type);
|
bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal type);
|
||||||
bool isDelcaredScopeVariable(Scope* scope, Literal key);
|
bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key);
|
||||||
|
|
||||||
//return false if undefined
|
//return false if undefined
|
||||||
bool setScopeVariable(Scope* scope, Literal key, Literal value, bool constCheck);
|
bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck);
|
||||||
bool getScopeVariable(Scope* scope, Literal key, Literal* value);
|
bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* value);
|
||||||
|
|
||||||
Literal getScopeType(Scope* scope, Literal key);
|
Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key);
|
||||||
|
|||||||
@@ -1,93 +1,93 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
typedef enum TokenType {
|
typedef enum Toy_TokenType {
|
||||||
//types
|
//types
|
||||||
TOKEN_NULL,
|
TOY_TOKEN_NULL,
|
||||||
TOKEN_BOOLEAN,
|
TOY_TOKEN_BOOLEAN,
|
||||||
TOKEN_INTEGER,
|
TOY_TOKEN_INTEGER,
|
||||||
TOKEN_FLOAT,
|
TOY_TOKEN_FLOAT,
|
||||||
TOKEN_STRING,
|
TOY_TOKEN_STRING,
|
||||||
TOKEN_ARRAY,
|
TOY_TOKEN_ARRAY,
|
||||||
TOKEN_DICTIONARY,
|
TOY_TOKEN_DICTIONARY,
|
||||||
TOKEN_FUNCTION,
|
TOY_TOKEN_FUNCTION,
|
||||||
TOKEN_OPAQUE,
|
TOY_TOKEN_OPAQUE,
|
||||||
TOKEN_ANY,
|
TOY_TOKEN_ANY,
|
||||||
|
|
||||||
//keywords and reserved words
|
//keywords and reserved words
|
||||||
TOKEN_AS,
|
TOY_TOKEN_AS,
|
||||||
TOKEN_ASSERT,
|
TOY_TOKEN_ASSERT,
|
||||||
TOKEN_BREAK,
|
TOY_TOKEN_BREAK,
|
||||||
TOKEN_CLASS,
|
TOY_TOKEN_CLASS,
|
||||||
TOKEN_CONST,
|
TOY_TOKEN_CONST,
|
||||||
TOKEN_CONTINUE,
|
TOY_TOKEN_CONTINUE,
|
||||||
TOKEN_DO,
|
TOY_TOKEN_DO,
|
||||||
TOKEN_ELSE,
|
TOY_TOKEN_ELSE,
|
||||||
TOKEN_EXPORT,
|
TOY_TOKEN_EXPORT,
|
||||||
TOKEN_FOR,
|
TOY_TOKEN_FOR,
|
||||||
TOKEN_FOREACH,
|
TOY_TOKEN_FOREACH,
|
||||||
TOKEN_IF,
|
TOY_TOKEN_IF,
|
||||||
TOKEN_IMPORT,
|
TOY_TOKEN_IMPORT,
|
||||||
TOKEN_IN,
|
TOY_TOKEN_IN,
|
||||||
TOKEN_OF,
|
TOY_TOKEN_OF,
|
||||||
TOKEN_PRINT,
|
TOY_TOKEN_PRINT,
|
||||||
TOKEN_RETURN,
|
TOY_TOKEN_RETURN,
|
||||||
TOKEN_TYPE,
|
TOY_TOKEN_TYPE,
|
||||||
TOKEN_ASTYPE,
|
TOY_TOKEN_ASTYPE,
|
||||||
TOKEN_TYPEOF,
|
TOY_TOKEN_TYPEOF,
|
||||||
TOKEN_VAR,
|
TOY_TOKEN_VAR,
|
||||||
TOKEN_WHILE,
|
TOY_TOKEN_WHILE,
|
||||||
|
|
||||||
//literal values
|
//literal values
|
||||||
TOKEN_IDENTIFIER,
|
TOY_TOKEN_IDENTIFIER,
|
||||||
TOKEN_LITERAL_TRUE,
|
TOY_TOKEN_LITERAL_TRUE,
|
||||||
TOKEN_LITERAL_FALSE,
|
TOY_TOKEN_LITERAL_FALSE,
|
||||||
TOKEN_LITERAL_INTEGER,
|
TOY_TOKEN_LITERAL_INTEGER,
|
||||||
TOKEN_LITERAL_FLOAT,
|
TOY_TOKEN_LITERAL_FLOAT,
|
||||||
TOKEN_LITERAL_STRING,
|
TOY_TOKEN_LITERAL_STRING,
|
||||||
|
|
||||||
//math operators
|
//math operators
|
||||||
TOKEN_PLUS,
|
TOY_TOKEN_PLUS,
|
||||||
TOKEN_MINUS,
|
TOY_TOKEN_MINUS,
|
||||||
TOKEN_MULTIPLY,
|
TOY_TOKEN_MULTIPLY,
|
||||||
TOKEN_DIVIDE,
|
TOY_TOKEN_DIVIDE,
|
||||||
TOKEN_MODULO,
|
TOY_TOKEN_MODULO,
|
||||||
TOKEN_PLUS_ASSIGN,
|
TOY_TOKEN_PLUS_ASSIGN,
|
||||||
TOKEN_MINUS_ASSIGN,
|
TOY_TOKEN_MINUS_ASSIGN,
|
||||||
TOKEN_MULTIPLY_ASSIGN,
|
TOY_TOKEN_MULTIPLY_ASSIGN,
|
||||||
TOKEN_DIVIDE_ASSIGN,
|
TOY_TOKEN_DIVIDE_ASSIGN,
|
||||||
TOKEN_MODULO_ASSIGN,
|
TOY_TOKEN_MODULO_ASSIGN,
|
||||||
TOKEN_PLUS_PLUS,
|
TOY_TOKEN_PLUS_PLUS,
|
||||||
TOKEN_MINUS_MINUS,
|
TOY_TOKEN_MINUS_MINUS,
|
||||||
TOKEN_ASSIGN,
|
TOY_TOKEN_ASSIGN,
|
||||||
|
|
||||||
//logical operators
|
//logical operators
|
||||||
TOKEN_PAREN_LEFT,
|
TOY_TOKEN_PAREN_LEFT,
|
||||||
TOKEN_PAREN_RIGHT,
|
TOY_TOKEN_PAREN_RIGHT,
|
||||||
TOKEN_BRACKET_LEFT,
|
TOY_TOKEN_BRACKET_LEFT,
|
||||||
TOKEN_BRACKET_RIGHT,
|
TOY_TOKEN_BRACKET_RIGHT,
|
||||||
TOKEN_BRACE_LEFT,
|
TOY_TOKEN_BRACE_LEFT,
|
||||||
TOKEN_BRACE_RIGHT,
|
TOY_TOKEN_BRACE_RIGHT,
|
||||||
TOKEN_NOT,
|
TOY_TOKEN_NOT,
|
||||||
TOKEN_NOT_EQUAL,
|
TOY_TOKEN_NOT_EQUAL,
|
||||||
TOKEN_EQUAL,
|
TOY_TOKEN_EQUAL,
|
||||||
TOKEN_LESS,
|
TOY_TOKEN_LESS,
|
||||||
TOKEN_GREATER,
|
TOY_TOKEN_GREATER,
|
||||||
TOKEN_LESS_EQUAL,
|
TOY_TOKEN_LESS_EQUAL,
|
||||||
TOKEN_GREATER_EQUAL,
|
TOY_TOKEN_GREATER_EQUAL,
|
||||||
TOKEN_AND,
|
TOY_TOKEN_AND,
|
||||||
TOKEN_OR,
|
TOY_TOKEN_OR,
|
||||||
|
|
||||||
//other operators
|
//other operators
|
||||||
TOKEN_QUESTION,
|
TOY_TOKEN_QUESTION,
|
||||||
TOKEN_COLON,
|
TOY_TOKEN_COLON,
|
||||||
TOKEN_SEMICOLON,
|
TOY_TOKEN_SEMICOLON,
|
||||||
TOKEN_COMMA,
|
TOY_TOKEN_COMMA,
|
||||||
TOKEN_DOT,
|
TOY_TOKEN_DOT,
|
||||||
TOKEN_PIPE,
|
TOY_TOKEN_PIPE,
|
||||||
TOKEN_REST,
|
TOY_TOKEN_REST,
|
||||||
|
|
||||||
//meta tokens
|
//meta tokens
|
||||||
TOKEN_PASS,
|
TOY_TOKEN_PASS,
|
||||||
TOKEN_ERROR,
|
TOY_TOKEN_ERROR,
|
||||||
TOKEN_EOF,
|
TOY_TOKEN_EOF,
|
||||||
} TokenType;
|
} Toy_TokenType;
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#include "ast_node.h"
|
#include "toy_ast_node.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
//lazy
|
//lazy
|
||||||
#define ASSERT(test_for_true) if (!(test_for_true)) {\
|
#define ASSERT(test_for_true) if (!(test_for_true)) {\
|
||||||
fprintf(stderr, ERROR "assert failed: %s\n" RESET, #test_for_true); \
|
fprintf(stderr, TOY_CC_ERROR "assert failed: %s\n" TOY_CC_RESET, #test_for_true); \
|
||||||
exit(-1); \
|
exit(-1); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,61 +17,61 @@ int main() {
|
|||||||
{
|
{
|
||||||
//test literals
|
//test literals
|
||||||
char* str = "foobar";
|
char* str = "foobar";
|
||||||
Literal literal = TO_STRING_LITERAL(createRefString(str));
|
Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefString(str));
|
||||||
|
|
||||||
//generate the node
|
//generate the node
|
||||||
ASTNode* node = NULL;
|
Toy_ASTNode* node = NULL;
|
||||||
emitASTNodeLiteral(&node, literal);
|
Toy_emitASTNodeLiteral(&node, literal);
|
||||||
|
|
||||||
//check node type
|
//check node type
|
||||||
ASSERT(node->type == AST_NODE_LITERAL);
|
ASSERT(node->type == TOY_AST_NODE_LITERAL);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(literal);
|
Toy_freeLiteral(literal);
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
//test unary
|
//test unary
|
||||||
{
|
{
|
||||||
//generate the child node
|
//generate the child node
|
||||||
char* str = "foobar";
|
char* str = "foobar";
|
||||||
Literal literal = TO_STRING_LITERAL(createRefString(str));
|
Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefString(str));
|
||||||
ASTNode* childNode = NULL;
|
Toy_ASTNode* childNode = NULL;
|
||||||
emitASTNodeLiteral(&childNode, literal);
|
Toy_emitASTNodeLiteral(&childNode, literal);
|
||||||
|
|
||||||
//generate the unary node
|
//generate the unary node
|
||||||
ASTNode* unary = NULL;
|
Toy_ASTNode* unary = NULL;
|
||||||
emitASTNodeUnary(&unary, OP_PRINT, childNode);
|
Toy_emitASTNodeUnary(&unary, TOY_OP_PRINT, childNode);
|
||||||
|
|
||||||
//check node type
|
//check node type
|
||||||
ASSERT(unary->type == AST_NODE_UNARY);
|
ASSERT(unary->type == TOY_AST_NODE_UNARY);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(literal);
|
Toy_freeLiteral(literal);
|
||||||
freeASTNode(unary);
|
Toy_freeASTNode(unary);
|
||||||
}
|
}
|
||||||
|
|
||||||
//test binary
|
//test binary
|
||||||
{
|
{
|
||||||
//generate the child node
|
//generate the child node
|
||||||
char* str = "foobar";
|
char* str = "foobar";
|
||||||
Literal literal = TO_STRING_LITERAL(createRefString(str));
|
Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefString(str));
|
||||||
ASTNode* nodeHandle = NULL;
|
Toy_ASTNode* nodeHandle = NULL;
|
||||||
emitASTNodeLiteral(&nodeHandle, literal);
|
Toy_emitASTNodeLiteral(&nodeHandle, literal);
|
||||||
|
|
||||||
ASTNode* rhsChildNode = NULL;
|
Toy_ASTNode* rhsChildNode = NULL;
|
||||||
emitASTNodeLiteral(&rhsChildNode, literal);
|
Toy_emitASTNodeLiteral(&rhsChildNode, literal);
|
||||||
|
|
||||||
//generate the unary node
|
//generate the unary node
|
||||||
emitASTNodeBinary(&nodeHandle, rhsChildNode, OP_PRINT);
|
Toy_emitASTNodeBinary(&nodeHandle, rhsChildNode, TOY_OP_PRINT);
|
||||||
|
|
||||||
//check node type
|
//check node type
|
||||||
ASSERT(nodeHandle->type == AST_NODE_BINARY);
|
ASSERT(nodeHandle->type == TOY_AST_NODE_BINARY);
|
||||||
ASSERT(nodeHandle->binary.opcode == OP_PRINT);
|
ASSERT(nodeHandle->binary.opcode == TOY_OP_PRINT);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeLiteral(literal);
|
Toy_freeLiteral(literal);
|
||||||
freeASTNode(nodeHandle);
|
Toy_freeASTNode(nodeHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: more tests for other AST node types
|
//TODO: more tests for other AST node types
|
||||||
@@ -82,35 +82,35 @@ int main() {
|
|||||||
char* idn = "foobar";
|
char* idn = "foobar";
|
||||||
char* str = "hello world";
|
char* str = "hello world";
|
||||||
|
|
||||||
ASTNode* dictionary;
|
Toy_ASTNode* dictionary;
|
||||||
ASTNode* left;
|
Toy_ASTNode* left;
|
||||||
ASTNode* right;
|
Toy_ASTNode* right;
|
||||||
|
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn));
|
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(idn));
|
||||||
Literal string = TO_STRING_LITERAL(createRefString(str));
|
Toy_Literal string = TOY_TO_STRING_LITERAL(Toy_createRefString(str));
|
||||||
|
|
||||||
emitASTNodeCompound(&dictionary, LITERAL_DICTIONARY);
|
Toy_emitASTNodeCompound(&dictionary, TOY_LITERAL_DICTIONARY);
|
||||||
emitASTNodeLiteral(&left, identifier);
|
Toy_emitASTNodeLiteral(&left, identifier);
|
||||||
emitASTNodeLiteral(&right, string);
|
Toy_emitASTNodeLiteral(&right, string);
|
||||||
|
|
||||||
//grow the node if needed
|
//grow the node if needed
|
||||||
if (dictionary->compound.capacity < dictionary->compound.count + 1) {
|
if (dictionary->compound.capacity < dictionary->compound.count + 1) {
|
||||||
int oldCapacity = dictionary->compound.capacity;
|
int oldCapacity = dictionary->compound.capacity;
|
||||||
|
|
||||||
dictionary->compound.capacity = GROW_CAPACITY(oldCapacity);
|
dictionary->compound.capacity = TOY_GROW_CAPACITY(oldCapacity);
|
||||||
dictionary->compound.nodes = GROW_ARRAY(ASTNode, dictionary->compound.nodes, oldCapacity, dictionary->compound.capacity);
|
dictionary->compound.nodes = TOY_GROW_ARRAY(Toy_ASTNode, dictionary->compound.nodes, oldCapacity, dictionary->compound.capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
//store the left and right in the node
|
//store the left and right in the node
|
||||||
setASTNodePair(&dictionary->compound.nodes[dictionary->compound.count++], left, right);
|
Toy_setASTNodePair(&dictionary->compound.nodes[dictionary->compound.count++], left, right);
|
||||||
|
|
||||||
//the real test
|
//the real test
|
||||||
freeASTNode(dictionary);
|
Toy_freeASTNode(dictionary);
|
||||||
freeLiteral(identifier);
|
Toy_freeLiteral(identifier);
|
||||||
freeLiteral(string);
|
Toy_freeLiteral(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "lexer.h"
|
#include "toy_lexer.h"
|
||||||
#include "parser.h"
|
#include "toy_parser.h"
|
||||||
#include "compiler.h"
|
#include "toy_compiler.h"
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include "../repl/repl_tools.h"
|
#include "../repl/repl_tools.h"
|
||||||
|
|
||||||
@@ -27,28 +27,28 @@ void error(char* msg) {
|
|||||||
int main() {
|
int main() {
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
char* source = readFile("scripts/call-from-host.toy", &size);
|
char* source = Toy_readFile("scripts/call-from-host.toy", &size);
|
||||||
unsigned char* tb = compileString(source, &size);
|
unsigned char* tb = Toy_compileString(source, &size);
|
||||||
free((void*)source);
|
free((void*)source);
|
||||||
|
|
||||||
if (!tb) {
|
if (!tb) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpreter interpreter;
|
Toy_Interpreter interpreter;
|
||||||
initInterpreter(&interpreter);
|
Toy_initInterpreter(&interpreter);
|
||||||
runInterpreter(&interpreter, tb, size);
|
Toy_runInterpreter(&interpreter, tb, size);
|
||||||
|
|
||||||
//test answer
|
//test answer
|
||||||
{
|
{
|
||||||
interpreter.printOutput("Testing answer");
|
interpreter.printOutput("Testing answer");
|
||||||
|
|
||||||
LiteralArray arguments;
|
Toy_LiteralArray arguments;
|
||||||
initLiteralArray(&arguments);
|
Toy_initLiteralArray(&arguments);
|
||||||
LiteralArray returns;
|
Toy_LiteralArray returns;
|
||||||
initLiteralArray(&returns);
|
Toy_initLiteralArray(&returns);
|
||||||
|
|
||||||
callFn(&interpreter, "answer", &arguments, &returns);
|
Toy_callFn(&interpreter, "answer", &arguments, &returns);
|
||||||
|
|
||||||
//check the results
|
//check the results
|
||||||
if (arguments.count != 0) {
|
if (arguments.count != 0) {
|
||||||
@@ -59,29 +59,29 @@ int main() {
|
|||||||
error("Returns has the wrong number of members\n");
|
error("Returns has the wrong number of members\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_INTEGER(returns.literals[0]) || AS_INTEGER(returns.literals[0]) != 42) {
|
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 42) {
|
||||||
error("Returned value is incorrect\n");
|
error("Returned value is incorrect\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
freeLiteralArray(&arguments);
|
Toy_freeLiteralArray(&arguments);
|
||||||
freeLiteralArray(&returns);
|
Toy_freeLiteralArray(&returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
//test identity
|
//test identity
|
||||||
{
|
{
|
||||||
interpreter.printOutput("Testing identity");
|
interpreter.printOutput("Testing identity");
|
||||||
|
|
||||||
LiteralArray arguments;
|
Toy_LiteralArray arguments;
|
||||||
initLiteralArray(&arguments);
|
Toy_initLiteralArray(&arguments);
|
||||||
LiteralArray returns;
|
Toy_LiteralArray returns;
|
||||||
initLiteralArray(&returns);
|
Toy_initLiteralArray(&returns);
|
||||||
|
|
||||||
//push an argument
|
//push an argument
|
||||||
float pi = 3.14;
|
float pi = 3.14;
|
||||||
Literal arg = TO_FLOAT_LITERAL(pi);
|
Toy_Literal arg = TOY_TO_FLOAT_LITERAL(pi);
|
||||||
pushLiteralArray(&arguments, arg);
|
Toy_pushLiteralArray(&arguments, arg);
|
||||||
|
|
||||||
callFn(&interpreter, "identity", &arguments, &returns);
|
Toy_callFn(&interpreter, "identity", &arguments, &returns);
|
||||||
|
|
||||||
//check the results
|
//check the results
|
||||||
if (arguments.count != 0) {
|
if (arguments.count != 0) {
|
||||||
@@ -94,24 +94,24 @@ int main() {
|
|||||||
|
|
||||||
float epsilon = 0.1; //because floats are evil
|
float epsilon = 0.1; //because floats are evil
|
||||||
|
|
||||||
if (!IS_FLOAT(returns.literals[0]) || fabs(AS_FLOAT(returns.literals[0]) - pi) > epsilon) {
|
if (!TOY_IS_FLOAT(returns.literals[0]) || fabs(TOY_AS_FLOAT(returns.literals[0]) - pi) > epsilon) {
|
||||||
error("Returned value is incorrect\n");
|
error("Returned value is incorrect\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
freeLiteralArray(&arguments);
|
Toy_freeLiteralArray(&arguments);
|
||||||
freeLiteralArray(&returns);
|
Toy_freeLiteralArray(&returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
//test makeCounter (closures)
|
//test makeCounter (closures)
|
||||||
{
|
{
|
||||||
interpreter.printOutput("Testing makeCounter (closures)");
|
interpreter.printOutput("Testing makeCounter (closures)");
|
||||||
|
|
||||||
LiteralArray arguments;
|
Toy_LiteralArray arguments;
|
||||||
initLiteralArray(&arguments);
|
Toy_initLiteralArray(&arguments);
|
||||||
LiteralArray returns;
|
Toy_LiteralArray returns;
|
||||||
initLiteralArray(&returns);
|
Toy_initLiteralArray(&returns);
|
||||||
|
|
||||||
callFn(&interpreter, "makeCounter", &arguments, &returns);
|
Toy_callFn(&interpreter, "makeCounter", &arguments, &returns);
|
||||||
|
|
||||||
//check the results
|
//check the results
|
||||||
if (arguments.count != 0) {
|
if (arguments.count != 0) {
|
||||||
@@ -123,19 +123,19 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//grab the resulting literal
|
//grab the resulting literal
|
||||||
Literal counter = popLiteralArray(&returns);
|
Toy_Literal counter = Toy_popLiteralArray(&returns);
|
||||||
|
|
||||||
freeLiteralArray(&arguments);
|
Toy_freeLiteralArray(&arguments);
|
||||||
freeLiteralArray(&returns);
|
Toy_freeLiteralArray(&returns);
|
||||||
|
|
||||||
//call counter repeatedly
|
//call counter repeatedly
|
||||||
{
|
{
|
||||||
LiteralArray arguments;
|
Toy_LiteralArray arguments;
|
||||||
initLiteralArray(&arguments);
|
Toy_initLiteralArray(&arguments);
|
||||||
LiteralArray returns;
|
Toy_LiteralArray returns;
|
||||||
initLiteralArray(&returns);
|
Toy_initLiteralArray(&returns);
|
||||||
|
|
||||||
callLiteralFn(&interpreter, counter, &arguments, &returns);
|
Toy_callLiteralFn(&interpreter, counter, &arguments, &returns);
|
||||||
|
|
||||||
//check the results
|
//check the results
|
||||||
if (arguments.count != 0) {
|
if (arguments.count != 0) {
|
||||||
@@ -146,21 +146,21 @@ int main() {
|
|||||||
error("Returns (1) has the wrong number of members\n");
|
error("Returns (1) has the wrong number of members\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_INTEGER(returns.literals[0]) || AS_INTEGER(returns.literals[0]) != 1) {
|
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 1) {
|
||||||
error("Returned value (1) is incorrect\n");
|
error("Returned value (1) is incorrect\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
freeLiteralArray(&arguments);
|
Toy_freeLiteralArray(&arguments);
|
||||||
freeLiteralArray(&returns);
|
Toy_freeLiteralArray(&returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
LiteralArray arguments;
|
Toy_LiteralArray arguments;
|
||||||
initLiteralArray(&arguments);
|
Toy_initLiteralArray(&arguments);
|
||||||
LiteralArray returns;
|
Toy_LiteralArray returns;
|
||||||
initLiteralArray(&returns);
|
Toy_initLiteralArray(&returns);
|
||||||
|
|
||||||
callLiteralFn(&interpreter, counter, &arguments, &returns);
|
Toy_callLiteralFn(&interpreter, counter, &arguments, &returns);
|
||||||
|
|
||||||
//check the results
|
//check the results
|
||||||
if (arguments.count != 0) {
|
if (arguments.count != 0) {
|
||||||
@@ -171,21 +171,21 @@ int main() {
|
|||||||
error("Returns (2) has the wrong number of members\n");
|
error("Returns (2) has the wrong number of members\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_INTEGER(returns.literals[0]) || AS_INTEGER(returns.literals[0]) != 2) {
|
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 2) {
|
||||||
error("Returned value (2) is incorrect\n");
|
error("Returned value (2) is incorrect\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
freeLiteralArray(&arguments);
|
Toy_freeLiteralArray(&arguments);
|
||||||
freeLiteralArray(&returns);
|
Toy_freeLiteralArray(&returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
LiteralArray arguments;
|
Toy_LiteralArray arguments;
|
||||||
initLiteralArray(&arguments);
|
Toy_initLiteralArray(&arguments);
|
||||||
LiteralArray returns;
|
Toy_LiteralArray returns;
|
||||||
initLiteralArray(&returns);
|
Toy_initLiteralArray(&returns);
|
||||||
|
|
||||||
callLiteralFn(&interpreter, counter, &arguments, &returns);
|
Toy_callLiteralFn(&interpreter, counter, &arguments, &returns);
|
||||||
|
|
||||||
//check the results
|
//check the results
|
||||||
if (arguments.count != 0) {
|
if (arguments.count != 0) {
|
||||||
@@ -196,36 +196,36 @@ int main() {
|
|||||||
error("Returns (3) has the wrong number of members\n");
|
error("Returns (3) has the wrong number of members\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IS_INTEGER(returns.literals[0]) || AS_INTEGER(returns.literals[0]) != 3) {
|
if (!TOY_IS_INTEGER(returns.literals[0]) || TOY_AS_INTEGER(returns.literals[0]) != 3) {
|
||||||
error("Returned value (3) is incorrect\n");
|
error("Returned value (3) is incorrect\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
freeLiteralArray(&arguments);
|
Toy_freeLiteralArray(&arguments);
|
||||||
freeLiteralArray(&returns);
|
Toy_freeLiteralArray(&returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
freeLiteral(counter);
|
Toy_freeLiteral(counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
//test assertion failure
|
//test assertion failure
|
||||||
{
|
{
|
||||||
interpreter.printOutput("Testing assertion failure");
|
interpreter.printOutput("Testing assertion failure");
|
||||||
|
|
||||||
setInterpreterAssert(&interpreter, noPrintFn);
|
Toy_setInterpreterAssert(&interpreter, noPrintFn);
|
||||||
|
|
||||||
LiteralArray arguments;
|
Toy_LiteralArray arguments;
|
||||||
initLiteralArray(&arguments);
|
Toy_initLiteralArray(&arguments);
|
||||||
LiteralArray returns;
|
Toy_LiteralArray returns;
|
||||||
initLiteralArray(&returns);
|
Toy_initLiteralArray(&returns);
|
||||||
|
|
||||||
bool ret = callFn(&interpreter, "fail", &arguments, &returns);
|
bool ret = Toy_callFn(&interpreter, "fail", &arguments, &returns);
|
||||||
|
|
||||||
//check the results
|
//check the results
|
||||||
if (arguments.count != 0) {
|
if (arguments.count != 0) {
|
||||||
error("Arguments has the wrong number of members\n");
|
error("Arguments has the wrong number of members\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (returns.count != 1 || !IS_NULL(returns.literals[0])) {
|
if (returns.count != 1 || !TOY_IS_NULL(returns.literals[0])) {
|
||||||
error("Returns has the wrong number of members\n");
|
error("Returns has the wrong number of members\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,15 +233,15 @@ int main() {
|
|||||||
error("Assertion gives the wrong return value\n");
|
error("Assertion gives the wrong return value\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
freeLiteralArray(&arguments);
|
Toy_freeLiteralArray(&arguments);
|
||||||
freeLiteralArray(&returns);
|
Toy_freeLiteralArray(&returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
//clean up
|
//clean up
|
||||||
freeInterpreter(&interpreter);
|
Toy_freeInterpreter(&interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#include "lexer.h"
|
#include "toy_lexer.h"
|
||||||
#include "parser.h"
|
#include "toy_parser.h"
|
||||||
#include "compiler.h"
|
#include "toy_compiler.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include "../repl/repl_tools.h"
|
#include "../repl/repl_tools.h"
|
||||||
|
|
||||||
@@ -15,9 +15,9 @@
|
|||||||
int main() {
|
int main() {
|
||||||
{
|
{
|
||||||
//test init & free
|
//test init & free
|
||||||
Compiler compiler;
|
Toy_Compiler compiler;
|
||||||
initCompiler(&compiler);
|
Toy_initCompiler(&compiler);
|
||||||
freeCompiler(&compiler);
|
Toy_freeCompiler(&compiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -25,70 +25,70 @@ int main() {
|
|||||||
char* source = "print null;";
|
char* source = "print null;";
|
||||||
|
|
||||||
//test basic compilation & collation
|
//test basic compilation & collation
|
||||||
Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
Parser parser;
|
Toy_Parser parser;
|
||||||
Compiler compiler;
|
Toy_Compiler compiler;
|
||||||
|
|
||||||
initLexer(&lexer, source);
|
Toy_initLexer(&lexer, source);
|
||||||
initParser(&parser, &lexer);
|
Toy_initParser(&parser, &lexer);
|
||||||
initCompiler(&compiler);
|
Toy_initCompiler(&compiler);
|
||||||
|
|
||||||
ASTNode* node = scanParser(&parser);
|
Toy_ASTNode* node = Toy_scanParser(&parser);
|
||||||
|
|
||||||
//write
|
//write
|
||||||
writeCompiler(&compiler, node);
|
Toy_writeCompiler(&compiler, node);
|
||||||
|
|
||||||
//collate
|
//collate
|
||||||
int size = 0;
|
int size = 0;
|
||||||
unsigned char* bytecode = collateCompiler(&compiler, &size);
|
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
FREE_ARRAY(unsigned char, bytecode, size);
|
TOY_FREE_ARRAY(unsigned char, bytecode, size);
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
freeParser(&parser);
|
Toy_freeParser(&parser);
|
||||||
freeCompiler(&compiler);
|
Toy_freeCompiler(&compiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//source
|
//source
|
||||||
size_t sourceLength = 0;
|
size_t sourceLength = 0;
|
||||||
char* source = readFile("scripts/compiler_sample_code.toy", &sourceLength);
|
char* source = Toy_readFile("scripts/compiler_sample_code.toy", &sourceLength);
|
||||||
|
|
||||||
//test basic compilation & collation
|
//test basic compilation & collation
|
||||||
Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
Parser parser;
|
Toy_Parser parser;
|
||||||
Compiler compiler;
|
Toy_Compiler compiler;
|
||||||
|
|
||||||
initLexer(&lexer, source);
|
Toy_initLexer(&lexer, source);
|
||||||
initParser(&parser, &lexer);
|
Toy_initParser(&parser, &lexer);
|
||||||
initCompiler(&compiler);
|
Toy_initCompiler(&compiler);
|
||||||
|
|
||||||
ASTNode* node = scanParser(&parser);
|
Toy_ASTNode* node = Toy_scanParser(&parser);
|
||||||
while (node != NULL) {
|
while (node != NULL) {
|
||||||
if (node->type == AST_NODE_ERROR) {
|
if (node->type == TOY_AST_NODE_ERROR) {
|
||||||
fprintf(stderr, ERROR "ERROR: Error node found" RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Error node found" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//write
|
//write
|
||||||
writeCompiler(&compiler, node);
|
Toy_writeCompiler(&compiler, node);
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
|
|
||||||
node = scanParser(&parser);
|
node = Toy_scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
//collate
|
//collate
|
||||||
int size = 0;
|
int size = 0;
|
||||||
unsigned char* bytecode = collateCompiler(&compiler, &size);
|
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
FREE_ARRAY(char, source, sourceLength);
|
TOY_FREE_ARRAY(char, source, sourceLength);
|
||||||
FREE_ARRAY(unsigned char, bytecode, size);
|
TOY_FREE_ARRAY(unsigned char, bytecode, size);
|
||||||
freeParser(&parser);
|
Toy_freeParser(&parser);
|
||||||
freeCompiler(&compiler);
|
Toy_freeCompiler(&compiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "lexer.h"
|
#include "toy_lexer.h"
|
||||||
#include "parser.h"
|
#include "toy_parser.h"
|
||||||
#include "compiler.h"
|
#include "toy_compiler.h"
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include "../repl/repl_tools.h"
|
#include "../repl/repl_tools.h"
|
||||||
|
|
||||||
@@ -24,27 +24,27 @@ static void noAssertFn(const char* output) {
|
|||||||
ignoredAssertions++;
|
ignoredAssertions++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, ERROR "Assertion failure: ");
|
fprintf(stderr, TOY_CC_ERROR "Assertion failure: ");
|
||||||
fprintf(stderr, "%s", output);
|
fprintf(stderr, "%s", output);
|
||||||
fprintf(stderr, "\n" RESET); //default new line
|
fprintf(stderr, "\n" TOY_CC_RESET); //default new line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void runBinaryCustom(unsigned char* tb, size_t size) {
|
void runBinaryCustom(unsigned char* tb, size_t size) {
|
||||||
Interpreter interpreter;
|
Toy_Interpreter interpreter;
|
||||||
initInterpreter(&interpreter);
|
Toy_initInterpreter(&interpreter);
|
||||||
|
|
||||||
//NOTE: suppress print output for testing
|
//NOTE: suppress print output for testing
|
||||||
setInterpreterPrint(&interpreter, noPrintFn);
|
Toy_setInterpreterPrint(&interpreter, noPrintFn);
|
||||||
setInterpreterAssert(&interpreter, noAssertFn);
|
Toy_setInterpreterAssert(&interpreter, noAssertFn);
|
||||||
|
|
||||||
runInterpreter(&interpreter, tb, size);
|
Toy_runInterpreter(&interpreter, tb, size);
|
||||||
freeInterpreter(&interpreter);
|
Toy_freeInterpreter(&interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void runSourceCustom(char* source) {
|
void runSourceCustom(char* source) {
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
unsigned char* tb = compileString(source, &size);
|
unsigned char* tb = Toy_compileString(source, &size);
|
||||||
if (!tb) {
|
if (!tb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ void runSourceCustom(char* source) {
|
|||||||
|
|
||||||
void runSourceFileCustom(char* fname) {
|
void runSourceFileCustom(char* fname) {
|
||||||
size_t size = 0; //not used
|
size_t size = 0; //not used
|
||||||
char* source = readFile(fname, &size);
|
char* source = Toy_readFile(fname, &size);
|
||||||
runSourceCustom(source);
|
runSourceCustom(source);
|
||||||
free((void*)source);
|
free((void*)source);
|
||||||
}
|
}
|
||||||
@@ -61,9 +61,9 @@ void runSourceFileCustom(char* fname) {
|
|||||||
int main() {
|
int main() {
|
||||||
{
|
{
|
||||||
//test init & free
|
//test init & free
|
||||||
Interpreter interpreter;
|
Toy_Interpreter interpreter;
|
||||||
initInterpreter(&interpreter);
|
Toy_initInterpreter(&interpreter);
|
||||||
freeInterpreter(&interpreter);
|
Toy_freeInterpreter(&interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -71,37 +71,37 @@ int main() {
|
|||||||
char* source = "print null;";
|
char* source = "print null;";
|
||||||
|
|
||||||
//test basic compilation & collation
|
//test basic compilation & collation
|
||||||
Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
Parser parser;
|
Toy_Parser parser;
|
||||||
Compiler compiler;
|
Toy_Compiler compiler;
|
||||||
Interpreter interpreter;
|
Toy_Interpreter interpreter;
|
||||||
|
|
||||||
initLexer(&lexer, source);
|
Toy_initLexer(&lexer, source);
|
||||||
initParser(&parser, &lexer);
|
Toy_initParser(&parser, &lexer);
|
||||||
initCompiler(&compiler);
|
Toy_initCompiler(&compiler);
|
||||||
initInterpreter(&interpreter);
|
Toy_initInterpreter(&interpreter);
|
||||||
|
|
||||||
ASTNode* node = scanParser(&parser);
|
Toy_ASTNode* node = Toy_scanParser(&parser);
|
||||||
|
|
||||||
//write
|
//write
|
||||||
writeCompiler(&compiler, node);
|
Toy_writeCompiler(&compiler, node);
|
||||||
|
|
||||||
//collate
|
//collate
|
||||||
int size = 0;
|
int size = 0;
|
||||||
unsigned char* bytecode = collateCompiler(&compiler, &size);
|
unsigned char* bytecode = Toy_collateCompiler(&compiler, &size);
|
||||||
|
|
||||||
//NOTE: suppress print output for testing
|
//NOTE: suppress print output for testing
|
||||||
setInterpreterPrint(&interpreter, noPrintFn);
|
Toy_setInterpreterPrint(&interpreter, noPrintFn);
|
||||||
setInterpreterAssert(&interpreter, noAssertFn);
|
Toy_setInterpreterAssert(&interpreter, noAssertFn);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
runInterpreter(&interpreter, bytecode, size);
|
Toy_runInterpreter(&interpreter, bytecode, size);
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
freeParser(&parser);
|
Toy_freeParser(&parser);
|
||||||
freeCompiler(&compiler);
|
Toy_freeCompiler(&compiler);
|
||||||
freeInterpreter(&interpreter);
|
Toy_freeInterpreter(&interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -144,11 +144,11 @@ int main() {
|
|||||||
|
|
||||||
//1, to allow for the assertion test
|
//1, to allow for the assertion test
|
||||||
if (ignoredAssertions > 1) {
|
if (ignoredAssertions > 1) {
|
||||||
fprintf(stderr, ERROR "Assertions hidden: %d\n", ignoredAssertions);
|
fprintf(stderr, TOY_CC_ERROR "Assertions hidden: %d\n", ignoredAssertions);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "lexer.h"
|
#include "toy_lexer.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -11,39 +11,39 @@ int main() {
|
|||||||
char* source = "print null;";
|
char* source = "print null;";
|
||||||
|
|
||||||
//test init & quit
|
//test init & quit
|
||||||
Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
initLexer(&lexer, source);
|
Toy_initLexer(&lexer, source);
|
||||||
|
|
||||||
//get each token
|
//get each token
|
||||||
Token print = scanLexer(&lexer);
|
Toy_Token print = Toy_scanLexer(&lexer);
|
||||||
Token null = scanLexer(&lexer);
|
Toy_Token null = Toy_scanLexer(&lexer);
|
||||||
Token semi = scanLexer(&lexer);
|
Toy_Token semi = Toy_scanLexer(&lexer);
|
||||||
Token eof = scanLexer(&lexer);
|
Toy_Token eof = Toy_scanLexer(&lexer);
|
||||||
|
|
||||||
//test each token is correct
|
//test each token is correct
|
||||||
if (strncmp(print.lexeme, "print", print.length)) {
|
if (strncmp(print.lexeme, "print", print.length)) {
|
||||||
fprintf(stderr, ERROR "ERROR: print lexeme is wrong: %s" RESET, print.lexeme);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: print lexeme is wrong: %s" TOY_CC_RESET, print.lexeme);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (strncmp(null.lexeme, "null", null.length)) {
|
if (strncmp(null.lexeme, "null", null.length)) {
|
||||||
fprintf(stderr, ERROR "ERROR: null lexeme is wrong: %s" RESET, null.lexeme);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: null lexeme is wrong: %s" TOY_CC_RESET, null.lexeme);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(semi.lexeme, ";", semi.length)) {
|
if (strncmp(semi.lexeme, ";", semi.length)) {
|
||||||
fprintf(stderr, ERROR "ERROR: semicolon lexeme is wrong: %s" RESET, semi.lexeme);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: semicolon lexeme is wrong: %s" TOY_CC_RESET, semi.lexeme);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eof.type != TOKEN_EOF) {
|
if (eof.type != TOY_TOKEN_EOF) {
|
||||||
fprintf(stderr, ERROR "ERROR: Failed to find EOF token" RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to find EOF token" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "lexer.h"
|
#include "toy_lexer.h"
|
||||||
#include "parser.h"
|
#include "toy_parser.h"
|
||||||
#include "compiler.h"
|
#include "toy_compiler.h"
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -25,57 +25,57 @@ static void noPrintFn(const char* output) {
|
|||||||
static int failedAsserts = 0;
|
static int failedAsserts = 0;
|
||||||
static void assertWrapper(const char* output) {
|
static void assertWrapper(const char* output) {
|
||||||
failedAsserts++;
|
failedAsserts++;
|
||||||
fprintf(stderr, ERROR "Assertion failure: ");
|
fprintf(stderr, TOY_CC_ERROR "Assertion failure: ");
|
||||||
fprintf(stderr, "%s", output);
|
fprintf(stderr, "%s", output);
|
||||||
fprintf(stderr, "\n" RESET); //default new line
|
fprintf(stderr, "\n" TOY_CC_RESET); //default new line
|
||||||
}
|
}
|
||||||
|
|
||||||
static void errorWrapper(const char* output) {
|
static void errorWrapper(const char* output) {
|
||||||
failedAsserts++;
|
failedAsserts++;
|
||||||
fprintf(stderr, ERROR "%s" RESET, output);
|
fprintf(stderr, TOY_CC_ERROR "%s" TOY_CC_RESET, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void runBinaryWithLibrary(unsigned char* tb, size_t size, char* library, HookFn hook) {
|
void runBinaryWithLibrary(unsigned char* tb, size_t size, char* library, Toy_HookFn hook) {
|
||||||
Interpreter interpreter;
|
Toy_Interpreter interpreter;
|
||||||
initInterpreter(&interpreter);
|
Toy_initInterpreter(&interpreter);
|
||||||
|
|
||||||
//NOTE: supress print output for testing
|
//NOTE: supress print output for testing
|
||||||
setInterpreterPrint(&interpreter, noPrintFn);
|
Toy_setInterpreterPrint(&interpreter, noPrintFn);
|
||||||
setInterpreterAssert(&interpreter, assertWrapper);
|
Toy_setInterpreterAssert(&interpreter, assertWrapper);
|
||||||
setInterpreterError(&interpreter, errorWrapper);
|
Toy_setInterpreterError(&interpreter, errorWrapper);
|
||||||
|
|
||||||
//inject the standard libraries into this interpreter
|
//inject the standard libraries into this interpreter
|
||||||
injectNativeHook(&interpreter, library, hook);
|
Toy_injectNativeHook(&interpreter, library, hook);
|
||||||
|
|
||||||
runInterpreter(&interpreter, tb, size);
|
Toy_runInterpreter(&interpreter, tb, size);
|
||||||
freeInterpreter(&interpreter);
|
Toy_freeInterpreter(&interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct Payload {
|
typedef struct Payload {
|
||||||
char* fname;
|
char* fname;
|
||||||
char* libname;
|
char* libname;
|
||||||
HookFn hook;
|
Toy_HookFn hook;
|
||||||
} Payload;
|
} Payload;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
//setup the runner filesystem (hacky)
|
//setup the runner filesystem (hacky)
|
||||||
initDriveDictionary();
|
Toy_initDriveDictionary();
|
||||||
|
|
||||||
Literal driveLiteral = TO_STRING_LITERAL(createRefString("scripts"));
|
Toy_Literal driveLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
|
||||||
Literal pathLiteral = TO_STRING_LITERAL(createRefString("scripts"));
|
Toy_Literal pathLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString("scripts"));
|
||||||
|
|
||||||
setLiteralDictionary(getDriveDictionary(), driveLiteral, pathLiteral);
|
Toy_setLiteralDictionary(Toy_getDriveDictionary(), driveLiteral, pathLiteral);
|
||||||
|
|
||||||
freeLiteral(driveLiteral);
|
Toy_freeLiteral(driveLiteral);
|
||||||
freeLiteral(pathLiteral);
|
Toy_freeLiteral(pathLiteral);
|
||||||
|
|
||||||
{
|
{
|
||||||
//run each file in test/scripts
|
//run each file in test/scripts
|
||||||
Payload payloads[] = {
|
Payload payloads[] = {
|
||||||
{"interactions.toy", "standard", hookStandard}, //interactions needs standard
|
{"interactions.toy", "standard", Toy_hookStandard}, //interactions needs standard
|
||||||
{"standard.toy", "standard", hookStandard},
|
{"standard.toy", "standard", Toy_hookStandard},
|
||||||
{"timer.toy", "timer", hookTimer},
|
{"timer.toy", "timer", Toy_hookTimer},
|
||||||
{"runner.toy", "runner", hookRunner},
|
{"runner.toy", "runner", Toy_hookRunner},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -87,18 +87,18 @@ int main() {
|
|||||||
|
|
||||||
//compile the source
|
//compile the source
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
char* source = readFile(fname, &size);
|
char* source = Toy_readFile(fname, &size);
|
||||||
if (!source) {
|
if (!source) {
|
||||||
printf(ERROR "Failed to load file: %s\n" RESET, fname);
|
printf(TOY_CC_ERROR "Failed to load file: %s\n" TOY_CC_RESET, fname);
|
||||||
failedAsserts++;
|
failedAsserts++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* tb = compileString(source, &size);
|
unsigned char* tb = Toy_compileString(source, &size);
|
||||||
free((void*)source);
|
free((void*)source);
|
||||||
|
|
||||||
if (!tb) {
|
if (!tb) {
|
||||||
printf(ERROR "Failed to compile file: %s\n" RESET, fname);
|
printf(TOY_CC_ERROR "Failed to compile file: %s\n" TOY_CC_RESET, fname);
|
||||||
failedAsserts++;
|
failedAsserts++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -108,13 +108,13 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//lib cleanup
|
//lib cleanup
|
||||||
freeDriveDictionary();
|
Toy_freeDriveDictionary();
|
||||||
|
|
||||||
if (!failedAsserts) {
|
if (!failedAsserts) {
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf(WARN "Problems detected in libraries\n" RESET);
|
printf(TOY_CC_WARN "Problems detected in libraries\n" TOY_CC_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
return failedAsserts;
|
return failedAsserts;
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
#include "literal.h"
|
#include "toy_literal.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
{
|
{
|
||||||
//test a single null literal
|
//test a single null literal
|
||||||
Literal literal = TO_NULL_LITERAL;
|
Toy_Literal literal = TOY_TO_NULL_LITERAL;
|
||||||
|
|
||||||
if (!IS_NULL(literal)) {
|
if (!TOY_IS_NULL(literal)) {
|
||||||
fprintf(stderr, ERROR "ERROR: null literal failed\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: null literal failed\n" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//test boolean literals
|
//test boolean literals
|
||||||
Literal t = TO_BOOLEAN_LITERAL(true);
|
Toy_Literal t = TOY_TO_BOOLEAN_LITERAL(true);
|
||||||
Literal f = TO_BOOLEAN_LITERAL(false);
|
Toy_Literal f = TOY_TO_BOOLEAN_LITERAL(false);
|
||||||
|
|
||||||
if (!IS_TRUTHY(t) || IS_TRUTHY(f)) {
|
if (!TOY_IS_TRUTHY(t) || TOY_IS_TRUTHY(f)) {
|
||||||
fprintf(stderr, ERROR "ERROR: boolean literal failed\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: boolean literal failed\n" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,20 +31,20 @@ int main() {
|
|||||||
//test string literals
|
//test string literals
|
||||||
char* buffer = "Hello world";
|
char* buffer = "Hello world";
|
||||||
|
|
||||||
Literal literal = TO_STRING_LITERAL(createRefString(buffer));
|
Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer));
|
||||||
|
|
||||||
freeLiteral(literal);
|
Toy_freeLiteral(literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//test identifier literals
|
//test identifier literals
|
||||||
char buffer[] = "Hello world";
|
char buffer[] = "Hello world";
|
||||||
|
|
||||||
Literal literal = TO_IDENTIFIER_LITERAL(createRefString(buffer));
|
Toy_Literal literal = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(buffer));
|
||||||
|
|
||||||
freeLiteral(literal);
|
Toy_freeLiteral(literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,72 +1,72 @@
|
|||||||
#include "literal_array.h"
|
#include "toy_literal_array.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
{
|
{
|
||||||
//test init & cleanup
|
//test init & cleanup
|
||||||
LiteralArray array;
|
Toy_LiteralArray array;
|
||||||
initLiteralArray(&array);
|
Toy_initLiteralArray(&array);
|
||||||
freeLiteralArray(&array);
|
Toy_freeLiteralArray(&array);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//test pushing and pulling
|
//test pushing and pulling
|
||||||
LiteralArray array;
|
Toy_LiteralArray array;
|
||||||
initLiteralArray(&array);
|
Toy_initLiteralArray(&array);
|
||||||
|
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
pushLiteralArray(&array, TO_INTEGER_LITERAL(i));
|
Toy_pushLiteralArray(&array, TOY_TO_INTEGER_LITERAL(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 90; i++) {
|
for (int i = 0; i < 90; i++) {
|
||||||
Literal lit = popLiteralArray(&array);
|
Toy_Literal lit = Toy_popLiteralArray(&array);
|
||||||
|
|
||||||
freeLiteral(lit);
|
Toy_freeLiteral(lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array.count != 10) {
|
if (array.count != 10) {
|
||||||
fprintf(stderr, ERROR "ERROR: Array didn't clear the correct number of literal integers\n" RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Array didn't clear the correct number of literal integers\n" TOY_CC_RESET);
|
||||||
freeLiteralArray(&array);
|
Toy_freeLiteralArray(&array);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeLiteralArray(&array);
|
Toy_freeLiteralArray(&array);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//check string, identifier and compound type behaviours
|
//check string, identifier and compound type behaviours
|
||||||
LiteralArray array;
|
Toy_LiteralArray array;
|
||||||
initLiteralArray(&array);
|
Toy_initLiteralArray(&array);
|
||||||
|
|
||||||
//raw
|
//raw
|
||||||
char* str_raw = "hello world";
|
char* str_raw = "hello world";
|
||||||
char* idn_raw = "foobar";
|
char* idn_raw = "foobar";
|
||||||
|
|
||||||
Literal string = TO_STRING_LITERAL(createRefString(str_raw));
|
Toy_Literal string = TOY_TO_STRING_LITERAL(Toy_createRefString(str_raw));
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw));
|
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(idn_raw));
|
||||||
|
|
||||||
//[string : string]
|
//[string : string]
|
||||||
Literal type = TO_TYPE_LITERAL(LITERAL_DICTIONARY, false);
|
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, false);
|
||||||
TYPE_PUSH_SUBTYPE(&type, TO_TYPE_LITERAL(LITERAL_STRING, false));
|
TOY_TYPE_PUSH_SUBTYPE(&type, TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, false));
|
||||||
TYPE_PUSH_SUBTYPE(&type, TO_TYPE_LITERAL(LITERAL_STRING, false));
|
TOY_TYPE_PUSH_SUBTYPE(&type, TOY_TO_TYPE_LITERAL(TOY_LITERAL_STRING, false));
|
||||||
|
|
||||||
//push
|
//push
|
||||||
pushLiteralArray(&array, string);
|
Toy_pushLiteralArray(&array, string);
|
||||||
pushLiteralArray(&array, identifier);
|
Toy_pushLiteralArray(&array, identifier);
|
||||||
pushLiteralArray(&array, type);
|
Toy_pushLiteralArray(&array, type);
|
||||||
|
|
||||||
//free the local literals
|
//free the local literals
|
||||||
freeLiteral(string);
|
Toy_freeLiteral(string);
|
||||||
freeLiteral(identifier);
|
Toy_freeLiteral(identifier);
|
||||||
freeLiteral(type);
|
Toy_freeLiteral(type);
|
||||||
|
|
||||||
freeLiteralArray(&array);
|
Toy_freeLiteralArray(&array);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
#include "literal_dictionary.h"
|
#include "toy_literal_dictionary.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
{
|
{
|
||||||
//test init & cleanup
|
//test init & cleanup
|
||||||
LiteralDictionary dictionary;
|
Toy_LiteralDictionary dictionary;
|
||||||
initLiteralDictionary(&dictionary);
|
Toy_initLiteralDictionary(&dictionary);
|
||||||
freeLiteralDictionary(&dictionary);
|
Toy_freeLiteralDictionary(&dictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -18,21 +18,21 @@ int main() {
|
|||||||
char* idn_raw = "foobar";
|
char* idn_raw = "foobar";
|
||||||
char* str_raw = "hello world";
|
char* str_raw = "hello world";
|
||||||
|
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw));
|
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(idn_raw));
|
||||||
Literal string = TO_STRING_LITERAL(createRefString(str_raw));
|
Toy_Literal string = TOY_TO_STRING_LITERAL(Toy_createRefString(str_raw));
|
||||||
|
|
||||||
LiteralDictionary dictionary;
|
Toy_LiteralDictionary dictionary;
|
||||||
initLiteralDictionary(&dictionary);
|
Toy_initLiteralDictionary(&dictionary);
|
||||||
|
|
||||||
setLiteralDictionary(&dictionary, identifier, string);
|
Toy_setLiteralDictionary(&dictionary, identifier, string);
|
||||||
|
|
||||||
freeLiteral(identifier);
|
Toy_freeLiteral(identifier);
|
||||||
freeLiteral(string);
|
Toy_freeLiteral(string);
|
||||||
|
|
||||||
freeLiteralDictionary(&dictionary);
|
Toy_freeLiteralDictionary(&dictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -32,29 +32,29 @@ void* allocator(void* pointer, size_t oldSize, size_t newSize) {
|
|||||||
void testMemoryAllocation() {
|
void testMemoryAllocation() {
|
||||||
{
|
{
|
||||||
//test single pointer
|
//test single pointer
|
||||||
int* integer = ALLOCATE(int, 1);
|
int* integer = TOY_ALLOCATE(int, 1);
|
||||||
FREE(int, integer);
|
TOY_FREE(int, integer);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//test single pointer array
|
//test single pointer array
|
||||||
int* array = ALLOCATE(int, 10);
|
int* array = TOY_ALLOCATE(int, 10);
|
||||||
|
|
||||||
array[1] = 42; //access the given memory
|
array[1] = 42; //access the given memory
|
||||||
|
|
||||||
FREE_ARRAY(int, array, 10);
|
TOY_FREE_ARRAY(int, array, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//test multiple pointer arrays
|
//test multiple pointer arrays
|
||||||
int* array1 = ALLOCATE(int, 10);
|
int* array1 = TOY_ALLOCATE(int, 10);
|
||||||
int* array2 = ALLOCATE(int, 10);
|
int* array2 = TOY_ALLOCATE(int, 10);
|
||||||
|
|
||||||
array1[1] = 42; //access the given memory
|
array1[1] = 42; //access the given memory
|
||||||
array2[1] = 42; //access the given memory
|
array2[1] = 42; //access the given memory
|
||||||
|
|
||||||
FREE_ARRAY(int, array1, 10);
|
TOY_FREE_ARRAY(int, array1, 10);
|
||||||
FREE_ARRAY(int, array2, 10);
|
TOY_FREE_ARRAY(int, array2, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,14 +63,14 @@ int main() {
|
|||||||
testMemoryAllocation();
|
testMemoryAllocation();
|
||||||
|
|
||||||
//test the custom allocator
|
//test the custom allocator
|
||||||
setMemoryAllocator(allocator);
|
Toy_setMemoryAllocator(allocator);
|
||||||
testMemoryAllocation();
|
testMemoryAllocation();
|
||||||
|
|
||||||
if (callCount != 8) {
|
if (callCount != 8) {
|
||||||
fprintf(stderr, ERROR "Unexpected call count for custom allocator; was called %d times" RESET, callCount);
|
fprintf(stderr, TOY_CC_ERROR "Unexpected call count for custom allocator; was called %d times" TOY_CC_RESET, callCount);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "lexer.h"
|
#include "toy_lexer.h"
|
||||||
#include "parser.h"
|
#include "toy_parser.h"
|
||||||
#include "compiler.h"
|
#include "toy_compiler.h"
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include "../repl/repl_tools.h"
|
#include "../repl/repl_tools.h"
|
||||||
|
|
||||||
@@ -24,37 +24,37 @@ static void noErrorFn(const char* output) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* compileStringCustom(char* source, size_t* size) {
|
unsigned char* compileStringCustom(char* source, size_t* size) {
|
||||||
Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
Parser parser;
|
Toy_Parser parser;
|
||||||
Compiler compiler;
|
Toy_Compiler compiler;
|
||||||
|
|
||||||
initLexer(&lexer, source);
|
Toy_initLexer(&lexer, source);
|
||||||
initParser(&parser, &lexer);
|
Toy_initParser(&parser, &lexer);
|
||||||
initCompiler(&compiler);
|
Toy_initCompiler(&compiler);
|
||||||
|
|
||||||
//run the parser until the end of the source
|
//run the parser until the end of the source
|
||||||
ASTNode* node = scanParser(&parser);
|
Toy_ASTNode* node = Toy_scanParser(&parser);
|
||||||
while(node != NULL) {
|
while(node != NULL) {
|
||||||
//pack up and leave
|
//pack up and leave
|
||||||
if (node->type == AST_NODE_ERROR) {
|
if (node->type == TOY_AST_NODE_ERROR) {
|
||||||
errorsTriggered++; //custom error catch
|
errorsTriggered++; //custom error catch
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
freeCompiler(&compiler);
|
Toy_freeCompiler(&compiler);
|
||||||
freeParser(&parser);
|
Toy_freeParser(&parser);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCompiler(&compiler, node);
|
Toy_writeCompiler(&compiler, node);
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
node = scanParser(&parser);
|
node = Toy_scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the bytecode dump
|
//get the bytecode dump
|
||||||
unsigned char* tb = collateCompiler(&compiler, (int*)(size));
|
unsigned char* tb = Toy_collateCompiler(&compiler, (int*)(size));
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeCompiler(&compiler);
|
Toy_freeCompiler(&compiler);
|
||||||
freeParser(&parser);
|
Toy_freeParser(&parser);
|
||||||
//no lexer to clean up
|
//no lexer to clean up
|
||||||
|
|
||||||
//finally
|
//finally
|
||||||
@@ -62,15 +62,15 @@ unsigned char* compileStringCustom(char* source, size_t* size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void runBinaryCustom(unsigned char* tb, size_t size) {
|
void runBinaryCustom(unsigned char* tb, size_t size) {
|
||||||
Interpreter interpreter;
|
Toy_Interpreter interpreter;
|
||||||
initInterpreter(&interpreter);
|
Toy_initInterpreter(&interpreter);
|
||||||
|
|
||||||
//NOTE: suppress print output for testing
|
//NOTE: suppress print output for testing
|
||||||
setInterpreterPrint(&interpreter, noPrintFn);
|
Toy_setInterpreterPrint(&interpreter, noPrintFn);
|
||||||
setInterpreterError(&interpreter, noErrorFn);
|
Toy_setInterpreterError(&interpreter, noErrorFn);
|
||||||
|
|
||||||
runInterpreter(&interpreter, tb, size);
|
Toy_runInterpreter(&interpreter, tb, size);
|
||||||
freeInterpreter(&interpreter);
|
Toy_freeInterpreter(&interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void runSourceCustom(char* source) {
|
void runSourceCustom(char* source) {
|
||||||
@@ -84,7 +84,7 @@ void runSourceCustom(char* source) {
|
|||||||
|
|
||||||
void runSourceFileCustom(char* fname) {
|
void runSourceFileCustom(char* fname) {
|
||||||
size_t size = 0; //not used
|
size_t size = 0; //not used
|
||||||
char* source = readFile(fname, &size);
|
char* source = Toy_readFile(fname, &size);
|
||||||
runSourceCustom(source);
|
runSourceCustom(source);
|
||||||
free((void*)source);
|
free((void*)source);
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ int main() {
|
|||||||
runSourceFileCustom(buffer);
|
runSourceFileCustom(buffer);
|
||||||
|
|
||||||
if (errorsTriggered == 0) {
|
if (errorsTriggered == 0) {
|
||||||
printf(ERROR "Expected error did not occur in %s\n" RESET, filenames[i]);
|
printf(TOY_CC_ERROR "Expected error did not occur in %s\n" TOY_CC_RESET, filenames[i]);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ int main() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "lexer.h"
|
#include "toy_lexer.h"
|
||||||
#include "parser.h"
|
#include "toy_parser.h"
|
||||||
#include "compiler.h"
|
#include "toy_compiler.h"
|
||||||
#include "interpreter.h"
|
#include "toy_interpreter.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
|
|
||||||
#include "../repl/repl_tools.h"
|
#include "../repl/repl_tools.h"
|
||||||
|
|
||||||
@@ -27,39 +27,39 @@ typedef struct ArbitraryData {
|
|||||||
int value;
|
int value;
|
||||||
} ArbitraryData;
|
} ArbitraryData;
|
||||||
|
|
||||||
static int produce(Interpreter* interpreter, LiteralArray* arguments) {
|
static int produce(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
ArbitraryData* data = ALLOCATE(ArbitraryData, 1);
|
ArbitraryData* data = TOY_ALLOCATE(ArbitraryData, 1);
|
||||||
data->value = 42;
|
data->value = 42;
|
||||||
|
|
||||||
Literal o = TO_OPAQUE_LITERAL(data, 0);
|
Toy_Literal o = TOY_TO_OPAQUE_LITERAL(data, 0);
|
||||||
|
|
||||||
pushLiteralArray(&interpreter->stack, o);
|
Toy_pushLiteralArray(&interpreter->stack, o);
|
||||||
|
|
||||||
freeLiteral(o);
|
Toy_freeLiteral(o);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int consume(Interpreter* interpreter, LiteralArray* arguments) {
|
static int consume(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
Literal o = popLiteralArray(arguments);
|
Toy_Literal o = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
Literal idn = o;
|
Toy_Literal idn = o;
|
||||||
|
|
||||||
if (parseIdentifierToValue(interpreter, &o)) {
|
if (Toy_parseIdentifierToValue(interpreter, &o)) {
|
||||||
freeLiteral(idn);
|
Toy_freeLiteral(idn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_OPAQUE(o) && ((ArbitraryData*)(AS_OPAQUE(o)))->value == 42) {
|
if (TOY_IS_OPAQUE(o) && ((ArbitraryData*)(TOY_AS_OPAQUE(o)))->value == 42) {
|
||||||
ArbitraryData* data = (ArbitraryData*)AS_OPAQUE(o);
|
ArbitraryData* data = (ArbitraryData*)TOY_AS_OPAQUE(o);
|
||||||
|
|
||||||
FREE(ArbitraryData, data);
|
TOY_FREE(ArbitraryData, data);
|
||||||
|
|
||||||
//all went well
|
//all went well
|
||||||
freeLiteral(o);
|
Toy_freeLiteral(o);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(ERROR "opaque failed: %d\n" RESET, IS_OPAQUE(o));
|
printf(TOY_CC_ERROR "opaque failed: %d\n" TOY_CC_RESET, TOY_IS_OPAQUE(o));
|
||||||
|
|
||||||
exit(-1);
|
exit(-1);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -68,28 +68,28 @@ static int consume(Interpreter* interpreter, LiteralArray* arguments) {
|
|||||||
int main() {
|
int main() {
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
char* source = readFile("scripts/opaque-data-type.toy", &size);
|
char* source = Toy_readFile("scripts/opaque-data-type.toy", &size);
|
||||||
unsigned char* tb = compileString(source, &size);
|
unsigned char* tb = Toy_compileString(source, &size);
|
||||||
free((void*)source);
|
free((void*)source);
|
||||||
|
|
||||||
if (!tb) {
|
if (!tb) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpreter interpreter;
|
Toy_Interpreter interpreter;
|
||||||
initInterpreter(&interpreter);
|
Toy_initInterpreter(&interpreter);
|
||||||
|
|
||||||
injectNativeFn(&interpreter, "produce", produce);
|
Toy_injectNativeFn(&interpreter, "produce", produce);
|
||||||
injectNativeFn(&interpreter, "consume", consume);
|
Toy_injectNativeFn(&interpreter, "consume", consume);
|
||||||
|
|
||||||
//run teh script
|
//run teh script
|
||||||
runInterpreter(&interpreter, tb, size);
|
Toy_runInterpreter(&interpreter, tb, size);
|
||||||
|
|
||||||
//clean up
|
//clean up
|
||||||
freeInterpreter(&interpreter);
|
Toy_freeInterpreter(&interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "parser.h"
|
#include "toy_parser.h"
|
||||||
|
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include "../repl/repl_tools.h"
|
#include "../repl/repl_tools.h"
|
||||||
|
|
||||||
@@ -14,12 +14,12 @@ int main() {
|
|||||||
char* source = "print null;";
|
char* source = "print null;";
|
||||||
|
|
||||||
//test init & quit
|
//test init & quit
|
||||||
Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
Parser parser;
|
Toy_Parser parser;
|
||||||
initLexer(&lexer, source);
|
Toy_initLexer(&lexer, source);
|
||||||
initParser(&parser, &lexer);
|
Toy_initParser(&parser, &lexer);
|
||||||
|
|
||||||
freeParser(&parser);
|
Toy_freeParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -27,63 +27,63 @@ int main() {
|
|||||||
char* source = "print null;";
|
char* source = "print null;";
|
||||||
|
|
||||||
//test parsing
|
//test parsing
|
||||||
Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
Parser parser;
|
Toy_Parser parser;
|
||||||
initLexer(&lexer, source);
|
Toy_initLexer(&lexer, source);
|
||||||
initParser(&parser, &lexer);
|
Toy_initParser(&parser, &lexer);
|
||||||
|
|
||||||
ASTNode* node = scanParser(&parser);
|
Toy_ASTNode* node = Toy_scanParser(&parser);
|
||||||
|
|
||||||
//inspect the node
|
//inspect the node
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
fprintf(stderr, ERROR "ERROR: ASTNode is null" RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is null" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->type != AST_NODE_UNARY || node->unary.opcode != OP_PRINT) {
|
if (node->type != TOY_AST_NODE_UNARY || node->unary.opcode != TOY_OP_PRINT) {
|
||||||
fprintf(stderr, ERROR "ERROR: ASTNode is not a unary print instruction" RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode is not a unary print instruction" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->unary.child->type != AST_NODE_LITERAL || !IS_NULL(node->unary.child->atomic.literal)) {
|
if (node->unary.child->type != TOY_AST_NODE_LITERAL || !TOY_IS_NULL(node->unary.child->atomic.literal)) {
|
||||||
fprintf(stderr, ERROR "ERROR: ASTNode to be printed is not a null literal" RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: ASTNode to be printed is not a null literal" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
freeParser(&parser);
|
Toy_freeParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//get the source file
|
//get the source file
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
char* source = readFile("scripts/parser_sample_code.toy", &size);
|
char* source = Toy_readFile("scripts/parser_sample_code.toy", &size);
|
||||||
|
|
||||||
//test parsing a chunk of junk (valgrind will find leaks)
|
//test parsing a chunk of junk (valgrind will find leaks)
|
||||||
Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
Parser parser;
|
Toy_Parser parser;
|
||||||
initLexer(&lexer, source);
|
Toy_initLexer(&lexer, source);
|
||||||
initParser(&parser, &lexer);
|
Toy_initParser(&parser, &lexer);
|
||||||
|
|
||||||
ASTNode* node = scanParser(&parser);
|
Toy_ASTNode* node = Toy_scanParser(&parser);
|
||||||
|
|
||||||
while (node != NULL) {
|
while (node != NULL) {
|
||||||
if (node->type == AST_NODE_ERROR) {
|
if (node->type == TOY_AST_NODE_ERROR) {
|
||||||
fprintf(stderr, ERROR "ERROR: Error node detected" RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Error node detected" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeASTNode(node);
|
Toy_freeASTNode(node);
|
||||||
node = scanParser(&parser);
|
node = Toy_scanParser(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
freeParser(&parser);
|
Toy_freeParser(&parser);
|
||||||
free((void*)source);
|
free((void*)source);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,124 +1,124 @@
|
|||||||
#include "scope.h"
|
#include "toy_scope.h"
|
||||||
|
|
||||||
#include "memory.h"
|
#include "toy_memory.h"
|
||||||
#include "console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
{
|
{
|
||||||
//test init & quit
|
//test init & quit
|
||||||
Scope* scope = pushScope(NULL);
|
Toy_Scope* scope = Toy_pushScope(NULL);
|
||||||
scope = popScope(scope);
|
scope = Toy_popScope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//prerequisites
|
//prerequisites
|
||||||
char* idn_raw = "foobar";
|
char* idn_raw = "foobar";
|
||||||
|
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw));
|
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(idn_raw));
|
||||||
Literal value = TO_INTEGER_LITERAL(42);
|
Toy_Literal value = TOY_TO_INTEGER_LITERAL(42);
|
||||||
Literal type = TO_TYPE_LITERAL(value.type, false);
|
Toy_Literal type = TOY_TO_TYPE_LITERAL(value.type, false);
|
||||||
|
|
||||||
//test declarations & assignments
|
//test declarations & assignments
|
||||||
Scope* scope = pushScope(NULL);
|
Toy_Scope* scope = Toy_pushScope(NULL);
|
||||||
|
|
||||||
//declare & assign
|
//declare & assign
|
||||||
if (!declareScopeVariable(scope, identifier, type)) {
|
if (!Toy_declareScopeVariable(scope, identifier, type)) {
|
||||||
printf(ERROR "Failed to declare scope variable" RESET);
|
printf(TOY_CC_ERROR "Failed to declare scope variable" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!setScopeVariable(scope, identifier, value, true)) {
|
if (!Toy_setScopeVariable(scope, identifier, value, true)) {
|
||||||
printf(ERROR "Failed to sete scope variable" RESET);
|
printf(TOY_CC_ERROR "Failed to sete scope variable" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
scope = popScope(scope);
|
scope = Toy_popScope(scope);
|
||||||
|
|
||||||
freeLiteral(identifier);
|
Toy_freeLiteral(identifier);
|
||||||
freeLiteral(value);
|
Toy_freeLiteral(value);
|
||||||
freeLiteral(type);
|
Toy_freeLiteral(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//prerequisites
|
//prerequisites
|
||||||
char* idn_raw = "foobar";
|
char* idn_raw = "foobar";
|
||||||
|
|
||||||
Literal identifier = TO_IDENTIFIER_LITERAL(createRefString(idn_raw));
|
Toy_Literal identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(idn_raw));
|
||||||
Literal type = TO_TYPE_LITERAL(LITERAL_INTEGER, false);
|
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_INTEGER, false);
|
||||||
|
|
||||||
//test declarations & assignments
|
//test declarations & assignments
|
||||||
Scope* scope = pushScope(NULL);
|
Toy_Scope* scope = Toy_pushScope(NULL);
|
||||||
|
|
||||||
//declare & assign
|
//declare & assign
|
||||||
if (!declareScopeVariable(scope, identifier, type)) {
|
if (!Toy_declareScopeVariable(scope, identifier, type)) {
|
||||||
printf(ERROR "Failed to declare the scope variable" RESET);
|
printf(TOY_CC_ERROR "Failed to declare the scope variable" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!setScopeVariable(scope, identifier, TO_INTEGER_LITERAL(42), true)) {
|
if (!Toy_setScopeVariable(scope, identifier, TOY_TO_INTEGER_LITERAL(42), true)) {
|
||||||
printf(ERROR "Failed to set the scope variable" RESET);
|
printf(TOY_CC_ERROR "Failed to set the scope variable" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//deeper scope
|
//deeper scope
|
||||||
scope = pushScope(scope);
|
scope = Toy_pushScope(scope);
|
||||||
|
|
||||||
//test shadowing
|
//test shadowing
|
||||||
Literal ref;
|
Toy_Literal ref;
|
||||||
if (!getScopeVariable(scope, identifier, &ref)) {
|
if (!Toy_getScopeVariable(scope, identifier, &ref)) {
|
||||||
printf(ERROR "Failed to get the scope variable" RESET);
|
printf(TOY_CC_ERROR "Failed to get the scope variable" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AS_INTEGER(ref) != 42) {
|
if (TOY_AS_INTEGER(ref) != 42) {
|
||||||
printf(ERROR "Failed to retreive the correct variable value" RESET);
|
printf(TOY_CC_ERROR "Failed to retreive the correct variable value" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!declareScopeVariable(scope, identifier, type)) {
|
if (!Toy_declareScopeVariable(scope, identifier, type)) {
|
||||||
printf(ERROR "Failed to declare the scope variable (shadowing)" RESET);
|
printf(TOY_CC_ERROR "Failed to declare the scope variable (shadowing)" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!setScopeVariable(scope, identifier, TO_INTEGER_LITERAL(69), true)) {
|
if (!Toy_setScopeVariable(scope, identifier, TOY_TO_INTEGER_LITERAL(69), true)) {
|
||||||
printf(ERROR "Failed to set the scope variable (shadowing)" RESET);
|
printf(TOY_CC_ERROR "Failed to set the scope variable (shadowing)" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getScopeVariable(scope, identifier, &ref)) {
|
if (!Toy_getScopeVariable(scope, identifier, &ref)) {
|
||||||
printf(ERROR "Failed to get the scope variable (shadowing)" RESET);
|
printf(TOY_CC_ERROR "Failed to get the scope variable (shadowing)" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AS_INTEGER(ref) != 69) {
|
if (TOY_AS_INTEGER(ref) != 69) {
|
||||||
printf(ERROR "Failed to retreive the correct variable value (shadowing)" RESET);
|
printf(TOY_CC_ERROR "Failed to retreive the correct variable value (shadowing)" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//unwind
|
//unwind
|
||||||
scope = popScope(scope);
|
scope = Toy_popScope(scope);
|
||||||
|
|
||||||
if (!getScopeVariable(scope, identifier, &ref)) {
|
if (!Toy_getScopeVariable(scope, identifier, &ref)) {
|
||||||
printf(ERROR "Failed to get the scope variable" RESET);
|
printf(TOY_CC_ERROR "Failed to get the scope variable" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AS_INTEGER(ref) != 42) {
|
if (TOY_AS_INTEGER(ref) != 42) {
|
||||||
printf(ERROR "Failed to retreive the correct variable value" RESET);
|
printf(TOY_CC_ERROR "Failed to retreive the correct variable value" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
scope = popScope(scope);
|
scope = Toy_popScope(scope);
|
||||||
|
|
||||||
freeLiteral(identifier);
|
Toy_freeLiteral(identifier);
|
||||||
freeLiteral(type);
|
Toy_freeLiteral(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(NOTICE "All good\n" RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
130
tools/uptown.cpp
Normal file
130
tools/uptown.cpp
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
//UPTOWN: Utility to Prepend Text Of Whatever Next
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
//protip: This gets more efficient the more files passed in
|
||||||
|
//protip: pass in the headers first
|
||||||
|
|
||||||
|
bool is_alpha(char c) {
|
||||||
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if (argc <= 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cache replacements for all files
|
||||||
|
std::map<std::string, std::string> replacements;
|
||||||
|
|
||||||
|
for (int fileCounter = 1; fileCounter < argc; fileCounter++) {
|
||||||
|
std::ifstream is; //input stream
|
||||||
|
std::string buffer; //store file
|
||||||
|
|
||||||
|
//open
|
||||||
|
is.open(argv[fileCounter]);
|
||||||
|
if (!is.is_open()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!is.eof()) {
|
||||||
|
char c = is.peek();
|
||||||
|
|
||||||
|
//skip comments (make it easier)
|
||||||
|
if (c == '/') {
|
||||||
|
buffer += is.get();
|
||||||
|
|
||||||
|
//single lines
|
||||||
|
if (is.peek() == '/') {
|
||||||
|
do {
|
||||||
|
buffer += is.get();
|
||||||
|
} while(is.peek() != '\n');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//multi-line
|
||||||
|
if (is.peek() == '*') {
|
||||||
|
while (true) {
|
||||||
|
do {
|
||||||
|
buffer += is.get();
|
||||||
|
} while(is.peek() != '*');
|
||||||
|
|
||||||
|
if (is.eof()) { //just in case
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
buffer += is.get();
|
||||||
|
if (is.peek() == '/') {
|
||||||
|
buffer += is.get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//skip strings (causes issues)
|
||||||
|
if (c == '"') {
|
||||||
|
do {
|
||||||
|
buffer += is.get();
|
||||||
|
} while (is.peek() != '"');
|
||||||
|
buffer += is.get();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//skip non-words
|
||||||
|
if (!is_alpha(c)) {
|
||||||
|
buffer += is.get();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//read word
|
||||||
|
std::string word = "";
|
||||||
|
while(is_alpha(is.peek())) {
|
||||||
|
word += is.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
//get replacement word, if it doesn't exist
|
||||||
|
if (replacements.find(word) == replacements.end()) {
|
||||||
|
std::cout << word << " : ";
|
||||||
|
std::string prepend = "";
|
||||||
|
|
||||||
|
getline(std::cin, prepend);
|
||||||
|
|
||||||
|
if (prepend.length() == 0) {
|
||||||
|
replacements[word] = word;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
replacements[word] = prepend + word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//append the replacement
|
||||||
|
buffer += replacements[word];
|
||||||
|
}
|
||||||
|
|
||||||
|
//finally
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
std::ofstream os;
|
||||||
|
|
||||||
|
os.open(argv[fileCounter]);
|
||||||
|
if (!os.is_open()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bugfix
|
||||||
|
if (!buffer.empty()) {
|
||||||
|
buffer.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
os << buffer;
|
||||||
|
|
||||||
|
os.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user