mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Merge branch 'Ratstail91:main' into main
This commit is contained in:
@@ -136,6 +136,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="repl\drive_system.c" />
|
||||
<ClCompile Include="repl\lib_math.c" />
|
||||
<ClCompile Include="repl\lib_random.c" />
|
||||
<ClCompile Include="repl\lib_runner.c" />
|
||||
<ClCompile Include="repl\lib_standard.c" />
|
||||
@@ -145,6 +146,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="repl\drive_system.h" />
|
||||
<ClInclude Include="repl\lib_math.h" />
|
||||
<ClInclude Include="repl\lib_random.h" />
|
||||
<ClInclude Include="repl\lib_runner.h" />
|
||||
<ClInclude Include="repl\lib_standard.h" />
|
||||
|
||||
@@ -221,7 +221,7 @@ static int nativeToRadians(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
|
||||
// cast int to float to handle all types of numbers
|
||||
float degrees = TOY_IS_INTEGER(degreesLiteral)? TOY_AS_INTEGER(degreesLiteral) : TOY_AS_FLOAT(degreesLiteral);
|
||||
|
||||
float result = degrees * (LIB_MATH_PI / 180.0);
|
||||
float result = degrees * (LIB_MATH_PI / 180.0f);
|
||||
|
||||
//return the result
|
||||
Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result);
|
||||
@@ -259,7 +259,7 @@ static int nativeToDegrees(Toy_Interpreter* interpreter, Toy_LiteralArray* argum
|
||||
// cast int to float to handle all types of numbers
|
||||
float radians = TOY_IS_INTEGER(radiansLiteral)? TOY_AS_INTEGER(radiansLiteral) : TOY_AS_FLOAT(radiansLiteral);
|
||||
|
||||
float result = radians * (180.0 / LIB_MATH_PI);
|
||||
float result = radians * (180.0f / LIB_MATH_PI);
|
||||
|
||||
//return the result
|
||||
Toy_Literal resultLiteral = TOY_TO_FLOAT_LITERAL(result);
|
||||
@@ -820,10 +820,10 @@ static int nativeCheckIsNaN(Toy_Interpreter* interpreter, Toy_LiteralArray* argu
|
||||
float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral);
|
||||
|
||||
// calculate the result
|
||||
float result = isnan(x);
|
||||
int result = isnan(x);
|
||||
|
||||
//return the result
|
||||
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result);
|
||||
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != 0);
|
||||
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||
|
||||
//cleanup
|
||||
@@ -859,10 +859,10 @@ static int nativeCheckIsFinite(Toy_Interpreter* interpreter, Toy_LiteralArray* a
|
||||
float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral);
|
||||
|
||||
// calculate the result
|
||||
float result = isfinite(x);
|
||||
int result = isfinite(x);
|
||||
|
||||
//return the result
|
||||
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result);
|
||||
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != 0);
|
||||
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||
|
||||
//cleanup
|
||||
@@ -898,10 +898,10 @@ static int nativeCheckIsInfinite(Toy_Interpreter* interpreter, Toy_LiteralArray*
|
||||
float x = TOY_IS_INTEGER(xLiteral)? TOY_AS_INTEGER(xLiteral) : TOY_AS_FLOAT(xLiteral);
|
||||
|
||||
// calculate the result
|
||||
float result = isinf(x);
|
||||
int result = isinf(x);
|
||||
|
||||
//return the result
|
||||
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result);
|
||||
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != 0);
|
||||
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||
|
||||
//cleanup
|
||||
@@ -950,10 +950,10 @@ static int nativeEpsilionCompare(Toy_Interpreter* interpreter, Toy_LiteralArray*
|
||||
float y = TOY_IS_INTEGER(yLiteral)? TOY_AS_INTEGER(yLiteral) : TOY_AS_FLOAT(yLiteral);
|
||||
|
||||
// calculate the result
|
||||
float result = (fabsf(x - y)) <= (LIB_MATH_EPSILON * fmaxf(1, fmaxf(fabsf(x), fabsf(y))));
|
||||
int result = (fabsf(x - y)) <= (LIB_MATH_EPSILON * fmaxf(1, fmaxf(fabsf(x), fabsf(y))));
|
||||
|
||||
// return the result
|
||||
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result);
|
||||
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != 0);
|
||||
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||
|
||||
// cleanup
|
||||
@@ -1002,8 +1002,8 @@ int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Liter
|
||||
|
||||
// Comparison
|
||||
{"checkIsNaN", nativeCheckIsNaN},
|
||||
{"chechIsFinite", nativeCheckIsFinite},
|
||||
{"chechIsInfinite", nativeCheckIsInfinite},
|
||||
{"checkIsFinite", nativeCheckIsFinite},
|
||||
{"checkIsInfinite", nativeCheckIsInfinite},
|
||||
{"epsilionCompare", nativeEpsilionCompare},
|
||||
|
||||
{NULL, NULL}
|
||||
|
||||
12
scripts/test.toy
Normal file
12
scripts/test.toy
Normal file
@@ -0,0 +1,12 @@
|
||||
import standard;
|
||||
var array = [42];
|
||||
|
||||
var result = null;
|
||||
|
||||
//problematic line
|
||||
result = max(0, array[0]);
|
||||
|
||||
assert result == 42, "Indexing in argument list failed";
|
||||
|
||||
|
||||
print "All good";
|
||||
@@ -124,6 +124,16 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
|
||||
//NO-OP
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_AND:
|
||||
Toy_freeASTNode(node->pathAnd.left);
|
||||
Toy_freeASTNode(node->pathAnd.right);
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_OR:
|
||||
Toy_freeASTNode(node->pathOr.left);
|
||||
Toy_freeASTNode(node->pathOr.right);
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_PREFIX_INCREMENT:
|
||||
Toy_freeLiteral(node->prefixIncrement.identifier);
|
||||
break;
|
||||
@@ -348,6 +358,26 @@ void Toy_emitASTNodeContinue(Toy_ASTNode** nodeHandle) {
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
void Toy_emitASTNodeAnd(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs) {
|
||||
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||
|
||||
tmp->type = TOY_AST_NODE_AND;
|
||||
tmp->binary.left = *nodeHandle;
|
||||
tmp->binary.right = rhs;
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
void Toy_emitASTNodeOr(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs) {
|
||||
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||
|
||||
tmp->type = TOY_AST_NODE_OR;
|
||||
tmp->binary.left = *nodeHandle;
|
||||
tmp->binary.right = rhs;
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
|
||||
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ typedef enum Toy_ASTNodeType {
|
||||
TOY_AST_NODE_FOR, //for control flow
|
||||
TOY_AST_NODE_BREAK, //for control flow
|
||||
TOY_AST_NODE_CONTINUE, //for control flow
|
||||
TOY_AST_NODE_AND, //for control flow
|
||||
TOY_AST_NODE_OR, //for control flow
|
||||
TOY_AST_NODE_PREFIX_INCREMENT, //increment a variable
|
||||
TOY_AST_NODE_POSTFIX_INCREMENT, //increment a variable
|
||||
TOY_AST_NODE_PREFIX_DECREMENT, //decrement a variable
|
||||
@@ -204,6 +206,24 @@ typedef struct Toy_NodeContinue {
|
||||
Toy_ASTNodeType type;
|
||||
} Toy_NodeContinue;
|
||||
|
||||
//and operator
|
||||
void Toy_emitASTNodeAnd(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs); //handled node becomes lhs
|
||||
|
||||
typedef struct Toy_NodeAnd {
|
||||
Toy_ASTNodeType type;
|
||||
Toy_ASTNode* left;
|
||||
Toy_ASTNode* right;
|
||||
} Toy_NodeAnd;
|
||||
|
||||
//or operator
|
||||
void Toy_emitASTNodeOr(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs); //handled node becomes lhs
|
||||
|
||||
typedef struct Toy_NodeOr {
|
||||
Toy_ASTNodeType type;
|
||||
Toy_ASTNode* left;
|
||||
Toy_ASTNode* right;
|
||||
} Toy_NodeOr;
|
||||
|
||||
//pre-post increment/decrement
|
||||
void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
|
||||
void Toy_emitASTNodePrefixDecrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
|
||||
@@ -263,6 +283,8 @@ union Toy_private_node {
|
||||
Toy_NodeFor pathFor;
|
||||
Toy_NodeBreak pathBreak;
|
||||
Toy_NodeContinue pathContinue;
|
||||
Toy_NodeAnd pathAnd;
|
||||
Toy_NodeOr pathOr;
|
||||
Toy_NodePrefixIncrement prefixIncrement;
|
||||
Toy_NodePrefixDecrement prefixDecrement;
|
||||
Toy_NodePostfixIncrement postfixIncrement;
|
||||
|
||||
@@ -64,7 +64,7 @@ The current patch version of Toy. This value is embedded into the bytecode.
|
||||
This value MUST fit into an unsigned char.
|
||||
!*/
|
||||
|
||||
#define TOY_VERSION_PATCH 1
|
||||
#define TOY_VERSION_PATCH 2
|
||||
|
||||
/*!
|
||||
### TOY_VERSION_BUILD
|
||||
|
||||
@@ -318,6 +318,12 @@ bool checkNodeInTree(Toy_ASTNode* tree, Toy_ASTNode* node) {
|
||||
case TOY_AST_NODE_FOR:
|
||||
return checkNodeInTree(tree->pathFor.preClause, node) || checkNodeInTree(tree->pathFor.condition, node) || checkNodeInTree(tree->pathFor.postClause, node) || checkNodeInTree(tree->pathFor.thenPath, node);
|
||||
|
||||
case TOY_AST_NODE_AND:
|
||||
return checkNodeInTree(tree->pathAnd.left, node) || checkNodeInTree(tree->pathAnd.right, node);
|
||||
|
||||
case TOY_AST_NODE_OR:
|
||||
return checkNodeInTree(tree->pathOr.left, node) || checkNodeInTree(tree->pathOr.right, node);
|
||||
|
||||
case TOY_AST_NODE_ERROR:
|
||||
case TOY_AST_NODE_LITERAL:
|
||||
case TOY_AST_NODE_BREAK:
|
||||
@@ -429,8 +435,6 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
||||
case TOY_OP_COMPARE_GREATER:
|
||||
case TOY_OP_COMPARE_GREATER_EQUAL:
|
||||
case TOY_OP_INVERT:
|
||||
case TOY_OP_AND:
|
||||
case TOY_OP_OR:
|
||||
//place the rhs result before the outer instruction
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)ret; //1 byte
|
||||
ret = TOY_OP_EOF;
|
||||
@@ -645,7 +649,7 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
||||
for (int i = 0; i < node->fnCall.arguments->fnCollection.count; i++) { //reverse order, to count from the beginning in the interpreter
|
||||
//sub-calls
|
||||
if (node->fnCall.arguments->fnCollection.nodes[i].type != TOY_AST_NODE_LITERAL) {
|
||||
Toy_Opcode override = Toy_writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||
Toy_Opcode override = Toy_writeCompilerWithJumps(compiler, &node->fnCall.arguments->fnCollection.nodes[i], breakAddressesPtr, continueAddressesPtr, jumpOffsets, node); //BUGFIX: use node as rootNode, to allow indexing within argument lists
|
||||
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||
}
|
||||
@@ -917,6 +921,54 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
|
||||
}
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_AND: {
|
||||
//process the lhs
|
||||
Toy_Opcode override = Toy_writeCompilerWithJumps(compiler, node->pathAnd.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||
}
|
||||
|
||||
//insert the AND opcode to signal a possible jump
|
||||
compiler->bytecode[compiler->count++] = TOY_OP_AND; //1 byte
|
||||
int jumpToEnd = compiler->count;
|
||||
compiler->count += sizeof(unsigned short); //2 bytes
|
||||
|
||||
//process the rhs
|
||||
override = Toy_writeCompilerWithJumps(compiler, node->pathAnd.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||
}
|
||||
|
||||
//set the spot to jump to, to proceed
|
||||
unsigned short tmpVal = compiler->count + jumpOffsets;
|
||||
memcpy(compiler->bytecode + jumpToEnd, &tmpVal, sizeof(tmpVal));
|
||||
}
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_OR: {
|
||||
//process the lhs
|
||||
Toy_Opcode override = Toy_writeCompilerWithJumps(compiler, node->pathOr.left, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||
}
|
||||
|
||||
//insert the AND opcode to signal a possible jump
|
||||
compiler->bytecode[compiler->count++] = TOY_OP_OR; //1 byte
|
||||
int jumpToEnd = compiler->count;
|
||||
compiler->count += sizeof(unsigned short); //2 bytes
|
||||
|
||||
//process the rhs
|
||||
override = Toy_writeCompilerWithJumps(compiler, node->pathOr.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets, rootNode);
|
||||
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||
}
|
||||
|
||||
//set the spot to jump to, to proceed
|
||||
unsigned short tmpVal = compiler->count + jumpOffsets;
|
||||
memcpy(compiler->bytecode + jumpToEnd, &tmpVal, sizeof(tmpVal));
|
||||
}
|
||||
break;
|
||||
|
||||
case TOY_AST_NODE_FN_RETURN: {
|
||||
//read each returned literal onto the stack, and return the number of values to return
|
||||
for (int i = 0; i < node->returns.returns->fnCollection.count; i++) {
|
||||
|
||||
@@ -582,7 +582,7 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
|
||||
typeIndex = (int)readByte(interpreter->bytecode, &interpreter->count);
|
||||
}
|
||||
|
||||
Toy_Literal identifier = interpreter->literalCache.literals[identifierIndex];
|
||||
Toy_Literal identifier = Toy_copyLiteral(interpreter->literalCache.literals[identifierIndex]);
|
||||
Toy_Literal type = Toy_copyLiteral(interpreter->literalCache.literals[typeIndex]);
|
||||
|
||||
Toy_Literal typeIdn = type;
|
||||
@@ -597,6 +597,10 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
|
||||
interpreter->errorOutput("Can't redefine the variable \"");
|
||||
Toy_printLiteralCustom(identifier, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\"\n");
|
||||
|
||||
Toy_freeLiteral(identifier);
|
||||
Toy_freeLiteral(type);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -623,14 +627,16 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
|
||||
Toy_printLiteralCustom(identifier, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\"\n");
|
||||
|
||||
Toy_freeLiteral(identifier);
|
||||
Toy_freeLiteral(type);
|
||||
Toy_freeLiteral(val);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Toy_freeLiteral(val);
|
||||
Toy_freeLiteral(identifier);
|
||||
Toy_freeLiteral(type);
|
||||
Toy_freeLiteral(val);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1042,57 +1048,63 @@ static bool execCompareLessEqual(Toy_Interpreter* interpreter, bool invert) {
|
||||
}
|
||||
|
||||
static bool execAnd(Toy_Interpreter* interpreter) {
|
||||
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
|
||||
Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack);
|
||||
|
||||
Toy_Literal rhsIdn = rhs;
|
||||
if (TOY_IS_IDENTIFIER(rhs) && Toy_parseIdentifierToValue(interpreter, &rhs)) {
|
||||
Toy_freeLiteral(rhsIdn);
|
||||
}
|
||||
|
||||
Toy_Literal lhsIdn = lhs;
|
||||
if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) {
|
||||
Toy_freeLiteral(lhsIdn);
|
||||
}
|
||||
|
||||
//short-circuit - broken, see issue #73
|
||||
//short-circuit - if not true
|
||||
if (!TOY_IS_TRUTHY(lhs)) {
|
||||
Toy_pushLiteralArray(&interpreter->stack, lhs);
|
||||
|
||||
int target = (int)readShort(interpreter->bytecode, &interpreter->count);
|
||||
|
||||
if (target + interpreter->codeStart > interpreter->length) {
|
||||
interpreter->errorOutput("[internal] AND Jump out of range\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//actually jump
|
||||
interpreter->count = target + interpreter->codeStart;
|
||||
}
|
||||
else {
|
||||
Toy_pushLiteralArray(&interpreter->stack, rhs);
|
||||
readShort(interpreter->bytecode, &interpreter->count); //discard
|
||||
}
|
||||
|
||||
Toy_freeLiteral(lhs);
|
||||
Toy_freeLiteral(rhs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool execOr(Toy_Interpreter* interpreter) {
|
||||
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
|
||||
Toy_Literal lhs = Toy_popLiteralArray(&interpreter->stack);
|
||||
|
||||
Toy_Literal rhsIdn = rhs;
|
||||
if (TOY_IS_IDENTIFIER(rhs) && Toy_parseIdentifierToValue(interpreter, &rhs)) {
|
||||
Toy_freeLiteral(rhsIdn);
|
||||
}
|
||||
|
||||
Toy_Literal lhsIdn = lhs;
|
||||
if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) {
|
||||
Toy_freeLiteral(lhsIdn);
|
||||
}
|
||||
|
||||
//short-circuit - broken, see issue #73
|
||||
//short-circuit - if is true
|
||||
if (TOY_IS_TRUTHY(lhs)) {
|
||||
Toy_pushLiteralArray(&interpreter->stack, lhs);
|
||||
|
||||
int target = (int)readShort(interpreter->bytecode, &interpreter->count);
|
||||
|
||||
if (target + interpreter->codeStart > interpreter->length) {
|
||||
interpreter->errorOutput("[internal] OR Jump out of range\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//actually jump
|
||||
interpreter->count = target + interpreter->codeStart;
|
||||
}
|
||||
else {
|
||||
Toy_pushLiteralArray(&interpreter->stack, rhs);
|
||||
readShort(interpreter->bytecode, &interpreter->count); //discard
|
||||
}
|
||||
|
||||
Toy_freeLiteral(lhs);
|
||||
Toy_freeLiteral(rhs);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1985,27 +1997,9 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
|
||||
}
|
||||
break;
|
||||
|
||||
case TOY_LITERAL_TYPE: {
|
||||
//what the literal is
|
||||
Toy_LiteralType literalType = (Toy_LiteralType)readByte(interpreter->bytecode, &interpreter->count);
|
||||
unsigned char constant = readByte(interpreter->bytecode, &interpreter->count);
|
||||
|
||||
Toy_Literal typeLiteral = TOY_TO_TYPE_LITERAL(literalType, constant);
|
||||
|
||||
//save the type
|
||||
Toy_pushLiteralArray(&interpreter->literalCache, typeLiteral);
|
||||
|
||||
#ifndef TOY_EXPORT
|
||||
if (Toy_commandLine.verbose) {
|
||||
printf("(type ");
|
||||
Toy_printLiteral(typeLiteral);
|
||||
printf(")\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case TOY_LITERAL_TYPE_INTERMEDIATE: {
|
||||
case TOY_LITERAL_TYPE:
|
||||
case TOY_LITERAL_TYPE_INTERMEDIATE:
|
||||
{
|
||||
//what the literal represents
|
||||
Toy_LiteralType literalType = (Toy_LiteralType)readByte(interpreter->bytecode, &interpreter->count);
|
||||
unsigned char constant = readByte(interpreter->bytecode, &interpreter->count);
|
||||
@@ -2322,6 +2316,13 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
|
||||
Toy_freeLiteral(argIdn);
|
||||
}
|
||||
|
||||
//BUGFIX: coerce ints to floats, if the function requires floats
|
||||
if (TOY_IS_INTEGER(arg) && TOY_IS_TYPE(paramArray->literals[i + 1]) && TOY_AS_TYPE(paramArray->literals[i + 1]).typeOf == TOY_LITERAL_FLOAT) {
|
||||
Toy_Literal f = TOY_TO_FLOAT_LITERAL( (float)TOY_AS_INTEGER(arg) );
|
||||
Toy_freeLiteral(arg);
|
||||
arg = f;
|
||||
}
|
||||
|
||||
if (!Toy_setScopeVariable(inner.scope, paramArray->literals[i], arg, false)) {
|
||||
interpreter->errorOutput("[internal] Could not define parameter (bad type?)\n");
|
||||
|
||||
@@ -2416,6 +2417,13 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
|
||||
for (int i = 0; i < returnsFromInner.count && returnValue; i++) {
|
||||
Toy_Literal ret = Toy_popLiteralArray(&returnsFromInner);
|
||||
|
||||
//BUGFIX: coerce the returned integers to floats, if specified
|
||||
if (returnArray->count > 0 && TOY_AS_TYPE(returnArray->literals[i]).typeOf == TOY_LITERAL_FLOAT && TOY_IS_INTEGER(ret)) {
|
||||
Toy_Literal f = TOY_TO_FLOAT_LITERAL( (float)TOY_AS_INTEGER(ret) );
|
||||
Toy_freeLiteral(ret);
|
||||
ret = f;
|
||||
}
|
||||
|
||||
//check the return types
|
||||
if (returnArray->count > 0 && TOY_AS_TYPE(returnArray->literals[i]).typeOf != ret.type) {
|
||||
interpreter->errorOutput("Bad type found in return value\n");
|
||||
|
||||
@@ -237,7 +237,7 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
|
||||
|
||||
//scan for a keyword
|
||||
for (int i = 0; Toy_keywordTypes[i].keyword; i++) {
|
||||
if (strlen(Toy_keywordTypes[i].keyword) == (long unsigned int)(lexer->current - lexer->start) && !strncmp(Toy_keywordTypes[i].keyword, &lexer->source[lexer->start], lexer->current - lexer->start)) {
|
||||
if (strlen(Toy_keywordTypes[i].keyword) == (size_t)(lexer->current - lexer->start) && !strncmp(Toy_keywordTypes[i].keyword, &lexer->source[lexer->start], lexer->current - lexer->start)) {
|
||||
Toy_Token token;
|
||||
|
||||
token.type = Toy_keywordTypes[i].type;
|
||||
@@ -317,10 +317,10 @@ Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer) {
|
||||
if (advance(lexer) != '&') {
|
||||
return makeErrorToken(lexer, "Unexpected '&'");
|
||||
} else {
|
||||
return makeToken(lexer, TOY_TOKEN_AND);
|
||||
return makeToken(lexer, TOY_TOKEN_AND_AND);
|
||||
}
|
||||
|
||||
case '|': return makeToken(lexer, match(lexer, '|') ? TOY_TOKEN_OR : TOY_TOKEN_PIPE);
|
||||
case '|': return makeToken(lexer, match(lexer, '|') ? TOY_TOKEN_OR_OR : TOY_TOKEN_PIPE);
|
||||
|
||||
case '?': return makeToken(lexer, TOY_TOKEN_QUESTION);
|
||||
case ':': return makeToken(lexer, TOY_TOKEN_COLON);
|
||||
|
||||
@@ -29,8 +29,8 @@ typedef enum Toy_Opcode {
|
||||
TOY_OP_SCOPE_BEGIN,
|
||||
TOY_OP_SCOPE_END,
|
||||
|
||||
TOY_OP_TYPE_DECL, //declare a type to be used (as a literal)
|
||||
TOY_OP_TYPE_DECL_LONG, //declare a type to be used (as a long literal)
|
||||
TOY_OP_TYPE_DECL_removed,
|
||||
TOY_OP_TYPE_DECL_LONG_removed,
|
||||
|
||||
TOY_OP_VAR_DECL, //declare a variable to be used (as a literal)
|
||||
TOY_OP_VAR_DECL_LONG, //declare a variable to be used (as a long literal)
|
||||
|
||||
@@ -168,6 +168,10 @@ static Toy_Opcode compound(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||
consume(parser, TOY_TOKEN_COMMA, "Expected ',' in array or dictionary");
|
||||
}
|
||||
|
||||
if (match(parser, TOY_TOKEN_BRACKET_RIGHT)) { //allow for trailing commas
|
||||
break;
|
||||
}
|
||||
|
||||
iterations++;
|
||||
|
||||
Toy_ASTNode* left = NULL;
|
||||
@@ -335,6 +339,28 @@ static Toy_Opcode grouping(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||
}
|
||||
}
|
||||
|
||||
static Toy_Opcode circuit(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||
advance(parser);
|
||||
|
||||
//handle short-circuitable operators - && ||
|
||||
switch (parser->previous.type) {
|
||||
case TOY_TOKEN_AND_AND: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_AND + 1);
|
||||
return TOY_OP_AND;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_OR_OR: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_OR + 1);
|
||||
return TOY_OP_OR;
|
||||
}
|
||||
|
||||
default: {
|
||||
error(parser, parser->previous, "Unexpected token passed to grouping precedence rule");
|
||||
return TOY_OP_EOF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||
advance(parser);
|
||||
|
||||
@@ -428,16 +454,6 @@ static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
|
||||
return TOY_OP_COMPARE_GREATER_EQUAL;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_AND: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_AND + 1);
|
||||
return TOY_OP_AND;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_OR: {
|
||||
parsePrecedence(parser, nodeHandle, PREC_OR + 1);
|
||||
return TOY_OP_OR;
|
||||
}
|
||||
|
||||
default:
|
||||
error(parser, parser->previous, "Unexpected token passed to binary precedence rule");
|
||||
return TOY_OP_EOF;
|
||||
@@ -998,8 +1014,8 @@ ParseRule parseRules[] = { //must match the token types
|
||||
{NULL, binary, PREC_COMPARISON},// TOKEN_GREATER,
|
||||
{NULL, binary, PREC_COMPARISON},// TOKEN_LESS_EQUAL,
|
||||
{NULL, binary, PREC_COMPARISON},// TOKEN_GREATER_EQUAL,
|
||||
{NULL, binary, PREC_AND},// TOKEN_AND,
|
||||
{NULL, binary, PREC_OR},// TOKEN_OR,
|
||||
{NULL, circuit, PREC_AND},// TOKEN_AND,
|
||||
{NULL, circuit, PREC_OR},// TOKEN_OR,
|
||||
|
||||
//other operators
|
||||
{NULL, question, PREC_TERNARY}, //TOKEN_QUESTION,
|
||||
@@ -1281,6 +1297,16 @@ static void parsePrecedence(Toy_Parser* parser, Toy_ASTNode** nodeHandle, Preced
|
||||
continue;
|
||||
}
|
||||
|
||||
if (opcode == TOY_OP_AND) {
|
||||
Toy_emitASTNodeAnd(nodeHandle, rhsNode);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (opcode == TOY_OP_OR) {
|
||||
Toy_emitASTNodeOr(nodeHandle, rhsNode);
|
||||
continue;
|
||||
}
|
||||
|
||||
Toy_emitASTNodeBinary(nodeHandle, rhsNode, opcode);
|
||||
|
||||
//optimise away the constants
|
||||
|
||||
@@ -74,8 +74,8 @@ typedef enum Toy_TokenType {
|
||||
TOY_TOKEN_GREATER,
|
||||
TOY_TOKEN_LESS_EQUAL,
|
||||
TOY_TOKEN_GREATER_EQUAL,
|
||||
TOY_TOKEN_AND,
|
||||
TOY_TOKEN_OR,
|
||||
TOY_TOKEN_AND_AND,
|
||||
TOY_TOKEN_OR_OR,
|
||||
|
||||
//other operators
|
||||
TOY_TOKEN_QUESTION,
|
||||
|
||||
@@ -10,4 +10,20 @@
|
||||
}
|
||||
|
||||
|
||||
//test function coercion
|
||||
{
|
||||
fn f(arg: float) {
|
||||
assert typeof arg == float, "argument coercion failed";
|
||||
}
|
||||
|
||||
f(42);
|
||||
|
||||
fn g(): float {
|
||||
return 42;
|
||||
}
|
||||
|
||||
assert typeof g() == float, "return coercion failed";
|
||||
}
|
||||
|
||||
|
||||
print "All good";
|
||||
|
||||
20
test/scripts/indexing-in-argument-list-bugfix.toy
Normal file
20
test/scripts/indexing-in-argument-list-bugfix.toy
Normal file
@@ -0,0 +1,20 @@
|
||||
fn max(lhs, rhs) {
|
||||
if (lhs > rhs) {
|
||||
return lhs;
|
||||
}
|
||||
else {
|
||||
return rhs;
|
||||
}
|
||||
}
|
||||
|
||||
var array = [42];
|
||||
|
||||
var result = null;
|
||||
|
||||
//problematic line
|
||||
result = max(0, array[0]);
|
||||
|
||||
assert result == 42, "Indexing in argument list failed";
|
||||
|
||||
|
||||
print "All good";
|
||||
@@ -144,8 +144,8 @@ import math;
|
||||
|
||||
// test atanh
|
||||
{
|
||||
assert chechIsInfinite(atanh(1)) == true, "atanh(1) failed";
|
||||
assert chechIsInfinite(atanh(-1)) == true, "atanh(-1) failed";
|
||||
assert checkIsInfinite(atanh(1)) == true, "atanh(1) failed";
|
||||
assert checkIsInfinite(atanh(-1)) == true, "atanh(-1) failed";
|
||||
assert epsilionCompare(atanh(0), 0), "atanh(0) failed";
|
||||
}
|
||||
|
||||
@@ -159,21 +159,21 @@ import math;
|
||||
}
|
||||
|
||||
|
||||
// test chechIsFinite
|
||||
// test checkIsFinite
|
||||
{
|
||||
assert chechIsFinite(NAN) == false, "chechIsFinite(NAN) failed";
|
||||
assert chechIsFinite(INFINITY) == false, "chechIsFinite(INFINITY) failed";
|
||||
assert chechIsFinite(0.0) == true, "chechIsFinite(0.0) failed";
|
||||
assert chechIsFinite(1) == true, "chechIsFinite(1) failed";
|
||||
assert checkIsFinite(NAN) == false, "checkIsFinite(NAN) failed";
|
||||
assert checkIsFinite(INFINITY) == false, "checkIsFinite(INFINITY) failed";
|
||||
assert checkIsFinite(0.0) == true, "checkIsFinite(0.0) failed";
|
||||
assert checkIsFinite(1) == true, "checkIsFinite(1) failed";
|
||||
}
|
||||
|
||||
|
||||
// test chechIsInfinite
|
||||
// test checkIsInfinite
|
||||
{
|
||||
assert chechIsInfinite(NAN) == false, "chechIsInfinite(NAN) failed";
|
||||
assert chechIsInfinite(INFINITY) == true, "chechIsInfinite(INFINITY) failed";
|
||||
assert chechIsInfinite(0.0) == false, "chechIsInfinite(0.0) failed";
|
||||
assert chechIsInfinite(1) == false, "chechIsInfinite(1) failed";
|
||||
assert checkIsInfinite(NAN) == false, "checkIsInfinite(NAN) failed";
|
||||
assert checkIsInfinite(INFINITY) == true, "checkIsInfinite(INFINITY) failed";
|
||||
assert checkIsInfinite(0.0) == false, "checkIsInfinite(0.0) failed";
|
||||
assert checkIsInfinite(1) == false, "checkIsInfinite(1) failed";
|
||||
}
|
||||
|
||||
// test epsilionCompare
|
||||
|
||||
14
test/scripts/short-circuit.toy
Normal file
14
test/scripts/short-circuit.toy
Normal file
@@ -0,0 +1,14 @@
|
||||
//These operators should short-circuit
|
||||
assert (true && false) == false, "(true && false) == false failed";
|
||||
assert (false && true) == false, "(false && true) == false failed";
|
||||
|
||||
assert (true || false) == true, "(true || false) == true failed";
|
||||
assert (false || true) == true, "(false || true) == true failed";
|
||||
|
||||
|
||||
//make sure the right value is being returned when chained
|
||||
assert "a" && "b" && "c" == "c", "chained && failed";
|
||||
assert "a" || "b" || "c" == "a", "chained || failed";
|
||||
|
||||
|
||||
print "All good";
|
||||
@@ -1,9 +0,0 @@
|
||||
//explicitly support && and || short circuits
|
||||
|
||||
assert 1 && 2 == 2, "&& short-circuit failed";
|
||||
|
||||
assert 1 || 2 == 1, "|| short-circuit failed";
|
||||
|
||||
|
||||
print "All good";
|
||||
|
||||
8
test/scripts/trailing-comma-bugfix.toy
Normal file
8
test/scripts/trailing-comma-bugfix.toy
Normal file
@@ -0,0 +1,8 @@
|
||||
var array = [
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9, //explicitly leave a trailing comma
|
||||
];
|
||||
|
||||
|
||||
print "All good";
|
||||
@@ -18,6 +18,7 @@ static void noPrintFn(const char* output) {
|
||||
//NO OP
|
||||
}
|
||||
|
||||
int failedAssertions = 0;
|
||||
int ignoredAssertions = 0;
|
||||
static void noAssertFn(const char* output) {
|
||||
if (strncmp(output, "!ignore", 7) == 0) {
|
||||
@@ -27,6 +28,7 @@ static void noAssertFn(const char* output) {
|
||||
fprintf(stderr, TOY_CC_ERROR "Assertion failure: ");
|
||||
fprintf(stderr, "%s", output);
|
||||
fprintf(stderr, "\n" TOY_CC_RESET); //default new line
|
||||
failedAssertions++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +129,7 @@ int main() {
|
||||
"index-assignment-left-bugfix.toy",
|
||||
"index-dictionaries.toy",
|
||||
"index-strings.toy",
|
||||
"indexing-in-argument-list-bugfix.toy",
|
||||
"jumps.toy",
|
||||
"jumps-in-functions.toy",
|
||||
"logicals.toy",
|
||||
@@ -138,8 +141,9 @@ int main() {
|
||||
"panic-within-functions.toy",
|
||||
"polyfill-insert.toy",
|
||||
"polyfill-remove.toy",
|
||||
"short-circuiting-support.toy",
|
||||
"short-circuit.toy",
|
||||
"ternary-expressions.toy",
|
||||
"trailing-comma-bugfix.toy",
|
||||
"types.toy",
|
||||
NULL
|
||||
};
|
||||
@@ -160,7 +164,10 @@ int main() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
return 0;
|
||||
if (failedAssertions == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
|
||||
return failedAssertions;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user