Compare commits

..

12 Commits

Author SHA1 Message Date
Kayne Ruse 3498baad9b Resolved #45, Exports region removed 2023-01-13 16:12:44 +00:00
Kayne Ruse 0649a141dd Moved time header includes, comment tweaks 2023-01-13 15:39:22 +00:00
Kayne Ruse 65e5905011 Updated license dates 2023-01-11 20:48:47 +00:00
Kayne Ruse bf64275aa9 Floats will always print with a trailing number 2023-01-08 13:26:04 +00:00
Kayne Ruse 08b400debf Added dictionary key mustfail test 2023-01-08 12:58:02 +00:00
Kayne Ruse 9ad2a6cf2e Tweaked build message 2023-01-08 23:46:04 +11:00
Kayne Ruse 8009f410a4 Added mustfail test, fixed compound type decl bug 2023-01-08 12:43:25 +00:00
Kayne Ruse 584fb115b6 Fixed the awful rule110 implementation 2022-11-28 16:48:45 +00:00
Kayne Ruse 70698a4a1a Simplified an optimisation 2022-11-27 02:25:33 +00:00
Kayne Ruse eb26d23363 Added FUNDING.yml, because why is this so popular? 2022-11-27 02:14:03 +00:00
Kayne Ruse c1625c53f4 Patched a bug in deepCopyRefString() 2022-11-26 21:33:46 +00:00
Kayne Ruse fb55f42d0e Tweaked where strlen() is called 2022-11-26 15:53:07 +00:00
27 changed files with 313 additions and 418 deletions
+5
View File
@@ -0,0 +1,5 @@
# These are supported funding model platforms
patreon: krgamestudios
ko_fi: krgamestudios
custom: ["https://www.paypal.com/donate/?hosted_button_id=73Q82T2ZHV8AA"]
+1 -1
View File
@@ -1,6 +1,6 @@
# License
Copyright (c) 2020-2022 Kayne Ruse, KR Game Studios
Copyright (c) 2020-2023 Kayne Ruse, KR Game Studios
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
+2 -1
View File
@@ -2,6 +2,7 @@
#include "memory.h"
#include <time.h>
#include <sys/time.h>
static int nativeClock(Interpreter* interpreter, LiteralArray* arguments) {
@@ -57,7 +58,7 @@ int hookStandard(Interpreter* interpreter, Literal identifier, Literal alias) {
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Literal name = TO_STRING_LITERAL(createRefStringLength(natives[i].name, strlen(natives[i].name)));
Literal name = TO_STRING_LITERAL(createRefString(natives[i].name));
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = LITERAL_FUNCTION_NATIVE;
+3 -2
View File
@@ -1,9 +1,10 @@
#include "lib_timer.h"
#include "toy_common.h"
#include "memory.h"
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
//GOD DAMN IT: https://stackoverflow.com/questions/15846762/timeval-subtract-explanation
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) {
@@ -374,7 +375,7 @@ int hookTimer(Interpreter* interpreter, Literal identifier, Literal alias) {
//load the dict with functions
for (int i = 0; natives[i].name; i++) {
Literal name = TO_STRING_LITERAL(createRefStringLength(natives[i].name, strlen(natives[i].name)));
Literal name = TO_STRING_LITERAL(createRefString(natives[i].name));
Literal func = TO_FUNCTION_LITERAL((void*)natives[i].fn, 0);
func.type = LITERAL_FUNCTION_NATIVE;
+1 -1
View File
@@ -100,7 +100,7 @@ int main(int argc, const char* argv[]) {
return 0;
}
//TODO: remove this when the interpreter meets the specification
//version
if (command.verbose) {
printf(NOTICE "Toy Programming Language Version %d.%d.%d\n" RESET, TOY_VERSION_MAJOR, TOY_VERSION_MINOR, TOY_VERSION_PATCH);
}
+40 -57
View File
@@ -1,66 +1,49 @@
var size: int const = 100;
//number of iterations
var SIZE: int const = 100;
var prev = [];
for (var i = 0; i < size; i++) {
prev.push(false);
//lookup table
var lookup = [
"*": [
"*": [
"*": " ",
" ": "*"
],
" ": [
"*": "*",
" ": " "
]
], " ": [
"*": [
"*": "*",
" ": "*"
],
" ": [
"*": "*",
" ": " "
]
]];
//initial line to build from
var prev: string = "";
for (var i = 0; i < SIZE -1; i++) {
prev += " ";
}
prev += "*"; //initial
print prev;
prev.set(size - 1, true);
fn calc(p, i) {
if (p[i-1] && p[i] && p[i+1]) {
return false;
}
if (p[i-1] && p[i] && !p[i+1]) {
return true;
}
if (p[i-1] && !p[i] && p[i+1]) {
return true;
}
if (p[i-1] && !p[i] && !p[i+1]) {
return false;
}
if (!p[i-1] && p[i] && p[i+1]) {
return true;
}
if (!p[i-1] && p[i] && !p[i+1]) {
return true;
}
if (!p[i-1] && !p[i] && p[i+1]) {
return true;
}
if (!p[i-1] && !p[i] && !p[i+1]) {
return false;
}
}
//run
for (var iteration = 0; iteration < 100; iteration++) {
var line = [false];
for (var i = 1; i < size-1; i++) {
line.push(calc(prev, i));
}
line.push(false);
//left
var output = (lookup[" "][prev[0]][prev[1]]);
var output = "";
for (var i = 0; i < line.length(); i++) {
if (line[i]) {
output += "*";
}
else {
output += " ";
}
//middle
for (var i = 1; i < SIZE-1; i++) {
output += (lookup[prev[i-1]][prev[i]][prev[i+1]]);
}
//right
output += (lookup[prev[SIZE-2]][prev[SIZE-1]][" "]);
print output;
prev = line;
prev = output;
}
+8 -11
View File
@@ -1,13 +1,10 @@
import timer;
var a = createTimer(1, 0);
var b = createTimer(2, 0);
{
var t = astype [int];
var arr: t = [1, 2, 3.14];
}
print a.compareTimer(b).timerToString();
print b.compareTimer(a).timerToString();
var c = createTimer(0, 1);
var d = createTimer(0, 2);
print c.compareTimer(d).timerToString();
print d.compareTimer(c).timerToString();
{
var t = astype [string:int];
var dict: t = ["one": 1, "two": 2, "pi": 3.14];
}
-15
View File
@@ -129,11 +129,6 @@ void freeASTNodeCustom(ASTNode* node, bool freeSelf) {
freeLiteral(node->import.identifier);
freeLiteral(node->import.alias);
break;
case AST_NODE_EXPORT:
freeLiteral(node->export.identifier);
freeLiteral(node->export.alias);
break;
}
if (freeSelf) {
@@ -371,13 +366,3 @@ void emitASTNodeImport(ASTNode** nodeHandle, Literal identifier, Literal alias)
*nodeHandle = tmp;
}
void emitASTNodeExport(ASTNode** nodeHandle, Literal identifier, Literal alias) {
ASTNode* tmp = ALLOCATE(ASTNode, 1);
tmp->type = AST_NODE_EXPORT;
tmp->export.identifier = copyLiteral(identifier);
tmp->export.alias = copyLiteral(alias);
*nodeHandle = tmp;
}
+3 -12
View File
@@ -32,8 +32,7 @@ typedef enum ASTNodeType {
AST_NODE_POSTFIX_INCREMENT, //increment a variable
AST_NODE_PREFIX_DECREMENT, //decrement a variable
AST_NODE_POSTFIX_DECREMENT, //decrement a variable
AST_NODE_IMPORT, //import a variable
AST_NODE_EXPORT, //export a variable
AST_NODE_IMPORT, //import a library
} ASTNodeType;
//literals
@@ -219,9 +218,8 @@ typedef struct NodePostfixDecrement {
Literal identifier;
} NodePostfixDecrement;
//import/export a variable
//import a library
void emitASTNodeImport(ASTNode** nodeHandle, Literal identifier, Literal alias);
void emitASTNodeExport(ASTNode** nodeHandle, Literal identifier, Literal alias);
typedef struct NodeImport {
ASTNodeType type;
@@ -229,12 +227,6 @@ typedef struct NodeImport {
Literal alias;
} NodeImport;
typedef struct NodeExport {
ASTNodeType type;
Literal identifier;
Literal alias;
} NodeExport;
union _node {
ASTNodeType type;
NodeLiteral atomic;
@@ -250,7 +242,7 @@ union _node {
NodeFnDecl fnDecl;
NodeFnCall fnCall;
NodeFnReturn returns;
NodeIf pathIf; //TODO: rename these to ifStmt?
NodeIf pathIf;
NodeWhile pathWhile;
NodeFor pathFor;
NodeBreak pathBreak;
@@ -260,7 +252,6 @@ union _node {
NodePostfixIncrement postfixIncrement;
NodePostfixDecrement postfixDecrement;
NodeImport import;
NodeExport export;
};
TOY_API void freeASTNode(ASTNode* node);
+5 -28
View File
@@ -18,7 +18,7 @@ void initCompiler(Compiler* compiler) {
}
//separated out, so it can be recursive
static int writeLiteralTypeToCacheOpt(LiteralArray* literalCache, Literal literal, bool skipDuplicationOptimisation) {
static int writeLiteralTypeToCache(LiteralArray* literalCache, Literal literal) {
bool shouldFree = false;
//if it's a compound type, recurse and store the results
@@ -32,7 +32,7 @@ static int writeLiteralTypeToCacheOpt(LiteralArray* literalCache, Literal litera
for (int i = 0; i < AS_TYPE(literal).count; i++) {
//write the values to the cache, and the indexes to the store
int subIndex = writeLiteralTypeToCacheOpt(literalCache, ((Literal*)(AS_TYPE(literal).subtypes))[i], false);
int subIndex = writeLiteralTypeToCache(literalCache, ((Literal*)(AS_TYPE(literal).subtypes))[i]);
Literal lit = TO_INTEGER_LITERAL(subIndex);
pushLiteralArray(store, lit);
@@ -45,8 +45,7 @@ static int writeLiteralTypeToCacheOpt(LiteralArray* literalCache, Literal litera
literal.type = LITERAL_TYPE_INTERMEDIATE; //NOTE: tweaking the type usually isn't a good idea
}
if (!skipDuplicationOptimisation) {
//BUGFIX: check if exactly this literal array exists
//optimisation: check if exactly this literal array exists
int index = findLiteralIndex(literalCache, literal);
if (index < 0) {
index = pushLiteralArray(literalCache, literal);
@@ -57,18 +56,6 @@ static int writeLiteralTypeToCacheOpt(LiteralArray* literalCache, Literal litera
}
return index;
}
else {
int index = pushLiteralArray(literalCache, literal);
if (shouldFree) {
freeLiteral(literal);
}
return index;
}
}
static int writeLiteralTypeToCache(LiteralArray* literalCache, Literal literal) {
return writeLiteralTypeToCacheOpt(literalCache, literal, false);
}
static int writeNodeCompoundToCache(Compiler* compiler, ASTNode* node) {
int index = -1;
@@ -200,7 +187,7 @@ static int writeNodeCollectionToCache(Compiler* compiler, ASTNode* node) {
case AST_NODE_VAR_DECL: {
//write each piece of the declaration to the cache
int identifierIndex = pushLiteralArray(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.identifier); //store without duplication optimisation
int typeIndex = writeLiteralTypeToCacheOpt(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.typeLiteral, false);
int typeIndex = writeLiteralTypeToCache(&compiler->literalCache, node->fnCollection.nodes[i].varDecl.typeLiteral);
Literal identifierLiteral = TO_INTEGER_LITERAL(identifierIndex);
pushLiteralArray(store, identifierLiteral);
@@ -214,7 +201,7 @@ static int writeNodeCollectionToCache(Compiler* compiler, ASTNode* node) {
case AST_NODE_LITERAL: {
//write each piece of the declaration to the cache
int typeIndex = writeLiteralTypeToCacheOpt(&compiler->literalCache, node->fnCollection.nodes[i].atomic.literal, false);
int typeIndex = writeLiteralTypeToCache(&compiler->literalCache, node->fnCollection.nodes[i].atomic.literal);
Literal typeLiteral = TO_INTEGER_LITERAL(typeIndex);
pushLiteralArray(store, typeLiteral);
@@ -859,16 +846,6 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, ASTNode* node, void* br
}
break;
case AST_NODE_EXPORT: {
//push the identifier, and the alias
writeLiteralToCompiler(compiler, node->import.identifier);
writeLiteralToCompiler(compiler, node->import.alias);
//push the import opcode
compiler->bytecode[compiler->count++] = (unsigned char)OP_EXPORT; //1 byte
}
break;
case AST_NODE_INDEX: {
//pass to the child nodes, then embed the opcode
+12 -106
View File
@@ -1227,8 +1227,6 @@ bool callLiteralFn(Interpreter* interpreter, Literal func, LiteralArray* argumen
inner.depth = interpreter->depth + 1;
inner.panic = false;
initLiteralArray(&inner.stack);
inner.exports = interpreter->exports;
inner.exportTypes = interpreter->exportTypes;
inner.hooks = interpreter->hooks;
setInterpreterPrint(&inner, interpreter->printOutput);
setInterpreterAssert(&inner, interpreter->assertOutput);
@@ -1473,7 +1471,16 @@ static bool execImport(Interpreter* interpreter) {
Literal identifier = popLiteralArray(&interpreter->stack);
//access the hooks
if (existsLiteralDictionary(interpreter->hooks, identifier)) {
if (!existsLiteralDictionary(interpreter->hooks, identifier)) {
interpreter->errorOutput("Unknown library name in import statement: ");
printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(alias);
freeLiteral(identifier);
return false;
}
Literal func = getLiteralDictionary(interpreter->hooks, identifier);
if (!IS_FUNCTION_NATIVE(func)) {
@@ -1497,77 +1504,6 @@ static bool execImport(Interpreter* interpreter) {
return true;
}
Literal lit = getLiteralDictionary(interpreter->exports, identifier);
Literal type = getLiteralDictionary(interpreter->exportTypes, identifier);
//use the alias
if (!IS_NULL(alias)) {
if (!declareScopeVariable(interpreter->scope, alias, type)) {
interpreter->errorOutput("Can't redefine the variable \"");
printLiteralCustom(alias, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(lit);
freeLiteral(type);
freeLiteral(alias);
freeLiteral(identifier);
return false;
}
setScopeVariable(interpreter->scope, alias, lit, false);
}
//use the original identifier
else {
if (!declareScopeVariable(interpreter->scope, identifier, type)) {
interpreter->errorOutput("Can't redefine the variable \"");
printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(lit);
freeLiteral(type);
freeLiteral(alias);
freeLiteral(identifier);
return false;
}
setScopeVariable(interpreter->scope, identifier, lit, false);
}
//cleanup
freeLiteral(lit);
freeLiteral(type);
freeLiteral(alias);
freeLiteral(identifier);
return true;
}
static bool execExport(Interpreter* interpreter) {
Literal alias = popLiteralArray(&interpreter->stack);
Literal identifier = popLiteralArray(&interpreter->stack);
Literal lit = TO_NULL_LITERAL;
getScopeVariable(interpreter->scope, identifier, &lit);
Literal type = getScopeType(interpreter->scope, identifier);
if (!IS_NULL(alias)) {
setLiteralDictionary(interpreter->exports, alias, lit);
setLiteralDictionary(interpreter->exportTypes, alias, type);
}
else {
setLiteralDictionary(interpreter->exports, identifier, lit);
setLiteralDictionary(interpreter->exportTypes, identifier, type);
}
//cleanup
freeLiteral(lit);
freeLiteral(type);
freeLiteral(alias);
freeLiteral(identifier);
return true;
}
static bool execIndex(Interpreter* interpreter, bool assignIntermediate) {
//assume -> compound, first, second, third are all on the stack
@@ -1592,7 +1528,8 @@ static bool execIndex(Interpreter* interpreter, bool assignIntermediate) {
}
if (!IS_ARRAY(compound) && !IS_DICTIONARY(compound) && !IS_STRING(compound)) {
interpreter->errorOutput("Unknown compound found in indexing notation\n");
interpreter->errorOutput("Unknown compound found in indexing notation: ");
printLiteralCustom(compound, interpreter->errorOutput);
freeLiteral(third);
freeLiteral(second);
freeLiteral(first);
@@ -2086,12 +2023,6 @@ static void execInterpreter(Interpreter* interpreter) {
}
break;
case OP_EXPORT:
if (!execExport(interpreter)) {
return;
}
break;
case OP_INDEX:
if (!execIndex(interpreter, false)) {
return;
@@ -2400,11 +2331,6 @@ static void readInterpreterSections(Interpreter* interpreter) {
//exposed functions
void initInterpreter(Interpreter* interpreter) {
//NOTE: separate initialization for exports
interpreter->exports = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(interpreter->exports);
interpreter->exportTypes = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(interpreter->exportTypes);
interpreter->hooks = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(interpreter->hooks);
@@ -2519,26 +2445,6 @@ void freeInterpreter(Interpreter* interpreter) {
interpreter->scope = popScope(interpreter->scope);
}
//BUGFIX: handle scopes/types in the exports
for (int i = 0; i < interpreter->exports->capacity; i++) {
if (IS_FUNCTION(interpreter->exports->entries[i].key)) {
popScope(AS_FUNCTION(interpreter->exports->entries[i].key).scope);
AS_FUNCTION(interpreter->exports->entries[i].key).scope = NULL;
}
if (IS_FUNCTION(interpreter->exports->entries[i].value)) {
popScope(AS_FUNCTION(interpreter->exports->entries[i].value).scope);
AS_FUNCTION(interpreter->exports->entries[i].value).scope = NULL;
}
}
freeLiteralDictionary(interpreter->exports);
FREE(LiteralDictionary, interpreter->exports);
interpreter->exports = NULL;
freeLiteralDictionary(interpreter->exportTypes);
FREE(LiteralDictionary, interpreter->exportTypes);
interpreter->exportTypes = NULL;
freeLiteralDictionary(interpreter->hooks);
FREE(LiteralDictionary, interpreter->hooks);
interpreter->hooks = NULL;
+1 -2
View File
@@ -21,8 +21,7 @@ typedef struct Interpreter {
Scope* scope;
LiteralArray stack;
LiteralDictionary* exports; //read-write - interface with Toy from C - this is a pointer, since it works at a script-level
LiteralDictionary* exportTypes;
//Library APIs
LiteralDictionary* hooks;
//debug outputs
+8 -2
View File
@@ -380,7 +380,7 @@ int hashLiteral(Literal lit) {
case LITERAL_FUNCTION:
case LITERAL_FUNCTION_NATIVE:
return 0; //TODO: find a way to hash these properly
return 0; //can't hash these
case LITERAL_IDENTIFIER:
return HASH_I(lit); //pre-computed
@@ -448,7 +448,14 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
case LITERAL_FLOAT: {
char buffer[256];
if (AS_FLOAT(literal) - (int)AS_FLOAT(literal)) {
snprintf(buffer, 256, "%g", AS_FLOAT(literal));
}
else {
snprintf(buffer, 256, "%.1f", AS_FLOAT(literal));
}
printFn(buffer);
}
break;
@@ -557,7 +564,6 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
}
break;
//TODO: functions
case LITERAL_FUNCTION:
case LITERAL_FUNCTION_NATIVE:
printFn("(function)");
-2
View File
@@ -77,8 +77,6 @@ bool setLiteralArray(LiteralArray* array, Literal index, Literal value) {
return false;
}
//TODO: implicit push when referencing one-past-the-end?
freeLiteral(array->literals[idx]);
array->literals[idx] = copyLiteral(value);
+1 -1
View File
@@ -46,7 +46,7 @@ typedef enum Opcode {
OP_TYPE_OF, //get the type of a variable
OP_IMPORT,
OP_EXPORT,
OP_EXPORT_removed,
//for indexing
OP_INDEX,
+2 -39
View File
@@ -418,7 +418,7 @@ static Opcode unary(Parser* parser, ASTNode** nodeHandle) {
//temp handle to potentially negate values
parsePrecedence(parser, &tmpNode, PREC_TERNARY); //can be a literal
//check for negative literals (optimisation)
//optimisation: check for negative literals
if (tmpNode->type == AST_NODE_LITERAL && (IS_INTEGER(tmpNode->atomic.literal) || IS_FLOAT(tmpNode->atomic.literal))) {
//negate directly, if int or float
Literal lit = tmpNode->atomic.literal;
@@ -888,7 +888,7 @@ ParseRule* getRule(TokenType type) {
return &parseRules[type];
}
//constant folding (optimisation)
//optimisation: constant folding
static bool calcStaticBinaryArithmetic(Parser* parser, ASTNode** nodeHandle) {
switch((*nodeHandle)->binary.opcode) {
case OP_ADDITION:
@@ -1321,37 +1321,6 @@ static void importStmt(Parser* parser, ASTNode** nodeHandle) {
freeLiteral(alias);
}
static void exportStmt(Parser* parser, ASTNode** nodeHandle) {
//read the identifier
ASTNode* node = NULL;
advance(parser);
identifier(parser, &node);
if (node == NULL) {
return;
}
Literal idn = copyLiteral(node->atomic.literal);
freeASTNode(node);
Literal alias = TO_NULL_LITERAL;
if (match(parser, TOKEN_AS)) {
ASTNode* node;
advance(parser);
identifier(parser, &node);
alias = copyLiteral(node->atomic.literal);
freeASTNode(node);
}
emitASTNodeExport(nodeHandle, idn, alias);
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of export statement");
freeLiteral(idn);
freeLiteral(alias);
}
//precedence functions
static void expressionStmt(Parser* parser, ASTNode** nodeHandle) {
//BUGFIX: check for empty statements
@@ -1431,12 +1400,6 @@ static void statement(Parser* parser, ASTNode** nodeHandle) {
return;
}
//export
if (match(parser, TOKEN_EXPORT)) {
exportStmt(parser, nodeHandle);
return;
}
//default
expressionStmt(parser, nodeHandle);
}
+3 -6
View File
@@ -57,17 +57,14 @@ int lengthRefString(RefString* refString) {
}
RefString* copyRefString(RefString* refString) {
//Cheaty McCheater Face
refString->refcount++;
return refString;
}
RefString* deepCopyRefString(RefString* refString) {
//deep copy, which can be modified immediately
RefString* newRefString = (RefString*)allocate(NULL, 0, sizeof(int) * 2 + refString->length + 1);
memcpy(newRefString, refString, refString->length + 1);
return newRefString;
//create a new string, with a new refcount
return createRefStringLength(refString->data, refString->length);
}
char* toCString(RefString* refString) {
+19 -2
View File
@@ -70,8 +70,14 @@ static bool checkType(Literal typeLiteral, Literal original, Literal value, bool
return false;
}
//if null, assume it's a new entry
//if null, assume it's a new array variable that needs checking
if (IS_NULL(original)) {
for (int i = 0; i < AS_ARRAY(value)->count; i++) {
if (!checkType( ((Literal*)(AS_TYPE(typeLiteral).subtypes))[0], TO_NULL_LITERAL, AS_ARRAY(value)->literals[i], constCheck)) {
return false;
}
}
return true;
}
@@ -97,8 +103,19 @@ static bool checkType(Literal typeLiteral, Literal original, Literal value, bool
return false;
}
//if null, assume it's a new entry to a parent
//if null, assume it's a new dictionary variable that needs checking
if (IS_NULL(original)) {
for (int i = 0; i < AS_DICTIONARY(value)->capacity; i++) {
//check the type of key and value
if (!checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[0], TO_NULL_LITERAL, AS_DICTIONARY(value)->entries[i].key, constCheck)) {
return false;
}
if (!checkType(((Literal*)(AS_TYPE(typeLiteral).subtypes))[1], TO_NULL_LITERAL, AS_DICTIONARY(value)->entries[i].value, constCheck)) {
return false;
}
}
return true;
}
+3 -9
View File
@@ -5,25 +5,19 @@
#include <stdint.h>
#define TOY_VERSION_MAJOR 0
#define TOY_VERSION_MINOR 6
#define TOY_VERSION_PATCH 3
#define TOY_VERSION_MINOR 7
#define TOY_VERSION_PATCH 0
#define TOY_VERSION_BUILD __DATE__ " " __TIME__
//platform exports/imports
//platform-specific specifications
#if defined(__linux__)
#define TOY_API extern
#include <time.h>
#include <sys/time.h>
#elif defined(_WIN32) || defined(WIN32)
#define TOY_API
#include <time.h>
#include <sys/time.h>
#else
#define TOY_API
#include <time.h>
#include <sys/time.h>
#endif
-52
View File
@@ -1,52 +0,0 @@
//test basic import/export
{
var variable: int = 42;
export variable as field;
}
{
import field as value;
assert value == 42, "import/export failed";
}
//test functions using import/export
{
fn f() {
import field;
assert field == 42, "import in function failed";
}
}
//test importing/exporting of functions
{
fn func() {
return 69;
}
export func;
}
{
import func;
assert func() == 69, "import/export of functions failed";
}
//test that variables retain their types with the typeof keyword
{
var t: type = int;
export t;
}
{
import t;
assert typeof t == type, "type retention failed";
}
print "All good";
@@ -0,0 +1,7 @@
{
var t = astype [int];
var arr: t = [1, 2, 3.14];
}
print "All good";
@@ -0,0 +1,7 @@
{
var t = astype [string:int];
var dict: t = ["one": 1, "two": 2, 3:4];
}
print "All good";
@@ -0,0 +1,7 @@
{
var t = astype [string:int];
var dict: t = ["one": 1, "two": 2, "pi": 3.14];
}
print "All good";
-11
View File
@@ -1,11 +0,0 @@
//test exports
var field: int = 42;
fn function() {
return 69;
}
export field;
export function;
print "All good";
-10
View File
@@ -1,10 +0,0 @@
//test imports
import field;
//import function;
//assert field == 42, "import field failed";
//assert function() == 69, "import function failed";
print "All good";
-33
View File
@@ -186,7 +186,6 @@ int main() {
"dot-chaining.toy",
"dottify-bugfix.toy",
"functions.toy",
"imports-and-exports.toy",
"index-arrays.toy",
"index-dictionaries.toy",
"index-strings.toy",
@@ -212,38 +211,6 @@ int main() {
}
}
{
//read source
size_t dummy;
size_t exportSize, importSize;
char* exportSource = readFile("scripts/separate-exports.toy", &dummy);
char* importSource = readFile("scripts/separate-imports.toy", &dummy);
//compile
unsigned char* exportBinary = compileString(exportSource, &exportSize);
unsigned char* importBinary = compileString(importSource, &importSize);
//run the interpreter over both binaries
Interpreter interpreter;
initInterpreter(&interpreter);
//NOTE: supress print output for testing
setInterpreterPrint(&interpreter, noPrintFn);
setInterpreterAssert(&interpreter, noAssertFn);
runInterpreter(&interpreter, exportBinary, exportSize); //automatically frees the binary data
resetInterpreter(&interpreter);
runInterpreter(&interpreter, importBinary, importSize); //automatically frees the binary data
freeInterpreter(&interpreter);
//cleanup
free((void*)exportSource);
free((void*)importSource);
}
//1, to allow for the assertion test
if (ignoredAssertions > 1) {
fprintf(stderr, ERROR "Assertions hidden: %d\n", ignoredAssertions);
+160
View File
@@ -0,0 +1,160 @@
#include "lexer.h"
#include "parser.h"
#include "compiler.h"
#include "interpreter.h"
#include "console_colors.h"
#include "memory.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//suppress the print output
static void noPrintFn(const char* output) {
//NO OP
}
int errorsTriggered = 0;
static void noErrorFn(const char* output) {
errorsTriggered++;
}
//compilation functions
char* readFile(char* path, size_t* fileSize) {
FILE* file = fopen(path, "rb");
if (file == NULL) {
fprintf(stderr, ERROR "Could not open file \"%s\"\n" RESET, path);
exit(-1);
}
fseek(file, 0L, SEEK_END);
*fileSize = ftell(file);
rewind(file);
char* buffer = (char*)malloc(*fileSize + 1);
if (buffer == NULL) {
fprintf(stderr, ERROR "Not enough memory to read \"%s\"\n" RESET, path);
exit(-1);
}
size_t bytesRead = fread(buffer, sizeof(char), *fileSize, file);
buffer[*fileSize] = '\0'; //NOTE: fread doesn't append this
if (bytesRead < *fileSize) {
fprintf(stderr, ERROR "Could not read file \"%s\"\n" RESET, path);
exit(-1);
}
fclose(file);
return buffer;
}
unsigned char* compileString(char* source, size_t* size) {
Lexer lexer;
Parser parser;
Compiler compiler;
initLexer(&lexer, source);
initParser(&parser, &lexer);
initCompiler(&compiler);
//run the parser until the end of the source
ASTNode* node = scanParser(&parser);
while(node != NULL) {
//pack up and leave
if (node->type == AST_NODE_ERROR) {
printf(ERROR "error node detected\n" RESET);
freeASTNode(node);
freeCompiler(&compiler);
freeParser(&parser);
return NULL;
}
writeCompiler(&compiler, node);
freeASTNode(node);
node = scanParser(&parser);
}
//get the bytecode dump
unsigned char* tb = collateCompiler(&compiler, (int*)(size));
//cleanup
freeCompiler(&compiler);
freeParser(&parser);
//no lexer to clean up
//finally
return tb;
}
void runBinary(unsigned char* tb, size_t size) {
Interpreter interpreter;
initInterpreter(&interpreter);
//NOTE: suppress print output for testing
setInterpreterPrint(&interpreter, noPrintFn);
setInterpreterError(&interpreter, noErrorFn);
runInterpreter(&interpreter, tb, size);
freeInterpreter(&interpreter);
}
void runSource(char* source) {
size_t size = 0;
unsigned char* tb = compileString(source, &size);
if (!tb) {
return;
}
runBinary(tb, size);
}
void runSourceFile(char* fname) {
size_t size = 0; //not used
char* source = readFile(fname, &size);
runSource(source);
free((void*)source);
}
int main() {
bool success = true;
{
//run each file in tests/scripts/
char* filenames[] = {
"declare-types-array.toy",
"declare-types-dictionary-key.toy",
"declare-types-dictionary-value.toy",
NULL
};
for (int i = 0; filenames[i]; i++) {
printf("Running (must fail) %s\n", filenames[i]);
char buffer[128];
snprintf(buffer, 128, "scripts/mustfail/%s", filenames[i]);
runSourceFile(buffer);
if (errorsTriggered == 0) {
printf(ERROR "Expected error did not occur in %s\n" RESET, filenames[i]);
success = false;
}
errorsTriggered = 0;
}
}
if (!success) {
return -1;
}
printf(NOTICE "All good\n" RESET);
return 0;
}