Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f84cdff883 | |||
| f869c9425a | |||
| 76ddd5703e | |||
| 669808730e | |||
| e6d9809da5 | |||
| 502032e514 | |||
| 6e9d42f892 | |||
| 70ca27486e | |||
| 12fa434e0f | |||
| efc1e764d2 | |||
| c5c0122243 | |||
| 348b7b8c24 | |||
| e243ad949a | |||
| 9b673f23ad | |||
| 624a0c80ba |
+317
-47
@@ -7,6 +7,61 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
|
//no arguments
|
||||||
|
if (arguments->count != 0) {
|
||||||
|
interpreter->errorOutput("Incorrect number of arguments to clock\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the time from C (what a pain)
|
||||||
|
time_t rawtime = time(NULL);
|
||||||
|
struct tm* timeinfo = localtime( &rawtime );
|
||||||
|
char* timestr = asctime(timeinfo);
|
||||||
|
|
||||||
|
//push to the stack
|
||||||
|
size_t len = strlen(timestr) - 1; //-1 for the newline
|
||||||
|
Toy_Literal timeLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(timestr, len));
|
||||||
|
|
||||||
|
//push to the stack
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
Toy_freeLiteral(timeLiteral);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nativeHash(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
|
if (arguments->count != 1) {
|
||||||
|
interpreter->errorOutput("Incorrect number of arguments to hash\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the self
|
||||||
|
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
|
//parse to value if needed
|
||||||
|
Toy_Literal selfLiteralIdn = selfLiteral;
|
||||||
|
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
|
||||||
|
Toy_freeLiteral(selfLiteralIdn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_IS_IDENTIFIER(selfLiteral)) {
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Literal result = TOY_TO_INTEGER_LITERAL(Toy_hashLiteral(selfLiteral));
|
||||||
|
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, result);
|
||||||
|
|
||||||
|
Toy_freeLiteral(result);
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int nativeAbs(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
static int nativeAbs(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
if (arguments->count != 1) {
|
if (arguments->count != 1) {
|
||||||
interpreter->errorOutput("Incorrect number of arguments to abs\n");
|
interpreter->errorOutput("Incorrect number of arguments to abs\n");
|
||||||
@@ -50,27 +105,262 @@ static int nativeAbs(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeClock(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
static int nativeCeil(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
if (arguments->count != 1) {
|
||||||
if (arguments->count != 0) {
|
interpreter->errorOutput("Incorrect number of arguments to ceil\n");
|
||||||
interpreter->errorOutput("Incorrect number of arguments to clock\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the time from C (what a pain)
|
//get the self
|
||||||
time_t rawtime = time(NULL);
|
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
|
||||||
struct tm* timeinfo = localtime( &rawtime );
|
|
||||||
char* timestr = asctime(timeinfo);
|
|
||||||
|
|
||||||
//push to the stack
|
//parse to value if needed
|
||||||
size_t len = strlen(timestr) - 1; //-1 for the newline
|
Toy_Literal selfLiteralIdn = selfLiteral;
|
||||||
Toy_Literal timeLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(timestr, len));
|
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
|
||||||
|
Toy_freeLiteral(selfLiteralIdn);
|
||||||
|
}
|
||||||
|
|
||||||
//push to the stack
|
if (TOY_IS_IDENTIFIER(selfLiteral)) {
|
||||||
Toy_pushLiteralArray(&interpreter->stack, timeLiteral);
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
//cleanup
|
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
|
||||||
Toy_freeLiteral(timeLiteral);
|
interpreter->errorOutput("Incorrect argument type passed to ceil\n");
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Literal result;
|
||||||
|
|
||||||
|
if (TOY_IS_INTEGER(selfLiteral)) {
|
||||||
|
//NO-OP
|
||||||
|
result = Toy_copyLiteral(selfLiteral);
|
||||||
|
}
|
||||||
|
if (TOY_IS_FLOAT(selfLiteral)) {
|
||||||
|
result = TOY_TO_INTEGER_LITERAL( (int)TOY_AS_FLOAT(selfLiteral) - TOY_AS_FLOAT(selfLiteral) == 0 ? (int)TOY_AS_FLOAT(selfLiteral) : (int)TOY_AS_FLOAT(selfLiteral) + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, result);
|
||||||
|
|
||||||
|
Toy_freeLiteral(result);
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nativeFloor(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
|
if (arguments->count != 1) {
|
||||||
|
interpreter->errorOutput("Incorrect number of arguments to floor\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the self
|
||||||
|
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
|
//parse to value if needed
|
||||||
|
Toy_Literal selfLiteralIdn = selfLiteral;
|
||||||
|
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
|
||||||
|
Toy_freeLiteral(selfLiteralIdn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_IS_IDENTIFIER(selfLiteral)) {
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to floor\n");
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Literal result;
|
||||||
|
|
||||||
|
if (TOY_IS_INTEGER(selfLiteral)) {
|
||||||
|
//NO-OP
|
||||||
|
result = Toy_copyLiteral(selfLiteral);
|
||||||
|
}
|
||||||
|
if (TOY_IS_FLOAT(selfLiteral)) {
|
||||||
|
result = TOY_TO_INTEGER_LITERAL( (int)TOY_AS_FLOAT(selfLiteral) );
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, result);
|
||||||
|
|
||||||
|
Toy_freeLiteral(result);
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nativeMax(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
|
//return value
|
||||||
|
Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL;
|
||||||
|
|
||||||
|
//iterate over all arguments
|
||||||
|
do {
|
||||||
|
//get the self
|
||||||
|
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
|
//parse to value if needed
|
||||||
|
Toy_Literal selfLiteralIdn = selfLiteral;
|
||||||
|
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
|
||||||
|
Toy_freeLiteral(selfLiteralIdn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_IS_IDENTIFIER(selfLiteral)) {
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to max\n");
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if not comparing yet...
|
||||||
|
if (TOY_IS_NULL(resultLiteral)) {
|
||||||
|
resultLiteral = selfLiteral;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cooerce if needed
|
||||||
|
if (TOY_IS_INTEGER(resultLiteral) && TOY_IS_FLOAT(selfLiteral)) {
|
||||||
|
resultLiteral = TOY_TO_FLOAT_LITERAL( TOY_AS_INTEGER(resultLiteral) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_IS_FLOAT(resultLiteral) && TOY_IS_INTEGER(selfLiteral)) {
|
||||||
|
selfLiteral = TOY_TO_FLOAT_LITERAL( TOY_AS_INTEGER(selfLiteral) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//compare
|
||||||
|
if (TOY_IS_INTEGER(resultLiteral) && TOY_AS_INTEGER(resultLiteral) < TOY_AS_INTEGER(selfLiteral)) {
|
||||||
|
//NOTE: just ints, don't free
|
||||||
|
resultLiteral = selfLiteral;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (TOY_IS_FLOAT(resultLiteral) && TOY_AS_FLOAT(resultLiteral) < TOY_AS_FLOAT(selfLiteral)) {
|
||||||
|
//NOTE: just floats, don't free
|
||||||
|
resultLiteral = selfLiteral;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (arguments->count > 0);
|
||||||
|
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||||
|
|
||||||
|
Toy_freeLiteral(resultLiteral);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nativeMin(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
|
//return value
|
||||||
|
Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL;
|
||||||
|
|
||||||
|
//iterate over all arguments
|
||||||
|
do {
|
||||||
|
//get the self
|
||||||
|
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
|
//parse to value if needed
|
||||||
|
Toy_Literal selfLiteralIdn = selfLiteral;
|
||||||
|
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
|
||||||
|
Toy_freeLiteral(selfLiteralIdn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_IS_IDENTIFIER(selfLiteral)) {
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to min\n");
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if not comparing yet...
|
||||||
|
if (TOY_IS_NULL(resultLiteral)) {
|
||||||
|
resultLiteral = selfLiteral;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cooerce if needed
|
||||||
|
if (TOY_IS_INTEGER(resultLiteral) && TOY_IS_FLOAT(selfLiteral)) {
|
||||||
|
resultLiteral = TOY_TO_FLOAT_LITERAL( TOY_AS_INTEGER(resultLiteral) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_IS_FLOAT(resultLiteral) && TOY_IS_INTEGER(selfLiteral)) {
|
||||||
|
selfLiteral = TOY_TO_FLOAT_LITERAL( TOY_AS_INTEGER(selfLiteral) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//compare
|
||||||
|
if (TOY_IS_INTEGER(resultLiteral) && TOY_AS_INTEGER(resultLiteral) > TOY_AS_INTEGER(selfLiteral)) {
|
||||||
|
//NOTE: just ints, don't free
|
||||||
|
resultLiteral = selfLiteral;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (TOY_IS_FLOAT(resultLiteral) && TOY_AS_FLOAT(resultLiteral) > TOY_AS_FLOAT(selfLiteral)) {
|
||||||
|
//NOTE: just floats, don't free
|
||||||
|
resultLiteral = selfLiteral;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (arguments->count > 0);
|
||||||
|
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||||
|
|
||||||
|
Toy_freeLiteral(resultLiteral);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nativeRound(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
|
if (arguments->count != 1) {
|
||||||
|
interpreter->errorOutput("Incorrect number of arguments to round\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the self
|
||||||
|
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
|
||||||
|
|
||||||
|
//parse to value if needed
|
||||||
|
Toy_Literal selfLiteralIdn = selfLiteral;
|
||||||
|
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
|
||||||
|
Toy_freeLiteral(selfLiteralIdn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_IS_IDENTIFIER(selfLiteral)) {
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(TOY_IS_INTEGER(selfLiteral) || TOY_IS_FLOAT(selfLiteral))) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to round\n");
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Literal result;
|
||||||
|
|
||||||
|
if (TOY_IS_INTEGER(selfLiteral)) {
|
||||||
|
//NO-OP
|
||||||
|
result = Toy_copyLiteral(selfLiteral);
|
||||||
|
}
|
||||||
|
if (TOY_IS_FLOAT(selfLiteral)) {
|
||||||
|
//catch the already-rounded case
|
||||||
|
if (TOY_AS_FLOAT(selfLiteral) == (int)TOY_AS_FLOAT(selfLiteral)) {
|
||||||
|
result = TOY_TO_INTEGER_LITERAL((int)TOY_AS_FLOAT(selfLiteral));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = TOY_TO_INTEGER_LITERAL( TOY_AS_FLOAT(selfLiteral) - (int)TOY_AS_FLOAT(selfLiteral) < 0.5 ? (int)TOY_AS_FLOAT(selfLiteral) : (int)TOY_AS_FLOAT(selfLiteral) + 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, result);
|
||||||
|
|
||||||
|
Toy_freeLiteral(result);
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -745,36 +1035,6 @@ static int nativeGetValues(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nativeHash(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
|
||||||
if (arguments->count != 1) {
|
|
||||||
interpreter->errorOutput("Incorrect number of arguments to hash\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//get the self
|
|
||||||
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
|
|
||||||
|
|
||||||
//parse to value if needed
|
|
||||||
Toy_Literal selfLiteralIdn = selfLiteral;
|
|
||||||
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
|
|
||||||
Toy_freeLiteral(selfLiteralIdn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TOY_IS_IDENTIFIER(selfLiteral)) {
|
|
||||||
Toy_freeLiteral(selfLiteral);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_Literal result = TOY_TO_INTEGER_LITERAL(Toy_hashLiteral(selfLiteral));
|
|
||||||
|
|
||||||
Toy_pushLiteralArray(&interpreter->stack, result);
|
|
||||||
|
|
||||||
Toy_freeLiteral(result);
|
|
||||||
Toy_freeLiteral(selfLiteral);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nativeIndexOf(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
static int nativeIndexOf(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
//no arguments
|
//no arguments
|
||||||
if (arguments->count != 2) {
|
if (arguments->count != 2) {
|
||||||
@@ -1740,8 +2000,19 @@ typedef struct Natives {
|
|||||||
int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_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[] = {
|
||||||
{"abs", nativeAbs},
|
//misc. utils
|
||||||
{"clock", nativeClock},
|
{"clock", nativeClock},
|
||||||
|
{"hash", nativeHash},
|
||||||
|
|
||||||
|
//math utils
|
||||||
|
{"abs", nativeAbs},
|
||||||
|
{"ceil", nativeCeil},
|
||||||
|
{"floor", nativeFloor},
|
||||||
|
{"max", nativeMax},
|
||||||
|
{"min", nativeMin},
|
||||||
|
{"round", nativeRound},
|
||||||
|
|
||||||
|
//compound utils
|
||||||
{"concat", nativeConcat}, //array, dictionary, string
|
{"concat", nativeConcat}, //array, dictionary, string
|
||||||
{"containsKey", nativeContainsKey}, //dictionary
|
{"containsKey", nativeContainsKey}, //dictionary
|
||||||
{"containsValue", nativeContainsValue}, //array, dictionary
|
{"containsValue", nativeContainsValue}, //array, dictionary
|
||||||
@@ -1750,7 +2021,6 @@ int Toy_hookStandard(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_L
|
|||||||
{"forEach", nativeForEach}, //array, dictionary
|
{"forEach", nativeForEach}, //array, dictionary
|
||||||
{"getKeys", nativeGetKeys}, //dictionary
|
{"getKeys", nativeGetKeys}, //dictionary
|
||||||
{"getValues", nativeGetValues}, //dictionary
|
{"getValues", nativeGetValues}, //dictionary
|
||||||
{"hash", nativeHash},
|
|
||||||
{"indexOf", nativeIndexOf}, //array
|
{"indexOf", nativeIndexOf}, //array
|
||||||
{"map", nativeMap}, //array, dictionary
|
{"map", nativeMap}, //array, dictionary
|
||||||
{"reduce", nativeReduce}, //array, dictionary
|
{"reduce", nativeReduce}, //array, dictionary
|
||||||
|
|||||||
+15
-9
@@ -40,17 +40,21 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_AST_NODE_BLOCK:
|
case TOY_AST_NODE_BLOCK:
|
||||||
for (int i = 0; i < node->block.count; i++) {
|
if (node->block.capacity > 0) {
|
||||||
freeASTNodeCustom(node->block.nodes + i, false);
|
for (int i = 0; i < node->block.count; i++) {
|
||||||
|
freeASTNodeCustom(node->block.nodes + i, false);
|
||||||
|
}
|
||||||
|
TOY_FREE_ARRAY(Toy_ASTNode, node->block.nodes, node->block.capacity);
|
||||||
}
|
}
|
||||||
TOY_FREE_ARRAY(Toy_ASTNode, node->block.nodes, node->block.capacity);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_AST_NODE_COMPOUND:
|
case TOY_AST_NODE_COMPOUND:
|
||||||
for (int i = 0; i < node->compound.count; i++) {
|
if (node->compound.capacity > 0) {
|
||||||
freeASTNodeCustom(node->compound.nodes + i, false);
|
for (int i = 0; i < node->compound.count; i++) {
|
||||||
|
freeASTNodeCustom(node->compound.nodes + i, false);
|
||||||
|
}
|
||||||
|
TOY_FREE_ARRAY(Toy_ASTNode, node->compound.nodes, node->compound.capacity);
|
||||||
}
|
}
|
||||||
TOY_FREE_ARRAY(Toy_ASTNode, node->compound.nodes, node->compound.capacity);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_AST_NODE_PAIR:
|
case TOY_AST_NODE_PAIR:
|
||||||
@@ -71,10 +75,12 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_AST_NODE_FN_COLLECTION:
|
case TOY_AST_NODE_FN_COLLECTION:
|
||||||
for (int i = 0; i < node->fnCollection.count; i++) {
|
if (node->fnCollection.capacity > 0) {
|
||||||
freeASTNodeCustom(node->fnCollection.nodes + i, false);
|
for (int i = 0; i < node->fnCollection.count; i++) {
|
||||||
|
freeASTNodeCustom(node->fnCollection.nodes + i, false);
|
||||||
|
}
|
||||||
|
TOY_FREE_ARRAY(Toy_ASTNode, node->fnCollection.nodes, node->fnCollection.capacity);
|
||||||
}
|
}
|
||||||
TOY_FREE_ARRAY(Toy_ASTNode, node->fnCollection.nodes, node->fnCollection.capacity);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_AST_NODE_FN_DECL:
|
case TOY_AST_NODE_FN_DECL:
|
||||||
|
|||||||
@@ -621,7 +621,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
|||||||
|
|
||||||
//simple indexing assignment if second is null
|
//simple indexing assignment if second is null
|
||||||
if (TOY_IS_NULL(second)) {
|
if (TOY_IS_NULL(second)) {
|
||||||
bool ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if (!Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, assign)) {
|
if (!Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, assign)) {
|
||||||
interpreter->errorOutput("Array index out of bounds in assignment");
|
interpreter->errorOutput("Array index out of bounds in assignment");
|
||||||
@@ -629,6 +629,7 @@ int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Toy_pushLiteralArray(&interpreter->stack, compound); //leave the array on the stack
|
Toy_pushLiteralArray(&interpreter->stack, compound); //leave the array on the stack
|
||||||
|
//...
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1385,7 +1386,7 @@ int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
|||||||
Toy_Literal subtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0];
|
Toy_Literal subtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0];
|
||||||
|
|
||||||
if (TOY_AS_TYPE(subtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(subtypeLiteral).typeOf != val.type) {
|
if (TOY_AS_TYPE(subtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(subtypeLiteral).typeOf != val.type) {
|
||||||
interpreter->errorOutput("Bad argument type in push");
|
interpreter->errorOutput("Bad argument type in push\n");
|
||||||
Toy_freeLiteral(typeLiteral);
|
Toy_freeLiteral(typeLiteral);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#define TOY_VERSION_MAJOR 1
|
#define TOY_VERSION_MAJOR 1
|
||||||
#define TOY_VERSION_MINOR 1
|
#define TOY_VERSION_MINOR 1
|
||||||
#define TOY_VERSION_PATCH 0
|
#define TOY_VERSION_PATCH 1
|
||||||
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
|
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
|
||||||
|
|
||||||
//platform/compiler-specific instructions
|
//platform/compiler-specific instructions
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ static int writeNodeCompoundToCache(Toy_Compiler* compiler, Toy_ASTNode* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//push the store to the cache, with instructions about how pack it
|
//push the store to the cache, with instructions about how pack it
|
||||||
Toy_Literal literal = TOY_TO_DICTIONARY_LITERAL(store);
|
Toy_Literal literal = TOY_TO_DICTIONARY_LITERAL((Toy_LiteralDictionary*)store); //cast from array to dict, because it's intermediate
|
||||||
literal.type = TOY_LITERAL_DICTIONARY_INTERMEDIATE; //god damn it - nested in a dictionary
|
literal.type = TOY_LITERAL_DICTIONARY_INTERMEDIATE; //god damn it - nested in a dictionary
|
||||||
index = Toy_pushLiteralArray(&compiler->literalCache, literal);
|
index = Toy_pushLiteralArray(&compiler->literalCache, literal);
|
||||||
Toy_freeLiteral(literal);
|
Toy_freeLiteral(literal);
|
||||||
|
|||||||
+127
-153
@@ -1651,7 +1651,7 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) {
|
if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) {
|
||||||
interpreter->errorOutput("Unknown compound found in indexing notation: ");
|
interpreter->errorOutput("Unknown compound found in index notation: ");
|
||||||
Toy_printLiteralCustom(compound, interpreter->errorOutput);
|
Toy_printLiteralCustom(compound, interpreter->errorOutput);
|
||||||
interpreter->errorOutput("\n");
|
interpreter->errorOutput("\n");
|
||||||
|
|
||||||
@@ -1689,7 +1689,7 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
|
|||||||
Toy_pushLiteralArray(&interpreter->stack, third);
|
Toy_pushLiteralArray(&interpreter->stack, third);
|
||||||
}
|
}
|
||||||
|
|
||||||
//call the _index function
|
//call the index function
|
||||||
if (Toy_private_index(interpreter, &arguments) < 0) {
|
if (Toy_private_index(interpreter, &arguments) < 0) {
|
||||||
interpreter->errorOutput("Something went wrong while indexing (simple index): ");
|
interpreter->errorOutput("Something went wrong while indexing (simple index): ");
|
||||||
Toy_printLiteralCustom(compoundIdn, interpreter->errorOutput);
|
Toy_printLiteralCustom(compoundIdn, interpreter->errorOutput);
|
||||||
@@ -1720,85 +1720,101 @@ static bool execIndex(Toy_Interpreter* interpreter, bool assignIntermediate) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool execIndexAssign(Toy_Interpreter* interpreter) {
|
static bool execIndexAssign(Toy_Interpreter* interpreter, int assignDepth) {
|
||||||
//assume -> compound, first, second, third, assign are all on the stack
|
//assume -> compound, first, second, third, assign are all on the stack
|
||||||
|
|
||||||
Toy_Literal assign = Toy_popLiteralArray(&interpreter->stack);
|
Toy_Literal assign = TOY_TO_NULL_LITERAL, third = TOY_TO_NULL_LITERAL, second = TOY_TO_NULL_LITERAL, first = TOY_TO_NULL_LITERAL, compound = TOY_TO_NULL_LITERAL, result = TOY_TO_NULL_LITERAL;
|
||||||
Toy_Literal third = Toy_popLiteralArray(&interpreter->stack);
|
Toy_Literal compoundIdn = TOY_TO_NULL_LITERAL;
|
||||||
Toy_Literal second = Toy_popLiteralArray(&interpreter->stack);
|
|
||||||
Toy_Literal first = Toy_popLiteralArray(&interpreter->stack);
|
|
||||||
Toy_Literal compound = Toy_popLiteralArray(&interpreter->stack);
|
|
||||||
|
|
||||||
Toy_Literal assignIdn = assign;
|
|
||||||
if (TOY_IS_IDENTIFIER(assign) && Toy_parseIdentifierToValue(interpreter, &assign)) {
|
|
||||||
Toy_freeLiteral(assignIdn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TOY_IS_IDENTIFIER(assign)) {
|
|
||||||
Toy_freeLiteral(compound);
|
|
||||||
Toy_freeLiteral(first);
|
|
||||||
Toy_freeLiteral(second);
|
|
||||||
Toy_freeLiteral(third);
|
|
||||||
Toy_freeLiteral(assign);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_Literal compoundIdn = compound;
|
|
||||||
bool freeIdn = false;
|
bool freeIdn = false;
|
||||||
if (TOY_IS_IDENTIFIER(compound) && Toy_parseIdentifierToValue(interpreter, &compound)) {
|
|
||||||
freeIdn = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TOY_IS_IDENTIFIER(compound)) {
|
|
||||||
Toy_freeLiteral(compound);
|
|
||||||
Toy_freeLiteral(first);
|
|
||||||
Toy_freeLiteral(second);
|
|
||||||
Toy_freeLiteral(third);
|
|
||||||
Toy_freeLiteral(assign);
|
|
||||||
if (freeIdn) {
|
|
||||||
Toy_freeLiteral(compoundIdn);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) {
|
|
||||||
interpreter->errorOutput("Unknown compound found in index assigning notation\n");
|
|
||||||
Toy_freeLiteral(assign);
|
|
||||||
Toy_freeLiteral(third);
|
|
||||||
Toy_freeLiteral(second);
|
|
||||||
Toy_freeLiteral(first);
|
|
||||||
Toy_freeLiteral(compound);
|
|
||||||
if (freeIdn) {
|
|
||||||
Toy_freeLiteral(compoundIdn);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//build the opcode
|
//build the opcode
|
||||||
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
||||||
char* opStr = "";
|
char* opStr = "";
|
||||||
switch(opcode) {
|
switch (opcode) {
|
||||||
case TOY_OP_VAR_ASSIGN:
|
case TOY_OP_VAR_ASSIGN:
|
||||||
opStr = "=";
|
opStr = "=";
|
||||||
break;
|
break;
|
||||||
case TOY_OP_VAR_ADDITION_ASSIGN:
|
case TOY_OP_VAR_ADDITION_ASSIGN:
|
||||||
opStr = "+=";
|
opStr = "+=";
|
||||||
break;
|
break;
|
||||||
case TOY_OP_VAR_SUBTRACTION_ASSIGN:
|
case TOY_OP_VAR_SUBTRACTION_ASSIGN:
|
||||||
opStr = "-=";
|
opStr = "-=";
|
||||||
break;
|
break;
|
||||||
case TOY_OP_VAR_MULTIPLICATION_ASSIGN:
|
case TOY_OP_VAR_MULTIPLICATION_ASSIGN:
|
||||||
opStr = "*=";
|
opStr = "*=";
|
||||||
break;
|
break;
|
||||||
case TOY_OP_VAR_DIVISION_ASSIGN:
|
case TOY_OP_VAR_DIVISION_ASSIGN:
|
||||||
opStr = "/=";
|
opStr = "/=";
|
||||||
break;
|
break;
|
||||||
case TOY_OP_VAR_MODULO_ASSIGN:
|
case TOY_OP_VAR_MODULO_ASSIGN:
|
||||||
opStr = "%=";
|
opStr = "%=";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
interpreter->errorOutput("bad opcode in index assigning notation\n");
|
interpreter->errorOutput("bad opcode in index assigning notation\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//iterate...
|
||||||
|
while(assignDepth-- >= 0) {
|
||||||
|
Toy_freeLiteral(assign);
|
||||||
|
Toy_freeLiteral(third);
|
||||||
|
Toy_freeLiteral(second);
|
||||||
|
Toy_freeLiteral(first);
|
||||||
|
Toy_freeLiteral(compound);
|
||||||
|
|
||||||
|
if (TOY_IS_NULL(result)) {
|
||||||
|
assign = Toy_popLiteralArray(&interpreter->stack);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assign = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
third = Toy_popLiteralArray(&interpreter->stack);
|
||||||
|
second = Toy_popLiteralArray(&interpreter->stack);
|
||||||
|
first = Toy_popLiteralArray(&interpreter->stack);
|
||||||
|
compound = Toy_popLiteralArray(&interpreter->stack);
|
||||||
|
|
||||||
|
if (TOY_IS_IDENTIFIER(compound)) {
|
||||||
|
if (freeIdn) {
|
||||||
|
Toy_freeLiteral(compoundIdn);
|
||||||
|
}
|
||||||
|
|
||||||
|
compoundIdn = compound;
|
||||||
|
Toy_parseIdentifierToValue(interpreter, &compound);
|
||||||
|
freeIdn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_IS_IDENTIFIER(compound)) {
|
||||||
|
Toy_freeLiteral(compound);
|
||||||
|
Toy_freeLiteral(first);
|
||||||
|
Toy_freeLiteral(second);
|
||||||
|
Toy_freeLiteral(third);
|
||||||
|
Toy_freeLiteral(assign);
|
||||||
|
if (freeIdn) {
|
||||||
|
Toy_freeLiteral(compoundIdn);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Literal assignIdn = assign;
|
||||||
|
if (TOY_IS_IDENTIFIER(assign) && Toy_parseIdentifierToValue(interpreter, &assign)) {
|
||||||
|
Toy_freeLiteral(assignIdn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_IS_IDENTIFIER(assign)) {
|
||||||
|
Toy_freeLiteral(compound);
|
||||||
|
Toy_freeLiteral(first);
|
||||||
|
Toy_freeLiteral(second);
|
||||||
|
Toy_freeLiteral(third);
|
||||||
|
Toy_freeLiteral(assign);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TOY_IS_ARRAY(compound) && !TOY_IS_DICTIONARY(compound) && !TOY_IS_STRING(compound)) {
|
||||||
|
interpreter->errorOutput("Unknown compound found in index assigning notation: ");
|
||||||
|
Toy_printLiteralCustom(compound, interpreter->errorOutput);
|
||||||
|
interpreter->errorOutput("\n");
|
||||||
Toy_freeLiteral(assign);
|
Toy_freeLiteral(assign);
|
||||||
Toy_freeLiteral(third);
|
Toy_freeLiteral(third);
|
||||||
Toy_freeLiteral(second);
|
Toy_freeLiteral(second);
|
||||||
@@ -1808,103 +1824,60 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
|
|||||||
Toy_freeLiteral(compoundIdn);
|
Toy_freeLiteral(compoundIdn);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
int opLength = strlen(opStr);
|
|
||||||
Toy_Literal op = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(opStr, opLength)); //TODO: static reference optimisation?
|
|
||||||
|
|
||||||
//build the argument list
|
|
||||||
Toy_LiteralArray arguments;
|
|
||||||
Toy_initLiteralArray(&arguments);
|
|
||||||
|
|
||||||
Toy_pushLiteralArray(&arguments, compound);
|
|
||||||
Toy_pushLiteralArray(&arguments, first);
|
|
||||||
Toy_pushLiteralArray(&arguments, second);
|
|
||||||
Toy_pushLiteralArray(&arguments, third);
|
|
||||||
Toy_pushLiteralArray(&arguments, assign); //it expects an assignment command
|
|
||||||
Toy_pushLiteralArray(&arguments, op); //it expects an assignment "opcode"
|
|
||||||
|
|
||||||
//call the _index function
|
|
||||||
if (Toy_private_index(interpreter, &arguments) < 0) {
|
|
||||||
//clean up
|
|
||||||
Toy_freeLiteral(assign);
|
|
||||||
Toy_freeLiteral(third);
|
|
||||||
Toy_freeLiteral(second);
|
|
||||||
Toy_freeLiteral(first);
|
|
||||||
Toy_freeLiteral(compound);
|
|
||||||
if (freeIdn) {
|
|
||||||
Toy_freeLiteral(compoundIdn);
|
|
||||||
}
|
}
|
||||||
Toy_freeLiteral(op);
|
|
||||||
Toy_freeLiteralArray(&arguments);
|
|
||||||
|
|
||||||
return false;
|
int opLength = strlen(opStr);
|
||||||
}
|
Toy_Literal op = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(opStr, opLength)); //TODO: static reference optimisation?
|
||||||
|
|
||||||
//save the result (assume top of the interpreter stack is the new compound value)
|
//build the argument list
|
||||||
Toy_Literal result = Toy_popLiteralArray(&interpreter->stack);
|
Toy_LiteralArray arguments;
|
||||||
|
Toy_initLiteralArray(&arguments);
|
||||||
|
|
||||||
//deep
|
Toy_pushLiteralArray(&arguments, compound);
|
||||||
if (!freeIdn) {
|
Toy_pushLiteralArray(&arguments, first);
|
||||||
while (interpreter->stack.count > 1) {
|
Toy_pushLiteralArray(&arguments, second);
|
||||||
//read the new values
|
Toy_pushLiteralArray(&arguments, third);
|
||||||
Toy_freeLiteral(compound);
|
Toy_pushLiteralArray(&arguments, assign); //it expects an assignment command
|
||||||
|
Toy_pushLiteralArray(&arguments, op); //it expects an assignment "opcode"
|
||||||
|
|
||||||
|
//call the index function
|
||||||
|
if (Toy_private_index(interpreter, &arguments) < 0) {
|
||||||
|
//clean up
|
||||||
|
Toy_freeLiteral(assign);
|
||||||
Toy_freeLiteral(third);
|
Toy_freeLiteral(third);
|
||||||
Toy_freeLiteral(second);
|
Toy_freeLiteral(second);
|
||||||
Toy_freeLiteral(first);
|
Toy_freeLiteral(first);
|
||||||
Toy_freeLiteralArray(&arguments);
|
Toy_freeLiteral(compound);
|
||||||
Toy_initLiteralArray(&arguments);
|
if (freeIdn) {
|
||||||
Toy_freeLiteral(op);
|
Toy_freeLiteral(compoundIdn);
|
||||||
|
|
||||||
//reuse these like an idiot
|
|
||||||
third = Toy_popLiteralArray(&interpreter->stack);
|
|
||||||
second = Toy_popLiteralArray(&interpreter->stack);
|
|
||||||
first = Toy_popLiteralArray(&interpreter->stack);
|
|
||||||
compound = Toy_popLiteralArray(&interpreter->stack);
|
|
||||||
|
|
||||||
char* opStr = "="; //shadow, but force assignment
|
|
||||||
int opLength = strlen(opStr);
|
|
||||||
op = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(opStr, opLength)); //TODO: static reference optimisation?
|
|
||||||
|
|
||||||
//assign to the idn / compound - with _index
|
|
||||||
Toy_pushLiteralArray(&arguments, compound); //
|
|
||||||
Toy_pushLiteralArray(&arguments, first);
|
|
||||||
Toy_pushLiteralArray(&arguments, second);
|
|
||||||
Toy_pushLiteralArray(&arguments, third);
|
|
||||||
Toy_pushLiteralArray(&arguments, result);
|
|
||||||
Toy_pushLiteralArray(&arguments, op);
|
|
||||||
|
|
||||||
if (Toy_private_index(interpreter, &arguments) < 0) {
|
|
||||||
interpreter->errorOutput("Something went wrong while indexing (index assign): ");
|
|
||||||
Toy_printLiteralCustom(compound, interpreter->errorOutput);
|
|
||||||
interpreter->errorOutput("\n");
|
|
||||||
|
|
||||||
//clean up
|
|
||||||
Toy_freeLiteral(assign);
|
|
||||||
Toy_freeLiteral(third);
|
|
||||||
Toy_freeLiteral(second);
|
|
||||||
Toy_freeLiteral(first);
|
|
||||||
if (freeIdn) {
|
|
||||||
Toy_freeLiteral(compoundIdn);
|
|
||||||
}
|
|
||||||
Toy_freeLiteral(op);
|
|
||||||
Toy_freeLiteralArray(&arguments);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
Toy_freeLiteral(op);
|
||||||
|
Toy_freeLiteralArray(&arguments);
|
||||||
|
|
||||||
Toy_freeLiteral(result);
|
return false;
|
||||||
result = Toy_popLiteralArray(&interpreter->stack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_freeLiteral(compound);
|
//save the result (assume top of the interpreter stack is the new compound value)
|
||||||
compound = Toy_popLiteralArray(&interpreter->stack);
|
result = Toy_popLiteralArray(&interpreter->stack);
|
||||||
compoundIdn = compound;
|
|
||||||
freeIdn = false;
|
Toy_freeLiteral(op);
|
||||||
|
Toy_freeLiteralArray(&arguments);
|
||||||
|
|
||||||
|
//if we loop, then we need to be assigning
|
||||||
|
opStr = "=";
|
||||||
|
}
|
||||||
|
|
||||||
|
//BUGFIX: make sure the compound name can be assigned
|
||||||
|
if (TOY_IS_NULL(compoundIdn)) {
|
||||||
|
compoundIdn = Toy_popLiteralArray(&interpreter->stack);
|
||||||
|
freeIdn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TOY_IS_IDENTIFIER(compoundIdn) && !Toy_setScopeVariable(interpreter->scope, compoundIdn, result, true)) {
|
if (TOY_IS_IDENTIFIER(compoundIdn) && !Toy_setScopeVariable(interpreter->scope, compoundIdn, result, true)) {
|
||||||
interpreter->errorOutput("Incorrect type assigned to compound member ");
|
interpreter->errorOutput("Incorrect type assigned to compound member ");
|
||||||
Toy_printLiteralCustom(compoundIdn, interpreter->errorOutput);
|
Toy_printLiteralCustom(compoundIdn, interpreter->errorOutput);
|
||||||
|
interpreter->errorOutput(", value: ");
|
||||||
|
Toy_printLiteralCustom(result, interpreter->errorOutput);
|
||||||
interpreter->errorOutput("\n");
|
interpreter->errorOutput("\n");
|
||||||
|
|
||||||
//clean up
|
//clean up
|
||||||
@@ -1916,8 +1889,6 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
|
|||||||
if (freeIdn) {
|
if (freeIdn) {
|
||||||
Toy_freeLiteral(compoundIdn);
|
Toy_freeLiteral(compoundIdn);
|
||||||
}
|
}
|
||||||
Toy_freeLiteral(op);
|
|
||||||
Toy_freeLiteralArray(&arguments);
|
|
||||||
Toy_freeLiteral(result);
|
Toy_freeLiteral(result);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1931,8 +1902,6 @@ static bool execIndexAssign(Toy_Interpreter* interpreter) {
|
|||||||
if (freeIdn) {
|
if (freeIdn) {
|
||||||
Toy_freeLiteral(compoundIdn);
|
Toy_freeLiteral(compoundIdn);
|
||||||
}
|
}
|
||||||
Toy_freeLiteral(op);
|
|
||||||
Toy_freeLiteralArray(&arguments);
|
|
||||||
Toy_freeLiteral(result);
|
Toy_freeLiteral(result);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -1945,6 +1914,9 @@ static void execInterpreter(Toy_Interpreter* interpreter) {
|
|||||||
interpreter->codeStart = interpreter->count;
|
interpreter->codeStart = interpreter->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//BUGFIX
|
||||||
|
int intermediateAssignDepth = 0;
|
||||||
|
|
||||||
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
||||||
|
|
||||||
while(opcode != TOY_OP_EOF && opcode != TOY_OP_SECTION_END && !interpreter->panic) {
|
while(opcode != TOY_OP_EOF && opcode != TOY_OP_SECTION_END && !interpreter->panic) {
|
||||||
@@ -2159,12 +2131,14 @@ static void execInterpreter(Toy_Interpreter* interpreter) {
|
|||||||
if (!execIndex(interpreter, true)) {
|
if (!execIndex(interpreter, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
intermediateAssignDepth++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_OP_INDEX_ASSIGN:
|
case TOY_OP_INDEX_ASSIGN:
|
||||||
if (!execIndexAssign(interpreter)) {
|
if (!execIndexAssign(interpreter, intermediateAssignDepth)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
intermediateAssignDepth = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_OP_POP_STACK:
|
case TOY_OP_POP_STACK:
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ void Toy_freeLiteral(Toy_Literal literal) {
|
|||||||
TOY_FREE_ARRAY(unsigned char, TOY_AS_FUNCTION(literal).inner.bytecode, TOY_AS_FUNCTION_BYTECODE_LENGTH(literal));
|
TOY_FREE_ARRAY(unsigned char, TOY_AS_FUNCTION(literal).inner.bytecode, TOY_AS_FUNCTION_BYTECODE_LENGTH(literal));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TOY_IS_TYPE(literal)) {
|
if (TOY_IS_TYPE(literal) && TOY_AS_TYPE(literal).capacity > 0) {
|
||||||
for (int i = 0; i < TOY_AS_TYPE(literal).count; i++) {
|
for (int i = 0; i < TOY_AS_TYPE(literal).count; i++) {
|
||||||
Toy_freeLiteral(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i]);
|
Toy_freeLiteral(((Toy_Literal*)(TOY_AS_TYPE(literal).subtypes))[i]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
struct Toy_Literal;
|
struct Toy_Literal;
|
||||||
struct Toy_Interpreter;
|
struct Toy_Interpreter;
|
||||||
struct Toy_LiteralArray;
|
struct Toy_LiteralArray;
|
||||||
|
struct Toy_LiteralDictionary;
|
||||||
struct Toy_Scope;
|
struct Toy_Scope;
|
||||||
typedef int (*Toy_NativeFn)(struct Toy_Interpreter* interpreter, struct Toy_LiteralArray* arguments);
|
typedef int (*Toy_NativeFn)(struct Toy_Interpreter* interpreter, struct Toy_LiteralArray* arguments);
|
||||||
typedef int (*Toy_HookFn)(struct Toy_Interpreter* interpreter, struct Toy_Literal identifier, struct Toy_Literal alias);
|
typedef int (*Toy_HookFn)(struct Toy_Interpreter* interpreter, struct Toy_Literal identifier, struct Toy_Literal alias);
|
||||||
@@ -49,8 +50,8 @@ typedef struct Toy_Literal {
|
|||||||
//string hash?
|
//string hash?
|
||||||
} string; //8
|
} string; //8
|
||||||
|
|
||||||
void* array; //8
|
struct Toy_LiteralArray* array; //8
|
||||||
void* dictionary; //8
|
struct Toy_LiteralDictionary* dictionary; //8
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
union {
|
union {
|
||||||
@@ -67,7 +68,8 @@ typedef struct Toy_Literal {
|
|||||||
} identifier; //16
|
} identifier; //16
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
void* subtypes; //8
|
|
||||||
|
struct Toy_Literal* subtypes; //8
|
||||||
Toy_LiteralType typeOf; //4
|
Toy_LiteralType typeOf; //4
|
||||||
unsigned char capacity; //1
|
unsigned char capacity; //1
|
||||||
unsigned char count; //1
|
unsigned char count; //1
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ void Toy_freeLiteralArray(Toy_LiteralArray* array) {
|
|||||||
Toy_freeLiteral(array->literals[i]);
|
Toy_freeLiteral(array->literals[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOY_FREE_ARRAY(Toy_Literal, array->literals, array->capacity);
|
if (array->capacity > 0) {
|
||||||
Toy_initLiteralArray(array);
|
TOY_FREE_ARRAY(Toy_Literal, array->literals, array->capacity);
|
||||||
|
Toy_initLiteralArray(array);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Toy_pushLiteralArray(Toy_LiteralArray* array, Toy_Literal literal) {
|
int Toy_pushLiteralArray(Toy_LiteralArray* array, Toy_Literal literal) {
|
||||||
|
|||||||
@@ -22,11 +22,13 @@ static Toy_private_dictionary_entry* getEntryArray(Toy_private_dictionary_entry*
|
|||||||
}
|
}
|
||||||
|
|
||||||
//find "key", starting at index
|
//find "key", starting at index
|
||||||
unsigned int index = hash % capacity;
|
int index = hash % capacity;
|
||||||
unsigned int start = index;
|
int start = index;
|
||||||
|
|
||||||
//increment once, so it can't equal start
|
//increment once, so it can't equal start
|
||||||
index = (index + 1) % capacity;
|
if (++index >= capacity) {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//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
|
||||||
@@ -44,7 +46,10 @@ static Toy_private_dictionary_entry* getEntryArray(Toy_private_dictionary_entry*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
index = (index + 1) % capacity;
|
if (++index >= capacity) {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
//index = (index + 1) % capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -73,7 +78,9 @@ static void adjustEntryCapacity(Toy_private_dictionary_entry** dictionaryHandle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//clear the old array
|
//clear the old array
|
||||||
TOY_FREE_ARRAY(Toy_private_dictionary_entry, *dictionaryHandle, oldCapacity);
|
if (oldCapacity > 0) {
|
||||||
|
TOY_FREE_ARRAY(Toy_private_dictionary_entry, *dictionaryHandle, oldCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
*dictionaryHandle = newEntries;
|
*dictionaryHandle = newEntries;
|
||||||
}
|
}
|
||||||
@@ -133,9 +140,11 @@ void Toy_initLiteralDictionary(Toy_LiteralDictionary* dictionary) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Toy_freeLiteralDictionary(Toy_LiteralDictionary* dictionary) {
|
void Toy_freeLiteralDictionary(Toy_LiteralDictionary* dictionary) {
|
||||||
freeEntryArray(dictionary->entries, dictionary->capacity);
|
if (dictionary->capacity > 0) {
|
||||||
dictionary->capacity = 0;
|
freeEntryArray(dictionary->entries, dictionary->capacity);
|
||||||
dictionary->contains = 0;
|
dictionary->capacity = 0;
|
||||||
|
dictionary->contains = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key, Toy_Literal value) {
|
void Toy_setLiteralDictionary(Toy_LiteralDictionary* dictionary, Toy_Literal key, Toy_Literal value) {
|
||||||
|
|||||||
+4
-4
@@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
//default allocator
|
//default allocator
|
||||||
void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
||||||
if (newSize == 0 && oldSize == 0) {
|
//causes issues, so just skip out with a NO-OP (DISABLED for performance reasons)
|
||||||
//causes issues, so just skip out with a NO-OP
|
// if (newSize == 0 && oldSize == 0) {
|
||||||
return NULL;
|
// return NULL;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (newSize == 0) {
|
if (newSize == 0) {
|
||||||
free(pointer);
|
free(pointer);
|
||||||
|
|||||||
+6
-6
@@ -140,7 +140,7 @@ static Toy_Opcode asType(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
|||||||
|
|
||||||
static Toy_Opcode typeOf(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
static Toy_Opcode typeOf(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||||
Toy_ASTNode* rhs = NULL;
|
Toy_ASTNode* rhs = NULL;
|
||||||
parsePrecedence(parser, &rhs, PREC_TERNARY);
|
parsePrecedence(parser, &rhs, PREC_CALL);
|
||||||
Toy_emitASTNodeUnary(nodeHandle, TOY_OP_TYPE_OF, rhs);
|
Toy_emitASTNodeUnary(nodeHandle, TOY_OP_TYPE_OF, rhs);
|
||||||
return TOY_OP_EOF;
|
return TOY_OP_EOF;
|
||||||
}
|
}
|
||||||
@@ -341,27 +341,27 @@ static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
|||||||
switch(parser->previous.type) {
|
switch(parser->previous.type) {
|
||||||
//arithmetic
|
//arithmetic
|
||||||
case TOY_TOKEN_PLUS: {
|
case TOY_TOKEN_PLUS: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_TERM);
|
parsePrecedence(parser, nodeHandle, PREC_TERM + 1);
|
||||||
return TOY_OP_ADDITION;
|
return TOY_OP_ADDITION;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_MINUS: {
|
case TOY_TOKEN_MINUS: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_TERM);
|
parsePrecedence(parser, nodeHandle, PREC_TERM + 1);
|
||||||
return TOY_OP_SUBTRACTION;
|
return TOY_OP_SUBTRACTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_MULTIPLY: {
|
case TOY_TOKEN_MULTIPLY: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
|
parsePrecedence(parser, nodeHandle, PREC_FACTOR + 1);
|
||||||
return TOY_OP_MULTIPLICATION;
|
return TOY_OP_MULTIPLICATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_DIVIDE: {
|
case TOY_TOKEN_DIVIDE: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
|
parsePrecedence(parser, nodeHandle, PREC_FACTOR + 1);
|
||||||
return TOY_OP_DIVISION;
|
return TOY_OP_DIVISION;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_MODULO: {
|
case TOY_TOKEN_MODULO: {
|
||||||
parsePrecedence(parser, nodeHandle, PREC_FACTOR);
|
parsePrecedence(parser, nodeHandle, PREC_FACTOR + 1);
|
||||||
return TOY_OP_MODULO;
|
return TOY_OP_MODULO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+54
-60
@@ -4,21 +4,19 @@
|
|||||||
|
|
||||||
//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(Toy_Scope* scope) {
|
static void freeAncestorChain(Toy_Scope* scope) {
|
||||||
scope->references--;
|
while (scope != NULL) {
|
||||||
|
Toy_Scope* next = scope->ancestor;
|
||||||
|
|
||||||
//free scope chain
|
scope->references--;
|
||||||
if (scope->ancestor != NULL) {
|
|
||||||
freeAncestorChain(scope->ancestor);
|
if (scope->references <= 0) {
|
||||||
|
Toy_freeLiteralDictionary(&scope->variables);
|
||||||
|
Toy_freeLiteralDictionary(&scope->types);
|
||||||
|
TOY_FREE(Toy_Scope, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
scope = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope->references > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Toy_freeLiteralDictionary(&scope->variables);
|
|
||||||
Toy_freeLiteralDictionary(&scope->types);
|
|
||||||
|
|
||||||
TOY_FREE(Toy_Scope, scope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//return false if invalid type
|
//return false if invalid type
|
||||||
@@ -259,74 +257,70 @@ bool Toy_declareScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal typ
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key) {
|
bool Toy_isDelcaredScopeVariable(Toy_Scope* scope, Toy_Literal key) {
|
||||||
if (scope == NULL) {
|
while (scope != NULL) {
|
||||||
return false;
|
if (Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope = scope->ancestor;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if it's not in this scope, keep searching up the chain
|
return false;
|
||||||
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
|
|
||||||
return Toy_isDelcaredScopeVariable(scope->ancestor, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//return false if undefined, or can't be assigned
|
//return false if undefined, or can't be assigned
|
||||||
bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck) {
|
bool Toy_setScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal value, bool constCheck) {
|
||||||
//dead end
|
while (scope != NULL) {
|
||||||
if (scope == NULL) {
|
//if it's not in this scope, keep searching up the chain
|
||||||
return false;
|
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||||
}
|
scope = scope->ancestor;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//if it's not in this scope, keep searching up the chain
|
//type checking
|
||||||
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
|
Toy_Literal typeLiteral = Toy_getLiteralDictionary(&scope->types, key);
|
||||||
return Toy_setScopeVariable(scope->ancestor, key, value, constCheck);
|
Toy_Literal original = Toy_getLiteralDictionary(&scope->variables, key);
|
||||||
}
|
|
||||||
|
|
||||||
//type checking
|
if (!checkType(typeLiteral, original, value, constCheck)) {
|
||||||
Toy_Literal typeLiteral = Toy_getLiteralDictionary(&scope->types, key);
|
Toy_freeLiteral(typeLiteral);
|
||||||
Toy_Literal original = Toy_getLiteralDictionary(&scope->variables, key);
|
Toy_freeLiteral(original);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//actually assign
|
||||||
|
Toy_setLiteralDictionary(&scope->variables, key, value); //key & value are copied here
|
||||||
|
|
||||||
if (!checkType(typeLiteral, original, value, constCheck)) {
|
|
||||||
Toy_freeLiteral(typeLiteral);
|
Toy_freeLiteral(typeLiteral);
|
||||||
Toy_freeLiteral(original);
|
Toy_freeLiteral(original);
|
||||||
return false;
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//actually assign
|
return false;
|
||||||
Toy_setLiteralDictionary(&scope->variables, key, value); //key & value are copied here
|
|
||||||
|
|
||||||
Toy_freeLiteral(typeLiteral);
|
|
||||||
Toy_freeLiteral(original);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* valueHandle) {
|
bool Toy_getScopeVariable(Toy_Scope* scope, Toy_Literal key, Toy_Literal* valueHandle) {
|
||||||
//dead end
|
//optimized to reduce call stack
|
||||||
if (scope == NULL) {
|
while (scope != NULL) {
|
||||||
return false;
|
if (Toy_existsLiteralDictionary(&scope->variables, key)) {
|
||||||
|
*valueHandle = Toy_getLiteralDictionary(&scope->variables, key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope = scope->ancestor;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if it's not in this scope, keep searching up the chain
|
return false;
|
||||||
if (!Toy_existsLiteralDictionary(&scope->variables, key)) {
|
|
||||||
return Toy_getScopeVariable(scope->ancestor, key, valueHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
*valueHandle = Toy_getLiteralDictionary(&scope->variables, key);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key) {
|
Toy_Literal Toy_getScopeType(Toy_Scope* scope, Toy_Literal key) {
|
||||||
//dead end
|
while (scope != NULL) {
|
||||||
if (scope == NULL) {
|
if (Toy_existsLiteralDictionary(&scope->types, key)) {
|
||||||
return TOY_TO_NULL_LITERAL;
|
return Toy_getLiteralDictionary(&scope->types, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
scope = scope->ancestor;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if it's not in this scope, keep searching up the chain
|
return TOY_TO_NULL_LITERAL;
|
||||||
if (!Toy_existsLiteralDictionary(&scope->types, key)) {
|
|
||||||
return Toy_getScopeType(scope->ancestor, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Toy_getLiteralDictionary(&scope->types, key);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,5 +38,12 @@ s += "bar";
|
|||||||
|
|
||||||
assert s == "foobar", "string addition failed (wasn't sticky enough)";
|
assert s == "foobar", "string addition failed (wasn't sticky enough)";
|
||||||
|
|
||||||
|
//check order of operations
|
||||||
|
assert 30 / 3 * 2 == 20, "Order of operations failed (raw numbers)";
|
||||||
|
var x = 30;
|
||||||
|
var y = 3;
|
||||||
|
var z = 2;
|
||||||
|
assert x / y * z == 20, "Order of operations failed (variables)";
|
||||||
|
|
||||||
|
|
||||||
print "All good";
|
print "All good";
|
||||||
@@ -1,5 +1,19 @@
|
|||||||
import standard;
|
import standard;
|
||||||
|
|
||||||
|
//test clock
|
||||||
|
{
|
||||||
|
//this depends on external factors, so only check the length
|
||||||
|
assert clock().length() == 24, "clock().length() failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//test hash
|
||||||
|
{
|
||||||
|
assert typeof "Hello world".hash() == int, "typeof \"Hello world\".hash() failed";
|
||||||
|
assert "Hello world".hash() == 994097935, "\"Hello world\".hash() failed"; //NOTE: specific value based on algorithm
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//test abs
|
//test abs
|
||||||
{
|
{
|
||||||
assert abs(-5) == 5, "abs(-integer) failed";
|
assert abs(-5) == 5, "abs(-integer) failed";
|
||||||
@@ -13,10 +27,77 @@ import standard;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//test clock
|
//test ceil
|
||||||
{
|
{
|
||||||
//this depends on external factors, so only check the length
|
assert ceil(4) == 4, "ceil(int) failed";
|
||||||
assert clock().length() == 24, "clock().length() failed";
|
assert ceil(4.0) == 4, "ceil(float) failed";
|
||||||
|
assert ceil(4.1) == 5, "ceil() failed";
|
||||||
|
|
||||||
|
var x = 4.1;
|
||||||
|
|
||||||
|
assert x.ceil() == 5, "var.ceil() failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//test floor
|
||||||
|
{
|
||||||
|
assert floor(4) == 4, "floor(int) failed";
|
||||||
|
assert floor(4.0) == 4, "floor(float) failed";
|
||||||
|
assert floor(4.1) == 4, "floor() failed";
|
||||||
|
|
||||||
|
var x = 4.1;
|
||||||
|
|
||||||
|
assert x.floor() == 4, "var.floor() failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//test max
|
||||||
|
{
|
||||||
|
assert max(1, 2, 3) == 3, "max() failed";
|
||||||
|
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = 3;
|
||||||
|
|
||||||
|
assert max(a, b, c) == 3, "var.max() failed";
|
||||||
|
|
||||||
|
assert max(1, 2, 3, 4, 5, 6, 7, 8, 9, 0) == 9, "max() with many args failed";
|
||||||
|
|
||||||
|
assert typeof max(1, 2, 3) == int, "typeof max() == int failed";
|
||||||
|
assert typeof max(1, 2, 3.4) == float, "typeof max() == float failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//test min
|
||||||
|
{
|
||||||
|
assert min(1, 2, 3) == 1, "min() failed";
|
||||||
|
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = 3;
|
||||||
|
|
||||||
|
assert min(a, b, c) == 1, "var.min() failed";
|
||||||
|
|
||||||
|
assert min(1, 2, 3, 4, 5, 6, 7, 8, 9, 0) == 0, "min() with many args failed";
|
||||||
|
|
||||||
|
assert typeof min(1, 2, 3) == int, "typeof min() == int failed";
|
||||||
|
assert typeof min(1, 2, 3.4) == float, "typeof min() == float failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//test round
|
||||||
|
{
|
||||||
|
assert round(4) == 4, "round(int) failed";
|
||||||
|
assert round(4.0) == 4, "round(float) failed";
|
||||||
|
assert round(4.1) == 4, "round(less than half) failed";
|
||||||
|
assert round(4.9) == 5, "round(greater than half) failed";
|
||||||
|
assert round(4.5) == 5, "round(exactly half) failed";
|
||||||
|
|
||||||
|
var x = 4.1;
|
||||||
|
|
||||||
|
assert x.round() == 4, "var.round() failed";
|
||||||
|
|
||||||
|
assert typeof round(1.0) == int, "typeof round() == int failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -175,13 +256,6 @@ import standard;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//test hash
|
|
||||||
{
|
|
||||||
assert typeof "Hello world".hash() == int, "typeof \"Hello world\".hash() failed";
|
|
||||||
assert "Hello world".hash() == 994097935, "\"Hello world\".hash() failed"; //NOTE: specific value based on algorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//test indexOf
|
//test indexOf
|
||||||
{
|
{
|
||||||
var a = [1, 2, 42, 3];
|
var a = [1, 2, 42, 3];
|
||||||
|
|||||||
+11
-4
@@ -10,25 +10,32 @@
|
|||||||
int currentMemoryUsed = 0;
|
int currentMemoryUsed = 0;
|
||||||
int maxMemoryUsed = 0;
|
int maxMemoryUsed = 0;
|
||||||
int memoryAllocCalls = 0;
|
int memoryAllocCalls = 0;
|
||||||
|
int memoryAllocFree = 0;
|
||||||
|
int memoryAllocRealloc = 0;
|
||||||
|
|
||||||
static void* trackerAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
static void* trackerAllocator(void* pointer, size_t oldSize, size_t newSize) {
|
||||||
|
//the number of raw calls
|
||||||
|
memoryAllocCalls++;
|
||||||
|
|
||||||
|
//causes issues, so just skip out with a NO-OP
|
||||||
if (newSize == 0 && oldSize == 0) {
|
if (newSize == 0 && oldSize == 0) {
|
||||||
//causes issues, so just skip out with a NO-OP
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
memoryAllocCalls++;
|
|
||||||
|
|
||||||
//track the changes
|
//track the changes
|
||||||
currentMemoryUsed = currentMemoryUsed - oldSize + newSize;
|
currentMemoryUsed = currentMemoryUsed - oldSize + newSize;
|
||||||
maxMemoryUsed = currentMemoryUsed > maxMemoryUsed ? currentMemoryUsed : maxMemoryUsed;
|
maxMemoryUsed = currentMemoryUsed > maxMemoryUsed ? currentMemoryUsed : maxMemoryUsed;
|
||||||
|
|
||||||
if (newSize == 0) {
|
if (newSize == 0) {
|
||||||
|
//the number of frees
|
||||||
|
memoryAllocFree++;
|
||||||
free(pointer);
|
free(pointer);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//the number of reallocations
|
||||||
|
memoryAllocRealloc++;
|
||||||
void* mem = realloc(pointer, newSize);
|
void* mem = realloc(pointer, newSize);
|
||||||
|
|
||||||
if (mem == NULL) {
|
if (mem == NULL) {
|
||||||
@@ -69,7 +76,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
Toy_freeDriveDictionary();
|
Toy_freeDriveDictionary();
|
||||||
|
|
||||||
//report output
|
//report output
|
||||||
printf("Memory report: %d max bytes, %d calls\n", maxMemoryUsed, memoryAllocCalls);
|
printf("Heap Memory Report:\n\t%d max bytes\n\t%d calls to the allocator\n\t%d calls to realloc()\n\t%d calls to free()\n\t%d discrepancies\n", maxMemoryUsed, memoryAllocCalls, memoryAllocRealloc, memoryAllocFree, memoryAllocCalls - memoryAllocRealloc - memoryAllocFree);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user