Added errorOutput to interpreter, moved builtin functions to their own file

This commit is contained in:
2022-09-04 15:15:30 +01:00
parent 22af1edb1d
commit ae270008b0
7 changed files with 551 additions and 506 deletions

View File

@@ -30,6 +30,9 @@ DONE: Address circular references
TODO: are compounds shallow or deep copies? Deep copies
TODO: third output stream, for lexer/parser/compiler/interpreter errors
TODO: slice and dot notation around the _index function
TODO: ternary operator
TODO: Nullish types
@@ -39,7 +42,6 @@ TODO: Assertion-based test scripts
TODO: standard library
TODO: external runner library
TODO: document how it all works
TODO: third output stream, for parser/compiler/interpreter errors
TODO: better and more consistent error messages
TODO: maximum recursion/function depth

View File

@@ -4,21 +4,30 @@
#include "common.h"
#include "memory.h"
#include "keyword_types.h"
#include "opcodes.h"
#include "lib_builtin.h"
#include <stdio.h>
#include <string.h>
static void stdoutWrapper(const char* output) {
static void printWrapper(const char* output) {
printf("%s", output);
printf("\n"); //default new line
}
static void stderrWrapper(const char* output) {
static void assertWrapper(const char* output) {
fprintf(stderr, ERROR "Assertion failure: ");
fprintf(stderr, "%s", output);
fprintf(stderr, "\n" RESET); //default new line
}
static void errorWrapper(const char* output) {
fprintf(stderr, ERROR "ERROR: ");
fprintf(stderr, "%s", output);
fprintf(stderr, RESET); //no newline
}
bool injectNativeFn(Interpreter* interpreter, char* name, NativeFn func) {
//reject reserved words
if (findTypeByKeyword(name) != TOKEN_EOF) {
@@ -64,413 +73,6 @@ bool parseIdentifierToValue(Interpreter* interpreter, Literal* literalPtr) {
return true;
}
int _set(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 3) {
(interpreter->printOutput)("Incorrect number of arguments to _set");
return -1;
}
Literal idn = arguments->literals[0];
Literal obj = arguments->literals[0];
Literal key = arguments->literals[1];
Literal val = arguments->literals[2];
if (!IS_IDENTIFIER(idn)) {
(interpreter->printOutput)("expected identifier in _set");
return -1;
}
parseIdentifierToValue(interpreter, &obj);
bool freeKey = false;
if (IS_IDENTIFIER(key)) {
parseIdentifierToValue(interpreter, &key);
freeKey = true;
}
bool freeVal = false;
if (IS_IDENTIFIER(val)) {
parseIdentifierToValue(interpreter, &val);
freeVal = true;
}
switch(obj.type) {
case LITERAL_ARRAY: {
Literal typeLiteral = getScopeType(interpreter->scope, key);
if (AS_TYPE(typeLiteral).typeOf == LITERAL_ARRAY) {
Literal subtypeLiteral = ((Literal*)(AS_TYPE(typeLiteral).subtypes))[0];
if (AS_TYPE(subtypeLiteral).typeOf != LITERAL_ANY && AS_TYPE(subtypeLiteral).typeOf != val.type) {
(interpreter->printOutput)("bad argument type in _set");
return -1;
}
}
if (!IS_INTEGER(key)) {
(interpreter->printOutput)("Expected integer index in _set");
return -1;
}
if (AS_ARRAY(obj)->count <= AS_INTEGER(key) || AS_INTEGER(key) < 0) {
(interpreter->printOutput)("Index out of bounds in _set");
return -1;
}
//don't use pushLiteralArray, since we're setting
freeLiteral(AS_ARRAY(obj)->literals[AS_INTEGER(key)]); //BUGFIX: clear any existing data first
AS_ARRAY(obj)->literals[AS_INTEGER(key)] = copyLiteral(val);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) {
printf(ERROR "ERROR: Incorrect type assigned to array (_set) \"");
printLiteral(val);
printf("\"\n" RESET);
return -1;
}
break;
}
case LITERAL_DICTIONARY: {
Literal typeLiteral = getScopeType(interpreter->scope, key);
if (AS_TYPE(typeLiteral).typeOf == LITERAL_DICTIONARY) {
Literal keySubtypeLiteral = ((Literal*)(AS_TYPE(typeLiteral).subtypes))[0];
Literal valSubtypeLiteral = ((Literal*)(AS_TYPE(typeLiteral).subtypes))[1];
if (AS_TYPE(keySubtypeLiteral).typeOf != LITERAL_ANY && AS_TYPE(keySubtypeLiteral).typeOf != key.type) {
(interpreter->printOutput)("bad argument type in _set");
return -1;
}
if (AS_TYPE(valSubtypeLiteral).typeOf != LITERAL_ANY && AS_TYPE(valSubtypeLiteral).typeOf != val.type) {
(interpreter->printOutput)("bad argument type in _set");
return -1;
}
}
setLiteralDictionary(AS_DICTIONARY(obj), key, val);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) {
printf(ERROR "ERROR: Incorrect type assigned to dictionary (_get) \"");
printLiteral(val);
printf("\"\n" RESET);
return -1;
}
break;
}
default:
(interpreter->printOutput)("Incorrect compound type in _set");
printLiteral(obj);
return -1;
}
freeLiteral(obj);
if (freeKey) {
freeLiteral(key);
}
if (freeVal) {
freeLiteral(val);
}
return 0;
}
int _get(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 2) {
(interpreter->printOutput)("Incorrect number of arguments to _get");
return -1;
}
Literal obj = arguments->literals[0];
Literal key = arguments->literals[1];
bool freeObj = false;
if (IS_IDENTIFIER(obj)) {
parseIdentifierToValue(interpreter, &obj);
freeObj = true;
}
bool freeKey = false;
if (IS_IDENTIFIER(key)) {
parseIdentifierToValue(interpreter, &key);
freeKey = true;
}
switch(obj.type) {
case LITERAL_ARRAY: {
if (!IS_INTEGER(key)) {
(interpreter->printOutput)("Expected integer index in _get");
return -1;
}
if (AS_ARRAY(obj)->count <= AS_INTEGER(key) || AS_INTEGER(key) < 0) {
(interpreter->printOutput)("Index out of bounds in _get");
return -1;
}
pushLiteralArray(&interpreter->stack, AS_ARRAY(obj)->literals[AS_INTEGER(key)]);
if (freeObj) {
freeLiteral(obj);
}
if (freeKey) {
freeLiteral(key);
}
return 1;
}
case LITERAL_DICTIONARY: {
Literal dict = getLiteralDictionary(AS_DICTIONARY(obj), key);
pushLiteralArray(&interpreter->stack, dict);
freeLiteral(dict);
if (freeObj) {
freeLiteral(obj);
}
if (freeKey) {
freeLiteral(key);
}
return 1;
}
default:
(interpreter->printOutput)("Incorrect compound type in _get ");
printLiteral(obj);
return -1;
}
}
int _push(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 2) {
(interpreter->printOutput)("Incorrect number of arguments to _push");
return -1;
}
Literal idn = arguments->literals[0];
Literal obj = arguments->literals[0];
Literal val = arguments->literals[1];
if (!IS_IDENTIFIER(idn)) {
(interpreter->printOutput)("expected identifier in _push");
return -1;
}
parseIdentifierToValue(interpreter, &obj);
bool freeVal = false;
if (IS_IDENTIFIER(val)) {
parseIdentifierToValue(interpreter, &val);
freeVal = true;
}
switch(obj.type) {
case LITERAL_ARRAY: {
Literal typeLiteral = getScopeType(interpreter->scope, val);
if (AS_TYPE(typeLiteral).typeOf == LITERAL_ARRAY) {
Literal subtypeLiteral = ((Literal*)(AS_TYPE(typeLiteral).subtypes))[0];
if (AS_TYPE(subtypeLiteral).typeOf != LITERAL_ANY && AS_TYPE(subtypeLiteral).typeOf != val.type) {
(interpreter->printOutput)("bad argument type in _push");
return -1;
}
}
pushLiteralArray(AS_ARRAY(obj), val);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) { //TODO: could definitely be more efficient than overwriting the whole original object
printf(ERROR "ERROR: Incorrect type assigned to array (_push) \"");
printLiteral(val);
printf("\"\n" RESET);
return -1;
}
freeLiteral(obj);
if (freeVal) {
freeLiteral(val);
}
return 0;
}
default:
(interpreter->printOutput)("Incorrect compound type in _push ");
printLiteral(obj);
return -1;
}
}
int _pop(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 1) {
(interpreter->printOutput)("Incorrect number of arguments to _pop");
return -1;
}
Literal idn = arguments->literals[0];
Literal obj = arguments->literals[0];
if (!IS_IDENTIFIER(idn)) {
(interpreter->printOutput)("expected identifier in _pop");
return -1;
}
parseIdentifierToValue(interpreter, &obj);
switch(obj.type) {
case LITERAL_ARRAY: {
Literal lit = popLiteralArray(AS_ARRAY(obj));
pushLiteralArray(&interpreter->stack, lit);
freeLiteral(lit);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) { //TODO: could definitely be more efficient than overwriting the whole original object
printf(ERROR "ERROR: Incorrect type assigned to array (_pop) \"");
printLiteral(obj);
printf("\"\n" RESET);
return -1;
}
freeLiteral(obj);
return 1;
}
default:
(interpreter->printOutput)("Incorrect compound type in _pop ");
printLiteral(obj);
return -1;
}
}
int _length(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 1) {
(interpreter->printOutput)("Incorrect number of arguments to _get");
return -1;
}
Literal obj = arguments->literals[0];
bool freeObj = false;
if (IS_IDENTIFIER(obj)) {
parseIdentifierToValue(interpreter, &obj);
freeObj = true;
}
switch(obj.type) {
case LITERAL_ARRAY: {
Literal lit = TO_INTEGER_LITERAL( AS_ARRAY(obj)->count );
pushLiteralArray(&interpreter->stack, lit);
freeLiteral(lit);
break;
}
case LITERAL_DICTIONARY: {
Literal lit = TO_INTEGER_LITERAL( AS_DICTIONARY(obj)->count );
pushLiteralArray(&interpreter->stack, lit);
freeLiteral(lit);
break;
}
case LITERAL_STRING: {
Literal lit = TO_INTEGER_LITERAL( strlen(AS_STRING(obj)) );
pushLiteralArray(&interpreter->stack, lit);
freeLiteral(lit);
break;
}
default:
(interpreter->printOutput)("Incorrect compound type in _length ");
printLiteral(obj);
return -1;
}
if (freeObj) {
freeLiteral(obj);
}
return 1;
}
int _clear(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 1) {
(interpreter->printOutput)("Incorrect number of arguments to _get");
return -1;
}
Literal idn = arguments->literals[0];
Literal obj = arguments->literals[0];
if (!IS_IDENTIFIER(idn)) {
(interpreter->printOutput)("expected identifier in _clear");
return -1;
}
parseIdentifierToValue(interpreter, &obj);
//NOTE: just pass in new compounds
switch(obj.type) {
case LITERAL_ARRAY: {
LiteralArray* array = ALLOCATE(LiteralArray, 1);
initLiteralArray(array);
Literal obj = TO_ARRAY_LITERAL(array);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) {
printf(ERROR "ERROR: Incorrect type assigned to array (_clear) \"");
printLiteral(obj);
printf("\"\n" RESET);
return -1;
}
freeLiteral(obj);
break;
}
case LITERAL_DICTIONARY: {
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(dictionary);
Literal obj = TO_DICTIONARY_LITERAL(dictionary);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) {
printf(ERROR "ERROR: Incorrect type assigned to dictionary (_clear) \"");
printLiteral(obj);
printf("\"\n" RESET);
return -1;
}
freeLiteral(obj);
break;
}
default:
(interpreter->printOutput)("Incorrect compound type in _clear ");
printLiteral(obj);
return -1;
}
freeLiteral(obj);
return 1;
}
void initInterpreter(Interpreter* interpreter) {
initLiteralArray(&interpreter->literalCache);
interpreter->scope = pushScope(NULL);
@@ -481,8 +83,9 @@ void initInterpreter(Interpreter* interpreter) {
initLiteralArray(&interpreter->stack);
setInterpreterPrint(interpreter, stdoutWrapper);
setInterpreterAssert(interpreter, stderrWrapper);
setInterpreterPrint(interpreter, printWrapper);
setInterpreterAssert(interpreter, assertWrapper);
setInterpreterError(interpreter, errorWrapper);
//globally available functions (tmp?)
injectNativeFn(interpreter, "_set", _set);
@@ -527,6 +130,10 @@ void setInterpreterAssert(Interpreter* interpreter, PrintFn assertOutput) {
interpreter->assertOutput = assertOutput;
}
void setInterpreterError(Interpreter* interpreter, PrintFn errorOutput) {
interpreter->errorOutput = errorOutput;
}
//utils
static unsigned char readByte(unsigned char* tb, int* count) {
unsigned char ret = *(unsigned char*)(tb + *count);
@@ -558,16 +165,20 @@ static char* readString(unsigned char* tb, int* count) {
return (char*)ret;
}
static void consumeByte(unsigned char byte, unsigned char* tb, int* count) {
static void consumeByte(Interpreter* interpreter, unsigned char byte, unsigned char* tb, int* count) {
if (byte != tb[*count]) {
printf("[internal] Failed to consume the correct byte (expected %u, found %u)\n", byte, tb[*count]);
char buffer[512];
snprintf(buffer, 512, "[internal] Failed to consume the correct byte (expected %u, found %u)\n", byte, tb[*count]);
interpreter->errorOutput(buffer);
}
*count += 1;
}
static void consumeShort(unsigned short bytes, unsigned char* tb, int* count) {
static void consumeShort(Interpreter* interpreter, unsigned short bytes, unsigned char* tb, int* count) {
if (bytes != *(unsigned short*)(tb + *count)) {
printf("[internal] Failed to consume the correct bytes (expected %u, found %u)\n", bytes, *(unsigned short*)(tb + *count));
char buffer[512];
snprintf(buffer, 512, "[internal] Failed to consume the correct bytes (expected %u, found %u)\n", bytes, *(unsigned short*)(tb + *count));
interpreter->errorOutput(buffer);
}
*count += 2;
}
@@ -579,9 +190,9 @@ static bool execAssert(Interpreter* interpreter) {
parseIdentifierToValue(interpreter, &lhs);
if (!IS_STRING(rhs)) {
printf(ERROR "ERROR: The assert keyword needs a string as the second argument, received: ");
printLiteral(rhs);
printf("\n" RESET);
interpreter->errorOutput("The assert keyword needs a string as the second argument, received: ");
printLiteralCustom(rhs, interpreter->errorOutput);
interpreter->errorOutput("\n");
return false;
}
@@ -671,9 +282,9 @@ static bool execNegate(Interpreter* interpreter) {
lit = TO_FLOAT_LITERAL(-AS_FLOAT(lit));
}
else {
printf(ERROR "[internal] The interpreter can't negate that literal: ");
printLiteral(lit);
printf("\n" RESET);
interpreter->errorOutput("[internal] The interpreter can't negate that literal: ");
printLiteralCustom(lit, interpreter->errorOutput);
interpreter->errorOutput("\n");
freeLiteral(lit);
@@ -703,9 +314,9 @@ static bool execInvert(Interpreter* interpreter) {
lit = TO_BOOLEAN_LITERAL(!AS_BOOLEAN(lit));
}
else {
printf(ERROR "[internal] The interpreter can't invert that literal: ");
printLiteral(lit);
printf("\n" RESET);
interpreter->errorOutput("[internal] The interpreter can't invert that literal: ");
printLiteralCustom(lit, interpreter->errorOutput);
interpreter->errorOutput("\n");
freeLiteral(lit);
@@ -739,7 +350,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
if (IS_STRING(lhs) && IS_STRING(rhs)) {
//check for overflow
if (strlen(AS_STRING(lhs)) + strlen(AS_STRING(rhs)) > MAX_STRING_LENGTH) {
printf(ERROR "ERROR: Can't concatenate these strings (result is too long)\n" RESET);
interpreter->errorOutput("Can't concatenate these strings (result is too long)\n");
return false;
}
@@ -785,7 +396,7 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
case OP_DIVISION:
case OP_VAR_DIVISION_ASSIGN:
if (AS_INTEGER(rhs) == 0) {
printf(ERROR "ERROR: Can't divide by zero (error found in interpreter)" RESET);
interpreter->errorOutput("Can't divide by zero (error found in interpreter)");
return false;
}
pushLiteralArray(&interpreter->stack, TO_INTEGER_LITERAL( AS_INTEGER(lhs) / AS_INTEGER(rhs) ));
@@ -794,21 +405,21 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
case OP_MODULO:
case OP_VAR_MODULO_ASSIGN:
if (AS_INTEGER(rhs) == 0) {
printf(ERROR "ERROR: Can't modulo by zero (error found in interpreter)" RESET);
interpreter->errorOutput("Can't modulo by zero (error found in interpreter)");
return false;
}
pushLiteralArray(&interpreter->stack, TO_INTEGER_LITERAL( AS_INTEGER(lhs) % AS_INTEGER(rhs) ));
return true;
default:
printf("[internal] bad opcode argument passed to execArithmetic()");
interpreter->errorOutput("[internal] bad opcode argument passed to execArithmetic()");
return false;
}
}
//catch bad modulo
if (opcode == OP_MODULO || opcode == OP_VAR_MODULO_ASSIGN) {
printf(ERROR "ERROR: Bad arithmetic argument (modulo on floats not allowed)\n" RESET);
interpreter->errorOutput("Bad arithmetic argument (modulo on floats not allowed)\n");
return false;
}
@@ -832,24 +443,24 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
case OP_DIVISION:
case OP_VAR_DIVISION_ASSIGN:
if (AS_FLOAT(rhs) == 0) {
printf(ERROR "ERROR: Can't divide by zero (error found in interpreter)" RESET);
interpreter->errorOutput("Can't divide by zero (error found in interpreter)");
return false;
}
pushLiteralArray(&interpreter->stack, TO_FLOAT_LITERAL( AS_FLOAT(lhs) / AS_FLOAT(rhs) ));
return true;
default:
printf(ERROR "[internal] bad opcode argument passed to execArithmetic()" RESET);
interpreter->errorOutput("[internal] bad opcode argument passed to execArithmetic()");
return false;
}
}
//wrong types
printf(ERROR "ERROR: Bad arithmetic argument ");
printLiteral(lhs);
printf(" and ");
printLiteral(rhs);
printf("\n" RESET);
interpreter->errorOutput("Bad arithmetic argument ");
printLiteralCustom(lhs, interpreter->errorOutput);
interpreter->errorOutput(" and ");
printLiteralCustom(rhs, interpreter->errorOutput);
interpreter->errorOutput("\n");
freeLiteral(lhs);
freeLiteral(rhs);
@@ -881,9 +492,9 @@ static bool execVarDecl(Interpreter* interpreter, bool lng) {
}
if (!declareScopeVariable(interpreter->scope, identifier, type)) {
printf(ERROR "ERROR: Can't redefine the variable \"");
printLiteral(identifier);
printf("\"\n" RESET);
interpreter->errorOutput("Can't redefine the variable \"");
printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return false;
}
@@ -896,9 +507,9 @@ static bool execVarDecl(Interpreter* interpreter, bool lng) {
}
if (!IS_NULL(val) && !setScopeVariable(interpreter->scope, identifier, val, false)) {
printf(ERROR "ERROR: Incorrect type assigned to variable \"");
printLiteral(identifier);
printf("\"\n" RESET);
interpreter->errorOutput("Incorrect type assigned to variable \"");
printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(identifier); //TODO: test this
freeLiteral(type);
@@ -938,16 +549,16 @@ static bool execFnDecl(Interpreter* interpreter, bool lng) {
Literal type = TO_TYPE_LITERAL(LITERAL_FUNCTION, true);
if (!declareScopeVariable(interpreter->scope, identifier, type)) {
printf(ERROR "ERROR: Can't redefine the function \"");
printLiteral(identifier);
printf("\"\n" RESET);
interpreter->errorOutput("Can't redefine the function \"");
printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return false;
}
if (!setScopeVariable(interpreter->scope, identifier, function, false)) { //scope gets copied here
printf(ERROR "ERROR: Incorrect type assigned to variable \"");
printLiteral(identifier);
printf("\"\n" RESET);
interpreter->errorOutput("Incorrect type assigned to variable \"");
printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return false;
}
@@ -970,16 +581,16 @@ static bool execVarAssign(Interpreter* interpreter) {
}
if (!IS_IDENTIFIER(lhs)) {
printf(ERROR "ERROR: Can't assign to a non-variable \"");
printLiteral(lhs);
printf("\"\n" RESET);
interpreter->errorOutput("Can't assign to a non-variable \"");
printLiteralCustom(lhs, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return false;
}
if (!isDelcaredScopeVariable(interpreter->scope, lhs)) {
printf(ERROR "ERROR: Undeclared variable \"");
printLiteral(lhs);
printf("\"\n" RESET);
interpreter->errorOutput("Undeclared variable \"");
printLiteralCustom(lhs, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(lhs);
freeLiteral(rhs);
@@ -987,9 +598,9 @@ static bool execVarAssign(Interpreter* interpreter) {
}
if (!setScopeVariable(interpreter->scope, lhs, rhs, true)) {
printf(ERROR "ERROR Incorrect type assigned to variable \"");
printLiteral(lhs);
printf("\"\n" RESET);
interpreter->errorOutput("Incorrect type assigned to variable \"");
printLiteralCustom(lhs, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(lhs);
freeLiteral(rhs);
@@ -1032,7 +643,7 @@ static bool execValCast(Interpreter* interpreter) {
Literal result = TO_NULL_LITERAL;
if (IS_NULL(value)) {
printf(ERROR "ERROR: Can't cast a null value\n" RESET);
interpreter->errorOutput("Can't cast a null value\n");
freeLiteral(value);
freeLiteral(type);
@@ -1111,7 +722,9 @@ static bool execValCast(Interpreter* interpreter) {
break;
default:
printf(ERROR"ERROR: Unknown cast type found %d, terminating\n" RESET, AS_TYPE(type).typeOf);
interpreter->errorOutput("Unknown cast type found: ");
printLiteralCustom(type, interpreter->errorOutput);
interpreter->errorOutput("\n");
return false;
}
@@ -1173,18 +786,19 @@ static bool execCompareLess(Interpreter* interpreter, bool invert) {
//not a number, return falure
if (!(IS_INTEGER(lhs) || IS_FLOAT(lhs))) {
printf(ERROR "ERROR: Incorrect type in comparison, value \"");
printLiteral(lhs);
printf("\"\n" RESET);
interpreter->errorOutput("Incorrect type in comparison, value \"");
printLiteralCustom(lhs, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(lhs);
freeLiteral(rhs);
return false;
}
if (!(IS_INTEGER(rhs) || IS_FLOAT(rhs))) {
printf(ERROR "ERROR: Incorrect type in comparison, value \"");
printLiteral(rhs);
printf("\"\n" RESET);
interpreter->errorOutput("Incorrect type in comparison, value \"");
printLiteralCustom(rhs, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(lhs);
freeLiteral(rhs);
return false;
@@ -1234,18 +848,20 @@ static bool execCompareLessEqual(Interpreter* interpreter, bool invert) {
//not a number, return falure
if (!(IS_INTEGER(lhs) || IS_FLOAT(lhs))) {
printf(ERROR "ERROR: Incorrect type in comparison, value \"");
printLiteral(lhs);
printf("\"\n" RESET);
interpreter->errorOutput("Incorrect type in comparison, value \"");
printLiteralCustom(lhs, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(lhs);
freeLiteral(rhs);
return false;
}
if (!(IS_INTEGER(rhs) || IS_FLOAT(rhs))) {
printf(ERROR "ERROR: Incorrect type in comparison, value \"");
printLiteral(rhs);
printf("\"\n" RESET);
interpreter->errorOutput("Incorrect type in comparison, value \"");
printLiteralCustom(rhs, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(lhs);
freeLiteral(rhs);
return false;
@@ -1339,7 +955,7 @@ static bool execJump(Interpreter* interpreter) {
int target = (int)readShort(interpreter->bytecode, &interpreter->count);
if (target + interpreter->codeStart > interpreter->length) {
printf(ERROR "[internal] Jump out of range\n" RESET);
interpreter->errorOutput("[internal] Jump out of range\n");
return false;
}
@@ -1353,7 +969,7 @@ static bool execFalseJump(Interpreter* interpreter) {
int target = (int)readShort(interpreter->bytecode, &interpreter->count);
if (target + interpreter->codeStart > interpreter->length) {
printf(ERROR "[internal] Jump out of range (false jump)\n" RESET);
interpreter->errorOutput("[internal] Jump out of range (false jump)\n");
return false;
}
@@ -1369,7 +985,7 @@ static bool execFalseJump(Interpreter* interpreter) {
}
if (IS_NULL(lit)) {
printf(ERROR "Error: Null detected in comparison\n" RESET);
interpreter->errorOutput("Null detected in comparison\n");
return false;
}
@@ -1434,9 +1050,9 @@ static bool execFnCall(Interpreter* interpreter) {
}
if (!IS_FUNCTION(func)) {
printf(ERROR "ERROR: Function not found: ");
printLiteral(identifier);
printf("\n" RESET);
interpreter->errorOutput("Function not found: ");
printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\n");
freeLiteral(identifier);
freeLiteralArray(&arguments);
@@ -1459,6 +1075,7 @@ static bool execFnCall(Interpreter* interpreter) {
initLiteralArray(&inner.stack);
setInterpreterPrint(&inner, interpreter->printOutput);
setInterpreterAssert(&inner, interpreter->assertOutput);
setInterpreterError(&inner, interpreter->errorOutput);
//prep the sections
readInterpreterSections(&inner);
@@ -1475,9 +1092,9 @@ static bool execFnCall(Interpreter* interpreter) {
//check the param total is correct
if ((IS_NULL(restParam) && paramArray->count != arguments.count * 2) || (!IS_NULL(restParam) && paramArray->count -2 > arguments.count * 2)) {
printf(ERROR "ERROR: Incorrect number of arguments passed to function \"");
printLiteral(identifier);
printf("\"\n" RESET);
interpreter->errorOutput("Incorrect number of arguments passed to function \"");
printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
//free, and skip out
freeLiteralArray(&arguments);
@@ -1491,11 +1108,13 @@ static bool execFnCall(Interpreter* interpreter) {
for (int i = 0; i < paramArray->count - (IS_NULL(restParam) ? 0 : 2); i += 2) { //don't count the rest parameter, if present
//declare and define each entry in the scope
if (!declareScopeVariable(inner.scope, paramArray->literals[i], paramArray->literals[i + 1])) {
printf(ERROR "[internal] Could not re-declare parameter\n" RESET);
interpreter->errorOutput("[internal] Could not re-declare parameter\n");
//free, and skip out
freeLiteralArray(&arguments);
popScope(inner.scope);
freeInterpreter(&inner);
return false;
}
@@ -1508,12 +1127,14 @@ static bool execFnCall(Interpreter* interpreter) {
}
if (!setScopeVariable(inner.scope, paramArray->literals[i], arg, false)) {
printf(ERROR "[internal] Could not define parameter (bad type?)\n" RESET);
interpreter->errorOutput("[internal] Could not define parameter (bad type?)\n");
//free, and skip out
freeLiteral(arg);
freeLiteralArray(&arguments);
popScope(inner.scope);
freeInterpreter(&inner);
return false;
}
freeLiteral(arg);
@@ -1536,25 +1157,29 @@ static bool execFnCall(Interpreter* interpreter) {
//declare & define the rest parameter
if (!declareScopeVariable(inner.scope, restParam, restType)) {
printf(ERROR "[internal] Could not declare rest parameter\n" RESET);
interpreter->errorOutput("[internal] Could not declare rest parameter\n");
//free, and skip out
freeLiteral(restType);
freeLiteralArray(&rest);
freeLiteralArray(&arguments);
popScope(inner.scope);
freeInterpreter(&inner);
return false;
}
Literal lit = TO_ARRAY_LITERAL(&rest);
if (!setScopeVariable(inner.scope, restParam, lit, false)) {
printf(ERROR "[internal] Could not define rest parameter\n" RESET);
interpreter->errorOutput("[internal] Could not define rest parameter\n");
//free, and skip out
freeLiteral(restType);
freeLiteral(lit);
freeLiteralArray(&arguments);
popScope(inner.scope);
freeInterpreter(&inner);
return false;
}
@@ -1583,7 +1208,7 @@ static bool execFnCall(Interpreter* interpreter) {
//TODO: remove this when multiple assignment is enabled - note the BUGFIX that balances the stack
if (returns.count > 1) {
printf(ERROR "ERROR: Too many values returned (multiple returns not yet supported)\n" RESET);
interpreter->errorOutput("Too many values returned (multiple returns not yet supported)\n");
returnValue = false;
}
@@ -1593,7 +1218,7 @@ static bool execFnCall(Interpreter* interpreter) {
//check the return types
if (returnArray->count > 0 && AS_TYPE(returnArray->literals[i]).typeOf != ret.type) {
printf(ERROR "ERROR: bad type found in return value\n" RESET);
interpreter->errorOutput("Bad type found in return value\n");
//free, and skip out
returnValue = false;
@@ -1857,8 +1482,7 @@ static void execInterpreter(Interpreter* interpreter) {
break;
default:
printf(ERROR "Error: Unknown opcode found %d, terminating\n" RESET, opcode);
printLiteralArray(&interpreter->stack, "\n");
interpreter->errorOutput("Unknown opcode found, terminating\n");
return;
}
@@ -2082,7 +1706,7 @@ static void readInterpreterSections(Interpreter* interpreter) {
}
}
consumeByte(OP_SECTION_END, interpreter->bytecode, &interpreter->count); //terminate the literal section
consumeByte(interpreter, OP_SECTION_END, interpreter->bytecode, &interpreter->count); //terminate the literal section
//read the function metadata
int functionCount = readShort(interpreter->bytecode, &interpreter->count);
@@ -2101,7 +1725,7 @@ static void readInterpreterSections(Interpreter* interpreter) {
//assert that the last memory slot is function end
if (bytes[size - 1] != OP_FN_END) {
printf(ERROR "[internal] Failed to find function end" RESET);
interpreter->errorOutput("[internal] Failed to find function end");
FREE_ARRAY(unsigned char, bytes, size);
return;
}
@@ -2112,7 +1736,7 @@ static void readInterpreterSections(Interpreter* interpreter) {
}
}
consumeByte(OP_SECTION_END, interpreter->bytecode, &interpreter->count); //terminate the function section
consumeByte(interpreter, OP_SECTION_END, interpreter->bytecode, &interpreter->count); //terminate the function section
}
void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length) {
@@ -2122,7 +1746,7 @@ void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int lengt
interpreter->count = 0;
if (!interpreter->bytecode) {
printf(ERROR "Error: No valid bytecode given\n" RESET);
interpreter->errorOutput("No valid bytecode given\n");
return;
}
@@ -2137,7 +1761,8 @@ void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int lengt
const unsigned char patch = readByte(interpreter->bytecode, &interpreter->count);
if (major != TOY_VERSION_MAJOR || minor != TOY_VERSION_MINOR || patch != TOY_VERSION_PATCH) {
printf(ERROR "Error: interpreter/bytecode version mismatch\n" RESET);
interpreter->errorOutput("Interpreter/bytecode version mismatch\n");
return;
}
const char* build = readString(interpreter->bytecode, &interpreter->count);
@@ -2148,7 +1773,7 @@ void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int lengt
}
}
consumeByte(OP_SECTION_END, interpreter->bytecode, &interpreter->count);
consumeByte(interpreter, OP_SECTION_END, interpreter->bytecode, &interpreter->count);
//read the sections of the bytecode
readInterpreterSections(interpreter);

View File

@@ -1,7 +1,5 @@
#pragma once
#include "opcodes.h"
#include "literal.h"
#include "literal_array.h"
#include "literal_dictionary.h"
@@ -26,6 +24,7 @@ typedef struct Interpreter {
// LiteralDictionary exports; //TODO: read-write - interface with Toy from C
PrintFn printOutput;
PrintFn assertOutput;
PrintFn errorOutput;
bool panic;
} Interpreter;
@@ -42,5 +41,6 @@ void freeInterpreter(Interpreter* interpreter);
//utilities for the host program
void setInterpreterPrint(Interpreter* interpreter, PrintFn printOutput);
void setInterpreterAssert(Interpreter* interpreter, PrintFn assertOutput);
void setInterpreterError(Interpreter* interpreter, PrintFn errorOutput);
void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length);

416
source/lib_builtin.c Normal file
View File

@@ -0,0 +1,416 @@
#include "lib_builtin.h"
#include "memory.h"
int _set(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 3) {
interpreter->errorOutput("Incorrect number of arguments to _set\n");
return -1;
}
Literal idn = arguments->literals[0];
Literal obj = arguments->literals[0];
Literal key = arguments->literals[1];
Literal val = arguments->literals[2];
if (!IS_IDENTIFIER(idn)) {
interpreter->errorOutput("Expected identifier in _set\n");
return -1;
}
parseIdentifierToValue(interpreter, &obj);
bool freeKey = false;
if (IS_IDENTIFIER(key)) {
parseIdentifierToValue(interpreter, &key);
freeKey = true;
}
bool freeVal = false;
if (IS_IDENTIFIER(val)) {
parseIdentifierToValue(interpreter, &val);
freeVal = true;
}
switch(obj.type) {
case LITERAL_ARRAY: {
Literal typeLiteral = getScopeType(interpreter->scope, key);
if (AS_TYPE(typeLiteral).typeOf == LITERAL_ARRAY) {
Literal subtypeLiteral = ((Literal*)(AS_TYPE(typeLiteral).subtypes))[0];
if (AS_TYPE(subtypeLiteral).typeOf != LITERAL_ANY && AS_TYPE(subtypeLiteral).typeOf != val.type) {
interpreter->errorOutput("Bad argument type in _set\n");
return -1;
}
}
if (!IS_INTEGER(key)) {
interpreter->errorOutput("Expected integer index in _set\n");
return -1;
}
if (AS_ARRAY(obj)->count <= AS_INTEGER(key) || AS_INTEGER(key) < 0) {
interpreter->errorOutput("Index out of bounds in _set\n");
return -1;
}
//don't use pushLiteralArray, since we're setting
freeLiteral(AS_ARRAY(obj)->literals[AS_INTEGER(key)]); //BUGFIX: clear any existing data first
AS_ARRAY(obj)->literals[AS_INTEGER(key)] = copyLiteral(val);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to array in _set: \"");
printLiteralCustom(val, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return -1;
}
break;
}
case LITERAL_DICTIONARY: {
Literal typeLiteral = getScopeType(interpreter->scope, key);
if (AS_TYPE(typeLiteral).typeOf == LITERAL_DICTIONARY) {
Literal keySubtypeLiteral = ((Literal*)(AS_TYPE(typeLiteral).subtypes))[0];
Literal valSubtypeLiteral = ((Literal*)(AS_TYPE(typeLiteral).subtypes))[1];
if (AS_TYPE(keySubtypeLiteral).typeOf != LITERAL_ANY && AS_TYPE(keySubtypeLiteral).typeOf != key.type) {
interpreter->printOutput("bad argument type in _set\n");
return -1;
}
if (AS_TYPE(valSubtypeLiteral).typeOf != LITERAL_ANY && AS_TYPE(valSubtypeLiteral).typeOf != val.type) {
interpreter->printOutput("bad argument type in _set\n");
return -1;
}
}
setLiteralDictionary(AS_DICTIONARY(obj), key, val);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to dictionary in _set: \"");
printLiteralCustom(val, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return -1;
}
break;
}
default:
interpreter->errorOutput("Incorrect compound type in _set: ");
printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return -1;
}
freeLiteral(obj);
if (freeKey) {
freeLiteral(key);
}
if (freeVal) {
freeLiteral(val);
}
return 0;
}
int _get(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _get");
return -1;
}
Literal obj = arguments->literals[0];
Literal key = arguments->literals[1];
bool freeObj = false;
if (IS_IDENTIFIER(obj)) {
parseIdentifierToValue(interpreter, &obj);
freeObj = true;
}
bool freeKey = false;
if (IS_IDENTIFIER(key)) {
parseIdentifierToValue(interpreter, &key);
freeKey = true;
}
switch(obj.type) {
case LITERAL_ARRAY: {
if (!IS_INTEGER(key)) {
interpreter->errorOutput("Expected integer index in _get\n");
return -1;
}
if (AS_ARRAY(obj)->count <= AS_INTEGER(key) || AS_INTEGER(key) < 0) {
interpreter->errorOutput("Index out of bounds in _get\n");
return -1;
}
pushLiteralArray(&interpreter->stack, AS_ARRAY(obj)->literals[AS_INTEGER(key)]);
if (freeObj) {
freeLiteral(obj);
}
if (freeKey) {
freeLiteral(key);
}
return 1;
}
case LITERAL_DICTIONARY: {
Literal dict = getLiteralDictionary(AS_DICTIONARY(obj), key);
pushLiteralArray(&interpreter->stack, dict);
freeLiteral(dict);
if (freeObj) {
freeLiteral(obj);
}
if (freeKey) {
freeLiteral(key);
}
return 1;
}
default:
interpreter->errorOutput("Incorrect compound type in _get \"");
printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return -1;
}
}
int _push(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to _push\n");
return -1;
}
Literal idn = arguments->literals[0];
Literal obj = arguments->literals[0];
Literal val = arguments->literals[1];
if (!IS_IDENTIFIER(idn)) {
interpreter->errorOutput("Expected identifier in _push\n");
return -1;
}
parseIdentifierToValue(interpreter, &obj);
bool freeVal = false;
if (IS_IDENTIFIER(val)) {
parseIdentifierToValue(interpreter, &val);
freeVal = true;
}
switch(obj.type) {
case LITERAL_ARRAY: {
Literal typeLiteral = getScopeType(interpreter->scope, val);
if (AS_TYPE(typeLiteral).typeOf == LITERAL_ARRAY) {
Literal subtypeLiteral = ((Literal*)(AS_TYPE(typeLiteral).subtypes))[0];
if (AS_TYPE(subtypeLiteral).typeOf != LITERAL_ANY && AS_TYPE(subtypeLiteral).typeOf != val.type) {
interpreter->errorOutput("Bad argument type in _push");
return -1;
}
}
pushLiteralArray(AS_ARRAY(obj), val);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) { //TODO: could definitely be more efficient than overwriting the whole original object
interpreter->errorOutput("Incorrect type assigned to array in _push: \"");
printLiteralCustom(val, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return -1;
}
freeLiteral(obj);
if (freeVal) {
freeLiteral(val);
}
return 0;
}
default:
interpreter->errorOutput("Incorrect compound type in _push: ");
printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
}
int _pop(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _pop\n");
return -1;
}
Literal idn = arguments->literals[0];
Literal obj = arguments->literals[0];
if (!IS_IDENTIFIER(idn)) {
interpreter->errorOutput("Expected identifier in _pop\n");
return -1;
}
parseIdentifierToValue(interpreter, &obj);
switch(obj.type) {
case LITERAL_ARRAY: {
Literal lit = popLiteralArray(AS_ARRAY(obj));
pushLiteralArray(&interpreter->stack, lit);
freeLiteral(lit);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) { //TODO: could definitely be more efficient than overwriting the whole original object
interpreter->errorOutput("Incorrect type assigned to array in _pop: ");
printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
freeLiteral(obj);
return 1;
}
default:
interpreter->errorOutput("Incorrect compound type in _pop: ");
printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
}
int _length(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _get\n");
return -1;
}
Literal obj = arguments->literals[0];
bool freeObj = false;
if (IS_IDENTIFIER(obj)) {
parseIdentifierToValue(interpreter, &obj);
freeObj = true;
}
switch(obj.type) {
case LITERAL_ARRAY: {
Literal lit = TO_INTEGER_LITERAL( AS_ARRAY(obj)->count );
pushLiteralArray(&interpreter->stack, lit);
freeLiteral(lit);
break;
}
case LITERAL_DICTIONARY: {
Literal lit = TO_INTEGER_LITERAL( AS_DICTIONARY(obj)->count );
pushLiteralArray(&interpreter->stack, lit);
freeLiteral(lit);
break;
}
case LITERAL_STRING: {
Literal lit = TO_INTEGER_LITERAL( strlen(AS_STRING(obj)) );
pushLiteralArray(&interpreter->stack, lit);
freeLiteral(lit);
break;
}
default:
interpreter->errorOutput("Incorrect compound type in _length: ");
printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
if (freeObj) {
freeLiteral(obj);
}
return 1;
}
int _clear(Interpreter* interpreter, LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to _clear\n");
return -1;
}
Literal idn = arguments->literals[0];
Literal obj = arguments->literals[0];
if (!IS_IDENTIFIER(idn)) {
interpreter->errorOutput("expected identifier in _clear\n");
return -1;
}
parseIdentifierToValue(interpreter, &obj);
//NOTE: just pass in new compounds
switch(obj.type) {
case LITERAL_ARRAY: {
LiteralArray* array = ALLOCATE(LiteralArray, 1);
initLiteralArray(array);
Literal obj = TO_ARRAY_LITERAL(array);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to array in _clear: ");
printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
freeLiteral(obj);
break;
}
case LITERAL_DICTIONARY: {
LiteralDictionary* dictionary = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(dictionary);
Literal obj = TO_DICTIONARY_LITERAL(dictionary);
if (!setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to dictionary in _clear: ");
printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
freeLiteral(obj);
break;
}
default:
interpreter->errorOutput("Incorrect compound type in _clear: ");
printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
freeLiteral(obj);
return 1;
}

11
source/lib_builtin.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include "interpreter.h"
int _set(Interpreter* interpreter, LiteralArray* arguments);
int _get(Interpreter* interpreter, LiteralArray* arguments);
int _push(Interpreter* interpreter, LiteralArray* arguments);
int _pop(Interpreter* interpreter, LiteralArray* arguments);
int _length(Interpreter* interpreter, LiteralArray* arguments);
int _clear(Interpreter* interpreter, LiteralArray* arguments);

View File

@@ -65,10 +65,3 @@ int findLiteralIndex(LiteralArray* array, Literal literal) {
return -1;
}
void printLiteralArray(LiteralArray* array, const char* delim) {
for (int i = 0; i < array->count; i++) {
printLiteral(array->literals[i]);
printf("%s", delim);
}
}

View File

@@ -14,5 +14,3 @@ Literal popLiteralArray(LiteralArray* array);
void freeLiteralArray(LiteralArray* array);
int findLiteralIndex(LiteralArray* array, Literal literal);
void printLiteralArray(LiteralArray* array, const char* delim);