Compare commits

..

30 Commits

Author SHA1 Message Date
Ratstail91 eaad8d5241 Messing with tests 2023-08-28 23:31:09 +10:00
Ratstail91 308fba1a8c Added carriage return as escapable character 2023-08-28 22:04:21 +10:00
Ratstail91 bcc9df928a Investigating mingw behaviour 2023-08-28 21:59:06 +10:00
Ratstail91 c66e77ec57 Merge branch 'main' of https://github.com/Add00/Toy into Add00-main 2023-08-28 21:30:21 +10:00
Add00 113c067c96 updated path error messages 2023-08-27 23:39:32 -04:00
Add00 01f710a4f3 Merge branch 'Ratstail91:main' into main 2023-08-24 17:14:33 -04:00
Add00 eb4c44193c added path method and more tests 2023-08-24 17:09:20 -04:00
Add00 214351abaa view result 2023-08-23 23:19:33 -04:00
Add00 73965bc0e4 input and output can now be closed 2023-08-21 22:47:32 -04:00
Add00 46e274d182 Merge branch 'Ratstail91:main' into main 2023-08-21 10:54:27 -04:00
Add00 925f13abf5 potential fix for mingw32 issue 2023-08-19 22:10:29 -04:00
Add00 9a56a86ec8 add read/write for bools, and fixed sanitize issue 2023-08-19 21:51:44 -04:00
Add00 3ddda21ff2 Improved error messages, and feedback improvements 2023-08-19 15:41:21 -04:00
Add00 65acdd2730 in and out file marked as static 2023-08-15 22:53:16 -04:00
Add00 1603ea1798 mostly fixed sanitization issue 2023-08-14 23:09:13 -04:00
Add00 79f2e231db fix stack overflow issue 2023-08-14 22:22:20 -04:00
Add00 ab0720a5ef memory leak and several bugs fixed 2023-08-14 22:02:33 -04:00
Add00 901940a3d0 Merge branch 'Ratstail91:main' into main 2023-08-14 18:56:13 -04:00
Add00 a0acd27be1 partly fixed memory leak issue 2023-08-13 22:27:54 -04:00
Add00 0c005d0af2 added file operations and additional tests 2023-08-12 16:02:54 -04:00
Add00 38ba2273dd added accessors, write and additional tests 2023-08-10 23:00:26 -04:00
Add00 1b8d8cfba0 Removed debug code 2023-08-09 08:48:40 -04:00
Add00 648a5f84db fixed close function 2023-08-08 23:41:23 -04:00
Add00 e2dda434f8 Fixed memory leak 2023-08-08 19:25:18 -04:00
Add00 5a8e2c0527 Fixed path 2023-08-08 19:05:35 -04:00
Add00 dea5cf6d43 removed HAL 2023-08-08 19:04:27 -04:00
Add00 930115f94c Merge branch 'Ratstail91:main' into main 2023-08-08 13:57:57 -04:00
Add00 2fa6b7ee23 added basic read, and an improved HAL 2023-08-06 09:39:06 -04:00
Add00 43b58eb421 Library rename, added HAL, added open function 2023-08-04 23:13:43 -04:00
Add00 36b4a494ae io library file creation 2023-08-02 22:19:09 -04:00
22 changed files with 1213 additions and 70 deletions
@@ -1,26 +1,17 @@
name: Continuous Integration v1.x
name: Comprehensive Tests
#trigger when these occur
on:
push:
branches:
- v1
branches: [ "main", "*" ]
pull_request:
types:
- opened
- edited
- reopened
branches:
- v1
workflow_dispatch:
branches: [ "main" ]
#testing the CI workflows under multiple supported conditions
jobs:
test-valgrind:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: install valgrind
run: sudo apt install valgrind
- name: make test (valgrind)
@@ -30,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: make test (sanitized)
run: make test-sanitized
@@ -38,6 +29,6 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: make test (mingw32)
run: make test
+1 -1
View File
@@ -1,6 +1,6 @@
# License
Copyright (c) 2020-2024 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 -2
View File
@@ -2,7 +2,7 @@
<image src="toylogo.png" />
</p>
# Toy v1
# Toy
The Toy programming language is an imperative bytecode-intermediate embedded scripting language. It isn't intended to operate on its own, but rather as part of another program, the "host". This process is intended to allow a decent amount of easy customisation by the host's end user, by exposing logic in script files. Alternatively, binary files in a custom format can be used as well.
@@ -83,4 +83,4 @@ Unnamed Individuals - Feedback
* Seth A. Robinson
Special thanks to http://craftinginterpreters.com/ for their fantastic book that set me on this path.
Special thanks to http://craftinginterpreters.com/ for their fantastic book that set me on this path.
+940
View File
@@ -0,0 +1,940 @@
#include "lib_fileio.h"
#include "toy_memory.h"
#include "drive_system.h"
#include <limits.h>
#include <stdio.h>
typedef struct Toy_File
{
FILE* fp;
Toy_RefString* mode;
Toy_RefString* path;
} Toy_File;
Toy_File* createToyFile(Toy_RefString* mode, Toy_RefString* path) {
Toy_File* file = TOY_ALLOCATE(Toy_File, 1);
file->fp = NULL;
file->mode = Toy_copyRefString(mode);
file->path = Toy_copyRefString(path);
return file;
}
void deleteToyFile(Toy_File* file) {
Toy_deleteRefString(file->mode);
Toy_deleteRefString(file->path);
TOY_FREE(Toy_File, file);
}
static int nativeOpen(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count < 1) {
interpreter->errorOutput("Too few arguments open(string, string) expects two arguments\n");
return -1;
}
else if (arguments->count > 2) {
interpreter->errorOutput("Too many arguments open(string, string) expects two arguments\n");
return -1;
}
Toy_Literal modeLiteral = arguments->count == 2? Toy_popLiteralArray(arguments) : TOY_TO_STRING_LITERAL(Toy_createRefString("r"));
Toy_Literal drivePathLiteral = Toy_popLiteralArray(arguments);
// parse the drivePath (if it's an identifier)
Toy_Literal drivePathLiteralIdn = drivePathLiteral;
if (TOY_IS_IDENTIFIER(drivePathLiteral) && Toy_parseIdentifierToValue(interpreter, &drivePathLiteral)) {
Toy_freeLiteral(drivePathLiteralIdn);
}
// check the drivePath type
if (!TOY_IS_STRING(drivePathLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a string as the first argument to open(string, string)\n");
Toy_freeLiteral(drivePathLiteral);
Toy_freeLiteral(modeLiteral);
return -1;
}
Toy_Literal filePathLiteral = Toy_getDrivePathLiteral(interpreter, &drivePathLiteral);
if (TOY_IS_NULL(filePathLiteral)) {
interpreter->errorOutput("File not found in the specified drive\n");
Toy_freeLiteral(drivePathLiteral);
Toy_freeLiteral(filePathLiteral);
Toy_freeLiteral(modeLiteral);
return -1;
}
// parse the mode (if it's an identifier)
Toy_Literal modeLiteralIdn = modeLiteral;
if (TOY_IS_IDENTIFIER(modeLiteral) && Toy_parseIdentifierToValue(interpreter, &modeLiteral)) {
Toy_freeLiteral(modeLiteralIdn);
}
// check the mode type
if (!TOY_IS_STRING(modeLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a string as the second argument to open(string, string)\n");
Toy_freeLiteral(drivePathLiteral);
Toy_freeLiteral(filePathLiteral);
Toy_freeLiteral(modeLiteral);
return -1;
}
const char* filePath = Toy_toCString(TOY_AS_STRING(filePathLiteral));
size_t filePathLength = Toy_lengthRefString(TOY_AS_STRING(filePathLiteral));
const char* mode = Toy_toCString(TOY_AS_STRING(modeLiteral));
// build file object
Toy_File* file = createToyFile(TOY_AS_STRING(modeLiteral), TOY_AS_STRING(filePathLiteral));
// attempt to open file
file->fp = fopen(filePath, mode);
// result
Toy_Literal fileLiteral = TOY_TO_NULL_LITERAL;
if (file->fp == NULL) {
deleteToyFile(file);
}
else {
fileLiteral = TOY_TO_OPAQUE_LITERAL(file, TOY_OPAQUE_TAG_FILE);
}
Toy_pushLiteralArray(&interpreter->stack, fileLiteral);
// cleanup
Toy_freeLiteral(fileLiteral);
Toy_freeLiteral(drivePathLiteral);
Toy_freeLiteral(filePathLiteral);
Toy_freeLiteral(modeLiteral);
return 1;
}
static int nativeClose(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments close() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type close() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
int result = 0;
if (
file->fp != stdout &&
file->fp != stdin &&
file->fp != NULL
) {
result = fclose(file->fp);
file->fp = NULL;
}
// return the result
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != EOF);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
deleteToyFile(file);
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count < 2) {
interpreter->errorOutput("Too few arguments read(type) expects one argument\n");
return -1;
}
else if (arguments->count > 2) {
interpreter->errorOutput("Too many arguments read(type) expects one argument\n");
return -1;
}
Toy_Literal typeLiteral = Toy_popLiteralArray(arguments);
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the type (if it's an identifier)
Toy_Literal typeLiteralIdn = typeLiteral;
if (TOY_IS_IDENTIFIER(typeLiteral) && Toy_parseIdentifierToValue(interpreter, &typeLiteral)) {
Toy_freeLiteral(typeLiteralIdn);
}
// check the type type
if (!TOY_IS_TYPE(typeLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a type as the first argument to read(type)\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(typeLiteral);
return -1;
}
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type, read(type) expects a file type\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(typeLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL;
int error = 0;
switch (TOY_AS_TYPE(typeLiteral).typeOf) {
case TOY_LITERAL_BOOLEAN: {
char value = '0';
error = fscanf(file->fp, "%c", &value);
resultLiteral = TOY_TO_BOOLEAN_LITERAL(value != '0');
break;
}
case TOY_LITERAL_INTEGER: {
int value = 0;
error = fscanf(file->fp, "%i", &value);
resultLiteral = TOY_TO_INTEGER_LITERAL(value);
break;
}
case TOY_LITERAL_FLOAT: {
float value = 0.0f;
error = fscanf(file->fp, "%f", &value);
resultLiteral = TOY_TO_FLOAT_LITERAL(value);
break;
}
case TOY_LITERAL_STRING: { //BUG: needs a terminator to show how much to read
char value[TOY_MAX_STRING_LENGTH] = {0};
size_t size = fread(value, sizeof(char), TOY_MAX_STRING_LENGTH - 1, file->fp);
value[size] = '\0';
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(value));
break;
}
default: {
// TODO handle other types
break;
}
}
if (error != EOF) {
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
}
else {
Toy_pushLiteralArray(&interpreter->stack, TOY_TO_NULL_LITERAL);
}
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(typeLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeWrite(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count < 2) {
interpreter->errorOutput("Too few arguments write(any) expects one argument\n");
return -1;
}
else if (arguments->count > 2) {
interpreter->errorOutput("Too many arguments write(any) expects one argument\n");
return -1;
}
Toy_Literal valueLiteral = Toy_popLiteralArray(arguments);
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the value (if it's an identifier)
Toy_Literal valueLiteralIdn = valueLiteral;
if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) {
Toy_freeLiteral(valueLiteralIdn);
}
// check the value type
if (TOY_IS_NULL(valueLiteral)) {
interpreter->errorOutput("Incorrect argument type expected non null value as the first argument to write(any)\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(valueLiteral);
return -1;
}
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type write(any) expects a file type\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(valueLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
int result = 0;
switch (valueLiteral.type) {
case TOY_LITERAL_BOOLEAN: {
result = fprintf(file->fp, "%i", TOY_AS_BOOLEAN(valueLiteral));
break;
}
case TOY_LITERAL_INTEGER: {
result = fprintf(file->fp, "%i", TOY_AS_INTEGER(valueLiteral));
break;
}
case TOY_LITERAL_FLOAT: {
result = fprintf(file->fp, "%f", TOY_AS_FLOAT(valueLiteral));
break;
}
case TOY_LITERAL_STRING: {
result = fprintf(file->fp, "%s", Toy_toCString(TOY_AS_STRING(valueLiteral)));
break;
}
default: {
// TODO handle other types
break;
}
}
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result > 0);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(valueLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeRename(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count < 2) {
interpreter->errorOutput("Too few arguments rename(string) expects one argument\n");
return -1;
}
else if (arguments->count > 2) {
interpreter->errorOutput("Too many arguments rename(string) expects one argument\n");
return -1;
}
Toy_Literal valueLiteral = Toy_popLiteralArray(arguments);
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the value (if it's an identifier)
Toy_Literal valueLiteralIdn = valueLiteral;
if (TOY_IS_IDENTIFIER(valueLiteral) && Toy_parseIdentifierToValue(interpreter, &valueLiteral)) {
Toy_freeLiteral(valueLiteralIdn);
}
// check the value type
if (!TOY_IS_STRING(valueLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a string as the first argument to rename(string)\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(valueLiteral);
return -1;
}
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type, rename(string) expects a file type\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(valueLiteral);
return -1;
}
Toy_Literal filePathLiteral = Toy_getDrivePathLiteral(interpreter, &valueLiteral);
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
const char* newName = Toy_toCString(TOY_AS_STRING(filePathLiteral));
// close the file
if (file->fp != NULL) {
fclose(file->fp);
file->fp = NULL;
}
// rename the file
int result = rename(Toy_toCString(file->path), newName);
// open file again
file->fp = fopen(newName, Toy_toCString(file->mode));
// update the file object's name
Toy_deleteRefString(file->path);
file->path = Toy_createRefString(newName);
// return result
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result == 0);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(filePathLiteral);
Toy_freeLiteral(valueLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeSeek(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count < 3) {
interpreter->errorOutput("Too few arguments seek(string, int) expects two arguments\n");
return -1;
}
else if (arguments->count > 3) {
interpreter->errorOutput("Too many arguments seek(string, int) expects two arguments\n");
return -1;
}
Toy_Literal offsetLiteral = Toy_popLiteralArray(arguments);
Toy_Literal originLiteral = Toy_popLiteralArray(arguments);
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the origin (if it's an identifier)
Toy_Literal originLiteralIdn = originLiteral;
if (TOY_IS_IDENTIFIER(originLiteral) && Toy_parseIdentifierToValue(interpreter, &originLiteral)) {
Toy_freeLiteral(originLiteralIdn);
}
// check the origin type
if (!TOY_IS_STRING(originLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a string as the first argument to seek(string, int)\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(offsetLiteral);
Toy_freeLiteral(originLiteral);
return -1;
}
// parse the offset (if it's an identifier)
Toy_Literal offsetLiteralIdn = offsetLiteral;
if (TOY_IS_IDENTIFIER(offsetLiteral) && Toy_parseIdentifierToValue(interpreter, &offsetLiteral)) {
Toy_freeLiteral(offsetLiteralIdn);
}
// check the offset type
if (!TOY_IS_INTEGER(offsetLiteral)) {
interpreter->errorOutput("Incorrect argument type expected a int as the second argument to seek(string, int)\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(offsetLiteral);
Toy_freeLiteral(originLiteral);
return -1;
}
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type seek(string, int) expects a file type\n");
Toy_freeLiteral(selfLiteral);
Toy_freeLiteral(offsetLiteral);
Toy_freeLiteral(originLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
Toy_RefString* orginString = TOY_AS_STRING(originLiteral);
int offset = TOY_AS_INTEGER(offsetLiteral);
int origin = -1;
if (Toy_equalsRefStringCString(orginString, "bgn")) {
origin = SEEK_SET;
}
else if (Toy_equalsRefStringCString(orginString, "cur")) {
origin = SEEK_CUR;
}
else if (Toy_equalsRefStringCString(orginString, "end")) {
origin = SEEK_END;
}
int result = origin >= SEEK_SET && origin <= SEEK_END?
fseek(file->fp, offset, origin) : -1;
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result == 0);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(originLiteral);
Toy_freeLiteral(offsetLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeError(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments error() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type error() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
int result = ferror(file->fp);
// return the result
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != 0);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeCompleted(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments completed() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type completed() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
int result = feof(file->fp);
// return the result
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != 0);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativePosition(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments position() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type position() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
// pervent integer overflow as ftell returns a long
int size = ftell(file->fp) > INT_MAX? INT_MAX : ftell(file->fp);
// return the result
Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(size);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeSize(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments size() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type size() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
int size = 0;
fseek(file->fp, 0, SEEK_END);
// pervent integer overflow as ftell returns a long
if (ftell(file->fp) > INT_MAX) {
size = INT_MAX;
}
else {
size = ftell(file->fp);
}
fseek(file->fp, 0, SEEK_SET);
// return the result
Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(size);
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativeMode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments mode() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type mode() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
// return the result
Toy_Literal resultLiteral = TOY_TO_STRING_LITERAL(Toy_copyRefString(file->mode));
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
static int nativePath(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
if (arguments->count != 1) {
interpreter->errorOutput("Too many arguments path() expects zero arguments\n");
return -1;
}
Toy_Literal selfLiteral = Toy_popLiteralArray(arguments);
// parse the self (if it's an identifier)
Toy_Literal selfLiteralIdn = selfLiteral;
if (TOY_IS_IDENTIFIER(selfLiteral) && Toy_parseIdentifierToValue(interpreter, &selfLiteral)) {
Toy_freeLiteral(selfLiteralIdn);
}
// check self type
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != TOY_OPAQUE_TAG_FILE) {
interpreter->errorOutput("Incorrect self type path() expects a file type\n");
Toy_freeLiteral(selfLiteral);
return -1;
}
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
// return the result
Toy_Literal resultLiteral = TOY_TO_STRING_LITERAL(Toy_copyRefString(file->path));
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
// cleanup
Toy_freeLiteral(resultLiteral);
Toy_freeLiteral(selfLiteral);
return 1;
}
// call the hook
typedef struct Natives {
char* name;
Toy_NativeFn fn;
} Natives;
typedef struct Variable {
Toy_Literal key;
Toy_Literal identifier;
Toy_Literal literal;
} Variable;
// Helper function create a int variable
void createToyVariableInt(Variable* variable, char* key, int literal) {
variable->key = TOY_TO_STRING_LITERAL(Toy_createRefString(key));
variable->identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(key));
variable->literal = TOY_TO_INTEGER_LITERAL(literal);
}
// Helper function create a file variable
void createToyVariableFile(Variable* variable, char* key, Toy_File* literal) {
variable->key = TOY_TO_STRING_LITERAL(Toy_createRefString(key));
variable->identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(key));
variable->literal = TOY_TO_OPAQUE_LITERAL(literal, TOY_OPAQUE_TAG_FILE);
}
// Helper function to clean up variables
void deleteToyVariables(Variable variables[], int size) {
for (int i = 0; i < size; i++) {
Toy_freeLiteral(variables[i].key);
Toy_freeLiteral(variables[i].identifier);
Toy_freeLiteral(variables[i].literal);
}
}
// Helper to check for naming conflicts with existing variables
bool scopeConflict(Toy_Interpreter* interpreter, Variable variables[], int size) {
for (int i = 0; i < size; i++) {
if (Toy_isDeclaredScopeVariable(interpreter->scope, variables[i].literal)) {
interpreter->errorOutput("Can't override an existing variable\n");
deleteToyVariables(variables, size);
return true;
}
}
return false;
}
// Helper to place variables into scope should be called after scopeConflict
void exposeVariablesToScope(Toy_Interpreter* interpreter, Variable variables[], int size) {
Toy_Literal intType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_INTEGER, false);
Toy_Literal opaqueType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_OPAQUE, false);
for (int i = 0; i < size; i++) {
if (TOY_IS_INTEGER(variables[i].literal)) {
Toy_declareScopeVariable(interpreter->scope, variables[i].identifier, intType);
}
else if (TOY_IS_OPAQUE(variables[i].literal)) {
Toy_declareScopeVariable(interpreter->scope, variables[i].identifier, opaqueType);
}
Toy_setScopeVariable(interpreter->scope, variables[i].identifier, variables[i].literal, true);
}
Toy_freeLiteral(intType);
Toy_freeLiteral(opaqueType);
}
int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
// build the natives list
Natives natives[] = {
// access
{"open", nativeOpen},
{"close", nativeClose},
// operations
{"read", nativeRead},
{"write", nativeWrite},
{"rename", nativeRename},
{"seek", nativeSeek},
// accessors
{"error", nativeError},
{"completed", nativeCompleted},
{"position", nativePosition},
{"size", nativeSize},
{"mode", nativeMode},
{"path", nativePath},
{NULL, NULL}
};
// global variables
const int VARIABLES_SIZE = 5;
Variable variables[VARIABLES_SIZE];
createToyVariableInt(&variables[0], "MAX_FILENAME_SIZE", FILENAME_MAX);
createToyVariableInt(&variables[1], "MAX_FILES_OPEN", FOPEN_MAX);
createToyVariableInt(&variables[2], "END_OF_FILE", EOF);
Toy_RefString* outMode = Toy_createRefString("w");
Toy_RefString* outName = Toy_createRefString("output");
static Toy_File* outFile;
outFile = createToyFile(outMode, outName);
outFile->fp = stdout;
createToyVariableFile(&variables[3], "output", outFile);
Toy_deleteRefString(outMode);
Toy_deleteRefString(outName);
Toy_RefString* inMode = Toy_createRefString("r");
Toy_RefString* inName = Toy_createRefString("input");
static Toy_File* inFile;
inFile = createToyFile(inMode, inName);
inFile->fp = stdin;
createToyVariableFile(&variables[4], "input", inFile);
Toy_deleteRefString(inMode);
Toy_deleteRefString(inName);
// store the library in an aliased dictionary
if (!TOY_IS_NULL(alias)) {
// make sure the name isn't taken
if (Toy_isDeclaredScopeVariable(interpreter->scope, alias)) {
interpreter->errorOutput("Can't override an existing variable\n");
Toy_freeLiteral(alias);
return -1;
}
// create the dictionary to load up with functions
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
// load the dict with functions
for (int i = 0; natives[i].name; i++) {
Toy_Literal name = TOY_TO_STRING_LITERAL(Toy_createRefString(natives[i].name));
Toy_Literal func = TOY_TO_FUNCTION_NATIVE_LITERAL(natives[i].fn);
Toy_setLiteralDictionary(dictionary, name, func);
Toy_freeLiteral(name);
Toy_freeLiteral(func);
}
// set global variables
for (int i = 0; i < VARIABLES_SIZE; i++) {
Toy_setLiteralDictionary(dictionary, variables[i].key, variables[i].literal);
}
// build the type
Toy_Literal type = TOY_TO_TYPE_LITERAL(TOY_LITERAL_DICTIONARY, true);
Toy_Literal anyType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_ANY, true);
Toy_Literal fnType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_FUNCTION_NATIVE, true);
TOY_TYPE_PUSH_SUBTYPE(&type, anyType);
TOY_TYPE_PUSH_SUBTYPE(&type, fnType);
// set scope
Toy_Literal dict = TOY_TO_DICTIONARY_LITERAL(dictionary);
Toy_declareScopeVariable(interpreter->scope, alias, type);
Toy_setScopeVariable(interpreter->scope, alias, dict, false);
// cleanup
Toy_freeLiteral(dict);
Toy_freeLiteral(type);
return 0;
}
// default
for (int i = 0; natives[i].name; i++) {
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
}
if (scopeConflict(interpreter, variables, VARIABLES_SIZE)) {
return -1;
}
exposeVariablesToScope(interpreter, variables, VARIABLES_SIZE);
deleteToyVariables(variables, VARIABLES_SIZE);
return 0;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include "toy_interpreter.h"
#define TOY_OPAQUE_TAG_FILE 300
int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias);
+3 -3
View File
@@ -661,7 +661,7 @@ static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* argument
}
//get the combined length for the new string
size_t length = TOY_AS_STRING(selfLiteral)->length + TOY_AS_STRING(otherLiteral)->length;
size_t length = TOY_AS_STRING(selfLiteral)->length + TOY_AS_STRING(otherLiteral)->length + 1;
if (length > TOY_MAX_STRING_LENGTH) {
interpreter->errorOutput("Can't concatenate these strings, result is too long (error found in concat)\n");
@@ -671,8 +671,8 @@ static int nativeConcat(Toy_Interpreter* interpreter, Toy_LiteralArray* argument
}
//allocate the space and generate
char* buffer = TOY_ALLOCATE(char, length + 1);
snprintf(buffer, length + 1, "%s%s", Toy_toCString(TOY_AS_STRING(selfLiteral)), Toy_toCString(TOY_AS_STRING(otherLiteral)));
char* buffer = TOY_ALLOCATE(char, length);
snprintf(buffer, length, "%s%s", Toy_toCString(TOY_AS_STRING(selfLiteral)), Toy_toCString(TOY_AS_STRING(otherLiteral)));
Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefString(buffer));
+2
View File
@@ -4,6 +4,7 @@
#include "lib_standard.h"
#include "lib_random.h"
#include "lib_runner.h"
#include "lib_fileio.h"
#include "lib_math.h"
#include "toy_console_colors.h"
@@ -31,6 +32,7 @@ void repl(const char* initialInput) {
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_injectNativeHook(&interpreter, "fileio", Toy_hookFileIO);
Toy_injectNativeHook(&interpreter, "math", Toy_hookMath);
for(;;) {
+2
View File
@@ -3,6 +3,7 @@
#include "lib_standard.h"
#include "lib_random.h"
#include "lib_runner.h"
#include "lib_fileio.h"
#include "lib_math.h"
#include "toy_console_colors.h"
@@ -116,6 +117,7 @@ void Toy_runBinary(const unsigned char* tb, size_t size) {
Toy_injectNativeHook(&interpreter, "standard", Toy_hookStandard);
Toy_injectNativeHook(&interpreter, "random", Toy_hookRandom);
Toy_injectNativeHook(&interpreter, "runner", Toy_hookRunner);
Toy_injectNativeHook(&interpreter, "fileio", Toy_hookFileIO);
Toy_injectNativeHook(&interpreter, "math", Toy_hookMath);
Toy_runInterpreter(&interpreter, tb, (int)size);
+61
View File
@@ -0,0 +1,61 @@
import math;
import fileio;
import standard;
fn circle(radius: int, centerX: int, centerY: int) {
for (var y: int = 0; y <= 2 * radius; y++) {
for (var x: int = 0; x <= 2 * radius; x++) {
var distance: int = round(sqrt((x - radius) * (x - radius) + (y - radius) * (y - radius)));
if (distance <= radius) {
output.write("*");
} else {
output.write(" ");
}
}
output.write("\n");
}
}
fn triangle(height: int) {
for (var i: int = 1; i <= height; i++) {
for (var j: int = 1; j <= height - i; j++) {
output.write(" ");
}
for (var j: int = 1; j <= 2 * i - 1; j++) {
output.write("*");
}
output.write("\n");
}
}
fn square(size: int) {
for (var i: int = 0; i < size; ++i) {
for (var j: int = 0; j < size; ++j) {
output.write("* ");
}
output.write("\n");
}
}
while (true) {
output.write("Enter:\n0\tfor circle\n1\tfor triangle\n2\tfor square\n> ");
var result: any = input.read(int);
if (result == 0) {
circle(2, 5, 5);
}
else if (result == 1) {
triangle(5);
}
else if (result == 2) {
square(5);
}
else {
output.write("invalid input :(\n");
}
}
+4 -4
View File
@@ -362,8 +362,8 @@ void Toy_emitASTNodeAnd(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_AND;
tmp->pathAnd.left = *nodeHandle;
tmp->pathAnd.right = rhs;
tmp->binary.left = *nodeHandle;
tmp->binary.right = rhs;
*nodeHandle = tmp;
}
@@ -372,8 +372,8 @@ void Toy_emitASTNodeOr(Toy_ASTNode** nodeHandle, Toy_ASTNode* rhs) {
Toy_ASTNode* tmp = TOY_ALLOCATE(Toy_ASTNode, 1);
tmp->type = TOY_AST_NODE_OR;
tmp->pathOr.left = *nodeHandle;
tmp->pathOr.right = rhs;
tmp->binary.left = *nodeHandle;
tmp->binary.right = rhs;
*nodeHandle = tmp;
}
+1 -1
View File
@@ -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 2
#define TOY_VERSION_PATCH 1
/*!
### TOY_VERSION_BUILD
+2 -2
View File
@@ -455,8 +455,8 @@ static void printToBuffer(const char* str) {
globalPrintBuffer = TOY_GROW_ARRAY(char, globalPrintBuffer, oldCapacity, globalPrintCapacity);
}
size_t total = snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str ? str : "\0");
globalPrintCount += total;
snprintf(globalPrintBuffer + globalPrintCount, strlen(str) + 1, "%s", str ? str : "\0");
globalPrintCount += strlen(str);
}
//exposed functions
+1 -1
View File
@@ -22,7 +22,7 @@ void* Toy_private_defaultMemoryAllocator(void* pointer, size_t oldSize, size_t n
void* mem = realloc(pointer, newSize);
if (mem == NULL) {
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %d, replacing %d)\n" TOY_CC_RESET, (int)newSize, (int)oldSize);
fprintf(stderr, TOY_CC_ERROR "[internal] Memory allocation error (requested %zu, replacing %zu)\n" TOY_CC_RESET, newSize, oldSize);
return NULL;
}
+1
View File
@@ -0,0 +1 @@
Hello, World!
+4
View File
@@ -0,0 +1,4 @@
1
8
12.5
test
+3
View File
@@ -0,0 +1,3 @@
08
12.500000
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+164
View File
@@ -0,0 +1,164 @@
import fileio;
var PATH: string const = "scripts:/lib/file/fileio.txt";
// reset file to orginal state
fn reset() {
var writer = open(PATH, "w");
writer.write("Hello, World!\n");
writer.close();
}
// test global constants
{
assert MAX_FILENAME_SIZE > 0, "MAX_FILENAME_SIZE failed";
assert MAX_FILES_OPEN > 0, "MAX_FILES_OPEN failed";
assert END_OF_FILE == -1, "END_OF_FILE failed";
}
// test read
{
var reader = open("scripts:/lib/file/inputs.txt", "r");
assert reader.read(bool) == true, "read true bool failed";
assert reader.read(int) == 8, "read int failed";
assert reader.read(float) == 12.5, "read float failed";
assert reader.read(string) == "\ntest", "read string failed";
// invaild types
assert reader.read(type) == null, "read type failed";
assert reader.read(any) == null, "read any failed";
reader.close();
}
// test write
{
var writer = open("scripts:/lib/file/outputs.txt", "w");
assert writer.write(false) == true, "write bool failed";
assert writer.write(8) == true, "write int failed";
assert writer.write("\n") == true, "write string failed";
assert writer.write(12.5) == true, "write float failed";
assert writer.write("\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n") == true, "write long string failed";
// invaild types
assert writer.write([0, 1, 2]) == false, "write array failed";
assert writer.write(["hi": "world"]) == false, "write dict failed";
writer.close();
}
// test open and close
{
var reader = open(PATH);
assert reader != null, "open failed in reading mode";
assert reader.close() == true, "close failed";
var file = open("scripts:/doesNotExist", "r");
assert file == null, "open failed on nonexisting file";
}
// test append
{
var appender = open(PATH, "a");
assert appender != null, "open failed on appending file";
assert appender.write("appended text") == true, "append failed";
appender.close();
reset();
}
// test read extended
{
var reader = open(PATH, "r+");
assert reader != null, "open failed on read extended mode";
assert reader.write("writen text") == true, "write in read extended failed";
var result = reader.read(string);
// print result;
// assert (result == "d!\n" || result == "d!\\r\n"), "read in read extended failed";
reader.close();
reset();
}
// test write extended
{
var writer = open(PATH, "w+");
assert writer != null, "open failed on write extended mode";
assert writer.write("writen text") == true, "write in write extended failed";
writer.seek("bgn", 0);
assert writer.read(string) == "writen text", "read in write extended failed";
writer.close();
reset();
}
// test rename
{
var reader = open(PATH, "r");
assert reader.rename("scripts:/lib/file/newName.txt") == true, "rename failed";
reader.rename(PATH);
reader.close();
}
// test seek
{
var reader = open(PATH, "r");
assert reader.seek("bgn", 6) == true, "seek from bgn failed";
var contents = reader.read(string);
assert contents == " World!\n", "seek failed to move file position (1st)";
assert reader.seek("end", -2) == true, "seek from end failed";
contents = reader.read(string);
print ">>>(" + contents + ")" + string( contents.length() );
assert contents == "\n", "seek failed to move file position (2nd)";
assert reader.seek("cur", -2) == true, "seek from cur failed";
contents = reader.read(string);
assert contents == "\n", "seek failed to move file position (3rd)";
assert reader.seek("CUR", 0) == false, "seek origin failed (1st)";
assert reader.seek("End", 0) == false, "seek origin failed (2nd)";
assert reader.seek("beG", 0) == false, "seek origin failed (3rd)";
assert reader.seek("xxx", 0) == false, "seek origin failed (4th)";
reader.close();
}
// test accessors
{
var reader = open(PATH, "r");
assert reader.error() == false, "error failed";
assert reader.completed() == false, "completed failed";
assert reader.position() == 0, "position failed";
assert reader.size() == 14, "size failed";
assert reader.mode() == "r", "mode failed";
reader.read(string);
assert reader.error() == false, "error failed";
assert reader.completed() == true, "completed after read failed";
assert reader.position() == 14, "position failed";
assert reader.size() == 14, "size failed";
assert reader.mode() == "r", "mode failed";
reader.close();
}
input.close();
output.close();
print "All good";
+3 -1
View File
@@ -182,4 +182,6 @@ import math;
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";
}
}
print "All good";
+3 -1
View File
@@ -18,6 +18,7 @@
#include "../repl/lib_standard.h"
#include "../repl/lib_random.h"
#include "../repl/lib_runner.h"
#include "../repl/lib_fileio.h"
#include "../repl/lib_math.h"
//supress the print output
@@ -43,7 +44,7 @@ void runBinaryWithLibrary(const unsigned char* tb, size_t size, const char* libr
Toy_initInterpreter(&interpreter);
//NOTE: supress print output for testing
Toy_setInterpreterPrint(&interpreter, noPrintFn);
// Toy_setInterpreterPrint(&interpreter, noPrintFn);
Toy_setInterpreterAssert(&interpreter, assertWrapper);
Toy_setInterpreterError(&interpreter, errorWrapper);
@@ -77,6 +78,7 @@ int main() {
{"standard.toy", "standard", Toy_hookStandard},
{"runner.toy", "runner", Toy_hookRunner},
{"random.toy", "random", Toy_hookRandom},
{"fileio.toy", "fileio", Toy_hookFileIO},
{"math.toy", "math", Toy_hookMath},
{NULL, NULL, NULL}
};
+3 -6
View File
@@ -906,8 +906,7 @@ void disassemble(const char *filename, options_t config) {
if (!strcmp(litf->fun, "MAIN")) {
printf("MAIN:\n");
printf("%s", str_replace_substr_all(litf->str, ".lit FUNCTION ", ".lit FUNCTION (code=FUN_) "));
printf("%s", litf->str);
dis_disassemble_section(&prg, prg->pc, prg->len, 0, false, config);
free(litf->fun);
free(litf->str);
@@ -916,10 +915,8 @@ void disassemble(const char *filename, options_t config) {
continue;
}
printf("FUN_%s:\n", litf->fun);
char sbtr[strlen(litf->fun) + 19];
sprintf(sbtr, ".lit FUNCTION (code=FUN_%s_) ", litf->fun);
printf("%s", str_replace_substr_all(litf->str, ".lit FUNCTION ", sbtr));
printf("FUNCTION_%s:\n", litf->fun);
printf("%s", litf->str);
queue_node_t *fqf = function_queue_front;
while (fqf != NULL) {
-32
View File
@@ -58,35 +58,3 @@ void str_append(char **str, const char *app) {
*str = realloc(*str, (strlen(*str) + strlen(app) + 1) * sizeof(char));
memcpy((*str) + strlen(*str), app, strlen(app) + 1);
}
char* str_replace_substr_all(char *mainstr, char *substr, char *newstr) {
int lenmain, lensub, i, j, lennew, startindex = -1, c;
lenmain = strlen(mainstr);
lensub = strlen(substr);
lennew = strlen(newstr);
char *result = (char*) malloc(sizeof(char) * (lenmain + 200));
for (c = 0, i = 0; i < lenmain; i++) {
if (lenmain - i >= lensub && *(mainstr + i) == *(substr)) {
startindex = i;
for (j = 1; j < lensub; j++)
if (*(mainstr + i + j) != *(substr + j)) {
startindex = -1;
break;
}
if (startindex != -1) {
for (j = 0; j < lennew; j++, c++) {
*(result + c) = *(newstr + j);
}
i = i + lensub - 1;
} else {
*(result + c) = *(mainstr + i);
c++;
}
} else {
*(result + c) = *(mainstr + i);
c++;
}
}
*(result + c) = '\0';
return result;
}
-1
View File
@@ -21,6 +21,5 @@ void dis_enqueue(void *x, queue_node_t **queue_front, queue_node_t **queue_rear,
void dis_dequeue(queue_node_t **queue_front, queue_node_t **queue_rear, uint32_t *len);
void str_append(char **str, const char *app);
char* str_replace_substr_all(char *mainstr, char *substr, char *newstr);
#endif /* UTILS_H_ */