Compare commits

...

28 Commits

Author SHA1 Message Date
Kayne Ruse cce8ae1ea3 Added disassembler, thanks @hiperiondev, bumped minor version 2023-08-14 23:06:05 +10:00
Kayne Ruse ce54912232 Removed an extra pair of SCOPE_BEGIN and SCOPE_END from function bytecode
This should reduce the memory footprint a bit
2023-08-14 22:17:33 +10:00
Kayne Ruse 23b55fc360 Fixed execFnDecl accidentally modifying the literalCache for a moment, resolved #105 2023-08-14 10:47:10 +10:00
Kayne Ruse 62fe86f99b Fixed indexing in argument lists, resolved #102 2023-08-09 02:25:07 +10:00
Ratstail91 401de578a5 Short circuitable operators are extremely loose 2023-08-06 04:53:46 +10:00
Kayne Ruse fb4258f9df Fixed broken test 2023-08-06 04:38:55 +10:00
Ratstail91 f885fdaf4c Short circuits are now functioning correctly, resolved #73 2023-08-06 04:28:02 +10:00
Kayne Ruse cfec1b6911 Added int to float coercions to function args and returns, when specified 2023-08-06 02:17:32 +10:00
Kayne Ruse a63bdaef1c Merge remote-tracking branch 'refs/remotes/origin/main' 2023-08-04 18:43:32 +10:00
Kayne Ruse 3783c94064 Allow trailing commas when writing a compound 2023-08-04 18:43:07 +10:00
Ratstail91 d292b33184 Tweaked types to stop MSVC complaining 2023-08-04 18:24:54 +10:00
Kayne Ruse 64944c24f6 Snipped some duplicate code, resolved #97 2023-08-04 14:52:01 +10:00
Kayne Ruse 604604e8bc Two opcodes weren't being used, resolved #98 2023-08-04 14:51:08 +10:00
Kayne Ruse 67e49b7477 Fixed the way an identifier was handled, resolved #99 2023-08-04 14:45:07 +10:00
Kayne Ruse 967963c9d7 Fixed a spelling mistake 2023-08-03 15:22:06 +10:00
Kayne Ruse 9b469e6eb0 Merge pull request #94 from Add00/main
Adding a math library to toy
2023-08-03 01:40:19 +10:00
Add00 f8094fa17e Added hyperbolic and additional comparisons 2023-08-02 11:25:27 -04:00
Add00 8714c56c3e Implemented feedback 2023-08-02 08:39:50 -04:00
Add00 9faaa311e0 Fixed Memory Leak 2023-08-01 17:50:20 -04:00
Add00 f5ba1181c0 Added arc versions of trigonometric functions 2023-08-01 13:41:55 -04:00
Add00 b06b2d9485 test cases and additional functions 2023-08-01 09:04:37 -04:00
Add00 e3e9ca7ece Added math library 2023-07-31 23:31:12 -04:00
Add00 81fe278c96 Added partial cos and sine implementations 2023-07-31 19:02:55 -04:00
Add00 027d093e21 Added math constants for pi and e 2023-07-31 13:56:06 -04:00
Add00 2eaf7fc71a Merge branch 'main' of https://github.com/Add00/Toy 2023-07-31 13:16:01 -04:00
Add00 c43310f316 Code clean up 2023-07-31 13:13:10 -04:00
Add00 6e07c5f2f4 Merge branch 'Ratstail91:main' into main 2023-07-31 13:11:06 -04:00
Add00 5317a12383 Added radian and degree conversion functions. 2023-07-30 23:17:43 -04:00
33 changed files with 2365 additions and 84 deletions
+2
View File
@@ -136,6 +136,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="repl\drive_system.c" /> <ClCompile Include="repl\drive_system.c" />
<ClCompile Include="repl\lib_math.c" />
<ClCompile Include="repl\lib_random.c" /> <ClCompile Include="repl\lib_random.c" />
<ClCompile Include="repl\lib_runner.c" /> <ClCompile Include="repl\lib_runner.c" />
<ClCompile Include="repl\lib_standard.c" /> <ClCompile Include="repl\lib_standard.c" />
@@ -145,6 +146,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="repl\drive_system.h" /> <ClInclude Include="repl\drive_system.h" />
<ClInclude Include="repl\lib_math.h" />
<ClInclude Include="repl\lib_random.h" /> <ClInclude Include="repl\lib_random.h" />
<ClInclude Include="repl\lib_runner.h" /> <ClInclude Include="repl\lib_runner.h" />
<ClInclude Include="repl\lib_standard.h" /> <ClInclude Include="repl\lib_standard.h" />
+1152
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include "toy_interpreter.h"
int Toy_hookMath(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+1 -1
View File
@@ -2,7 +2,7 @@ CC=gcc
IDIR+=. ../source IDIR+=. ../source
CFLAGS+=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable CFLAGS+=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS+=-ltoy LIBS+=-ltoy -lm
ODIR = obj ODIR = obj
SRC = $(wildcard *.c) SRC = $(wildcard *.c)
+2
View File
@@ -4,6 +4,7 @@
#include "lib_standard.h" #include "lib_standard.h"
#include "lib_random.h" #include "lib_random.h"
#include "lib_runner.h" #include "lib_runner.h"
#include "lib_math.h"
#include "toy_console_colors.h" #include "toy_console_colors.h"
@@ -30,6 +31,7 @@ void repl(const char* initialInput) {
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom); Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_injectNativeHook(&interpreter, "math", Toy_hookMath);
for(;;) { for(;;) {
if (!initialInput) { if (!initialInput) {
+2
View File
@@ -3,6 +3,7 @@
#include "lib_standard.h" #include "lib_standard.h"
#include "lib_random.h" #include "lib_random.h"
#include "lib_runner.h" #include "lib_runner.h"
#include "lib_math.h"
#include "toy_console_colors.h" #include "toy_console_colors.h"
@@ -115,6 +116,7 @@ void Toy_runBinary(const unsigned char* tb, size_t size) {
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard); Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom); Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner); Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_injectNativeHook(&interpreter, "math", Toy_hookMath);
Toy_runInterpreter(&interpreter, tb, (int)size); Toy_runInterpreter(&interpreter, tb, (int)size);
Toy_freeInterpreter(&interpreter); Toy_freeInterpreter(&interpreter);
+12
View 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";
+30
View File
@@ -124,6 +124,16 @@ static void freeASTNodeCustom(Toy_ASTNode* node, bool freeSelf) {
//NO-OP //NO-OP
break; 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: case TOY_AST_NODE_PREFIX_INCREMENT:
Toy_freeLiteral(node->prefixIncrement.identifier); Toy_freeLiteral(node->prefixIncrement.identifier);
break; break;
@@ -348,6 +358,26 @@ void Toy_emitASTNodeContinue(Toy_ASTNode** nodeHandle) {
*nodeHandle = tmp; *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) { void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1); Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
+22
View File
@@ -29,6 +29,8 @@ typedef enum Toy_ASTNodeType {
TOY_AST_NODE_FOR, //for control flow TOY_AST_NODE_FOR, //for control flow
TOY_AST_NODE_BREAK, //for control flow TOY_AST_NODE_BREAK, //for control flow
TOY_AST_NODE_CONTINUE, //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_PREFIX_INCREMENT, //increment a variable
TOY_AST_NODE_POSTFIX_INCREMENT, //increment a variable TOY_AST_NODE_POSTFIX_INCREMENT, //increment a variable
TOY_AST_NODE_PREFIX_DECREMENT, //decrement a variable TOY_AST_NODE_PREFIX_DECREMENT, //decrement a variable
@@ -204,6 +206,24 @@ typedef struct Toy_NodeContinue {
Toy_ASTNodeType type; Toy_ASTNodeType type;
} Toy_NodeContinue; } 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 //pre-post increment/decrement
void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier); void Toy_emitASTNodePrefixIncrement(Toy_ASTNode** nodeHandle, Toy_Literal identifier);
void Toy_emitASTNodePrefixDecrement(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_NodeFor pathFor;
Toy_NodeBreak pathBreak; Toy_NodeBreak pathBreak;
Toy_NodeContinue pathContinue; Toy_NodeContinue pathContinue;
Toy_NodeAnd pathAnd;
Toy_NodeOr pathOr;
Toy_NodePrefixIncrement prefixIncrement; Toy_NodePrefixIncrement prefixIncrement;
Toy_NodePrefixDecrement prefixDecrement; Toy_NodePrefixDecrement prefixDecrement;
Toy_NodePostfixIncrement postfixIncrement; Toy_NodePostfixIncrement postfixIncrement;
+2 -2
View File
@@ -54,7 +54,7 @@ The current minor version of Toy. This value is embedded into the bytecode, and
This value MUST fit into an unsigned char. This value MUST fit into an unsigned char.
!*/ !*/
#define TOY_VERSION_MINOR 2 #define TOY_VERSION_MINOR 3
/*! /*!
### TOY_VERSION_PATCH ### TOY_VERSION_PATCH
@@ -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. This value MUST fit into an unsigned char.
!*/ !*/
#define TOY_VERSION_PATCH 1 #define TOY_VERSION_PATCH 0
/*! /*!
### TOY_VERSION_BUILD ### TOY_VERSION_BUILD
+61 -5
View File
@@ -318,6 +318,12 @@ bool checkNodeInTree(Toy_ASTNode* tree, Toy_ASTNode* node) {
case TOY_AST_NODE_FOR: 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); 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_ERROR:
case TOY_AST_NODE_LITERAL: case TOY_AST_NODE_LITERAL:
case TOY_AST_NODE_BREAK: 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:
case TOY_OP_COMPARE_GREATER_EQUAL: case TOY_OP_COMPARE_GREATER_EQUAL:
case TOY_OP_INVERT: case TOY_OP_INVERT:
case TOY_OP_AND:
case TOY_OP_OR:
//place the rhs result before the outer instruction //place the rhs result before the outer instruction
compiler->bytecode[compiler->count++] = (unsigned char)ret; //1 byte compiler->bytecode[compiler->count++] = (unsigned char)ret; //1 byte
ret = TOY_OP_EOF; ret = TOY_OP_EOF;
@@ -583,9 +587,13 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
Toy_initCompiler(fnCompiler); Toy_initCompiler(fnCompiler);
Toy_writeCompiler(fnCompiler, node->fnDecl.arguments); //can be empty, but not NULL Toy_writeCompiler(fnCompiler, node->fnDecl.arguments); //can be empty, but not NULL
Toy_writeCompiler(fnCompiler, node->fnDecl.returns); //can be empty, but not NULL Toy_writeCompiler(fnCompiler, node->fnDecl.returns); //can be empty, but not NULL
Toy_Opcode override = Toy_writeCompilerWithJumps(fnCompiler, node->fnDecl.block, NULL, NULL, -4, rootNode); //can be empty, but not NULL
//BUGFIX: copied from TOY_AST_NODE_BLOCK, omitting the SCOPE_BEGIN and SCOPE_END opcodes (might squeeze a few bytes out of the interpreter's scopes by declaring one less)
for (int i = 0; i < node->fnDecl.block->block.count; i++) {
Toy_Opcode override = Toy_writeCompilerWithJumps(fnCompiler, &(node->fnDecl.block->block.nodes[i]), NULL, NULL, -4, &(node->fnDecl.block->block.nodes[i]));
if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte fnCompiler->bytecode[fnCompiler->count++] = (unsigned char)override; //1 byte
}
} }
//adopt the panic state if anything happened //adopt the panic state if anything happened
@@ -645,7 +653,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 for (int i = 0; i < node->fnCall.arguments->fnCollection.count; i++) { //reverse order, to count from the beginning in the interpreter
//sub-calls //sub-calls
if (node->fnCall.arguments->fnCollection.nodes[i].type != TOY_AST_NODE_LITERAL) { 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 if (override != TOY_OP_EOF) {//compensate for indexing & dot notation being screwy
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
} }
@@ -917,6 +925,54 @@ static Toy_Opcode Toy_writeCompilerWithJumps(Toy_Compiler* compiler, Toy_ASTNode
} }
break; 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: { case TOY_AST_NODE_FN_RETURN: {
//read each returned literal onto the stack, and return the number of values to 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++) { for (int i = 0; i < node->returns.returns->fnCollection.count; i++) {
+68 -43
View File
@@ -582,7 +582,7 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
typeIndex = (int)readByte(interpreter->bytecode, &interpreter->count); 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 type = Toy_copyLiteral(interpreter->literalCache.literals[typeIndex]);
Toy_Literal typeIdn = type; Toy_Literal typeIdn = type;
@@ -597,6 +597,10 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
interpreter->errorOutput("Can't redefine the variable \""); interpreter->errorOutput("Can't redefine the variable \"");
Toy_printLiteralCustom(identifier, interpreter->errorOutput); Toy_printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
Toy_freeLiteral(identifier);
Toy_freeLiteral(type);
return false; return false;
} }
@@ -623,14 +627,16 @@ static bool execVarDecl(Toy_Interpreter* interpreter, bool lng) {
Toy_printLiteralCustom(identifier, interpreter->errorOutput); Toy_printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
Toy_freeLiteral(identifier);
Toy_freeLiteral(type); Toy_freeLiteral(type);
Toy_freeLiteral(val); Toy_freeLiteral(val);
return false; return false;
} }
Toy_freeLiteral(val); Toy_freeLiteral(identifier);
Toy_freeLiteral(type); Toy_freeLiteral(type);
Toy_freeLiteral(val);
return true; return true;
} }
@@ -649,8 +655,15 @@ static bool execFnDecl(Toy_Interpreter* interpreter, bool lng) {
functionIndex = (int)readByte(interpreter->bytecode, &interpreter->count); functionIndex = (int)readByte(interpreter->bytecode, &interpreter->count);
} }
Toy_Literal identifier = interpreter->literalCache.literals[identifierIndex]; Toy_Literal identifier = Toy_copyLiteral(interpreter->literalCache.literals[identifierIndex]);
Toy_Literal function = interpreter->literalCache.literals[functionIndex]; Toy_Literal function = Toy_copyLiteral(interpreter->literalCache.literals[functionIndex]);
if (!TOY_IS_IDENTIFIER(identifier) || !TOY_IS_FUNCTION(function)) {
interpreter->errorOutput("Failed to declare a function, unknown literal error\n");
Toy_freeLiteral(identifier);
Toy_freeLiteral(function);
return false;
}
TOY_AS_FUNCTION(function).scope = Toy_pushScope(interpreter->scope); //hacked in (needed for closure persistance) TOY_AS_FUNCTION(function).scope = Toy_pushScope(interpreter->scope); //hacked in (needed for closure persistance)
@@ -660,6 +673,10 @@ static bool execFnDecl(Toy_Interpreter* interpreter, bool lng) {
interpreter->errorOutput("Can't redefine the function \""); interpreter->errorOutput("Can't redefine the function \"");
Toy_printLiteralCustom(identifier, interpreter->errorOutput); Toy_printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
Toy_freeLiteral(identifier);
Toy_freeLiteral(function);
return false; return false;
} }
@@ -667,6 +684,10 @@ static bool execFnDecl(Toy_Interpreter* interpreter, bool lng) {
interpreter->errorOutput("Incorrect type assigned to variable \""); interpreter->errorOutput("Incorrect type assigned to variable \"");
Toy_printLiteralCustom(identifier, interpreter->errorOutput); Toy_printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
Toy_freeLiteral(identifier);
Toy_freeLiteral(function);
return false; return false;
} }
@@ -674,6 +695,8 @@ static bool execFnDecl(Toy_Interpreter* interpreter, bool lng) {
TOY_AS_FUNCTION(function).scope = NULL; TOY_AS_FUNCTION(function).scope = NULL;
Toy_freeLiteral(type); Toy_freeLiteral(type);
Toy_freeLiteral(identifier);
Toy_freeLiteral(function);
return true; return true;
} }
@@ -1042,57 +1065,63 @@ static bool execCompareLessEqual(Toy_Interpreter* interpreter, bool invert) {
} }
static bool execAnd(Toy_Interpreter* interpreter) { static bool execAnd(Toy_Interpreter* interpreter) {
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal lhs = 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; Toy_Literal lhsIdn = lhs;
if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) { if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) {
Toy_freeLiteral(lhsIdn); Toy_freeLiteral(lhsIdn);
} }
//short-circuit - broken, see issue #73 //short-circuit - if not true
if (!TOY_IS_TRUTHY(lhs)) { if (!TOY_IS_TRUTHY(lhs)) {
Toy_pushLiteralArray(&interpreter->stack, 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 { else {
Toy_pushLiteralArray(&interpreter->stack, rhs); readShort(interpreter->bytecode, &interpreter->count); //discard
} }
Toy_freeLiteral(lhs); Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return true; return true;
} }
static bool execOr(Toy_Interpreter* interpreter) { static bool execOr(Toy_Interpreter* interpreter) {
Toy_Literal rhs = Toy_popLiteralArray(&interpreter->stack);
Toy_Literal lhs = 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; Toy_Literal lhsIdn = lhs;
if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) { if (TOY_IS_IDENTIFIER(lhs) && Toy_parseIdentifierToValue(interpreter, &lhs)) {
Toy_freeLiteral(lhsIdn); Toy_freeLiteral(lhsIdn);
} }
//short-circuit - broken, see issue #73 //short-circuit - if is true
if (TOY_IS_TRUTHY(lhs)) { if (TOY_IS_TRUTHY(lhs)) {
Toy_pushLiteralArray(&interpreter->stack, 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 { else {
Toy_pushLiteralArray(&interpreter->stack, rhs); readShort(interpreter->bytecode, &interpreter->count); //discard
} }
Toy_freeLiteral(lhs); Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return true; return true;
} }
@@ -1985,27 +2014,9 @@ static void readInterpreterSections(Toy_Interpreter* interpreter) {
} }
break; break;
case TOY_LITERAL_TYPE: { case TOY_LITERAL_TYPE:
//what the literal is case TOY_LITERAL_TYPE_INTERMEDIATE:
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: {
//what the literal represents //what the literal represents
Toy_LiteralType literalType = (Toy_LiteralType)readByte(interpreter->bytecode, &interpreter->count); Toy_LiteralType literalType = (Toy_LiteralType)readByte(interpreter->bytecode, &interpreter->count);
unsigned char constant = readByte(interpreter->bytecode, &interpreter->count); unsigned char constant = readByte(interpreter->bytecode, &interpreter->count);
@@ -2322,6 +2333,13 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
Toy_freeLiteral(argIdn); 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)) { if (!Toy_setScopeVariable(inner.scope, paramArray->literals[i], arg, false)) {
interpreter->errorOutput("[internal] Could not define parameter (bad type?)\n"); interpreter->errorOutput("[internal] Could not define parameter (bad type?)\n");
@@ -2416,6 +2434,13 @@ bool Toy_callLiteralFn(Toy_Interpreter* interpreter, Toy_Literal func, Toy_Liter
for (int i = 0; i < returnsFromInner.count && returnValue; i++) { for (int i = 0; i < returnsFromInner.count && returnValue; i++) {
Toy_Literal ret = Toy_popLiteralArray(&returnsFromInner); 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 //check the return types
if (returnArray->count > 0 && TOY_AS_TYPE(returnArray->literals[i]).typeOf != ret.type) { if (returnArray->count > 0 && TOY_AS_TYPE(returnArray->literals[i]).typeOf != ret.type) {
interpreter->errorOutput("Bad type found in return value\n"); interpreter->errorOutput("Bad type found in return value\n");
+3 -3
View File
@@ -237,7 +237,7 @@ static Toy_Token makeKeywordOrIdentifier(Toy_Lexer* lexer) {
//scan for a keyword //scan for a keyword
for (int i = 0; Toy_keywordTypes[i].keyword; i++) { 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; Toy_Token token;
token.type = Toy_keywordTypes[i].type; token.type = Toy_keywordTypes[i].type;
@@ -317,10 +317,10 @@ Toy_Token Toy_private_scanLexer(Toy_Lexer* lexer) {
if (advance(lexer) != '&') { if (advance(lexer) != '&') {
return makeErrorToken(lexer, "Unexpected '&'"); return makeErrorToken(lexer, "Unexpected '&'");
} else { } 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_QUESTION);
case ':': return makeToken(lexer, TOY_TOKEN_COLON); case ':': return makeToken(lexer, TOY_TOKEN_COLON);
+2 -2
View File
@@ -29,8 +29,8 @@ typedef enum Toy_Opcode {
TOY_OP_SCOPE_BEGIN, TOY_OP_SCOPE_BEGIN,
TOY_OP_SCOPE_END, TOY_OP_SCOPE_END,
TOY_OP_TYPE_DECL, //declare a type to be used (as a literal) TOY_OP_TYPE_DECL_removed,
TOY_OP_TYPE_DECL_LONG, //declare a type to be used (as a long literal) TOY_OP_TYPE_DECL_LONG_removed,
TOY_OP_VAR_DECL, //declare a variable to be used (as a literal) TOY_OP_VAR_DECL, //declare a variable to be used (as a literal)
TOY_OP_VAR_DECL_LONG, //declare a variable to be used (as a long literal) TOY_OP_VAR_DECL_LONG, //declare a variable to be used (as a long literal)
+38 -12
View File
@@ -168,6 +168,10 @@ static Toy_Opcode compound(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
consume(parser, TOY_TOKEN_COMMA, "Expected ',' in array or dictionary"); consume(parser, TOY_TOKEN_COMMA, "Expected ',' in array or dictionary");
} }
if (match(parser, TOY_TOKEN_BRACKET_RIGHT)) { //allow for trailing commas
break;
}
iterations++; iterations++;
Toy_ASTNode* left = NULL; 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) { static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
advance(parser); advance(parser);
@@ -428,16 +454,6 @@ static Toy_Opcode binary(Toy_Parser* parser, Toy_ASTNode** nodeHandle) {
return TOY_OP_COMPARE_GREATER_EQUAL; 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: default:
error(parser, parser->previous, "Unexpected token passed to binary precedence rule"); error(parser, parser->previous, "Unexpected token passed to binary precedence rule");
return TOY_OP_EOF; 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_GREATER,
{NULL, binary, PREC_COMPARISON},// TOKEN_LESS_EQUAL, {NULL, binary, PREC_COMPARISON},// TOKEN_LESS_EQUAL,
{NULL, binary, PREC_COMPARISON},// TOKEN_GREATER_EQUAL, {NULL, binary, PREC_COMPARISON},// TOKEN_GREATER_EQUAL,
{NULL, binary, PREC_AND},// TOKEN_AND, {NULL, circuit, PREC_AND},// TOKEN_AND,
{NULL, binary, PREC_OR},// TOKEN_OR, {NULL, circuit, PREC_OR},// TOKEN_OR,
//other operators //other operators
{NULL, question, PREC_TERNARY}, //TOKEN_QUESTION, {NULL, question, PREC_TERNARY}, //TOKEN_QUESTION,
@@ -1281,6 +1297,16 @@ static void parsePrecedence(Toy_Parser* parser, Toy_ASTNode** nodeHandle, Preced
continue; 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); Toy_emitASTNodeBinary(nodeHandle, rhsNode, opcode);
//optimise away the constants //optimise away the constants
+2 -2
View File
@@ -74,8 +74,8 @@ typedef enum Toy_TokenType {
TOY_TOKEN_GREATER, TOY_TOKEN_GREATER,
TOY_TOKEN_LESS_EQUAL, TOY_TOKEN_LESS_EQUAL,
TOY_TOKEN_GREATER_EQUAL, TOY_TOKEN_GREATER_EQUAL,
TOY_TOKEN_AND, TOY_TOKEN_AND_AND,
TOY_TOKEN_OR, TOY_TOKEN_OR_OR,
//other operators //other operators
TOY_TOKEN_QUESTION, TOY_TOKEN_QUESTION,
+1 -1
View File
@@ -2,7 +2,7 @@ CC=gcc
IDIR +=. ../source ../repl IDIR +=. ../source ../repl
CFLAGS +=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable CFLAGS +=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS += LIBS +=-lm
ODIR = obj ODIR = obj
TARGETS = $(wildcard ../source/*.c) $(wildcard ../repl/lib_*.c) ../repl/repl_tools.c ../repl/drive_system.c TARGETS = $(wildcard ../source/*.c) $(wildcard ../repl/lib_*.c) ../repl/repl_tools.c ../repl/drive_system.c
TESTS = $(wildcard test_*.c) TESTS = $(wildcard test_*.c)
+16
View File
@@ -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"; print "All good";
@@ -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";
+185
View File
@@ -0,0 +1,185 @@
import math;
// test pow
{
assert pow(5, 3) == 125, "pow(5, 3) failed";
assert pow(-5, 3) == -125, "pow(-5, 3) failed";
assert pow(-5.5, 3) == -166.375, "pow(-5.5, 3) failed";
assert pow(0, 1) == 0.0, "pow(0, 1) failed";
assert pow(-0.0, 1) == -0.0, "pow(0, 1) failed";
}
// test sqrt
{
assert sqrt(25) == 5, "sqrt(25) failed";
assert sqrt(256.0) == 16, "sqrt(256.0) failed";
assert checkIsNaN(sqrt(-256.0)), "sqrt(-256.0) failed";
assert sqrt(1) == 1, "sqrt(1) failed";
assert sqrt(0) == 0, "sqrt(0) failed";
}
// test cbrt
{
assert cbrt(64) == 4, "cbrt(64) failed";
assert cbrt(4096.0) == 16, "cbrt(4096.0) failed";
assert cbrt(-64) == -4, "cbrt(-64) failed";
assert cbrt(1) == 1, "cbrt(1) failed";
assert cbrt(0) == 0, "cbrt(0) failed";
}
// test hypot
{
assert hypot(3, 4) == 5, "hypot(3, 4) failed";
}
// test toRad
{
assert toRadians(0) == 0, "toRadians(0) failed";
assert toRadians(180) == PI, "toRadians(180) failed";
assert toRadians(360) == 2 * PI, "toRadians(360) failed";
}
// test toDeg
{
assert toDegrees(0) == 0, "toDegrees(0) failed";
assert toDegrees(PI) == 180, "toDegrees(PI) failed";
assert toDegrees(2 * PI) == 360, "toDegrees(2*PI) failed";
}
// test sin
{
assert epsilionCompare(sin(PI), 0), "sin(PI) failed";
assert epsilionCompare(sin(PI / 2), 1), "sin(PI/2) failed";
assert epsilionCompare(sin(0), 0), "sin(0) failed";
}
// test cos
{
assert epsilionCompare(cos(PI), -1), "cos(PI) failed";
assert epsilionCompare(cos(PI / 2), 0), "cos(PI/2) failed";
assert epsilionCompare(cos(0), 1), "cos(0) failed";
}
// test tan
{
assert epsilionCompare(tan(PI), 0), "tan(PI) failed";
assert epsilionCompare(tan(PI / 4), 1), "tan(PI/4) failed";
assert epsilionCompare(tan(0), 0), "tan(0) failed";
}
// test asin
{
assert epsilionCompare(asin(1), 1.570796), "asin(1) failed";
assert epsilionCompare(asin(-0.5), -0.523599), "asin(-0.5) failed";
assert epsilionCompare(asin(0), 0), "asin(0) failed";
}
// test acos
{
assert epsilionCompare(acos(1), 0), "acos(1) failed";
assert epsilionCompare(acos(0.5), 1.047198), "acos(0.5) failed";
assert epsilionCompare(acos(0), 1.570796), "acos(0) failed";
}
// test atan
{
assert epsilionCompare(atan(1), 0.785398), "acos(1) failed";
assert epsilionCompare(atan(INFINITY), 1.570796), "atan(INFINITY) failed";
assert epsilionCompare(atan(0), 0), "atan(0) failed";
}
// test atan2
{
assert epsilionCompare(atans(0, 0), 0), "atan2(0, 0) failed";
assert epsilionCompare(atans(7, 0), 1.570796), "atans(7, 0) failed";
}
// test sinh
{
assert epsilionCompare(sinh(1), 1.175201), "sinh(1) failed";
assert epsilionCompare(sinh(-1), -1.175201), "sinh(-1) failed";
assert epsilionCompare(sinh(0), 0), "sinh(0) failed";
}
// test cosh
{
assert epsilionCompare(cosh(1), 1.543081), "cosh(1) failed";
assert epsilionCompare(cosh(-1), 1.543081), "cosh(-1) failed";
assert epsilionCompare(cosh(0), 1), "cosh(0) failed";
}
// test tanh
{
assert epsilionCompare(tanh(1), 0.761594), "tanh(1) failed";
assert epsilionCompare(tanh(-1), -0.761594), "tanh(-1) failed";
assert epsilionCompare(tanh(0), 0), "tanh(0) failed";
}
// test asinh
{
assert epsilionCompare(asinh(1), 0.881374), "asinh(1) failed";
assert epsilionCompare(asinh(-1), -0.881374), "asinh(-1) failed";
assert epsilionCompare(asinh(0), 0), "asinh(0) failed";
}
// test acosh
{
assert epsilionCompare(acosh(1), 0), "acosh(1) failed";
assert checkIsNaN(acosh(-1)) == true, "acosh(-1) failed";
assert checkIsNaN(acosh(0)) == true, "acosh(0) failed";
}
// test atanh
{
assert checkIsInfinite(atanh(1)) == true, "atanh(1) failed";
assert checkIsInfinite(atanh(-1)) == true, "atanh(-1) failed";
assert epsilionCompare(atanh(0), 0), "atanh(0) failed";
}
// test checkIsNaN
{
assert checkIsNaN(NAN) == true, "checkIsNaN(NAN) failed";
assert checkIsNaN(INFINITY) == false, "checkIsNaN(INFINITY) failed";
assert checkIsNaN(0.0) == false, "checkIsNaN(0.0) failed";
assert checkIsNaN(INFINITY - INFINITY) == true, "checkIsNaN(INFINITY - INFINITY) failed";
}
// test checkIsFinite
{
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 checkIsInfinite
{
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
{
assert epsilionCompare(1, 1) == true, "epsilionCompare(1, 1) failed";
assert epsilionCompare(1, 1.000001) == true, "epsilionCompare(1, 1.000001) failed";
assert epsilionCompare(1, 1.001) == false, "epsilionCompare(1, 1.001) failed";
assert epsilionCompare(0, 0) == true, "epsilionCompare(0, 0) failed";
}
+14
View 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
View File
@@ -0,0 +1,8 @@
var array = [
1, 2, 3,
4, 5, 6,
7, 8, 9, //explicitly leave a trailing comma
];
print "All good";
+9 -2
View File
@@ -18,6 +18,7 @@ static void noPrintFn(const char* output) {
//NO OP //NO OP
} }
int failedAssertions = 0;
int ignoredAssertions = 0; int ignoredAssertions = 0;
static void noAssertFn(const char* output) { static void noAssertFn(const char* output) {
if (strncmp(output, "!ignore", 7) == 0) { 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, TOY_CC_ERROR "Assertion failure: ");
fprintf(stderr, "%s", output); fprintf(stderr, "%s", output);
fprintf(stderr, "\n" TOY_CC_RESET); //default new line fprintf(stderr, "\n" TOY_CC_RESET); //default new line
failedAssertions++;
} }
} }
@@ -127,6 +129,7 @@ int main() {
"index-assignment-left-bugfix.toy", "index-assignment-left-bugfix.toy",
"index-dictionaries.toy", "index-dictionaries.toy",
"index-strings.toy", "index-strings.toy",
"indexing-in-argument-list-bugfix.toy",
"jumps.toy", "jumps.toy",
"jumps-in-functions.toy", "jumps-in-functions.toy",
"logicals.toy", "logicals.toy",
@@ -138,8 +141,9 @@ int main() {
"panic-within-functions.toy", "panic-within-functions.toy",
"polyfill-insert.toy", "polyfill-insert.toy",
"polyfill-remove.toy", "polyfill-remove.toy",
"short-circuiting-support.toy", "short-circuit.toy",
"ternary-expressions.toy", "ternary-expressions.toy",
"trailing-comma-bugfix.toy",
"types.toy", "types.toy",
NULL NULL
}; };
@@ -160,7 +164,10 @@ int main() {
return -1; return -1;
} }
if (failedAssertions == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET); printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
return 0; }
return failedAssertions;
} }
+2
View File
@@ -18,6 +18,7 @@
#include "../repl/lib_standard.h" #include "../repl/lib_standard.h"
#include "../repl/lib_random.h" #include "../repl/lib_random.h"
#include "../repl/lib_runner.h" #include "../repl/lib_runner.h"
#include "../repl/lib_math.h"
//supress the print output //supress the print output
static void noPrintFn(const char* output) { static void noPrintFn(const char* output) {
@@ -76,6 +77,7 @@ int main() {
{"standard.toy", "standard", Toy_hookStandard}, {"standard.toy", "standard", Toy_hookStandard},
{"runner.toy", "runner", Toy_hookRunner}, {"runner.toy", "runner", Toy_hookRunner},
{"random.toy", "random", Toy_hookRandom}, {"random.toy", "random", Toy_hookRandom},
{"math.toy", "math", Toy_hookMath},
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
BIN
View File
Binary file not shown.
+550
View File
@@ -0,0 +1,550 @@
/*
* disassembler.c
*
* Created on: 10 ago. 2023
* Original Author: egonzalez
*
* Further modified by Kayne Ruse, and added to the Toy Programming Language tool repository.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "disassembler.h"
#define SPC(n) printf("%.*s", n, "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |");
#define EP(x) [x] = #x
const char *OP_STR[] = {
EP(DIS_OP_EOF), //
EP(DIS_OP_PASS), //
EP(DIS_OP_ASSERT), //
EP(DIS_OP_PRINT), //
EP(DIS_OP_LITERAL), //
EP(DIS_OP_LITERAL_LONG), //
EP(DIS_OP_LITERAL_RAW), //
EP(DIS_OP_NEGATE), //
EP(DIS_OP_ADDITION), //
EP(DIS_OP_SUBTRACTION), //
EP(DIS_OP_MULTIPLICATION), //
EP(DIS_OP_DIVISION), //
EP(DIS_OP_MODULO), //
EP(DIS_OP_GROUPING_BEGIN), //
EP(DIS_OP_GROUPING_END), //
EP(DIS_OP_SCOPE_BEGIN), //
EP(DIS_OP_SCOPE_END), //
EP(DIS_OP_TYPE_DECL_removed), //
EP(DIS_OP_TYPE_DECL_LONG_removed), //
EP(DIS_OP_VAR_DECL), //
EP(DIS_OP_VAR_DECL_LONG), //
EP(DIS_OP_FN_DECL), //
EP(DIS_OP_FN_DECL_LONG), //
EP(DIS_OP_VAR_ASSIGN), //
EP(DIS_OP_VAR_ADDITION_ASSIGN), //
EP(DIS_OP_VAR_SUBTRACTION_ASSIGN), //
EP(DIS_OP_VAR_MULTIPLICATION_ASSIGN), //
EP(DIS_OP_VAR_DIVISION_ASSIGN), //
EP(DIS_OP_VAR_MODULO_ASSIGN), //
EP(DIS_OP_TYPE_CAST), //
EP(DIS_OP_TYPE_OF), //
EP(DIS_OP_IMPORT), //
EP(DIS_OP_EXPORT_removed), //
EP(DIS_OP_INDEX), //
EP(DIS_OP_INDEX_ASSIGN), //
EP(DIS_OP_INDEX_ASSIGN_INTERMEDIATE), //
EP(DIS_OP_DOT), //
EP(DIS_OP_COMPARE_EQUAL), //
EP(DIS_OP_COMPARE_NOT_EQUAL), //
EP(DIS_OP_COMPARE_LESS), //
EP(DIS_OP_COMPARE_LESS_EQUAL), //
EP(DIS_OP_COMPARE_GREATER), //
EP(DIS_OP_COMPARE_GREATER_EQUAL), //
EP(DIS_OP_INVERT), //
EP(DIS_OP_AND), //
EP(DIS_OP_OR), //
EP(DIS_OP_JUMP), //
EP(DIS_OP_IF_FALSE_JUMP), //
EP(DIS_OP_FN_CALL), //
EP(DIS_OP_FN_RETURN), //
EP(DIS_OP_POP_STACK), //
EP(DIS_OP_TERNARY), //
EP(DIS_OP_FN_END), //
};
const char *LIT_STR[] = {
EP(DIS_LITERAL_NULL), //
EP(DIS_LITERAL_BOOLEAN), //
EP(DIS_LITERAL_INTEGER), //
EP(DIS_LITERAL_FLOAT), //
EP(DIS_LITERAL_STRING), //
EP(DIS_LITERAL_ARRAY), //
EP(DIS_LITERAL_DICTIONARY), //
EP(DIS_LITERAL_FUNCTION), //
EP(DIS_LITERAL_IDENTIFIER), //
EP(DIS_LITERAL_TYPE), //
EP(DIS_LITERAL_OPAQUE), //
EP(DIS_LITERAL_ANY), //
EP(DIS_LITERAL_TYPE_INTERMEDIATE), //
EP(DIS_LITERAL_ARRAY_INTERMEDIATE), //
EP(DIS_LITERAL_DICTIONARY_INTERMEDIATE), //
EP(DIS_LITERAL_FUNCTION_INTERMEDIATE), //
EP(DIS_LITERAL_FUNCTION_ARG_REST), //
EP(DIS_LITERAL_FUNCTION_NATIVE), //
EP(DIS_LITERAL_FUNCTION_HOOK), //
EP(DIS_LITERAL_INDEX_BLANK), //
};
enum DIS_ARG_TYPE {
DIS_ARG_NONE, //
DIS_ARG_BYTE, //
DIS_ARG_WORD, //
DIS_ARG_INTEGER, //
DIS_ARG_FLOAT, //
DIS_ARG_STRING //
};
const uint8_t OP_ARGS[DIS_OP_END_OPCODES][2] = {
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_EOF
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_PASS
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_ASSERT
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_PRINT
{ DIS_ARG_BYTE, DIS_ARG_NONE }, // DIS_OP_LITERAL
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_LITERAL_LONG
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_LITERAL_RAW
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_NEGATE
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_ADDITION
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_SUBTRACTION
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_MULTIPLICATION
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_DIVISION
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_MODULO
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_GROUPING_BEGIN
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_GROUPING_END
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_SCOPE_BEGIN
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_SCOPE_END
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_DECL_removed
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_DECL_LONG_removed
{ DIS_ARG_BYTE, DIS_ARG_BYTE }, // DIS_OP_VAR_DECL
{ DIS_ARG_WORD, DIS_ARG_WORD }, // DIS_OP_VAR_DECL_LONG
{ DIS_ARG_BYTE, DIS_ARG_BYTE }, // DIS_OP_FN_DECL
{ DIS_ARG_WORD, DIS_ARG_WORD }, // DIS_OP_FN_DECL_LONG
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_ADDITION_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_SUBTRACTION_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_MULTIPLICATION_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_DIVISION_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_VAR_MODULO_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_CAST
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TYPE_OF
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_IMPORT
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_EXPORT_removed
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_INDEX
{ DIS_ARG_BYTE, DIS_ARG_NONE }, // DIS_OP_INDEX_ASSIGN
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_INDEX_ASSIGN_INTERMEDIATE
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_DOT
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_EQUAL
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_NOT_EQUAL
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_LESS
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_LESS_EQUAL
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_GREATER
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_COMPARE_GREATER_EQUAL
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_INVERT
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_AND
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_OR
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_JUMP
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_IF_FALSE_JUMP
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_FN_CALL
{ DIS_ARG_WORD, DIS_ARG_NONE }, // DIS_OP_FN_RETURN
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_POP_STACK
{ DIS_ARG_NONE, DIS_ARG_NONE }, // DIS_OP_TERNARY
};
typedef struct dis_program_s {
uint8_t *program;
uint32_t len;
uint32_t pc;
} dis_program_t;
typedef struct dis_func_op_s {
uint32_t start;
uint32_t end;
} dis_func_op_t;
static void dis_print_opcode(uint8_t op);
static uint8_t readByte(const uint8_t *tb, uint32_t *count) {
uint8_t ret = *(uint8_t*) (tb + *count);
*count += 1;
return ret;
}
static uint16_t readWord(const uint8_t *tb, uint32_t *count) {
uint16_t ret = 0;
memcpy(&ret, tb + *count, 2);
*count += 2;
return ret;
}
static int32_t readInt(const uint8_t *tb, uint32_t *count) {
int ret = 0;
memcpy(&ret, tb + *count, 4);
*count += 4;
return ret;
}
static float readFloat(const uint8_t *tb, uint32_t *count) {
float ret = 0;
memcpy(&ret, tb + *count, 4);
*count += 4;
return ret;
}
static char* readString(const uint8_t *tb, uint32_t *count) {
const unsigned char *ret = tb + *count;
*count += strlen((char*) ret) + 1; //+1 for null character
return (char*) ret;
}
static void consumeByte(uint8_t byte, uint8_t *tb, uint32_t *count) {
if (byte != tb[*count]) {
printf("[internal] Failed to consume the correct byte (expected %u, found %u)\n", byte, tb[*count]);
exit(1);
}
*count += 1;
}
///////////////////////////////////////////////////////////////////////////////
static void dis_disassembler_init(dis_program_t **prg) {
(*prg) = malloc(sizeof(struct dis_program_s));
(*prg)->len = 0;
(*prg)->pc = 0;
}
static void dis_disassembler_deinit(dis_program_t **prg) {
free((*prg)->program);
free((*prg));
}
static uint8_t dis_load_file(const char *filename, dis_program_t **prg) {
FILE *f;
size_t fsize, bytes;
uint32_t count = 0;
uint8_t buf = 0;
f = fopen(filename, "r");
if (f == NULL) {
printf("Not able to open the file.\n");
return 1;
}
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fseek(f, 0, SEEK_SET);
(*prg)->program = malloc(fsize * sizeof(uint8_t));
while ((bytes = fread(&buf, sizeof(uint8_t), 1, f)) == 1)
(*prg)->program[count++] = buf;
(*prg)->len = fsize;
printf("\nFile: %s\nSize: %zu\n", filename, fsize);
fclose(f);
return 0;
}
static void dis_read_header(dis_program_t **prg) {
const unsigned char major = readByte((*prg)->program, &((*prg)->pc));
const unsigned char minor = readByte((*prg)->program, &((*prg)->pc));
const unsigned char patch = readByte((*prg)->program, &((*prg)->pc));
const char *build = readString((*prg)->program, &((*prg)->pc));
printf("[Header Version: %d.%d.%d (%s)]\n", major, minor, patch, build);
}
static void dis_print_opcode(uint8_t op) {
if (op == 255) {
printf("SECTION_END");
return;
}
if (op < DIS_OP_END_OPCODES)
printf("%s", (OP_STR[op] + 7));
else
printf("(OP UNKNOWN [%c])", op);
}
///////////////////////////////////////////////////////////////////////////////
#define S_OP(n) \
switch (OP_ARGS[opcode][n]) { \
case DIS_ARG_NONE: \
break; \
case DIS_ARG_BYTE: \
uint = readByte((*prg)->program, &pc); \
printf(" b(%d)", uint); \
break; \
case DIS_ARG_WORD: \
uint = readWord((*prg)->program, &pc);\
printf(" w(%d)", uint); \
break; \
case DIS_ARG_INTEGER: \
intg = readInt((*prg)->program, &pc); \
printf(" i(%d)", intg); \
break; \
case DIS_ARG_FLOAT: \
flt = readFloat((*prg)->program, &pc); \
printf(" f(%f)", flt); \
break; \
case DIS_ARG_STRING: \
str = readString((*prg)->program, &pc); \
printf(" s(%s)", str); \
break; \
default: \
printf("ERROR, unknown argument type\n"); \
exit(1); \
}
static void dis_disassemble_section(dis_program_t **prg, uint32_t pc, uint32_t len, uint8_t spaces, bool is_function) {
uint8_t opcode;
uint32_t uint;
int32_t intg;
float flt;
char *str;
//first 4 bytes of the program section within a function are actually specifying the parameter and return lists
if (is_function) {
printf("\n");
uint16_t args = readWord((*prg)->program, &pc);
uint16_t rets = readWord((*prg)->program, &pc);
SPC(spaces);
printf("| [args literal %d, rets literal %d]", args, rets);
}
while (pc < len) {
opcode = (*prg)->program[pc];
printf("\n");
SPC(spaces);
printf("| [ %05d ](%03d) ", pc++, opcode);
dis_print_opcode(opcode);
if (opcode > DIS_OP_END_OPCODES)
continue;
S_OP(0);
S_OP(1);
}
}
#define LIT_ADD(a, b, c) b[c] = a; ++c;
static void dis_read_interpreter_sections(dis_program_t **prg, uint32_t *pc, uint8_t spaces) {
uint32_t literal_count = 0;
uint8_t literal_type[65536];
const unsigned short literalCount = readWord((*prg)->program, pc);
printf("\n");
SPC(spaces);
printf("| ( Reading %d literals )\n", literalCount);
for (int i = 0; i < literalCount; i++) {
const unsigned char literalType = readByte((*prg)->program, pc);
switch (literalType) {
case DIS_LITERAL_NULL:
LIT_ADD(DIS_LITERAL_NULL, literal_type, literal_count);
SPC(spaces);
printf("| | [%d] ( null )\n", i);
break;
case DIS_LITERAL_BOOLEAN: {
const bool b = readByte((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_BOOLEAN, literal_type, literal_count);
SPC(spaces);
printf("| | [%d] ( boolean %s )\n", i, b ? "true" : "false");
}
break;
case DIS_LITERAL_INTEGER: {
const int d = readInt((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_INTEGER, literal_type, literal_count);
SPC(spaces);
printf("| | [%d] ( integer %d )\n", i, d);
}
break;
case DIS_LITERAL_FLOAT: {
const float f = readFloat((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_FLOAT, literal_type, literal_count);
SPC(spaces);
printf("| | [%d] ( float %f )\n", i, f);
}
break;
case DIS_LITERAL_STRING: {
const char *s = readString((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_STRING, literal_type, literal_count);
SPC(spaces);
printf("| | [%d] ( string \"%s\" )\n", i, s);
}
break;
case DIS_LITERAL_ARRAY_INTERMEDIATE:
case DIS_LITERAL_ARRAY: {
unsigned short length = readWord((*prg)->program, pc);
SPC(spaces);
printf("| | [%d] ( array ", i);
for (int i = 0; i < length; i++) {
int index = readWord((*prg)->program, pc);
printf("%d ", index);
LIT_ADD(DIS_LITERAL_NULL, literal_type, literal_count);
if (!(i % 15) && i != 0) {
printf("\n");
SPC(spaces);
printf("| | ");
}
}
printf(")\n");
LIT_ADD(DIS_LITERAL_ARRAY, literal_type, literal_count);
}
break;
case DIS_LITERAL_DICTIONARY_INTERMEDIATE:
case DIS_LITERAL_DICTIONARY: {
unsigned short length = readWord((*prg)->program, pc);
SPC(spaces);
printf("| | [%d] ( dictionary ", i);
for (int i = 0; i < length / 2; i++) {
int key = readWord((*prg)->program, pc);
int val = readWord((*prg)->program, pc);
printf("(key: %d, val:%d) ", key, val);
if(!(i % 5) && i != 0){
printf("\n");
SPC(spaces);
printf("| | ");
}
}
printf(")\n");
LIT_ADD(DIS_LITERAL_DICTIONARY, literal_type, literal_count);
}
break;
case DIS_LITERAL_FUNCTION: {
unsigned short index = readWord((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_FUNCTION_INTERMEDIATE, literal_type, literal_count);
SPC(spaces);
printf("| | [%d] ( function index: %d )\n", i, index);
}
break;
case DIS_LITERAL_IDENTIFIER: {
const char *str = readString((*prg)->program, pc);
LIT_ADD(DIS_LITERAL_IDENTIFIER, literal_type, literal_count);
SPC(spaces);
printf("| | [%d] ( identifier %s )\n", i, str);
}
break;
case DIS_LITERAL_TYPE:
case DIS_LITERAL_TYPE_INTERMEDIATE: {
uint8_t literalType = readByte((*prg)->program, pc);
uint8_t constant = readByte((*prg)->program, pc);
SPC(spaces);
printf("| | [%d] ( type %s: %d)\n", i, (LIT_STR[literalType] + 12), constant);
if (literalType == DIS_LITERAL_ARRAY) {
uint16_t vt = readWord((*prg)->program, pc);
SPC(spaces);
printf("| | | ( subtype: %d)\n", vt);
}
if (literalType == DIS_LITERAL_DICTIONARY) {
uint8_t kt = readWord((*prg)->program, pc);
uint8_t vt = readWord((*prg)->program, pc);
SPC(spaces);
printf("| | | ( subtype: [%d, %d] )\n", kt, vt);
}
LIT_ADD(literalType, literal_type, literal_count);
}
break;
case DIS_LITERAL_INDEX_BLANK:
LIT_ADD(DIS_LITERAL_INDEX_BLANK, literal_type, literal_count);
SPC(spaces);
printf("| | [%d] ( blank )\n", i);
break;
}
}
consumeByte(DIS_OP_SECTION_END, (*prg)->program, pc);
int functionCount = readWord((*prg)->program, pc);
int functionSize = readWord((*prg)->program, pc);
if (functionCount) {
SPC(spaces);
printf("| | \n");
SPC(spaces);
printf("| | ( fun count: %d, total size: %d )\n", functionCount, functionSize);
uint32_t fcnt = 0;
for (uint32_t i = 0; i < literal_count; i++) {
if (literal_type[i] == DIS_LITERAL_FUNCTION_INTERMEDIATE) {
size_t size = (size_t) readWord((*prg)->program, pc);
uint32_t fpc_start = *pc;
uint32_t fpc_end = *pc + size - 1;
SPC(spaces);
printf("| | |\n");
SPC(spaces);
printf("| | | ( fun %d [ start: %d, end: %d ] )", fcnt, fpc_start, fpc_end);
if ((*prg)->program[*pc + size - 1] != DIS_OP_FN_END) {
printf("\nERROR: Failed to find function end\n");
exit(1);
}
dis_read_interpreter_sections(prg, &fpc_start, spaces + 4);
SPC(spaces);
printf("| | |\n");
SPC(spaces + 4);
printf("| ------ CODE ------");
dis_disassemble_section(prg, fpc_start, fpc_end, spaces + 4, true);
printf("\n");
SPC(spaces + 4);
printf("| ---- END CODE ----\n");
fcnt++;
*pc += size;
}
}
}
consumeByte(DIS_OP_SECTION_END, (*prg)->program, pc);
}
///////////////////////////////////////////////////////////////////////////////
void disassemble(const char *filename) {
dis_program_t *prg;
dis_disassembler_init(&prg);
if (dis_load_file(filename, &prg))
exit(1);
dis_read_header(&prg);
consumeByte(DIS_OP_SECTION_END, prg->program, &(prg->pc));
printf("\n| ---- LITERALS ----");
dis_read_interpreter_sections(&prg, &(prg->pc), 0);
printf("| -- END LITERALS --\n|");
printf("\n| ---- PROGRAM ----");
dis_disassemble_section(&prg, prg->pc, prg->len, 0, false);
printf("\n| -- END PROGRAM --");
printf("\n\n");
dis_disassembler_deinit(&prg);
}
+119
View File
@@ -0,0 +1,119 @@
#ifndef DISASSEMBLER_H_
#define DISASSEMBLER_H_
typedef enum DIS_OPCODES {
DIS_OP_EOF, //
// do nothing
DIS_OP_PASS, //
// basic statements
DIS_OP_ASSERT, //
DIS_OP_PRINT, //
// data
DIS_OP_LITERAL, //
DIS_OP_LITERAL_LONG, // for more than 256 literals in a chunk
DIS_OP_LITERAL_RAW, // forcibly get the raw value of the literal
// arithmetic operators
DIS_OP_NEGATE, //
DIS_OP_ADDITION, //
DIS_OP_SUBTRACTION, //
DIS_OP_MULTIPLICATION, //
DIS_OP_DIVISION, //
DIS_OP_MODULO, //
DIS_OP_GROUPING_BEGIN, //
DIS_OP_GROUPING_END, //
// variable stuff
DIS_OP_SCOPE_BEGIN, //
DIS_OP_SCOPE_END, //
DIS_OP_TYPE_DECL_removed, // deprecated
DIS_OP_TYPE_DECL_LONG_removed, // deprecated
DIS_OP_VAR_DECL, // declare a variable to be used (as a literal)
DIS_OP_VAR_DECL_LONG, // declare a variable to be used (as a long literal)
DIS_OP_FN_DECL, // declare a function to be used (as a literal)
DIS_OP_FN_DECL_LONG, // declare a function to be used (as a long literal)
DIS_OP_VAR_ASSIGN, // assign to a literal
DIS_OP_VAR_ADDITION_ASSIGN, //
DIS_OP_VAR_SUBTRACTION_ASSIGN, //
DIS_OP_VAR_MULTIPLICATION_ASSIGN, //
DIS_OP_VAR_DIVISION_ASSIGN, //
DIS_OP_VAR_MODULO_ASSIGN, //
DIS_OP_TYPE_CAST, // temporarily change a type of an atomic value
DIS_OP_TYPE_OF, // get the type of a variable
DIS_OP_IMPORT, //
DIS_OP_EXPORT_removed, // deprecated
// for indexing
DIS_OP_INDEX, //
DIS_OP_INDEX_ASSIGN, //
DIS_OP_INDEX_ASSIGN_INTERMEDIATE, //
DIS_OP_DOT, //
// comparison of values
DIS_OP_COMPARE_EQUAL, //
DIS_OP_COMPARE_NOT_EQUAL, //
DIS_OP_COMPARE_LESS, //
DIS_OP_COMPARE_LESS_EQUAL, //
DIS_OP_COMPARE_GREATER, //
DIS_OP_COMPARE_GREATER_EQUAL, //
DIS_OP_INVERT, // for booleans
// logical operators
DIS_OP_AND, //
DIS_OP_OR, //
// jumps, and conditional jumps (absolute)
DIS_OP_JUMP, //
DIS_OP_IF_FALSE_JUMP, //
DIS_OP_FN_CALL, //
DIS_OP_FN_RETURN, //
// pop the stack at the end of a complex statement
DIS_OP_POP_STACK, //
//ternary shorthand
DIS_OP_TERNARY, //
//meta
DIS_OP_FN_END, // different from SECTION_END
DIS_OP_END_OPCODES, // mark for end opcodes list. Not valid opcode
DIS_OP_SECTION_END = 255,
} dis_opcode_t;
typedef enum DIS_LITERAL_TYPE {
DIS_LITERAL_NULL, //
DIS_LITERAL_BOOLEAN, //
DIS_LITERAL_INTEGER, //
DIS_LITERAL_FLOAT, //
DIS_LITERAL_STRING, //
DIS_LITERAL_ARRAY, //
DIS_LITERAL_DICTIONARY, //
DIS_LITERAL_FUNCTION, //
DIS_LITERAL_IDENTIFIER, //
DIS_LITERAL_TYPE, //
DIS_LITERAL_OPAQUE, //
DIS_LITERAL_ANY, //
// these are meta-level types - not for general use
DIS_LITERAL_TYPE_INTERMEDIATE, // used to process types in the compiler only
DIS_LITERAL_ARRAY_INTERMEDIATE, // used to process arrays in the compiler only
DIS_LITERAL_DICTIONARY_INTERMEDIATE, // used to process dictionaries in the compiler only
DIS_LITERAL_FUNCTION_INTERMEDIATE, // used to process functions in the compiler only
DIS_LITERAL_FUNCTION_ARG_REST, // used to process function rest parameters only
DIS_LITERAL_FUNCTION_NATIVE, // for handling native functions only
DIS_LITERAL_FUNCTION_HOOK, // for handling hook functions within literals only
DIS_LITERAL_INDEX_BLANK, // for blank indexing i.e. arr[:]
} dis_literal_type_t;
extern void disassemble(const char *filename);
#endif /* DISASSEMBLER_H_ */
+8
View File
@@ -0,0 +1,8 @@
#include <stdlib.h>
#include "disassembler.h"
int main(int argc, const char* argv[]) {
disassemble(argv[1]);
return EXIT_SUCCESS;
}
+27
View File
@@ -0,0 +1,27 @@
CC=gcc
IDIR+=.
CFLAGS+=$(addprefix -I,$(IDIR)) -g -Wall -W -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable
LIBS+=
ODIR = obj
SRC = $(wildcard *.c)
OBJ = $(addprefix $(ODIR)/,$(SRC:.c=.o))
OUTNAME=
OUT=disassembler
all: $(OBJ)
$(CC) $(CFLAGS) -o $(OUT) $(OBJ) $(LIBS)
$(OBJ): | $(ODIR)
$(ODIR):
mkdir $(ODIR)
$(ODIR)/%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
.PHONY: clean
clean:
$(RM) -r $(ODIR)