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

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;
}