mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
added accessors, write and additional tests
This commit is contained in:
@@ -4,12 +4,12 @@
|
|||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
typedef struct Toy_File
|
typedef struct Toy_File
|
||||||
{
|
{
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
int error;
|
Toy_RefString* mode;
|
||||||
int size;
|
|
||||||
} Toy_File;
|
} Toy_File;
|
||||||
|
|
||||||
static int nativeOpen(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
static int nativeOpen(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
@@ -70,30 +70,21 @@ static int nativeOpen(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
|||||||
|
|
||||||
// build file object
|
// build file object
|
||||||
Toy_File* file = TOY_ALLOCATE(Toy_File, 1);
|
Toy_File* file = TOY_ALLOCATE(Toy_File, 1);
|
||||||
file->error = 0;
|
|
||||||
file->fp = NULL;
|
file->fp = NULL;
|
||||||
file->size = 0;
|
file->mode = Toy_createRefString(mode);
|
||||||
|
|
||||||
// attempt to open file
|
// attempt to open file
|
||||||
file->fp = fopen(filePath, mode);
|
file->fp = fopen(filePath, mode);
|
||||||
if (file->fp == NULL) {
|
|
||||||
TOY_FREE(Toy_File, file);
|
|
||||||
fprintf(stderr, "File not found: %s\n", filePath);
|
|
||||||
file->error = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set size
|
|
||||||
if (!file->error) {
|
|
||||||
fseek(file->fp, 0, SEEK_END);
|
|
||||||
|
|
||||||
// pervent integer overflow as ftell returns a long
|
|
||||||
file->size = ftell(file->fp) > INT_MAX? INT_MAX : ftell(file->fp);
|
|
||||||
|
|
||||||
fseek(file->fp, 0, SEEK_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
// result
|
// result
|
||||||
Toy_Literal fileLiteral = TOY_TO_OPAQUE_LITERAL(file, TOY_OPAQUE_TAG_FILE);
|
Toy_Literal fileLiteral = TOY_TO_NULL_LITERAL;
|
||||||
|
if (file->fp == NULL) {
|
||||||
|
TOY_FREE(Toy_File, file);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fileLiteral = TOY_TO_OPAQUE_LITERAL(file, TOY_OPAQUE_TAG_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
Toy_pushLiteralArray(&interpreter->stack, fileLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, fileLiteral);
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
@@ -130,19 +121,17 @@ static int nativeClose(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments
|
|||||||
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
|
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (file->error > 0) {
|
if (file->fp != NULL) {
|
||||||
result = file->error;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = fclose(file->fp);
|
result = fclose(file->fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the result
|
// return the result
|
||||||
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result > 0);
|
Toy_Literal resultLiteral = TOY_TO_BOOLEAN_LITERAL(result != EOF);
|
||||||
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
TOY_FREE(Toy_File, file);
|
TOY_FREE(Toy_File, file);
|
||||||
|
Toy_deleteRefString(file->mode);
|
||||||
Toy_freeLiteral(selfLiteral);
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -179,7 +168,7 @@ static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check self type
|
// check self type
|
||||||
if (!(TOY_IS_OPAQUE(selfLiteral) || TOY_GET_OPAQUE_TAG(selfLiteral) == 900)) {
|
if (!TOY_IS_OPAQUE(selfLiteral) && TOY_GET_OPAQUE_TAG(selfLiteral) != 900) {
|
||||||
interpreter->errorOutput("Incorrect argument type passed to read\n");
|
interpreter->errorOutput("Incorrect argument type passed to read\n");
|
||||||
Toy_freeLiteral(selfLiteral);
|
Toy_freeLiteral(selfLiteral);
|
||||||
Toy_freeLiteral(valueLiteral);
|
Toy_freeLiteral(valueLiteral);
|
||||||
@@ -189,15 +178,27 @@ static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
|||||||
|
|
||||||
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
|
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
|
||||||
|
|
||||||
Toy_Literal resultLiteral = {0};
|
Toy_Literal resultLiteral = TOY_TO_NULL_LITERAL;
|
||||||
|
|
||||||
if (file->error == 0) {
|
switch (valueLiteral.as.type.typeOf)
|
||||||
switch (selfLiteral.type)
|
|
||||||
{
|
{
|
||||||
|
case TOY_LITERAL_BOOLEAN:
|
||||||
|
{
|
||||||
|
char value[TOY_MAX_STRING_LENGTH] = {0};
|
||||||
|
fgets(value, sizeof(value) - 1, file->fp);
|
||||||
|
value[TOY_MAX_STRING_LENGTH] = '\0';
|
||||||
|
|
||||||
|
Toy_Literal stringLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(value));
|
||||||
|
resultLiteral = TOY_TO_BOOLEAN_LITERAL(TOY_IS_TRUTHY(stringLiteral));
|
||||||
|
Toy_freeLiteral(stringLiteral);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case TOY_LITERAL_INTEGER:
|
case TOY_LITERAL_INTEGER:
|
||||||
{
|
{
|
||||||
int value = 0;
|
int value = 0;
|
||||||
file->error = fscanf(file->fp, "%i", &value);
|
fscanf(file->fp, "%i", &value);
|
||||||
|
|
||||||
resultLiteral = TOY_TO_INTEGER_LITERAL(value);
|
resultLiteral = TOY_TO_INTEGER_LITERAL(value);
|
||||||
|
|
||||||
@@ -207,7 +208,7 @@ static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
|||||||
case TOY_LITERAL_FLOAT:
|
case TOY_LITERAL_FLOAT:
|
||||||
{
|
{
|
||||||
float value = 0.0f;
|
float value = 0.0f;
|
||||||
file->error = fscanf(file->fp, "%f", &value);
|
fscanf(file->fp, "%f", &value);
|
||||||
|
|
||||||
resultLiteral = TOY_TO_FLOAT_LITERAL(value);
|
resultLiteral = TOY_TO_FLOAT_LITERAL(value);
|
||||||
|
|
||||||
@@ -220,15 +221,15 @@ static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
|||||||
fgets(value, sizeof(value) - 1, file->fp);
|
fgets(value, sizeof(value) - 1, file->fp);
|
||||||
value[TOY_MAX_STRING_LENGTH] = '\0';
|
value[TOY_MAX_STRING_LENGTH] = '\0';
|
||||||
|
|
||||||
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(value, TOY_MAX_STRING_LENGTH));
|
resultLiteral = TOY_TO_STRING_LITERAL(Toy_createRefString(value));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
// TODO handle other types
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||||
|
|
||||||
@@ -240,6 +241,282 @@ static int nativeRead(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nativeWrite(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
|
if (arguments->count != 2) {
|
||||||
|
interpreter->errorOutput("Incorrect number of arguments to write\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 passed to write\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) == 900)) {
|
||||||
|
interpreter->errorOutput("Incorrect argument type passed to read\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_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 nativeError(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
|
if (arguments->count != 1) {
|
||||||
|
interpreter->errorOutput("Incorrect number of arguments to error\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 argument type passed to error\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_INTEGER_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("Incorrect number of arguments to error\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 argument type passed to error\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_INTEGER_LITERAL(result == 0);
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nativePosition(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
|
if (arguments->count != 1) {
|
||||||
|
interpreter->errorOutput("Incorrect number of arguments to size\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 argument type passed to size\n");
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_File* file = (Toy_File*)TOY_AS_OPAQUE(selfLiteral);
|
||||||
|
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
// pervent integer overflow as ftell returns a long
|
||||||
|
if (ftell(file->fp) > INT_MAX) {
|
||||||
|
size = INT_MAX;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
size = ftell(file->fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the result
|
||||||
|
Toy_Literal resultLiteral = TOY_TO_INTEGER_LITERAL(size);
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nativeSize(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
|
if (arguments->count != 1) {
|
||||||
|
interpreter->errorOutput("Incorrect number of arguments to size\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 argument type passed to size\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(selfLiteral);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nativeMode(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
|
||||||
|
if (arguments->count != 1) {
|
||||||
|
interpreter->errorOutput("Incorrect number of arguments to mode\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 argument type passed to mode\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(file->mode);
|
||||||
|
Toy_pushLiteralArray(&interpreter->stack, resultLiteral);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
Toy_freeLiteral(resultLiteral);
|
||||||
|
Toy_freeLiteral(selfLiteral);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// call the hook
|
// call the hook
|
||||||
typedef struct Natives {
|
typedef struct Natives {
|
||||||
char* name;
|
char* name;
|
||||||
@@ -252,13 +529,20 @@ typedef struct Variable {
|
|||||||
Toy_Literal literal;
|
Toy_Literal literal;
|
||||||
} Variable;
|
} Variable;
|
||||||
|
|
||||||
// Helper function create a variable
|
// Helper function create a int variable
|
||||||
void createToyVariable(Variable* variable, char* key, int literal) {
|
void createToyVariableInt(Variable* variable, char* key, int literal) {
|
||||||
variable->key = TOY_TO_STRING_LITERAL(Toy_createRefString(key));
|
variable->key = TOY_TO_STRING_LITERAL(Toy_createRefString(key));
|
||||||
variable->identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(key));
|
variable->identifier = TOY_TO_IDENTIFIER_LITERAL(Toy_createRefString(key));
|
||||||
variable->literal = TOY_TO_INTEGER_LITERAL(literal);
|
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
|
// Helper function to clean up variables
|
||||||
void deleteToyVariables(Variable variables[], int size) {
|
void deleteToyVariables(Variable variables[], int size) {
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
@@ -269,6 +553,7 @@ void deleteToyVariables(Variable variables[], int size) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to check for naming conflicts with existing variables
|
||||||
bool scopeConflict(Toy_Interpreter* interpreter, Variable variables[], int size) {
|
bool scopeConflict(Toy_Interpreter* interpreter, Variable variables[], int size) {
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
if (Toy_isDeclaredScopeVariable(interpreter->scope, variables[i].literal)) {
|
if (Toy_isDeclaredScopeVariable(interpreter->scope, variables[i].literal)) {
|
||||||
@@ -283,29 +568,65 @@ bool scopeConflict(Toy_Interpreter* interpreter, Variable variables[], int size)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to place variables into scope should be called after scopeConflict
|
||||||
void exposeVariablesToScope(Toy_Interpreter* interpreter, Variable variables[], int size) {
|
void exposeVariablesToScope(Toy_Interpreter* interpreter, Variable variables[], int size) {
|
||||||
Toy_Literal intType = TOY_TO_TYPE_LITERAL(TOY_LITERAL_INTEGER, true);
|
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++) {
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (variables[i].literal.type == TOY_LITERAL_INTEGER) {
|
||||||
Toy_declareScopeVariable(interpreter->scope, variables[i].identifier, intType);
|
Toy_declareScopeVariable(interpreter->scope, variables[i].identifier, intType);
|
||||||
Toy_setScopeVariable(interpreter->scope, variables[i].identifier, variables[i].literal, false);
|
}
|
||||||
|
else if (variables[i].literal.type == TOY_LITERAL_OPAQUE) {
|
||||||
|
Toy_declareScopeVariable(interpreter->scope, variables[i].identifier, opaqueType);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_setScopeVariable(interpreter->scope, variables[i].identifier, variables[i].literal, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_freeLiteral(intType);
|
Toy_freeLiteral(intType);
|
||||||
|
Toy_freeLiteral(opaqueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
|
int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Literal alias) {
|
||||||
// build the natives list
|
// build the natives list
|
||||||
Natives natives[] = {
|
Natives natives[] = {
|
||||||
// Access
|
// access
|
||||||
{"open", nativeOpen},
|
{"open", nativeOpen},
|
||||||
{"close", nativeClose},
|
{"close", nativeClose},
|
||||||
|
|
||||||
//
|
// input/output
|
||||||
{"read", nativeRead},
|
{"read", nativeRead},
|
||||||
|
{"write", nativeWrite},
|
||||||
|
|
||||||
|
// accessors
|
||||||
|
{"error", nativeError},
|
||||||
|
{"completed", nativeCompleted},
|
||||||
|
{"position", nativePosition},
|
||||||
|
{"size", nativeSize},
|
||||||
|
{"mode", nativeMode},
|
||||||
|
|
||||||
{NULL, NULL}
|
{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_File* outFile = TOY_ALLOCATE(Toy_File, 1);
|
||||||
|
outFile->fp = stdout;
|
||||||
|
|
||||||
|
createToyVariableFile(&variables[3], "output", outFile);
|
||||||
|
|
||||||
|
Toy_File* inFile = TOY_ALLOCATE(Toy_File, 1);
|
||||||
|
inFile->fp = stdin;
|
||||||
|
|
||||||
|
createToyVariableFile(&variables[4], "input", inFile);
|
||||||
|
|
||||||
// store the library in an aliased dictionary
|
// store the library in an aliased dictionary
|
||||||
if (!TOY_IS_NULL(alias)) {
|
if (!TOY_IS_NULL(alias)) {
|
||||||
// make sure the name isn't taken
|
// make sure the name isn't taken
|
||||||
@@ -315,7 +636,43 @@ int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// 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
|
// default
|
||||||
@@ -323,13 +680,6 @@ int Toy_hookFileIO(Toy_Interpreter* interpreter, Toy_Literal identifier, Toy_Lit
|
|||||||
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
Toy_injectNativeFn(interpreter, natives[i].name, natives[i].fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int VARIABLES_SIZE = 3;
|
|
||||||
Variable variables[VARIABLES_SIZE];
|
|
||||||
|
|
||||||
createToyVariable(&variables[0], "MAX_FILENAME_SIZE", FILENAME_MAX);
|
|
||||||
createToyVariable(&variables[1], "MAX_FILES_OPEN", FOPEN_MAX);
|
|
||||||
createToyVariable(&variables[2], "END_OF_FILE", EOF);
|
|
||||||
|
|
||||||
if (scopeConflict(interpreter, variables, VARIABLES_SIZE)) {
|
if (scopeConflict(interpreter, variables, VARIABLES_SIZE)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
61
scripts/shapes.toy
Normal file
61
scripts/shapes.toy
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
output.write("Enter:\n0\tfor circle\n1\tfor triangle\n2\tfor square\n> ");
|
||||||
|
var result: any = input.read(int);
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
circle(5, 5, 5);
|
||||||
|
}
|
||||||
|
else if (result == 1) {
|
||||||
|
triangle(5);
|
||||||
|
}
|
||||||
|
else if (result == 2) {
|
||||||
|
square(5);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
output.write("invalid input :(\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,55 @@
|
|||||||
import fileio;
|
import fileio;
|
||||||
|
|
||||||
// test open
|
// 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 open and close
|
||||||
|
{
|
||||||
|
var file = open("scripts:/lib/file/fileio.txt", "r");
|
||||||
|
assert file != null, "open failed";
|
||||||
|
|
||||||
|
var wrong = open("scripts:/doesNotExist", "r");
|
||||||
|
assert wrong == null, "open failed";
|
||||||
|
|
||||||
|
assert file.close() == true, "close failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
// test accessors
|
||||||
{
|
{
|
||||||
var file = open("scripts:/lib/file/fileio.txt", "r");
|
var file = open("scripts:/lib/file/fileio.txt", "r");
|
||||||
|
|
||||||
// file.read(string);
|
print file.error();
|
||||||
|
print file.completed();
|
||||||
|
print file.position();
|
||||||
|
print file.size();
|
||||||
|
print file.mode();
|
||||||
|
|
||||||
// TODO:
|
file.close();
|
||||||
// file.write(12, ",", 12);
|
}
|
||||||
// file.size();
|
|
||||||
// file.isOpened();
|
// test output
|
||||||
// file.getrror();
|
{
|
||||||
// file.position();
|
// assert output.write(8), "write int failed";
|
||||||
// file.mode();
|
// assert output.write("\n"), "write string failed";
|
||||||
|
// assert output.write(12.5), "write float failed";
|
||||||
print file.close();
|
}
|
||||||
|
|
||||||
|
// test input
|
||||||
|
{
|
||||||
|
// // enter 8
|
||||||
|
// assert input.read(int) == 8, "read int failed";
|
||||||
|
|
||||||
|
// // enter 12.5
|
||||||
|
// assert input.read(float) == 12.5, "read float failed";
|
||||||
|
|
||||||
|
// // enter test
|
||||||
|
// assert input.read(string) == "test\n", "read string failed";
|
||||||
|
|
||||||
|
// // invaild types
|
||||||
|
// assert input.read(type) == null, "type failed";
|
||||||
|
// assert input.read(any) == null, "any failed";
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user