Added types and constness

Fixed #144
This commit is contained in:
2024-11-02 11:39:14 +11:00
parent 3ad53c5e0e
commit 7173f7770f
14 changed files with 266 additions and 44 deletions

View File

@@ -1,3 +1,3 @@
print "\tHello\nworld";

View File

@@ -74,6 +74,7 @@ static void synchronize(Toy_Parser* parser) {
case TOY_TOKEN_KEYWORD_RETURN: case TOY_TOKEN_KEYWORD_RETURN:
case TOY_TOKEN_KEYWORD_VAR: case TOY_TOKEN_KEYWORD_VAR:
case TOY_TOKEN_KEYWORD_WHILE: case TOY_TOKEN_KEYWORD_WHILE:
case TOY_TOKEN_KEYWORD_YIELD:
parser->error = true; parser->error = true;
parser->panic = false; parser->panic = false;
return; return;
@@ -124,7 +125,6 @@ static ParsingTuple parsingRulesetTable[] = {
{PREC_NONE,nameString,NULL},// TOY_TOKEN_NAME, {PREC_NONE,nameString,NULL},// TOY_TOKEN_NAME,
//types //types
{PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_TYPE,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_BOOLEAN, {PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_BOOLEAN,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_INTEGER, {PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_INTEGER,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_FLOAT, {PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_FLOAT,
@@ -133,6 +133,7 @@ static ParsingTuple parsingRulesetTable[] = {
{PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_TABLE, {PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_TABLE,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_FUNCTION, {PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_FUNCTION,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_OPAQUE, {PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_OPAQUE,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_TYPE,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_ANY, {PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_ANY,
//keywords and reserved words //keywords and reserved words
@@ -222,8 +223,48 @@ static ParsingTuple parsingRulesetTable[] = {
{PREC_NONE,NULL,NULL},// TOY_TOKEN_EOF, {PREC_NONE,NULL,NULL},// TOY_TOKEN_EOF,
}; };
static Toy_ValueType readType(Toy_Parser* parser) {
advance(parser);
switch(parser->previous.type) {
case TOY_TOKEN_TYPE_BOOLEAN:
return TOY_VALUE_BOOLEAN;
case TOY_TOKEN_TYPE_INTEGER:
return TOY_VALUE_INTEGER;
case TOY_TOKEN_TYPE_FLOAT:
return TOY_VALUE_FLOAT;
case TOY_TOKEN_TYPE_STRING:
return TOY_VALUE_STRING;
case TOY_TOKEN_TYPE_ARRAY:
return TOY_VALUE_ARRAY;
case TOY_TOKEN_TYPE_TABLE:
return TOY_VALUE_TABLE;
case TOY_TOKEN_TYPE_FUNCTION:
return TOY_VALUE_FUNCTION;
case TOY_TOKEN_TYPE_OPAQUE:
return TOY_VALUE_OPAQUE;
case TOY_TOKEN_TYPE_TYPE:
return TOY_VALUE_TYPE;
case TOY_TOKEN_TYPE_ANY:
return TOY_VALUE_ANY;
default:
printError(parser, parser->previous, "Expected type identifier");
return TOY_VALUE_UNKNOWN;
}
}
static Toy_AstFlag nameString(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) { static Toy_AstFlag nameString(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
Toy_String* name = Toy_createNameStringLength(bucketHandle, parser->previous.lexeme, parser->previous.length, TOY_VALUE_UNKNOWN); Toy_String* name = Toy_createNameStringLength(bucketHandle, parser->previous.lexeme, parser->previous.length, TOY_VALUE_UNKNOWN, false);
Toy_AstFlag flag = TOY_AST_FLAG_NONE; Toy_AstFlag flag = TOY_AST_FLAG_NONE;
@@ -558,7 +599,7 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
return; return;
} }
else if (flag >= 10 && flag <= 19) { else if (flag >= 10 && flag <= 19) {
Toy_String* name = Toy_createNameStringLength(bucketHandle, prevToken.lexeme, prevToken.length, TOY_VALUE_UNKNOWN); Toy_String* name = Toy_createNameStringLength(bucketHandle, prevToken.lexeme, prevToken.length, TOY_VALUE_UNKNOWN, false);
Toy_private_emitAstVariableAssignment(bucketHandle, rootHandle, name, flag, ptr); Toy_private_emitAstVariableAssignment(bucketHandle, rootHandle, name, flag, ptr);
} }
else if (flag >= 20 && flag <= 29) { else if (flag >= 20 && flag <= 29) {
@@ -605,11 +646,20 @@ static void makeVariableDeclarationStmt(Toy_Bucket** bucketHandle, Toy_Parser* p
Toy_Token nameToken = parser->previous; Toy_Token nameToken = parser->previous;
//TODO: read the type specifier if present //read the type specifier if present
// Toy_Token typeToken = TOY_BLANK_TOKEN(); Toy_ValueType varType = TOY_VALUE_ANY;
bool constant = false;
if (match(parser, TOY_TOKEN_OPERATOR_COLON)) {
varType = readType(parser);
if (match(parser, TOY_TOKEN_KEYWORD_CONST)) {
constant = true;
}
}
//build the string //build the string
Toy_String* nameStr = Toy_createNameStringLength(bucketHandle, nameToken.lexeme, nameToken.length, TOY_VALUE_NULL); Toy_String* nameStr = Toy_createNameStringLength(bucketHandle, nameToken.lexeme, nameToken.length, varType, constant);
//if there's an assignment, read it, or default to null //if there's an assignment, read it, or default to null
Toy_Ast* expr = NULL; Toy_Ast* expr = NULL;

View File

@@ -261,7 +261,7 @@ static void writeInstructionVarDeclare(Toy_Routine** rt, Toy_AstVarDeclare ast)
EMIT_BYTE(rt, code, TOY_OPCODE_DECLARE); EMIT_BYTE(rt, code, TOY_OPCODE_DECLARE);
EMIT_BYTE(rt, code, Toy_getNameStringType(ast.name)); EMIT_BYTE(rt, code, Toy_getNameStringType(ast.name));
EMIT_BYTE(rt, code, ast.name->length); //quick optimisation to skip a 'strlen()' call EMIT_BYTE(rt, code, ast.name->length); //quick optimisation to skip a 'strlen()' call
EMIT_BYTE(rt, code, 0); EMIT_BYTE(rt, code, Toy_getNameStringConstant(ast.name) ? 1 : 0); //check for constness
emitString(rt, ast.name); emitString(rt, ast.name);
} }

View File

@@ -20,7 +20,7 @@ static void decrementRefCount(Toy_Scope* scope) {
} }
} }
static Toy_Value* lookupScope(Toy_Scope* scope, Toy_String* key, unsigned int hash, bool recursive) { static Toy_TableEntry* lookupScope(Toy_Scope* scope, Toy_String* key, unsigned int hash, bool recursive) {
//terminate //terminate
if (scope == NULL) { if (scope == NULL) {
return NULL; return NULL;
@@ -32,7 +32,7 @@ static Toy_Value* lookupScope(Toy_Scope* scope, Toy_String* key, unsigned int ha
while (true) { while (true) {
//found the entry //found the entry
if (TOY_VALUE_IS_STRING(scope->table->data[probe].key) && Toy_compareStrings(TOY_VALUE_AS_STRING(scope->table->data[probe].key), key) == 0) { if (TOY_VALUE_IS_STRING(scope->table->data[probe].key) && Toy_compareStrings(TOY_VALUE_AS_STRING(scope->table->data[probe].key), key) == 0) {
return &(scope->table->data[probe].value); return &(scope->table->data[probe]);
} }
//if its an empty slot (didn't find it here) //if its an empty slot (didn't find it here)
@@ -99,16 +99,32 @@ void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
exit(-1); exit(-1);
} }
Toy_Value* valuePtr = lookupScope(scope, key, Toy_hashString(key), false); Toy_TableEntry* entryPtr = lookupScope(scope, key, Toy_hashString(key), false);
if (valuePtr != NULL) {
if (entryPtr != NULL) {
char buffer[key->length + 256]; char buffer[key->length + 256];
sprintf(buffer, "Can't redefine a variable: %s", key->as.name.data); sprintf(buffer, "Can't redefine a variable: %s", key->as.name.data);
Toy_error(buffer); Toy_error(buffer);
return; return;
} }
//type check
Toy_ValueType kt = Toy_getNameStringType(key);
if (kt != TOY_VALUE_ANY && value.type != TOY_VALUE_NULL && kt != value.type) {
char buffer[key->length + 256];
sprintf(buffer, "Incorrect value type assigned to in variable declaration '%s' (expected %d, got %d)", key->as.name.data, (int)kt, (int)value.type);
Toy_error(buffer);
return;
}
//constness check
if (Toy_getNameStringConstant(key) && value.type == TOY_VALUE_NULL) {
char buffer[key->length + 256];
sprintf(buffer, "Can't declare %s as const with value 'null'", key->as.name.data);
Toy_error(buffer);
return;
}
Toy_insertTable(&scope->table, TOY_VALUE_FROM_STRING(Toy_copyString(key)), value); Toy_insertTable(&scope->table, TOY_VALUE_FROM_STRING(Toy_copyString(key)), value);
} }
@@ -118,16 +134,33 @@ void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
exit(-1); exit(-1);
} }
Toy_Value* valuePtr = lookupScope(scope, key, Toy_hashString(key), true); Toy_TableEntry* entryPtr = lookupScope(scope, key, Toy_hashString(key), true);
if (valuePtr == NULL) { if (entryPtr == NULL) {
char buffer[key->length + 256]; char buffer[key->length + 256];
sprintf(buffer, "Undefined variable: %s", key->as.name.data); sprintf(buffer, "Undefined variable: %s", key->as.name.data);
Toy_error(buffer); Toy_error(buffer);
return; return;
} }
*valuePtr = value; //type check
Toy_ValueType kt = Toy_getNameStringType( TOY_VALUE_AS_STRING(entryPtr->key) );
if (kt != TOY_VALUE_ANY && value.type != TOY_VALUE_NULL && kt != value.type) {
char buffer[key->length + 256];
sprintf(buffer, "Incorrect value type assigned to in variable assignment '%s' (expected %d, got %d)", key->as.name.data, (int)kt, (int)value.type);
Toy_error(buffer);
return;
}
//constness check
if (Toy_getNameStringConstant( TOY_VALUE_AS_STRING(entryPtr->key) )) {
char buffer[key->length + 256];
sprintf(buffer, "Can't assign to const %s", key->as.name.data);
Toy_error(buffer);
return;
}
entryPtr->value = value;
} }
Toy_Value Toy_accessScope(Toy_Scope* scope, Toy_String* key) { Toy_Value Toy_accessScope(Toy_Scope* scope, Toy_String* key) {
@@ -136,16 +169,16 @@ Toy_Value Toy_accessScope(Toy_Scope* scope, Toy_String* key) {
exit(-1); exit(-1);
} }
Toy_Value* valuePtr = lookupScope(scope, key, Toy_hashString(key), true); Toy_TableEntry* entryPtr = lookupScope(scope, key, Toy_hashString(key), true);
if (valuePtr == NULL) { if (entryPtr == NULL) {
char buffer[key->length + 256]; char buffer[key->length + 256];
sprintf(buffer, "Undefined variable: %s", key->as.name.data); sprintf(buffer, "Undefined variable: %s\n", key->as.name.data); //TODO: Toy_error
Toy_error(buffer); Toy_error(buffer);
return TOY_VALUE_FROM_NULL(); return TOY_VALUE_FROM_NULL();
} }
return *valuePtr; return entryPtr->value;
} }
bool Toy_isDeclaredScope(Toy_Scope* scope, Toy_String* key) { bool Toy_isDeclaredScope(Toy_Scope* scope, Toy_String* key) {
@@ -154,7 +187,7 @@ bool Toy_isDeclaredScope(Toy_Scope* scope, Toy_String* key) {
exit(-1); exit(-1);
} }
Toy_Value* valuePtr = lookupScope(scope, key, Toy_hashString(key), true); Toy_TableEntry* entryPtr = lookupScope(scope, key, Toy_hashString(key), true);
return valuePtr != NULL; return entryPtr != NULL;
} }

View File

@@ -91,14 +91,18 @@ Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstrin
return result; return result;
} }
Toy_String* Toy_createNameStringLength(Toy_Bucket** bucketHandle, const char* cname, unsigned int length, Toy_ValueType type) { Toy_String* Toy_createNameStringLength(Toy_Bucket** bucketHandle, const char* cname, unsigned int length, Toy_ValueType type, bool constant) {
//name strings can't be broken up //name strings can't be broken up
if (sizeof(Toy_String) + length + 1 > (*bucketHandle)->capacity) { if (sizeof(Toy_String) + length + 1 > (*bucketHandle)->capacity) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't partition enough space for a name string, requested %d length (%d total) but buckets have a capacity of %d\n" TOY_CC_RESET, (int)length, (int)(sizeof(Toy_String) + length + 1), (int)((*bucketHandle)->capacity)); fprintf(stderr, TOY_CC_ERROR "ERROR: Can't partition enough space for a name string, requested %d length (%d total) but buckets have a capacity of %d\n" TOY_CC_RESET, (int)length, (int)(sizeof(Toy_String) + length + 1), (int)((*bucketHandle)->capacity));
exit(-1); exit(-1);
} }
if (type == TOY_VALUE_NULL) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't declare a name string with type 'null'\n" TOY_CC_RESET);
exit(-1);
}
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String) + length + 1); Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String) + length + 1);
ret->type = TOY_STRING_NAME; ret->type = TOY_STRING_NAME;
@@ -108,6 +112,7 @@ Toy_String* Toy_createNameStringLength(Toy_Bucket** bucketHandle, const char* cn
memcpy(ret->as.name.data, cname, length + 1); memcpy(ret->as.name.data, cname, length + 1);
ret->as.name.data[length] = '\0'; ret->as.name.data[length] = '\0';
ret->as.name.type = type; ret->as.name.type = type;
ret->as.name.constant = constant;
return ret; return ret;
} }
@@ -204,6 +209,15 @@ Toy_ValueType Toy_getNameStringType(Toy_String* str) {
return str->as.name.type; return str->as.name.type;
} }
Toy_ValueType Toy_getNameStringConstant(Toy_String* str) {
if (str->type != TOY_STRING_NAME) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't get the variable constness of a non-name string\n" TOY_CC_RESET);
exit(-1);
}
return str->as.name.constant;
}
char* Toy_getStringRawBuffer(Toy_String* str) { char* Toy_getStringRawBuffer(Toy_String* str) {
if (str->type == TOY_STRING_NAME) { if (str->type == TOY_STRING_NAME) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't get raw string buffer of a name string\n" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "ERROR: Can't get raw string buffer of a name string\n" TOY_CC_RESET);

View File

@@ -30,15 +30,16 @@ typedef struct Toy_String { //32 | 64 BITNESS
struct { struct {
Toy_ValueType type; //4 | 4 Toy_ValueType type; //4 | 4
bool constant; //1 | 1
char data[]; //- | - char data[]; //- | -
} name; //4 | 4 } name; //8 | 8
} as; //8 | 16 } as; //8 | 16
} Toy_String; //24 | 32 } Toy_String; //24 | 32
TOY_API Toy_String* Toy_createString(Toy_Bucket** bucketHandle, const char* cstring); TOY_API Toy_String* Toy_createString(Toy_Bucket** bucketHandle, const char* cstring);
TOY_API Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstring, unsigned int length); TOY_API Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstring, unsigned int length);
TOY_API Toy_String* Toy_createNameStringLength(Toy_Bucket** bucketHandle, const char* cname, unsigned int length, Toy_ValueType type); //for variable names TOY_API Toy_String* Toy_createNameStringLength(Toy_Bucket** bucketHandle, const char* cname, unsigned int length, Toy_ValueType type, bool constant); //for variable names
TOY_API Toy_String* Toy_copyString(Toy_String* str); TOY_API Toy_String* Toy_copyString(Toy_String* str);
TOY_API Toy_String* Toy_deepCopyString(Toy_Bucket** bucketHandle, Toy_String* str); TOY_API Toy_String* Toy_deepCopyString(Toy_Bucket** bucketHandle, Toy_String* str);
@@ -50,6 +51,7 @@ TOY_API void Toy_freeString(Toy_String* str);
TOY_API unsigned int Toy_getStringLength(Toy_String* str); TOY_API unsigned int Toy_getStringLength(Toy_String* str);
TOY_API unsigned int Toy_getStringRefCount(Toy_String* str); TOY_API unsigned int Toy_getStringRefCount(Toy_String* str);
TOY_API Toy_ValueType Toy_getNameStringType(Toy_String* str); TOY_API Toy_ValueType Toy_getNameStringType(Toy_String* str);
TOY_API Toy_ValueType Toy_getNameStringConstant(Toy_String* str);
TOY_API char* Toy_getStringRawBuffer(Toy_String* str); //allocates the buffer on the heap, needs to be freed TOY_API char* Toy_getStringRawBuffer(Toy_String* str); //allocates the buffer on the heap, needs to be freed

View File

@@ -9,7 +9,6 @@ typedef enum Toy_TokenType {
TOY_TOKEN_NAME, TOY_TOKEN_NAME,
//types //types
TOY_TOKEN_TYPE_TYPE,
TOY_TOKEN_TYPE_BOOLEAN, TOY_TOKEN_TYPE_BOOLEAN,
TOY_TOKEN_TYPE_INTEGER, TOY_TOKEN_TYPE_INTEGER,
TOY_TOKEN_TYPE_FLOAT, TOY_TOKEN_TYPE_FLOAT,
@@ -18,6 +17,7 @@ typedef enum Toy_TokenType {
TOY_TOKEN_TYPE_TABLE, TOY_TOKEN_TYPE_TABLE,
TOY_TOKEN_TYPE_FUNCTION, TOY_TOKEN_TYPE_FUNCTION,
TOY_TOKEN_TYPE_OPAQUE, TOY_TOKEN_TYPE_OPAQUE,
TOY_TOKEN_TYPE_TYPE,
TOY_TOKEN_TYPE_ANY, TOY_TOKEN_TYPE_ANY,
//keywords and reserved words //keywords and reserved words

View File

@@ -80,7 +80,7 @@ static void processRead(Toy_VM* vm) {
else if (stringType == TOY_STRING_NAME) { else if (stringType == TOY_STRING_NAME) {
Toy_ValueType valueType = TOY_VALUE_UNKNOWN; Toy_ValueType valueType = TOY_VALUE_UNKNOWN;
value = TOY_VALUE_FROM_STRING(Toy_createNameStringLength(&vm->stringBucket, cstring, len, valueType)); value = TOY_VALUE_FROM_STRING(Toy_createNameStringLength(&vm->stringBucket, cstring, len, valueType, false));
} }
else { else {
Toy_error("Invalid string type found"); Toy_error("Invalid string type found");
@@ -139,7 +139,7 @@ static void processRead(Toy_VM* vm) {
static void processDeclare(Toy_VM* vm) { static void processDeclare(Toy_VM* vm) {
Toy_ValueType type = READ_BYTE(vm); //variable type Toy_ValueType type = READ_BYTE(vm); //variable type
unsigned int len = READ_BYTE(vm); //name length unsigned int len = READ_BYTE(vm); //name length
fixAlignment(vm); //one spare byte bool constant = READ_BYTE(vm); //constness
//grab the jump //grab the jump
unsigned int jump = *(unsigned int*)(vm->routine + vm->jumpsAddr + READ_INT(vm)); unsigned int jump = *(unsigned int*)(vm->routine + vm->jumpsAddr + READ_INT(vm));
@@ -148,7 +148,7 @@ static void processDeclare(Toy_VM* vm) {
char* cstring = (char*)(vm->routine + vm->dataAddr + jump); char* cstring = (char*)(vm->routine + vm->dataAddr + jump);
//build the name string //build the name string
Toy_String* name = Toy_createNameStringLength(&vm->stringBucket, cstring, len, type); Toy_String* name = Toy_createNameStringLength(&vm->stringBucket, cstring, len, type, constant);
//get the value //get the value
Toy_Value value = Toy_popStack(&vm->stack); Toy_Value value = Toy_popStack(&vm->stack);

View File

@@ -255,7 +255,7 @@ int test_type_emission(Toy_Bucket** bucketHandle) {
{ {
//build the AST //build the AST
Toy_Ast* ast = NULL; Toy_Ast* ast = NULL;
Toy_String* name = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_NULL); Toy_String* name = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_ANY, false);
Toy_private_emitAstVariableDeclaration(bucketHandle, &ast, name, NULL); Toy_private_emitAstVariableDeclaration(bucketHandle, &ast, name, NULL);
@@ -284,7 +284,7 @@ int test_type_emission(Toy_Bucket** bucketHandle) {
//build the AST //build the AST
Toy_Ast* ast = NULL; Toy_Ast* ast = NULL;
Toy_Ast* right = NULL; Toy_Ast* right = NULL;
Toy_String* name = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_INTEGER); Toy_String* name = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_INTEGER, false);
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_FROM_INTEGER(69)); Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_FROM_INTEGER(69));
Toy_private_emitAstVariableAssignment(bucketHandle, &ast, name, TOY_AST_FLAG_ASSIGN, right); Toy_private_emitAstVariableAssignment(bucketHandle, &ast, name, TOY_AST_FLAG_ASSIGN, right);
@@ -310,7 +310,7 @@ int test_type_emission(Toy_Bucket** bucketHandle) {
//build the AST //build the AST
Toy_Ast* ast = NULL; Toy_Ast* ast = NULL;
Toy_Ast* right = NULL; Toy_Ast* right = NULL;
Toy_String* name = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_INTEGER); Toy_String* name = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_INTEGER, false);
Toy_private_emitAstVariableAccess(bucketHandle, &ast, name); Toy_private_emitAstVariableAccess(bucketHandle, &ast, name);
//check if it worked //check if it worked

View File

@@ -829,7 +829,115 @@ int test_routine_keywords(Toy_Bucket** bucketHandle) {
*(int*)(code + 4) != 42 || *(int*)(code + 4) != 42 ||
*((unsigned char*)(code + 8)) != TOY_OPCODE_DECLARE || *((unsigned char*)(code + 8)) != TOY_OPCODE_DECLARE ||
*((unsigned char*)(code + 9)) != TOY_VALUE_NULL || //NOTE: will change in future *((unsigned char*)(code + 9)) != TOY_VALUE_ANY ||
*((unsigned char*)(code + 10)) != 6 || //strlen
*((unsigned char*)(code + 11)) != 0 ||
*(unsigned int*)(code + 12) != 0 || //the jump index
*((unsigned char*)(code + 16)) != TOY_OPCODE_RETURN ||
*((unsigned char*)(code + 17)) != 0 ||
*((unsigned char*)(code + 18)) != 0 ||
*((unsigned char*)(code + 19)) != 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 + 20;
//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], "foobar" ) != 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);
}
//var declare (with type)
{
//setup
const char* source = "var foobar: int = 42;";
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] != 8 || //data size
header[4] != 0 || //subs size
// header[??] != ?? || //params address
header[5] != 32 || //code address
header[6] != 52 || //jumps address
header[7] != 56 || //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_INTEGER ||
*((unsigned char*)(code + 2)) != 0 ||
*((unsigned char*)(code + 3)) != 0 ||
*(int*)(code + 4) != 42 ||
*((unsigned char*)(code + 8)) != TOY_OPCODE_DECLARE ||
*((unsigned char*)(code + 9)) != TOY_VALUE_INTEGER ||
*((unsigned char*)(code + 10)) != 6 || //strlen *((unsigned char*)(code + 10)) != 6 || //strlen
*((unsigned char*)(code + 11)) != 0 || *((unsigned char*)(code + 11)) != 0 ||

View File

@@ -304,8 +304,8 @@ int test_scope_elements() {
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
Toy_Scope* scope = Toy_pushScope(&bucket, NULL); Toy_Scope* scope = Toy_pushScope(&bucket, NULL);
Toy_String* hello1 = Toy_createNameStringLength(&bucket, "hello", 5, TOY_VALUE_NULL); Toy_String* hello1 = Toy_createNameStringLength(&bucket, "hello", 5, TOY_VALUE_ANY, false);
Toy_String* hello2 = Toy_createNameStringLength(&bucket, "hello", 5, TOY_VALUE_NULL); Toy_String* hello2 = Toy_createNameStringLength(&bucket, "hello", 5, TOY_VALUE_ANY, false);
//check nothing is here //check nothing is here
if (Toy_isDeclaredScope(scope, hello2)) { if (Toy_isDeclaredScope(scope, hello2)) {
@@ -389,7 +389,7 @@ int test_scope_elements() {
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
Toy_Scope* scope = Toy_pushScope(&bucket, NULL); Toy_Scope* scope = Toy_pushScope(&bucket, NULL);
Toy_String* hello = Toy_createNameStringLength(&bucket, "hello", 5, TOY_VALUE_NULL); Toy_String* hello = Toy_createNameStringLength(&bucket, "hello", 5, TOY_VALUE_ANY, false);
//declare and push //declare and push
Toy_declareScope(scope, hello, TOY_VALUE_FROM_INTEGER(42)); Toy_declareScope(scope, hello, TOY_VALUE_FROM_INTEGER(42));

View File

@@ -106,7 +106,7 @@ int test_string_allocation() {
Toy_Bucket* bucket = Toy_allocateBucket(1024); Toy_Bucket* bucket = Toy_allocateBucket(1024);
const char* cstring = "Hello world"; const char* cstring = "Hello world";
Toy_String* str = Toy_createNameStringLength(&bucket, cstring, strlen(cstring), TOY_VALUE_NULL); Toy_String* str = Toy_createNameStringLength(&bucket, cstring, strlen(cstring), TOY_VALUE_UNKNOWN, false);
//shallow and deep //shallow and deep
Toy_String* shallow = Toy_copyString(str); Toy_String* shallow = Toy_copyString(str);
@@ -652,9 +652,9 @@ int test_string_equality() {
{ {
//setup //setup
Toy_Bucket* bucket = Toy_allocateBucket(1024); Toy_Bucket* bucket = Toy_allocateBucket(1024);
Toy_String* helloWorldOne = Toy_createNameStringLength(&bucket, "Hello world", strlen("Hello world"), TOY_VALUE_NULL); Toy_String* helloWorldOne = Toy_createNameStringLength(&bucket, "Hello world", strlen("Hello world"), TOY_VALUE_UNKNOWN, false);
Toy_String* helloWorldTwo = Toy_createNameStringLength(&bucket, "Hello world", strlen("Hello world"), TOY_VALUE_NULL); Toy_String* helloWorldTwo = Toy_createNameStringLength(&bucket, "Hello world", strlen("Hello world"), TOY_VALUE_UNKNOWN, false);
Toy_String* helloEveryone = Toy_createNameStringLength(&bucket, "Hello everyone", strlen("Hello everyone"), TOY_VALUE_NULL); //TODO: compare types? Toy_String* helloEveryone = Toy_createNameStringLength(&bucket, "Hello everyone", strlen("Hello everyone"), TOY_VALUE_UNKNOWN, false); //TODO: compare types?
int result = 0; //for print the errors int result = 0; //for print the errors

View File

@@ -330,7 +330,7 @@ int test_scope(Toy_Bucket** bucketHandle) {
Toy_runVM(&vm); Toy_runVM(&vm);
//check the final state of the stack //check the final state of the stack
Toy_String* key = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_NULL); Toy_String* key = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_ANY, false);
if (vm.stack == NULL || if (vm.stack == NULL ||
vm.stack->count != 0 || vm.stack->count != 0 ||
@@ -377,7 +377,7 @@ int test_scope(Toy_Bucket** bucketHandle) {
Toy_runVM(&vm); Toy_runVM(&vm);
//check the final state of the stack //check the final state of the stack
Toy_String* key = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_NULL); Toy_String* key = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_UNKNOWN, false);
if (vm.stack == NULL || if (vm.stack == NULL ||
vm.stack->count != 0 || vm.stack->count != 0 ||

View File

@@ -52,4 +52,19 @@ print !false; //true
//precedence //precedence
print true && false || true; //TODO: a warning is needed for this print true && false || true; //TODO: a warning is needed for this
//types
var a: int;
var b: int = 42;
a = 69;
b = 8891;
print a;
print b;
//constants
var c: int const = 42;
print c;
//TODO: type casting //TODO: type casting