mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
String literals are being parsed, compiled and printed, read more
Strings, due to their potentially large size, are stored outside of a routine's code section, in the data section. To access the correct string, you must read the jump index, then the real address from the jump table - and extra layer of indirection will result in more flexible data down the road, I hope. Other changes include: * Added string concat operator .. * Added TOY_STRING_MAX_LENGTH * Strings can't be created or concatenated longer than the max length * The parser will display a warning if the bucket is too small for a string at max length, but it will continue * Added TOY_BUCKET_IDEAL to correspend with max string length * The bucket now allocates an address that is 4-byte aligned * Fixed missing entries in the parser rule table * Corrected some failing TOY_BITNESS tests
This commit is contained in:
@@ -37,7 +37,7 @@ jobs:
|
|||||||
if: matrix.commands.gdb == false || matrix.platforms.gdb_skip == false
|
if: matrix.commands.gdb == false || matrix.platforms.gdb_skip == false
|
||||||
run: ${{ matrix.commands.exec }}
|
run: ${{ matrix.commands.exec }}
|
||||||
|
|
||||||
#TODO: hook this up to real script files
|
#TODO: hook this up to real script files, preferably in the test section
|
||||||
run-test-repl-scripts:
|
run-test-repl-scripts:
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
needs: run-test-cases
|
needs: run-test-cases
|
||||||
@@ -49,6 +49,7 @@ jobs:
|
|||||||
- { os: macos-latest }
|
- { os: macos-latest }
|
||||||
commands:
|
commands:
|
||||||
- { build: make repl, run: out/repl.exe -f '../scripts/example.toy' }
|
- { build: make repl, run: out/repl.exe -f '../scripts/example.toy' }
|
||||||
|
- { build: make repl, run: out/repl.exe -f '../scripts/example-print.toy' }
|
||||||
|
|
||||||
runs-on: ${{ matrix.platforms.os }}
|
runs-on: ${{ matrix.platforms.os }}
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ static void errorAndExitCallback(const char* msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//main file
|
//main file
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) { //TODO: this needs an interactive terminal mode
|
||||||
Toy_setPrintCallback(printCallback);
|
Toy_setPrintCallback(printCallback);
|
||||||
Toy_setErrorCallback(errorAndExitCallback);
|
Toy_setErrorCallback(errorAndExitCallback);
|
||||||
Toy_setAssertFailureCallback(errorAndExitCallback);
|
Toy_setAssertFailureCallback(errorAndExitCallback);
|
||||||
@@ -218,7 +218,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
Toy_Parser parser;
|
Toy_Parser parser;
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
|
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
||||||
|
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
|
|||||||
@@ -3,3 +3,9 @@ print 42;
|
|||||||
|
|
||||||
//it can handle complex expressions
|
//it can handle complex expressions
|
||||||
print 3 * 5;
|
print 3 * 5;
|
||||||
|
|
||||||
|
//strings should work
|
||||||
|
print "Hello world!";
|
||||||
|
|
||||||
|
//so should concat
|
||||||
|
print "Hello" .. "world!";
|
||||||
@@ -45,6 +45,7 @@ typedef enum Toy_AstFlag {
|
|||||||
TOY_AST_FLAG_COMPARE_GREATER_EQUAL,
|
TOY_AST_FLAG_COMPARE_GREATER_EQUAL,
|
||||||
TOY_AST_FLAG_AND,
|
TOY_AST_FLAG_AND,
|
||||||
TOY_AST_FLAG_OR,
|
TOY_AST_FLAG_OR,
|
||||||
|
TOY_AST_FLAG_CONCAT,
|
||||||
|
|
||||||
//unary flags
|
//unary flags
|
||||||
TOY_AST_FLAG_NEGATE,
|
TOY_AST_FLAG_NEGATE,
|
||||||
@@ -108,7 +109,7 @@ typedef struct Toy_AstEnd {
|
|||||||
union Toy_Ast { //32 | 64 BITNESS
|
union Toy_Ast { //32 | 64 BITNESS
|
||||||
Toy_AstType type; //4 | 4
|
Toy_AstType type; //4 | 4
|
||||||
Toy_AstBlock block; //16 | 32
|
Toy_AstBlock block; //16 | 32
|
||||||
Toy_AstValue value; //12 | 12
|
Toy_AstValue value; //12 | 24
|
||||||
Toy_AstUnary unary; //12 | 16
|
Toy_AstUnary unary; //12 | 16
|
||||||
Toy_AstBinary binary; //16 | 24
|
Toy_AstBinary binary; //16 | 24
|
||||||
Toy_AstGroup group; //8 | 16
|
Toy_AstGroup group; //8 | 16
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ void* Toy_partitionBucket(Toy_Bucket** bucketHandle, unsigned int amount) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//BUGFIX: the endpoint must be aligned to the word size, otherwise you'll get a bus error from moving pointers
|
||||||
|
if (amount % 4 != 0) {
|
||||||
|
amount += 4 - (amount % 4); //ceil
|
||||||
|
}
|
||||||
|
|
||||||
//if you try to allocate too much space
|
//if you try to allocate too much space
|
||||||
if ((*bucketHandle)->capacity < amount) {
|
if ((*bucketHandle)->capacity < amount) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to partition a 'Toy_Bucket': requested %d from a bucket of %d capacity\n" TOY_CC_RESET, (int)amount, (int)((*bucketHandle)->capacity));
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to partition a 'Toy_Bucket': requested %d from a bucket of %d capacity\n" TOY_CC_RESET, (int)amount, (int)((*bucketHandle)->capacity));
|
||||||
|
|||||||
@@ -20,3 +20,9 @@ TOY_API Toy_Bucket* Toy_allocateBucket(unsigned int capacity);
|
|||||||
TOY_API void* Toy_partitionBucket(Toy_Bucket** bucketHandle, unsigned int amount);
|
TOY_API void* Toy_partitionBucket(Toy_Bucket** bucketHandle, unsigned int amount);
|
||||||
TOY_API void Toy_freeBucket(Toy_Bucket** bucketHandle);
|
TOY_API void Toy_freeBucket(Toy_Bucket** bucketHandle);
|
||||||
|
|
||||||
|
//some useful bucket sizes
|
||||||
|
#define TOY_BUCKET_SMALL 256
|
||||||
|
#define TOY_BUCKET_MEDIUM 512
|
||||||
|
#define TOY_BUCKET_LARGE 1024
|
||||||
|
|
||||||
|
#define TOY_BUCKET_IDEAL 1024
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ typedef enum Toy_OpcodeType {
|
|||||||
|
|
||||||
//various action instructions
|
//various action instructions
|
||||||
TOY_OPCODE_PRINT,
|
TOY_OPCODE_PRINT,
|
||||||
|
TOY_OPCODE_CONCAT,
|
||||||
//TODO: clear the program stack
|
//TODO: clear the program stack
|
||||||
|
|
||||||
//meta instructions
|
//meta instructions
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#include "toy_parser.h"
|
#include "toy_parser.h"
|
||||||
#include "toy_console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
|
#include "toy_value.h"
|
||||||
|
#include "toy_string.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
//utilities
|
//utilities
|
||||||
@@ -107,14 +110,14 @@ typedef struct ParsingTuple {
|
|||||||
|
|
||||||
static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle, ParsingPrecedence precRule);
|
static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle, ParsingPrecedence precRule);
|
||||||
|
|
||||||
static Toy_AstFlag atomic(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
static Toy_AstFlag literal(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
static Toy_AstFlag unary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
static Toy_AstFlag unary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
static Toy_AstFlag binary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
static Toy_AstFlag binary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
|
|
||||||
//precedence definitions
|
//precedence definitions
|
||||||
static ParsingTuple parsingRulesetTable[] = {
|
static ParsingTuple parsingRulesetTable[] = {
|
||||||
{PREC_PRIMARY,atomic,NULL},// TOY_TOKEN_NULL,
|
{PREC_PRIMARY,literal,NULL},// TOY_TOKEN_NULL,
|
||||||
|
|
||||||
//variable names
|
//variable names
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_IDENTIFIER,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_IDENTIFIER,
|
||||||
@@ -157,11 +160,11 @@ static ParsingTuple parsingRulesetTable[] = {
|
|||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_YIELD,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_YIELD,
|
||||||
|
|
||||||
//literal values
|
//literal values
|
||||||
{PREC_PRIMARY,atomic,NULL},// TOY_TOKEN_LITERAL_TRUE,
|
{PREC_PRIMARY,literal,NULL},// TOY_TOKEN_LITERAL_TRUE,
|
||||||
{PREC_PRIMARY,atomic,NULL},// TOY_TOKEN_LITERAL_FALSE,
|
{PREC_PRIMARY,literal,NULL},// TOY_TOKEN_LITERAL_FALSE,
|
||||||
{PREC_PRIMARY,atomic,NULL},// TOY_TOKEN_LITERAL_INTEGER,
|
{PREC_PRIMARY,literal,NULL},// TOY_TOKEN_LITERAL_INTEGER,
|
||||||
{PREC_PRIMARY,atomic,NULL},// TOY_TOKEN_LITERAL_FLOAT,
|
{PREC_PRIMARY,literal,NULL},// TOY_TOKEN_LITERAL_FLOAT,
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_LITERAL_STRING,
|
{PREC_PRIMARY,literal,NULL},// TOY_TOKEN_LITERAL_STRING,
|
||||||
|
|
||||||
//math operators
|
//math operators
|
||||||
{PREC_TERM,NULL,binary},// TOY_TOKEN_OPERATOR_ADD,
|
{PREC_TERM,NULL,binary},// TOY_TOKEN_OPERATOR_ADD,
|
||||||
@@ -201,7 +204,11 @@ static ParsingTuple parsingRulesetTable[] = {
|
|||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_QUESTION,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_QUESTION,
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_COLON,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_COLON,
|
||||||
|
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_CONCAT, // ..
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_SEMICOLON, // ;
|
||||||
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_COMMA, // ,
|
||||||
|
|
||||||
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_DOT, // .
|
||||||
|
{PREC_CALL,NULL,binary},// TOY_TOKEN_OPERATOR_CONCAT, // ..
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_REST, // ...
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_REST, // ...
|
||||||
|
|
||||||
//unused operators
|
//unused operators
|
||||||
@@ -214,7 +221,7 @@ static ParsingTuple parsingRulesetTable[] = {
|
|||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_EOF,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_EOF,
|
||||||
};
|
};
|
||||||
|
|
||||||
static Toy_AstFlag atomic(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
static Toy_AstFlag literal(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
switch(parser->previous.type) {
|
switch(parser->previous.type) {
|
||||||
case TOY_TOKEN_NULL:
|
case TOY_TOKEN_NULL:
|
||||||
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_FROM_NULL());
|
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_FROM_NULL());
|
||||||
@@ -262,8 +269,40 @@ static Toy_AstFlag atomic(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
|
|||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case TOY_TOKEN_LITERAL_STRING: {
|
||||||
|
char buffer[parser->previous.length + 1];
|
||||||
|
|
||||||
|
unsigned int i = 0, o = 0;
|
||||||
|
do {
|
||||||
|
buffer[i] = parser->previous.lexeme[o];
|
||||||
|
if (buffer[i] == '\\' && parser->previous.lexeme[++o]) {
|
||||||
|
//also handle escape characters
|
||||||
|
switch(parser->previous.lexeme[o]) {
|
||||||
|
case 'n':
|
||||||
|
buffer[i] = '\n';
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
buffer[i] = '\t';
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
buffer[i] = '\\';
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
buffer[i] = '"';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} while (parser->previous.lexeme[o++] && i < parser->previous.length);
|
||||||
|
|
||||||
|
buffer[i] = '\0';
|
||||||
|
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_FROM_STRING(Toy_createStringLength(bucketHandle, buffer, i)));
|
||||||
|
|
||||||
|
return TOY_AST_FLAG_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printError(parser, parser->previous, "Unexpected token passed to atomic precedence rule");
|
printError(parser, parser->previous, "Unexpected token passed to literal precedence rule");
|
||||||
Toy_private_emitAstError(bucketHandle, rootHandle);
|
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
}
|
}
|
||||||
@@ -405,6 +444,11 @@ static Toy_AstFlag binary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
|
|||||||
return TOY_AST_FLAG_COMPARE_GREATER_EQUAL;
|
return TOY_AST_FLAG_COMPARE_GREATER_EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case TOY_TOKEN_OPERATOR_CONCAT: {
|
||||||
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_CALL + 1);
|
||||||
|
return TOY_AST_FLAG_CONCAT;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printError(parser, parser->previous, "Unexpected token passed to binary precedence rule");
|
printError(parser, parser->previous, "Unexpected token passed to binary precedence rule");
|
||||||
Toy_private_emitAstError(bucketHandle, rootHandle);
|
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||||
@@ -574,6 +618,11 @@ void Toy_bindParser(Toy_Parser* parser, Toy_Lexer* lexer) {
|
|||||||
Toy_Ast* Toy_scanParser(Toy_Bucket** bucketHandle, Toy_Parser* parser) {
|
Toy_Ast* Toy_scanParser(Toy_Bucket** bucketHandle, Toy_Parser* parser) {
|
||||||
Toy_Ast* rootHandle = NULL;
|
Toy_Ast* rootHandle = NULL;
|
||||||
|
|
||||||
|
//double check bucket capacity for strings
|
||||||
|
if ((*bucketHandle)->capacity < TOY_STRING_MAX_LENGTH) {
|
||||||
|
fprintf(stderr, TOY_CC_WARN "WARNING: Bucket capacity in Toy_scanParser() is smaller than TOY_STRING_MAX_LENGTH" TOY_CC_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
//check for EOF
|
//check for EOF
|
||||||
if (match(parser, TOY_TOKEN_EOF)) {
|
if (match(parser, TOY_TOKEN_EOF)) {
|
||||||
Toy_private_emitAstEnd(bucketHandle, &rootHandle);
|
Toy_private_emitAstEnd(bucketHandle, &rootHandle);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "toy_opcodes.h"
|
#include "toy_opcodes.h"
|
||||||
#include "toy_value.h"
|
#include "toy_value.h"
|
||||||
|
#include "toy_string.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -17,7 +18,7 @@ static void expand(void** handle, unsigned int* capacity, unsigned int* count, u
|
|||||||
(*handle) = realloc((*handle), (*capacity));
|
(*handle) = realloc((*handle), (*capacity));
|
||||||
|
|
||||||
if ((*handle) == NULL) {
|
if ((*handle) == NULL) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate a 'Toy_Routine' of %d capacity\n" TOY_CC_RESET, (int)(*capacity));
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate %d space for a part of 'Toy_Routine'\n" TOY_CC_RESET, (int)(*capacity));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,48 +46,91 @@ static void emitFloat(void** handle, unsigned int* capacity, unsigned int* count
|
|||||||
}
|
}
|
||||||
|
|
||||||
//write instructions based on the AST types
|
//write instructions based on the AST types
|
||||||
#define EMIT_BYTE(rt, byte) \
|
#define EMIT_BYTE(rt, part, byte) \
|
||||||
emitByte((void**)(&((*rt)->code)), &((*rt)->codeCapacity), &((*rt)->codeCount), byte);
|
emitByte((void**)(&((*rt)->part)), &((*rt)->part##Capacity), &((*rt)->part##Count), byte);
|
||||||
#define EMIT_INT(rt, code, byte) \
|
#define EMIT_INT(rt, part, bytes) \
|
||||||
emitInt((void**)(&((*rt)->code)), &((*rt)->codeCapacity), &((*rt)->codeCount), byte);
|
emitInt((void**)(&((*rt)->part)), &((*rt)->part##Capacity), &((*rt)->part##Count), bytes);
|
||||||
#define EMIT_FLOAT(rt, code, byte) \
|
#define EMIT_FLOAT(rt, part, bytes) \
|
||||||
emitFloat((void**)(&((*rt)->code)), &((*rt)->codeCapacity), &((*rt)->codeCount), byte);
|
emitFloat((void**)(&((*rt)->part)), &((*rt)->part##Capacity), &((*rt)->part##Count), bytes);
|
||||||
|
|
||||||
|
static void emitToJumpTable(Toy_Routine** rt, unsigned int startAddr) {
|
||||||
|
EMIT_INT(rt, code, (*rt)->jumpsCount); //mark the jump index in the code
|
||||||
|
EMIT_INT(rt, jumps, startAddr); //save address at the jump index
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitString(Toy_Routine** rt, Toy_String* str) {
|
||||||
|
//4-byte alignment
|
||||||
|
unsigned int length = str->length + 1;
|
||||||
|
if (length % 4 != 0) {
|
||||||
|
length += 4 - (length % 4); //ceil
|
||||||
|
}
|
||||||
|
|
||||||
|
//grab the current start address
|
||||||
|
unsigned int startAddr = (*rt)->dataCount;
|
||||||
|
|
||||||
|
//move the string into the data section
|
||||||
|
expand((void**)(&((*rt)->data)), &((*rt)->dataCapacity), &((*rt)->dataCount), (*rt)->dataCount + length);
|
||||||
|
|
||||||
|
if (str->type == TOY_STRING_NODE) {
|
||||||
|
char* buffer = Toy_getStringRawBuffer(str);
|
||||||
|
memcpy((*rt)->data + (*rt)->dataCount, buffer, str->length + 1);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
else if (str->type == TOY_STRING_LEAF) {
|
||||||
|
memcpy((*rt)->data + (*rt)->dataCount, str->as.leaf.data, str->length + 1);
|
||||||
|
}
|
||||||
|
else if (str->type == TOY_STRING_NAME) {
|
||||||
|
memcpy((*rt)->data + (*rt)->dataCount, str->as.name.data, str->length + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*rt)->dataCount += length;
|
||||||
|
|
||||||
|
//mark the jump position
|
||||||
|
emitToJumpTable(rt, startAddr);
|
||||||
|
}
|
||||||
|
|
||||||
static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast); //forward declare for recursion
|
static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast); //forward declare for recursion
|
||||||
|
|
||||||
static void writeInstructionValue(Toy_Routine** rt, Toy_AstValue ast) {
|
static void writeInstructionValue(Toy_Routine** rt, Toy_AstValue ast) {
|
||||||
//TODO: store more complex values in the data code
|
//TODO: store more complex values in the data code
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_READ);
|
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
|
||||||
EMIT_BYTE(rt, ast.value.type);
|
EMIT_BYTE(rt, code, ast.value.type);
|
||||||
|
|
||||||
//emit the raw value based on the type
|
//emit the raw value based on the type
|
||||||
if (TOY_VALUE_IS_NULL(ast.value)) {
|
if (TOY_VALUE_IS_NULL(ast.value)) {
|
||||||
//NOTHING - null's type data is enough
|
//NOTHING - null's type data is enough
|
||||||
|
|
||||||
//4-byte alignment
|
//4-byte alignment
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code, 0);
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code, 0);
|
||||||
}
|
}
|
||||||
else if (TOY_VALUE_IS_BOOLEAN(ast.value)) {
|
else if (TOY_VALUE_IS_BOOLEAN(ast.value)) {
|
||||||
EMIT_BYTE(rt, TOY_VALUE_AS_BOOLEAN(ast.value));
|
EMIT_BYTE(rt, code, TOY_VALUE_AS_BOOLEAN(ast.value));
|
||||||
|
|
||||||
//4-byte alignment
|
//4-byte alignment
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code, 0);
|
||||||
}
|
}
|
||||||
else if (TOY_VALUE_IS_INTEGER(ast.value)) {
|
else if (TOY_VALUE_IS_INTEGER(ast.value)) {
|
||||||
//4-byte alignment
|
//4-byte alignment
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code, 0);
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
|
||||||
EMIT_INT(rt, code, TOY_VALUE_AS_INTEGER(ast.value));
|
EMIT_INT(rt, code, TOY_VALUE_AS_INTEGER(ast.value));
|
||||||
}
|
}
|
||||||
else if (TOY_VALUE_IS_FLOAT(ast.value)) {
|
else if (TOY_VALUE_IS_FLOAT(ast.value)) {
|
||||||
//4-byte alignment
|
//4-byte alignment
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code, 0);
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
|
||||||
EMIT_FLOAT(rt, code, TOY_VALUE_AS_FLOAT(ast.value));
|
EMIT_FLOAT(rt, code, TOY_VALUE_AS_FLOAT(ast.value));
|
||||||
}
|
}
|
||||||
|
else if (TOY_VALUE_IS_STRING(ast.value)) {
|
||||||
|
//4-byte alignment
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
|
||||||
|
emitString(rt, TOY_VALUE_AS_STRING(ast.value));
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST type found: Unknown value type\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST type found: Unknown value type\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -98,12 +142,12 @@ static void writeInstructionUnary(Toy_Routine** rt, Toy_AstUnary ast) {
|
|||||||
writeRoutineCode(rt, ast.child);
|
writeRoutineCode(rt, ast.child);
|
||||||
|
|
||||||
if (ast.flag == TOY_AST_FLAG_NEGATE) {
|
if (ast.flag == TOY_AST_FLAG_NEGATE) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_NEGATE);
|
EMIT_BYTE(rt, code, TOY_OPCODE_NEGATE);
|
||||||
|
|
||||||
//4-byte alignment
|
//4-byte alignment
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code, 0);
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code, 0);
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code, 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST unary flag found\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST unary flag found\n" TOY_CC_RESET);
|
||||||
@@ -117,80 +161,83 @@ static void writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) {
|
|||||||
writeRoutineCode(rt, ast.right);
|
writeRoutineCode(rt, ast.right);
|
||||||
|
|
||||||
if (ast.flag == TOY_AST_FLAG_ADD) {
|
if (ast.flag == TOY_AST_FLAG_ADD) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_ADD);
|
EMIT_BYTE(rt, code,TOY_OPCODE_ADD);
|
||||||
}
|
}
|
||||||
else if (ast.flag == TOY_AST_FLAG_SUBTRACT) {
|
else if (ast.flag == TOY_AST_FLAG_SUBTRACT) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_SUBTRACT);
|
EMIT_BYTE(rt, code,TOY_OPCODE_SUBTRACT);
|
||||||
}
|
}
|
||||||
else if (ast.flag == TOY_AST_FLAG_MULTIPLY) {
|
else if (ast.flag == TOY_AST_FLAG_MULTIPLY) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_MULTIPLY);
|
EMIT_BYTE(rt, code,TOY_OPCODE_MULTIPLY);
|
||||||
}
|
}
|
||||||
else if (ast.flag == TOY_AST_FLAG_DIVIDE) {
|
else if (ast.flag == TOY_AST_FLAG_DIVIDE) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_DIVIDE);
|
EMIT_BYTE(rt, code,TOY_OPCODE_DIVIDE);
|
||||||
}
|
}
|
||||||
else if (ast.flag == TOY_AST_FLAG_MODULO) {
|
else if (ast.flag == TOY_AST_FLAG_MODULO) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_MODULO);
|
EMIT_BYTE(rt, code,TOY_OPCODE_MODULO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// else if (ast.flag == TOY_AST_FLAG_ASSIGN) {
|
// else if (ast.flag == TOY_AST_FLAG_ASSIGN) {
|
||||||
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||||
// //TODO: emit the env symbol to store TOP(S) within
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
// }
|
// }
|
||||||
// else if (ast.flag == TOY_AST_FLAG_ADD_ASSIGN) {
|
// else if (ast.flag == TOY_AST_FLAG_ADD_ASSIGN) {
|
||||||
// EMIT_BYTE(rt, TOY_OPCODE_ADD);
|
// EMIT_BYTE(rt, code,TOY_OPCODE_ADD);
|
||||||
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||||
// //TODO: emit the env symbol to store TOP(S) within
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
// }
|
// }
|
||||||
// else if (ast.flag == TOY_AST_FLAG_SUBTRACT_ASSIGN) {
|
// else if (ast.flag == TOY_AST_FLAG_SUBTRACT_ASSIGN) {
|
||||||
// EMIT_BYTE(rt, TOY_OPCODE_SUBTRACT);
|
// EMIT_BYTE(rt, code,TOY_OPCODE_SUBTRACT);
|
||||||
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||||
// //TODO: emit the env symbol to store TOP(S) within
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
// }
|
// }
|
||||||
// else if (ast.flag == TOY_AST_FLAG_MULTIPLY_ASSIGN) {
|
// else if (ast.flag == TOY_AST_FLAG_MULTIPLY_ASSIGN) {
|
||||||
// EMIT_BYTE(rt, TOY_OPCODE_MULTIPLY);
|
// EMIT_BYTE(rt, code,TOY_OPCODE_MULTIPLY);
|
||||||
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||||
// //TODO: emit the env symbol to store TOP(S) within
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
// }
|
// }
|
||||||
// else if (ast.flag == TOY_AST_FLAG_DIVIDE_ASSIGN) {
|
// else if (ast.flag == TOY_AST_FLAG_DIVIDE_ASSIGN) {
|
||||||
// EMIT_BYTE(rt, TOY_OPCODE_DIVIDE);
|
// EMIT_BYTE(rt, code,TOY_OPCODE_DIVIDE);
|
||||||
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||||
// //TODO: emit the env symbol to store TOP(S) within
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
// }
|
// }
|
||||||
// else if (ast.flag == TOY_AST_FLAG_MODULO_ASSIGN) {
|
// else if (ast.flag == TOY_AST_FLAG_MODULO_ASSIGN) {
|
||||||
// EMIT_BYTE(rt, TOY_OPCODE_MODULO);
|
// EMIT_BYTE(rt, code,TOY_OPCODE_MODULO);
|
||||||
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
|
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||||
// //TODO: emit the env symbol to store TOP(S) within
|
// //TODO: emit the env symbol to store TOP(S) within
|
||||||
// }
|
// }
|
||||||
|
|
||||||
else if (ast.flag == TOY_AST_FLAG_COMPARE_EQUAL) {
|
else if (ast.flag == TOY_AST_FLAG_COMPARE_EQUAL) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_EQUAL);
|
EMIT_BYTE(rt, code,TOY_OPCODE_COMPARE_EQUAL);
|
||||||
}
|
}
|
||||||
else if (ast.flag == TOY_AST_FLAG_COMPARE_NOT) {
|
else if (ast.flag == TOY_AST_FLAG_COMPARE_NOT) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_EQUAL);
|
EMIT_BYTE(rt, code,TOY_OPCODE_COMPARE_EQUAL);
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_NEGATE); //squeezed into one word
|
EMIT_BYTE(rt, code,TOY_OPCODE_NEGATE); //squeezed into one word
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code,0);
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code,0);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (ast.flag == TOY_AST_FLAG_COMPARE_LESS) {
|
else if (ast.flag == TOY_AST_FLAG_COMPARE_LESS) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_LESS);
|
EMIT_BYTE(rt, code,TOY_OPCODE_COMPARE_LESS);
|
||||||
}
|
}
|
||||||
else if (ast.flag == TOY_AST_FLAG_COMPARE_LESS_EQUAL) {
|
else if (ast.flag == TOY_AST_FLAG_COMPARE_LESS_EQUAL) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_LESS_EQUAL);
|
EMIT_BYTE(rt, code,TOY_OPCODE_COMPARE_LESS_EQUAL);
|
||||||
}
|
}
|
||||||
else if (ast.flag == TOY_AST_FLAG_COMPARE_GREATER) {
|
else if (ast.flag == TOY_AST_FLAG_COMPARE_GREATER) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_GREATER);
|
EMIT_BYTE(rt, code,TOY_OPCODE_COMPARE_GREATER);
|
||||||
}
|
}
|
||||||
else if (ast.flag == TOY_AST_FLAG_COMPARE_GREATER_EQUAL) {
|
else if (ast.flag == TOY_AST_FLAG_COMPARE_GREATER_EQUAL) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_GREATER_EQUAL);
|
EMIT_BYTE(rt, code,TOY_OPCODE_COMPARE_GREATER_EQUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (ast.flag == TOY_AST_FLAG_AND) {
|
else if (ast.flag == TOY_AST_FLAG_AND) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_AND);
|
EMIT_BYTE(rt, code,TOY_OPCODE_AND);
|
||||||
}
|
}
|
||||||
else if (ast.flag == TOY_AST_FLAG_OR) {
|
else if (ast.flag == TOY_AST_FLAG_OR) {
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_OR);
|
EMIT_BYTE(rt, code,TOY_OPCODE_OR);
|
||||||
|
}
|
||||||
|
else if (ast.flag == TOY_AST_FLAG_CONCAT) {
|
||||||
|
EMIT_BYTE(rt, code, TOY_OPCODE_CONCAT);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST binary flag found\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST binary flag found\n" TOY_CC_RESET);
|
||||||
@@ -198,9 +245,9 @@ static void writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//4-byte alignment (covers most cases)
|
//4-byte alignment (covers most cases)
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code,0);
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code,0);
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeInstructionPrint(Toy_Routine** rt, Toy_AstPrint ast) {
|
static void writeInstructionPrint(Toy_Routine** rt, Toy_AstPrint ast) {
|
||||||
@@ -208,12 +255,12 @@ static void writeInstructionPrint(Toy_Routine** rt, Toy_AstPrint ast) {
|
|||||||
writeRoutineCode(rt, ast.child);
|
writeRoutineCode(rt, ast.child);
|
||||||
|
|
||||||
//output the print opcode
|
//output the print opcode
|
||||||
EMIT_BYTE(rt, TOY_OPCODE_PRINT);
|
EMIT_BYTE(rt, code,TOY_OPCODE_PRINT);
|
||||||
|
|
||||||
//4-byte alignment
|
//4-byte alignment
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code,0);
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code,0);
|
||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, code,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//routine structure
|
//routine structure
|
||||||
@@ -274,39 +321,31 @@ static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// static void writeRoutineJumps(Toy_Routine* rt) {
|
|
||||||
// //
|
|
||||||
// }
|
|
||||||
|
|
||||||
// static void writeRoutineData(Toy_Routine* rt) {
|
|
||||||
// //
|
|
||||||
// }
|
|
||||||
|
|
||||||
static void* writeRoutine(Toy_Routine* rt, Toy_Ast* ast) {
|
static void* writeRoutine(Toy_Routine* rt, Toy_Ast* ast) {
|
||||||
//build the routine's parts
|
//build the routine's parts
|
||||||
//TODO: param
|
//TODO: param
|
||||||
//code
|
//code
|
||||||
writeRoutineCode(&rt, ast);
|
writeRoutineCode(&rt, ast);
|
||||||
EMIT_BYTE(&rt, TOY_OPCODE_RETURN); //temp terminator
|
EMIT_BYTE(&rt, code, TOY_OPCODE_RETURN); //temp terminator
|
||||||
EMIT_BYTE(&rt, 0); //4-byte alignment
|
EMIT_BYTE(&rt, code, 0); //4-byte alignment
|
||||||
EMIT_BYTE(&rt, 0);
|
EMIT_BYTE(&rt, code, 0);
|
||||||
EMIT_BYTE(&rt, 0);
|
EMIT_BYTE(&rt, code, 0);
|
||||||
//TODO: jumps
|
|
||||||
//TODO: data
|
|
||||||
|
|
||||||
//write the header and combine the parts
|
//write the header and combine the parts
|
||||||
void* buffer = NULL;
|
void* buffer = NULL;
|
||||||
unsigned int capacity = 0, count = 0;
|
unsigned int capacity = 0, count = 0;
|
||||||
// int paramAddr = 0, codeAddr = 0, jumpsAddr = 0, dataAddr = 0, subsAddr = 0;
|
// int paramAddr = 0, codeAddr = 0, subsAddr = 0;
|
||||||
int codeAddr = 0;
|
int codeAddr = 0;
|
||||||
|
int jumpsAddr = 0;
|
||||||
|
int dataAddr = 0;
|
||||||
|
|
||||||
emitInt(&buffer, &capacity, &count, 0); //total size (overwritten later)
|
emitInt(&buffer, &capacity, &count, 0); //total size (overwritten later)
|
||||||
emitInt(&buffer, &capacity, &count, rt->paramCount); //param count
|
emitInt(&buffer, &capacity, &count, rt->paramCount); //param size
|
||||||
emitInt(&buffer, &capacity, &count, rt->jumpsCount); //jumps count
|
emitInt(&buffer, &capacity, &count, rt->jumpsCount); //jumps size
|
||||||
emitInt(&buffer, &capacity, &count, rt->dataCount); //data count
|
emitInt(&buffer, &capacity, &count, rt->dataCount); //data size
|
||||||
emitInt(&buffer, &capacity, &count, rt->subsCount); //routine count
|
emitInt(&buffer, &capacity, &count, rt->subsCount); //routine size
|
||||||
|
|
||||||
//generate blank spaces, cache their positions in the []Addr variables
|
//generate blank spaces, cache their positions in the *Addr variables (for storing the start positions)
|
||||||
if (rt->paramCount > 0) {
|
if (rt->paramCount > 0) {
|
||||||
// paramAddr = count;
|
// paramAddr = count;
|
||||||
emitInt((void**)&buffer, &capacity, &count, 0); //params
|
emitInt((void**)&buffer, &capacity, &count, 0); //params
|
||||||
@@ -316,11 +355,11 @@ static void* writeRoutine(Toy_Routine* rt, Toy_Ast* ast) {
|
|||||||
emitInt((void**)&buffer, &capacity, &count, 0); //code
|
emitInt((void**)&buffer, &capacity, &count, 0); //code
|
||||||
}
|
}
|
||||||
if (rt->jumpsCount > 0) {
|
if (rt->jumpsCount > 0) {
|
||||||
// jumpsAddr = count;
|
jumpsAddr = count;
|
||||||
emitInt((void**)&buffer, &capacity, &count, 0); //jumps
|
emitInt((void**)&buffer, &capacity, &count, 0); //jumps
|
||||||
}
|
}
|
||||||
if (rt->dataCount > 0) {
|
if (rt->dataCount > 0) {
|
||||||
// dataAddr = count;
|
dataAddr = count;
|
||||||
emitInt((void**)&buffer, &capacity, &count, 0); //data
|
emitInt((void**)&buffer, &capacity, &count, 0); //data
|
||||||
}
|
}
|
||||||
if (rt->subsCount > 0) {
|
if (rt->subsCount > 0) {
|
||||||
@@ -337,6 +376,22 @@ static void* writeRoutine(Toy_Routine* rt, Toy_Ast* ast) {
|
|||||||
count += rt->codeCount;
|
count += rt->codeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rt->jumpsCount > 0) {
|
||||||
|
expand(&buffer, &capacity, &count, rt->jumpsCount);
|
||||||
|
memcpy((buffer + count), rt->jumps, rt->jumpsCount);
|
||||||
|
|
||||||
|
*((int*)(buffer + jumpsAddr)) = count;
|
||||||
|
count += rt->jumpsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rt->dataCount > 0) {
|
||||||
|
expand(&buffer, &capacity, &count, rt->dataCount);
|
||||||
|
memcpy((buffer + count), rt->data, rt->dataCount);
|
||||||
|
|
||||||
|
*((int*)(buffer + dataAddr)) = count;
|
||||||
|
count += rt->dataCount;
|
||||||
|
}
|
||||||
|
|
||||||
//finally, record the total size within the header, and return the result
|
//finally, record the total size within the header, and return the result
|
||||||
*((int*)buffer) = count;
|
*((int*)buffer) = count;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ typedef struct Toy_Routine {
|
|||||||
unsigned int jumpsCapacity;
|
unsigned int jumpsCapacity;
|
||||||
unsigned int jumpsCount;
|
unsigned int jumpsCount;
|
||||||
|
|
||||||
unsigned char* data; //{type,val} tuples of data
|
unsigned char* data; //data for longer stuff
|
||||||
unsigned int dataCapacity;
|
unsigned int dataCapacity;
|
||||||
unsigned int dataCount;
|
unsigned int dataCount;
|
||||||
|
|
||||||
|
|||||||
@@ -42,13 +42,18 @@ Toy_String* Toy_createString(Toy_Bucket** bucketHandle, const char* cstring) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstring, int length) {
|
Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstring, int length) {
|
||||||
|
if (length > TOY_STRING_MAX_LENGTH) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't create a string longer than %d\n" TOY_CC_RESET, TOY_STRING_MAX_LENGTH);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String) + length + 1); //TODO: compensate for partitioning more space than bucket capacity
|
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String) + length + 1); //TODO: compensate for partitioning more space than bucket capacity
|
||||||
|
|
||||||
ret->type = TOY_STRING_LEAF;
|
ret->type = TOY_STRING_LEAF;
|
||||||
ret->length = length;
|
ret->length = length;
|
||||||
ret->refCount = 1;
|
ret->refCount = 1;
|
||||||
ret->cachedHash = 0; //don't calc until needed
|
ret->cachedHash = 0; //don't calc until needed
|
||||||
memcpy(ret->as.leaf.data, cstring, length);
|
memcpy(ret->as.leaf.data, cstring, length + 1);
|
||||||
ret->as.leaf.data[length] = '\0';
|
ret->as.leaf.data[length] = '\0';
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -57,13 +62,18 @@ Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstrin
|
|||||||
TOY_API Toy_String* Toy_createNameString(Toy_Bucket** bucketHandle, const char* cname) {
|
TOY_API Toy_String* Toy_createNameString(Toy_Bucket** bucketHandle, const char* cname) {
|
||||||
int length = strlen(cname);
|
int length = strlen(cname);
|
||||||
|
|
||||||
|
if (length > TOY_STRING_MAX_LENGTH) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't create a name string longer than %d\n" TOY_CC_RESET, TOY_STRING_MAX_LENGTH);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String) + length + 1); //TODO: compensate for partitioning more space than bucket capacity
|
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String) + length + 1); //TODO: compensate for partitioning more space than bucket capacity
|
||||||
|
|
||||||
ret->type = TOY_STRING_NAME;
|
ret->type = TOY_STRING_NAME;
|
||||||
ret->length = length;
|
ret->length = length;
|
||||||
ret->refCount = 1;
|
ret->refCount = 1;
|
||||||
ret->cachedHash = 0; //don't calc until needed
|
ret->cachedHash = 0; //don't calc until needed
|
||||||
memcpy(ret->as.name.data, cname, length);
|
memcpy(ret->as.name.data, cname, length + 1);
|
||||||
ret->as.name.data[length] = '\0';
|
ret->as.name.data[length] = '\0';
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -98,7 +108,7 @@ Toy_String* Toy_deepCopyString(Toy_Bucket** bucketHandle, Toy_String* str) {
|
|||||||
ret->length = str->length;
|
ret->length = str->length;
|
||||||
ret->refCount = 1;
|
ret->refCount = 1;
|
||||||
ret->cachedHash = str->cachedHash;
|
ret->cachedHash = str->cachedHash;
|
||||||
memcpy(ret->as.name.data, str->as.name.data, str->length);
|
memcpy(ret->as.name.data, str->as.name.data, str->length + 1);
|
||||||
ret->as.name.data[ret->length] = '\0';
|
ret->as.name.data[ret->length] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +126,11 @@ Toy_String* Toy_concatStrings(Toy_Bucket** bucketHandle, Toy_String* left, Toy_S
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (left->length + right->length > TOY_STRING_MAX_LENGTH) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't concat a string longer than %d\n" TOY_CC_RESET, TOY_STRING_MAX_LENGTH);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String));
|
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String));
|
||||||
|
|
||||||
ret->type = TOY_STRING_NODE;
|
ret->type = TOY_STRING_NODE;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include "toy_bucket.h"
|
#include "toy_bucket.h"
|
||||||
#include "toy_value.h"
|
#include "toy_value.h"
|
||||||
|
|
||||||
|
#define TOY_STRING_MAX_LENGTH 1000
|
||||||
|
|
||||||
//rope pattern
|
//rope pattern
|
||||||
typedef struct Toy_String { //32 | 64 BITNESS
|
typedef struct Toy_String { //32 | 64 BITNESS
|
||||||
enum Toy_StringType {
|
enum Toy_StringType {
|
||||||
|
|||||||
@@ -15,23 +15,25 @@ typedef enum Toy_ValueType {
|
|||||||
TOY_VALUE_DICTIONARY,
|
TOY_VALUE_DICTIONARY,
|
||||||
TOY_VALUE_FUNCTION,
|
TOY_VALUE_FUNCTION,
|
||||||
TOY_VALUE_OPAQUE,
|
TOY_VALUE_OPAQUE,
|
||||||
|
|
||||||
|
//TODO: type, any
|
||||||
} Toy_ValueType;
|
} Toy_ValueType;
|
||||||
|
|
||||||
//8 bytes in size
|
//8 bytes in size
|
||||||
typedef struct Toy_Value { //32 | 64 BITNESS
|
typedef struct Toy_Value { //32 | 64 BITNESS
|
||||||
union {
|
union {
|
||||||
bool boolean; //1 | 1
|
bool boolean; //1 | 1
|
||||||
int integer; //4 | 4
|
int integer; //4 | 4
|
||||||
float number; //4 | 4
|
float number; //4 | 4
|
||||||
struct Toy_String* string; //4 | 8
|
struct Toy_String* string; //4 | 8
|
||||||
//TODO: arrays
|
//TODO: arrays
|
||||||
//TODO: dictonaries
|
//TODO: dictonaries
|
||||||
//TODO: functions
|
//TODO: functions
|
||||||
//TODO: opaque
|
//TODO: opaque
|
||||||
} as; //4 | 8
|
} as; //4 | 8
|
||||||
|
|
||||||
Toy_ValueType type; //4 | 4
|
Toy_ValueType type; //4 | 4
|
||||||
} Toy_Value; //8 | 12
|
} Toy_Value; //8 | 16
|
||||||
|
|
||||||
#define TOY_VALUE_IS_NULL(value) ((value).type == TOY_VALUE_NULL)
|
#define TOY_VALUE_IS_NULL(value) ((value).type == TOY_VALUE_NULL)
|
||||||
#define TOY_VALUE_IS_BOOLEAN(value) ((value).type == TOY_VALUE_BOOLEAN)
|
#define TOY_VALUE_IS_BOOLEAN(value) ((value).type == TOY_VALUE_BOOLEAN)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "toy_print.h"
|
#include "toy_print.h"
|
||||||
#include "toy_opcodes.h"
|
#include "toy_opcodes.h"
|
||||||
#include "toy_value.h"
|
#include "toy_value.h"
|
||||||
|
#include "toy_string.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -64,8 +65,17 @@ static void processRead(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_STRING: {
|
case TOY_VALUE_STRING: {
|
||||||
//
|
fix_alignment(vm);
|
||||||
// break;
|
//grab the jump as an integer
|
||||||
|
unsigned int jump = *(unsigned int*)(vm->routine + vm->jumpsAddr + READ_INT(vm));
|
||||||
|
|
||||||
|
//jumps are relative to the data address
|
||||||
|
char* cstring = (char*)(vm->routine + vm->dataAddr + jump);
|
||||||
|
|
||||||
|
//build a string from the data section
|
||||||
|
value = TOY_VALUE_FROM_STRING(Toy_createString(&vm->stringBucket, cstring));
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY: {
|
case TOY_VALUE_ARRAY: {
|
||||||
@@ -264,7 +274,24 @@ static void processPrint(Toy_VM* vm) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_STRING: //TODO: decide on how long strings, etc. live for in memory
|
case TOY_VALUE_STRING: {
|
||||||
|
Toy_String* str = TOY_VALUE_AS_STRING(value);
|
||||||
|
|
||||||
|
//TODO: decide on how long strings, etc. live for in memory
|
||||||
|
if (str->type == TOY_STRING_NODE) {
|
||||||
|
char* buffer = Toy_getStringRawBuffer(str);
|
||||||
|
Toy_print(buffer);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
else if (str->type == TOY_STRING_LEAF) {
|
||||||
|
Toy_print(str->as.leaf.data);
|
||||||
|
}
|
||||||
|
else if (str->type == TOY_STRING_NAME) {
|
||||||
|
Toy_print(str->as.name.data); //should this be a thing?
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY:
|
case TOY_VALUE_ARRAY:
|
||||||
case TOY_VALUE_DICTIONARY:
|
case TOY_VALUE_DICTIONARY:
|
||||||
case TOY_VALUE_FUNCTION:
|
case TOY_VALUE_FUNCTION:
|
||||||
@@ -274,6 +301,25 @@ static void processPrint(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void processConcat(Toy_VM* vm) {
|
||||||
|
Toy_Value right = Toy_popStack(&vm->stack);
|
||||||
|
Toy_Value left = Toy_popStack(&vm->stack);
|
||||||
|
|
||||||
|
if (!TOY_VALUE_IS_STRING(left)) {
|
||||||
|
Toy_error("Failed to concatenate a value that is not a string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TOY_VALUE_IS_STRING(left)) {
|
||||||
|
Toy_error("Failed to concatenate a value that is not a string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//all good
|
||||||
|
Toy_String* result = Toy_concatStrings(&vm->stringBucket, TOY_VALUE_AS_STRING(left), TOY_VALUE_AS_STRING(right));
|
||||||
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_STRING(result));
|
||||||
|
}
|
||||||
|
|
||||||
static void process(Toy_VM* vm) {
|
static void process(Toy_VM* vm) {
|
||||||
while(true) {
|
while(true) {
|
||||||
Toy_OpcodeType opcode = READ_BYTE(vm);
|
Toy_OpcodeType opcode = READ_BYTE(vm);
|
||||||
@@ -320,6 +366,10 @@ static void process(Toy_VM* vm) {
|
|||||||
processPrint(vm);
|
processPrint(vm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_CONCAT:
|
||||||
|
processConcat(vm);
|
||||||
|
break;
|
||||||
|
|
||||||
//not yet implemented
|
//not yet implemented
|
||||||
case TOY_OPCODE_LOAD:
|
case TOY_OPCODE_LOAD:
|
||||||
case TOY_OPCODE_LOAD_LONG:
|
case TOY_OPCODE_LOAD_LONG:
|
||||||
@@ -373,32 +423,34 @@ void Toy_bindVMToRoutine(Toy_VM* vm, unsigned char* routine) {
|
|||||||
|
|
||||||
//read the header metadata
|
//read the header metadata
|
||||||
vm->routineSize = READ_UNSIGNED_INT(vm);
|
vm->routineSize = READ_UNSIGNED_INT(vm);
|
||||||
vm->paramCount = READ_UNSIGNED_INT(vm);
|
vm->paramSize = READ_UNSIGNED_INT(vm);
|
||||||
vm->jumpsCount = READ_UNSIGNED_INT(vm);
|
vm->jumpsSize = READ_UNSIGNED_INT(vm);
|
||||||
vm->dataCount = READ_UNSIGNED_INT(vm);
|
vm->dataSize = READ_UNSIGNED_INT(vm);
|
||||||
vm->subsCount = READ_UNSIGNED_INT(vm);
|
vm->subsSize = READ_UNSIGNED_INT(vm);
|
||||||
|
|
||||||
//read the header addresses
|
//read the header addresses
|
||||||
if (vm->paramCount > 0) {
|
if (vm->paramSize > 0) {
|
||||||
vm->paramAddr = READ_UNSIGNED_INT(vm);
|
vm->paramAddr = READ_UNSIGNED_INT(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
vm->codeAddr = READ_UNSIGNED_INT(vm); //required
|
vm->codeAddr = READ_UNSIGNED_INT(vm); //required
|
||||||
|
|
||||||
if (vm->jumpsCount > 0) {
|
if (vm->jumpsSize > 0) {
|
||||||
vm->jumpsAddr = READ_UNSIGNED_INT(vm);
|
vm->jumpsAddr = READ_UNSIGNED_INT(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vm->dataCount > 0) {
|
if (vm->dataSize > 0) {
|
||||||
vm->dataAddr = READ_UNSIGNED_INT(vm);
|
vm->dataAddr = READ_UNSIGNED_INT(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vm->subsCount > 0) {
|
if (vm->subsSize > 0) {
|
||||||
vm->subsAddr = READ_UNSIGNED_INT(vm);
|
vm->subsAddr = READ_UNSIGNED_INT(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
//preallocate the scope & stack
|
//allocate the stack, scope, and memory
|
||||||
vm->stack = Toy_allocateStack();
|
vm->stack = Toy_allocateStack();
|
||||||
|
//TODO: scope
|
||||||
|
vm->stringBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_runVM(Toy_VM* vm) {
|
void Toy_runVM(Toy_VM* vm) {
|
||||||
@@ -412,13 +464,12 @@ void Toy_runVM(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Toy_freeVM(Toy_VM* vm) {
|
void Toy_freeVM(Toy_VM* vm) {
|
||||||
//clear the stack
|
//clear the stack, scope and memory
|
||||||
Toy_freeStack(vm->stack);
|
Toy_freeStack(vm->stack);
|
||||||
|
|
||||||
//TODO: clear the scope
|
//TODO: clear the scope
|
||||||
|
Toy_freeBucket(&vm->stringBucket);
|
||||||
|
|
||||||
//free the bytecode
|
//free the bytecode
|
||||||
|
|
||||||
free(vm->bc);
|
free(vm->bc);
|
||||||
Toy_resetVM(vm);
|
Toy_resetVM(vm);
|
||||||
}
|
}
|
||||||
@@ -429,10 +480,10 @@ void Toy_resetVM(Toy_VM* vm) {
|
|||||||
vm->routine = NULL;
|
vm->routine = NULL;
|
||||||
vm->routineSize = 0;
|
vm->routineSize = 0;
|
||||||
|
|
||||||
vm->paramCount = 0;
|
vm->paramSize = 0;
|
||||||
vm->jumpsCount = 0;
|
vm->jumpsSize = 0;
|
||||||
vm->dataCount = 0;
|
vm->dataSize = 0;
|
||||||
vm->subsCount = 0;
|
vm->subsSize = 0;
|
||||||
|
|
||||||
vm->paramAddr = 0;
|
vm->paramAddr = 0;
|
||||||
vm->codeAddr = 0;
|
vm->codeAddr = 0;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
|
|
||||||
#include "toy_stack.h"
|
#include "toy_stack.h"
|
||||||
|
#include "toy_bucket.h"
|
||||||
|
|
||||||
typedef struct Toy_VM {
|
typedef struct Toy_VM {
|
||||||
//hold the raw bytecode
|
//hold the raw bytecode
|
||||||
@@ -12,10 +13,10 @@ typedef struct Toy_VM {
|
|||||||
unsigned char* routine;
|
unsigned char* routine;
|
||||||
unsigned int routineSize;
|
unsigned int routineSize;
|
||||||
|
|
||||||
unsigned int paramCount;
|
unsigned int paramSize;
|
||||||
unsigned int jumpsCount;
|
unsigned int jumpsSize;
|
||||||
unsigned int dataCount;
|
unsigned int dataSize;
|
||||||
unsigned int subsCount;
|
unsigned int subsSize;
|
||||||
|
|
||||||
unsigned int paramAddr;
|
unsigned int paramAddr;
|
||||||
unsigned int codeAddr;
|
unsigned int codeAddr;
|
||||||
@@ -30,6 +31,9 @@ typedef struct Toy_VM {
|
|||||||
|
|
||||||
//stack - immediate-level values only
|
//stack - immediate-level values only
|
||||||
Toy_Stack* stack;
|
Toy_Stack* stack;
|
||||||
|
|
||||||
|
//easy access to memory
|
||||||
|
Toy_Bucket* stringBucket;
|
||||||
} Toy_VM;
|
} Toy_VM;
|
||||||
|
|
||||||
TOY_API void Toy_bindVM(Toy_VM* vm, unsigned char* bytecode); //process the version data
|
TOY_API void Toy_bindVM(Toy_VM* vm, unsigned char* bytecode); //process the version data
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ int test_sizeof_ast_64bit() {
|
|||||||
//run for each type
|
//run for each type
|
||||||
TEST_SIZEOF(Toy_AstType, 4);
|
TEST_SIZEOF(Toy_AstType, 4);
|
||||||
TEST_SIZEOF(Toy_AstBlock, 32);
|
TEST_SIZEOF(Toy_AstBlock, 32);
|
||||||
TEST_SIZEOF(Toy_AstValue, 12);
|
TEST_SIZEOF(Toy_AstValue, 24);
|
||||||
TEST_SIZEOF(Toy_AstUnary, 16);
|
TEST_SIZEOF(Toy_AstUnary, 16);
|
||||||
TEST_SIZEOF(Toy_AstBinary, 24);
|
TEST_SIZEOF(Toy_AstBinary, 24);
|
||||||
TEST_SIZEOF(Toy_AstGroup, 16);
|
TEST_SIZEOF(Toy_AstGroup, 16);
|
||||||
@@ -245,7 +245,7 @@ int main() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucketHandle = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucketHandle = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_type_emission(&bucketHandle);
|
res = test_type_emission(&bucketHandle);
|
||||||
Toy_freeBucket(&bucketHandle);
|
Toy_freeBucket(&bucketHandle);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
|
|||||||
@@ -69,33 +69,6 @@ int test_buckets() {
|
|||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
//test partitioning a bucket, several times, with an internal expansion, and awkward sizes
|
|
||||||
{
|
|
||||||
//init
|
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(32);
|
|
||||||
|
|
||||||
//grab some memory
|
|
||||||
void* a = Toy_partitionBucket(&bucket, 16);
|
|
||||||
void* b = Toy_partitionBucket(&bucket, 10);
|
|
||||||
void* c = Toy_partitionBucket(&bucket, 10);
|
|
||||||
void* d = Toy_partitionBucket(&bucket, 10);
|
|
||||||
|
|
||||||
//checks - awkward and mismatched sizes is not officially supported, but it should work
|
|
||||||
if (
|
|
||||||
bucket->capacity != 32 ||
|
|
||||||
bucket->count != 20 ||
|
|
||||||
bucket->next == NULL ||
|
|
||||||
bucket->next->capacity != 32 ||
|
|
||||||
bucket->next->count != 26)
|
|
||||||
{
|
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to expand 'Toy_Bucket' with awkward/mismatched sizes correctly\n" TOY_CC_RESET);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//cleanup
|
|
||||||
Toy_freeBucket(&bucket);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ int main() {
|
|||||||
int total = 0, res = 0;
|
int total = 0, res = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_bytecode_header(&bucket);
|
res = test_bytecode_header(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -185,7 +185,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_bytecode_from_source(&bucket);
|
res = test_bytecode_from_source(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -195,4 +195,4 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include "toy_parser.h"
|
#include "toy_parser.h"
|
||||||
#include "toy_console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
#include "toy_string.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
Toy_Ast* makeAstFromSource(Toy_Bucket** bucketHandle, const char* source) {
|
Toy_Ast* makeAstFromSource(Toy_Bucket** bucketHandle, const char* source) {
|
||||||
@@ -184,7 +186,7 @@ int test_values(Toy_Bucket** bucketHandle) {
|
|||||||
TOY_VALUE_IS_INTEGER(ast->block.child->value.value) == false ||
|
TOY_VALUE_IS_INTEGER(ast->block.child->value.value) == false ||
|
||||||
TOY_VALUE_AS_INTEGER(ast->block.child->value.value) != 1234567890)
|
TOY_VALUE_AS_INTEGER(ast->block.child->value.value) != 1234567890)
|
||||||
{
|
{
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with integer value 42 with separators\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with integer value 1_234_567_890\n" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +204,26 @@ int test_values(Toy_Bucket** bucketHandle) {
|
|||||||
TOY_VALUE_IS_FLOAT(ast->block.child->value.value) == false ||
|
TOY_VALUE_IS_FLOAT(ast->block.child->value.value) == false ||
|
||||||
TOY_VALUE_AS_FLOAT(ast->block.child->value.value) != 3.14159265f)
|
TOY_VALUE_AS_FLOAT(ast->block.child->value.value) != 3.14159265f)
|
||||||
{
|
{
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with float value 3.1415 with separators\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with float value 3.141_592_65\n" TOY_CC_RESET);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//test string
|
||||||
|
{
|
||||||
|
Toy_Ast* ast = makeAstFromSource(bucketHandle, "\"Hello world!\";");
|
||||||
|
|
||||||
|
//check if it worked
|
||||||
|
if (
|
||||||
|
ast == NULL ||
|
||||||
|
ast->type != TOY_AST_BLOCK ||
|
||||||
|
ast->block.child == NULL ||
|
||||||
|
ast->block.child->type != TOY_AST_VALUE ||
|
||||||
|
TOY_VALUE_IS_STRING(ast->block.child->value.value) == false ||
|
||||||
|
TOY_VALUE_AS_STRING(ast->block.child->value.value)->type != TOY_STRING_LEAF ||
|
||||||
|
strcmp(TOY_VALUE_AS_STRING(ast->block.child->value.value)->as.leaf.data, "Hello world!") != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with string value 'Hello world!'\n" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -578,7 +599,7 @@ int main() {
|
|||||||
int total = 0, res = 0;
|
int total = 0, res = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_simple_empty_parsers(&bucket);
|
res = test_simple_empty_parsers(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -588,7 +609,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_values(&bucket);
|
res = test_values(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -598,7 +619,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_unary(&bucket);
|
res = test_unary(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -608,7 +629,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_binary(&bucket);
|
res = test_binary(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -618,7 +639,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_precedence(&bucket);
|
res = test_precedence(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
|
|||||||
@@ -318,6 +318,105 @@ int test_routine_expressions(Toy_Bucket** bucketHandle) {
|
|||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//produce a string value
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
const char* source = "\"Hello world!\";";
|
||||||
|
Toy_Lexer lexer;
|
||||||
|
Toy_Parser parser;
|
||||||
|
|
||||||
|
Toy_bindLexer(&lexer, source);
|
||||||
|
Toy_bindParser(&parser, &lexer);
|
||||||
|
Toy_Ast* ast = Toy_scanParser(bucketHandle, &parser);
|
||||||
|
|
||||||
|
//run
|
||||||
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
|
int len = ((int*)buffer)[0];
|
||||||
|
|
||||||
|
//check header
|
||||||
|
int* header = (int*)buffer;
|
||||||
|
|
||||||
|
if (header[0] != 64 || //total size
|
||||||
|
header[1] != 0 || //param size
|
||||||
|
header[2] != 4 || //jumps size
|
||||||
|
header[3] != 16 || //data size
|
||||||
|
header[4] != 0 || //subs size
|
||||||
|
|
||||||
|
// header[??] != ?? || //params address
|
||||||
|
header[5] != 32 || //code address
|
||||||
|
header[6] != 44 || //jumps address
|
||||||
|
header[7] != 48 || //data address
|
||||||
|
// header[??] != ?? || //subs address
|
||||||
|
|
||||||
|
false)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to produce the expected routine header, source: %s\n" TOY_CC_RESET, source);
|
||||||
|
|
||||||
|
//cleanup and return
|
||||||
|
free(buffer);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* code = buffer + 32; //8 values in the header, each 4 bytes
|
||||||
|
|
||||||
|
//check code
|
||||||
|
if (
|
||||||
|
//code start
|
||||||
|
*((unsigned char*)(code + 0)) != TOY_OPCODE_READ ||
|
||||||
|
*((unsigned char*)(code + 1)) != TOY_VALUE_STRING ||
|
||||||
|
*((unsigned char*)(code + 2)) != 0 ||
|
||||||
|
*((unsigned char*)(code + 3)) != 0 ||
|
||||||
|
*(unsigned int*)(code + 4) != 0 || //the jump index
|
||||||
|
*((unsigned char*)(code + 8)) != TOY_OPCODE_RETURN ||
|
||||||
|
*((unsigned char*)(code + 9)) != 0 ||
|
||||||
|
*((unsigned char*)(code + 10)) != 0 ||
|
||||||
|
*((unsigned char*)(code + 11)) != 0 ||
|
||||||
|
|
||||||
|
false)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to produce the expected routine code, source: %s\n" TOY_CC_RESET, source);
|
||||||
|
|
||||||
|
//cleanup and return
|
||||||
|
free(buffer);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* jumps = code + 12;
|
||||||
|
|
||||||
|
//check jumps
|
||||||
|
if (
|
||||||
|
//code start
|
||||||
|
*(unsigned int*)(jumps + 0) != 0 || //the address relative to the start of the data section
|
||||||
|
|
||||||
|
false)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to produce the expected routine jumps, source: %s\n" TOY_CC_RESET, source);
|
||||||
|
|
||||||
|
//cleanup and return
|
||||||
|
free(buffer);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* data = jumps + 4;
|
||||||
|
|
||||||
|
//check data
|
||||||
|
if (
|
||||||
|
//data start (the end of the data is padded to the nearest multiple of 4)
|
||||||
|
strcmp( ((char*)data) + ((unsigned int*)jumps)[0], "Hello world!" ) != 0 ||
|
||||||
|
|
||||||
|
false)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to produce the expected routine data, source: %s\n" TOY_CC_RESET, source);
|
||||||
|
|
||||||
|
//cleanup and return
|
||||||
|
free(buffer);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,7 +785,7 @@ int main() {
|
|||||||
int total = 0, res = 0;
|
int total = 0, res = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_routine_expressions(&bucket);
|
res = test_routine_expressions(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -696,7 +795,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_routine_binary(&bucket);
|
res = test_routine_binary(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -706,7 +805,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_routine_keywords(&bucket);
|
res = test_routine_keywords(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -716,4 +815,4 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ int test_string_allocation() {
|
|||||||
//allocate a single string from a c-string
|
//allocate a single string from a c-string
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
|
|
||||||
const char* cstring = "Hello world";
|
const char* cstring = "Hello world";
|
||||||
Toy_String* str = Toy_createString(&bucket, cstring);
|
Toy_String* str = Toy_createString(&bucket, cstring);
|
||||||
@@ -77,7 +77,7 @@ int test_string_allocation() {
|
|||||||
//copy and deep copy a string
|
//copy and deep copy a string
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
|
|
||||||
const char* cstring = "Hello world";
|
const char* cstring = "Hello world";
|
||||||
Toy_String* str = Toy_createString(&bucket, cstring);
|
Toy_String* str = Toy_createString(&bucket, cstring);
|
||||||
@@ -103,7 +103,7 @@ int test_string_allocation() {
|
|||||||
//copy and deep copy a name string
|
//copy and deep copy a name string
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
|
|
||||||
const char* cstring = "Hello world";
|
const char* cstring = "Hello world";
|
||||||
Toy_String* str = Toy_createNameString(&bucket, cstring);
|
Toy_String* str = Toy_createNameString(&bucket, cstring);
|
||||||
@@ -129,7 +129,7 @@ int test_string_allocation() {
|
|||||||
//allocate a zero-length string
|
//allocate a zero-length string
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
|
|
||||||
const char* cstring = "";
|
const char* cstring = "";
|
||||||
Toy_String* str = Toy_createString(&bucket, cstring);
|
Toy_String* str = Toy_createString(&bucket, cstring);
|
||||||
@@ -138,8 +138,7 @@ int test_string_allocation() {
|
|||||||
if (str->type != TOY_STRING_LEAF ||
|
if (str->type != TOY_STRING_LEAF ||
|
||||||
str->length != 0 ||
|
str->length != 0 ||
|
||||||
str->refCount != 1 ||
|
str->refCount != 1 ||
|
||||||
strcmp(str->as.leaf.data, "") != 0 ||
|
strcmp(str->as.leaf.data, "") != 0)
|
||||||
bucket->count != sizeof(Toy_String) + 1) //1 for the null character
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate a Toy_String with zero length\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate a Toy_String with zero length\n" TOY_CC_RESET);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
@@ -157,7 +156,7 @@ int test_string_allocation() {
|
|||||||
|
|
||||||
int test_string_concatenation() {
|
int test_string_concatenation() {
|
||||||
//one big bucket o' fun
|
//one big bucket o' fun
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
|
|
||||||
//concatenate two strings, and check the refcounts
|
//concatenate two strings, and check the refcounts
|
||||||
{
|
{
|
||||||
@@ -298,7 +297,7 @@ int test_string_equality() {
|
|||||||
//simple string equality (no concats)
|
//simple string equality (no concats)
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_String* helloWorldOne = Toy_createString(&bucket, "Hello world");
|
Toy_String* helloWorldOne = Toy_createString(&bucket, "Hello world");
|
||||||
Toy_String* helloWorldTwo = Toy_createString(&bucket, "Hello world");
|
Toy_String* helloWorldTwo = Toy_createString(&bucket, "Hello world");
|
||||||
Toy_String* helloEveryone = Toy_createString(&bucket, "Hello everyone");
|
Toy_String* helloEveryone = Toy_createString(&bucket, "Hello everyone");
|
||||||
@@ -348,7 +347,7 @@ int test_string_equality() {
|
|||||||
//string equality (with concat left)
|
//string equality (with concat left)
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_String* helloWorldOne = Toy_concatStrings(&bucket, Toy_createString(&bucket, "Hello "), Toy_createString(&bucket, "world"));
|
Toy_String* helloWorldOne = Toy_concatStrings(&bucket, Toy_createString(&bucket, "Hello "), Toy_createString(&bucket, "world"));
|
||||||
Toy_String* helloWorldTwo = Toy_createString(&bucket, "Hello world");
|
Toy_String* helloWorldTwo = Toy_createString(&bucket, "Hello world");
|
||||||
Toy_String* helloEveryone = Toy_createString(&bucket, "Hello everyone");
|
Toy_String* helloEveryone = Toy_createString(&bucket, "Hello everyone");
|
||||||
@@ -398,7 +397,7 @@ int test_string_equality() {
|
|||||||
//string equality (with concat right)
|
//string equality (with concat right)
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_String* helloWorldOne = Toy_createString(&bucket, "Hello world");
|
Toy_String* helloWorldOne = Toy_createString(&bucket, "Hello world");
|
||||||
Toy_String* helloWorldTwo = Toy_concatStrings(&bucket, Toy_createString(&bucket, "Hello "), Toy_createString(&bucket, "world"));
|
Toy_String* helloWorldTwo = Toy_concatStrings(&bucket, Toy_createString(&bucket, "Hello "), Toy_createString(&bucket, "world"));
|
||||||
Toy_String* helloEveryone = Toy_createString(&bucket, "Hello everyone");
|
Toy_String* helloEveryone = Toy_createString(&bucket, "Hello everyone");
|
||||||
@@ -424,7 +423,7 @@ int test_string_equality() {
|
|||||||
//string equality (with concat both)
|
//string equality (with concat both)
|
||||||
{
|
{
|
||||||
//setup - these concat points are deliberately different
|
//setup - these concat points are deliberately different
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_String* helloWorldOne = Toy_concatStrings(&bucket, Toy_createString(&bucket, "Hello "), Toy_createString(&bucket, "world"));
|
Toy_String* helloWorldOne = Toy_concatStrings(&bucket, Toy_createString(&bucket, "Hello "), Toy_createString(&bucket, "world"));
|
||||||
Toy_String* helloWorldTwo = Toy_concatStrings(&bucket, Toy_createString(&bucket, "Hello"), Toy_createString(&bucket, " world"));
|
Toy_String* helloWorldTwo = Toy_concatStrings(&bucket, Toy_createString(&bucket, "Hello"), Toy_createString(&bucket, " world"));
|
||||||
Toy_String* helloEveryone = Toy_concatStrings(&bucket, Toy_createString(&bucket, "Hell"), Toy_createString(&bucket, "world"));
|
Toy_String* helloEveryone = Toy_concatStrings(&bucket, Toy_createString(&bucket, "Hell"), Toy_createString(&bucket, "world"));
|
||||||
@@ -462,7 +461,7 @@ int test_string_equality() {
|
|||||||
//string equality (with concat arbitrary)
|
//string equality (with concat arbitrary)
|
||||||
{
|
{
|
||||||
//setup - The quick brown fox jumps over the lazy dog.
|
//setup - The quick brown fox jumps over the lazy dog.
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_String* helloWorldOne = Toy_concatStrings(&bucket,
|
Toy_String* helloWorldOne = Toy_concatStrings(&bucket,
|
||||||
Toy_createString(&bucket, "The quick brown "),
|
Toy_createString(&bucket, "The quick brown "),
|
||||||
Toy_concatStrings(&bucket,
|
Toy_concatStrings(&bucket,
|
||||||
@@ -526,7 +525,7 @@ int test_string_equality() {
|
|||||||
//string equality (empty strings, no concats)
|
//string equality (empty strings, no concats)
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_String* helloWorldOne = Toy_createString(&bucket, "");
|
Toy_String* helloWorldOne = Toy_createString(&bucket, "");
|
||||||
Toy_String* helloWorldTwo = Toy_createString(&bucket, "");
|
Toy_String* helloWorldTwo = Toy_createString(&bucket, "");
|
||||||
Toy_String* helloEveryone = Toy_createString(&bucket, "Hello everyone");
|
Toy_String* helloEveryone = Toy_createString(&bucket, "Hello everyone");
|
||||||
@@ -576,7 +575,7 @@ int test_string_equality() {
|
|||||||
//string equality (empty strings, deep concats)
|
//string equality (empty strings, deep concats)
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_String* helloWorldOne = Toy_concatStrings(&bucket,
|
Toy_String* helloWorldOne = Toy_concatStrings(&bucket,
|
||||||
Toy_createString(&bucket, ""),
|
Toy_createString(&bucket, ""),
|
||||||
Toy_concatStrings(&bucket,
|
Toy_concatStrings(&bucket,
|
||||||
@@ -652,7 +651,7 @@ int test_string_equality() {
|
|||||||
//simple name equality
|
//simple name equality
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_String* helloWorldOne = Toy_createNameString(&bucket, "Hello world");
|
Toy_String* helloWorldOne = Toy_createNameString(&bucket, "Hello world");
|
||||||
Toy_String* helloWorldTwo = Toy_createNameString(&bucket, "Hello world");
|
Toy_String* helloWorldTwo = Toy_createNameString(&bucket, "Hello world");
|
||||||
Toy_String* helloEveryone = Toy_createNameString(&bucket, "Hello everyone");
|
Toy_String* helloEveryone = Toy_createNameString(&bucket, "Hello everyone");
|
||||||
@@ -706,7 +705,7 @@ int test_string_diffs() {
|
|||||||
//simple string diffs (no concats)
|
//simple string diffs (no concats)
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_String* helloEveryone = Toy_createString(&bucket, "Hello everyone");
|
Toy_String* helloEveryone = Toy_createString(&bucket, "Hello everyone");
|
||||||
Toy_String* helloUniverse = Toy_createString(&bucket, "Hello universe");
|
Toy_String* helloUniverse = Toy_createString(&bucket, "Hello universe");
|
||||||
|
|
||||||
@@ -743,7 +742,7 @@ int test_string_diffs() {
|
|||||||
//string diffs (with concat arbitrary)
|
//string diffs (with concat arbitrary)
|
||||||
{
|
{
|
||||||
//setup - The quick brown fox jumps over the lazy dog.
|
//setup - The quick brown fox jumps over the lazy dog.
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
Toy_String* pangram = Toy_concatStrings(&bucket,
|
Toy_String* pangram = Toy_concatStrings(&bucket,
|
||||||
Toy_createString(&bucket, "The quick brown "),
|
Toy_createString(&bucket, "The quick brown "),
|
||||||
Toy_concatStrings(&bucket,
|
Toy_concatStrings(&bucket,
|
||||||
|
|||||||
@@ -9,7 +9,11 @@
|
|||||||
int main() {
|
int main() {
|
||||||
//test for the correct size
|
//test for the correct size
|
||||||
{
|
{
|
||||||
|
#if TOY_BITNESS == 64
|
||||||
|
if (sizeof(Toy_Value) != 16) {
|
||||||
|
#else
|
||||||
if (sizeof(Toy_Value) != 8) {
|
if (sizeof(Toy_Value) != 8) {
|
||||||
|
#endif
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: 'Toy_Value' is an unexpected size in memory\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: 'Toy_Value' is an unexpected size in memory\n" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -56,7 +60,7 @@ int main() {
|
|||||||
//test value hashing
|
//test value hashing
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(512);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
|
|
||||||
//values
|
//values
|
||||||
Toy_Value n = TOY_VALUE_FROM_NULL();
|
Toy_Value n = TOY_VALUE_FROM_NULL();
|
||||||
|
|||||||
@@ -55,10 +55,10 @@ int test_setup_and_teardown(Toy_Bucket** bucketHandle) {
|
|||||||
if (
|
if (
|
||||||
vm.routine - vm.bc != headerSize ||
|
vm.routine - vm.bc != headerSize ||
|
||||||
vm.routineSize != 72 ||
|
vm.routineSize != 72 ||
|
||||||
vm.paramCount != 0 ||
|
vm.paramSize != 0 ||
|
||||||
vm.jumpsCount != 0 ||
|
vm.jumpsSize != 0 ||
|
||||||
vm.dataCount != 0 ||
|
vm.dataSize != 0 ||
|
||||||
vm.subsCount != 0
|
vm.subsSize != 0
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to setup and teadown Toy_VM, source: %s\n" TOY_CC_RESET, source);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to setup and teadown Toy_VM, source: %s\n" TOY_CC_RESET, source);
|
||||||
@@ -210,6 +210,89 @@ int test_keywords(Toy_Bucket** bucketHandle) {
|
|||||||
//teadown
|
//teadown
|
||||||
Toy_resetPrintCallback();
|
Toy_resetPrintCallback();
|
||||||
free(callbackUtilReceived);
|
free(callbackUtilReceived);
|
||||||
|
callbackUtilReceived = NULL;
|
||||||
|
Toy_freeVM(&vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
//test print with a string
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_setPrintCallback(callbackUtil);
|
||||||
|
const char* source = "print \"Hello world!\";";
|
||||||
|
|
||||||
|
Toy_Lexer lexer;
|
||||||
|
Toy_bindLexer(&lexer, source);
|
||||||
|
|
||||||
|
Toy_Parser parser;
|
||||||
|
Toy_bindParser(&parser, &lexer);
|
||||||
|
|
||||||
|
Toy_Ast* ast = Toy_scanParser(bucketHandle, &parser);
|
||||||
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
|
|
||||||
|
Toy_VM vm;
|
||||||
|
Toy_bindVM(&vm, bc.ptr);
|
||||||
|
|
||||||
|
//run
|
||||||
|
Toy_runVM(&vm);
|
||||||
|
|
||||||
|
//check the final state of the stack
|
||||||
|
if (callbackUtilReceived == NULL ||
|
||||||
|
strcmp(callbackUtilReceived, "Hello world!") != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected value '%s' passed to print keyword, source: %s\n" TOY_CC_RESET, callbackUtilReceived != NULL ? callbackUtilReceived : "NULL", source);
|
||||||
|
|
||||||
|
//cleanup and return
|
||||||
|
Toy_resetPrintCallback();
|
||||||
|
free(callbackUtilReceived);
|
||||||
|
Toy_freeVM(&vm);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//teadown
|
||||||
|
Toy_resetPrintCallback();
|
||||||
|
free(callbackUtilReceived);
|
||||||
|
callbackUtilReceived = NULL;
|
||||||
|
Toy_freeVM(&vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
//test print with a string concat
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_setPrintCallback(callbackUtil);
|
||||||
|
const char* source = "print \"Hello\" .. \"world!\";";
|
||||||
|
|
||||||
|
Toy_Lexer lexer;
|
||||||
|
Toy_bindLexer(&lexer, source);
|
||||||
|
|
||||||
|
Toy_Parser parser;
|
||||||
|
Toy_bindParser(&parser, &lexer);
|
||||||
|
|
||||||
|
Toy_Ast* ast = Toy_scanParser(bucketHandle, &parser);
|
||||||
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
|
|
||||||
|
Toy_VM vm;
|
||||||
|
Toy_bindVM(&vm, bc.ptr);
|
||||||
|
|
||||||
|
//run
|
||||||
|
Toy_runVM(&vm);
|
||||||
|
|
||||||
|
//check the final state of the stack
|
||||||
|
if (callbackUtilReceived == NULL ||
|
||||||
|
strcmp(callbackUtilReceived, "Helloworld!") != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected value '%s' passed to print keyword, source: %s\n" TOY_CC_RESET, callbackUtilReceived != NULL ? callbackUtilReceived : "NULL", source);
|
||||||
|
|
||||||
|
//cleanup and return
|
||||||
|
Toy_resetPrintCallback();
|
||||||
|
free(callbackUtilReceived);
|
||||||
|
Toy_freeVM(&vm);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//teadown
|
||||||
|
Toy_resetPrintCallback();
|
||||||
|
free(callbackUtilReceived);
|
||||||
|
callbackUtilReceived = NULL;
|
||||||
Toy_freeVM(&vm);
|
Toy_freeVM(&vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +304,7 @@ int main() {
|
|||||||
int total = 0, res = 0;
|
int total = 0, res = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_setup_and_teardown(&bucket);
|
res = test_setup_and_teardown(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -231,7 +314,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_simple_execution(&bucket);
|
res = test_simple_execution(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -241,7 +324,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_opcode_not_equal(&bucket);
|
res = test_opcode_not_equal(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -251,7 +334,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_keywords(&bucket);
|
res = test_keywords(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user