mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
@@ -1,3 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
print "\tHello\nworld";
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 ||
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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 ||
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user