mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 06:44:07 +10:00
Added simple assignment, read more
I was coding earlier this week, but my brain was so foggy I ended up not knowing what I was doing. After a few days break, I've cleaned up the mess, which took hours. Changes: * Variables can be assigned * Added new value types as placeholders * Added 'compare' and 'assign' to the AST * Added duplicate opcode * Added functions to copy and free values * Max name length is 255 chars * Compound assigns are squeezed into one word To be completed: * Tests for this commit's changes * Compound assignments * Variable access
This commit is contained in:
28
.notes/read-opcode-layout.txt
Normal file
28
.notes/read-opcode-layout.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
TOY_OPCODE_DECLARE:
|
||||
{Declare, type, length, 0} ; {emitString()}
|
||||
|
||||
# write value
|
||||
TOY_OPCODE_READ:
|
||||
null -> {Read, type, 0, 0}
|
||||
bool -> {Read, type, value, 0}
|
||||
int -> {Read, type, 0, 0} ; {value}
|
||||
float -> {Read, type, 0, 0} ; {value}
|
||||
string -> {Read, type, leaf, 0} ; {emitString()}
|
||||
|
||||
# write assignment
|
||||
TOY_AST_FLAG_ASSIGN:
|
||||
{Read, type(string), name, length} ;
|
||||
{emitString()} ;
|
||||
{writeCode()} ;
|
||||
{Assign, 0, 0, 0} ;
|
||||
|
||||
TOY_AST_FLAG_ADD_ASSIGN:
|
||||
{Read, type(string), name, length} ;
|
||||
{emitString()} ;
|
||||
{Duplicate, 0, 0, 0} ;
|
||||
{writeCode()} ;
|
||||
{Assign, 0, 0, 0}
|
||||
{Add, Assign, 0, 0} ;
|
||||
|
||||
//subtract, multiply, divide, modulo all mimic add
|
||||
|
||||
5
makefile
5
makefile
@@ -26,7 +26,10 @@ repl: source
|
||||
|
||||
#various kinds of available tests
|
||||
.PHONY: tests
|
||||
tests: clean test-cases test-integrations test-benchmarks
|
||||
tests: clean test-cases
|
||||
|
||||
.PHONY: test-all
|
||||
test-all: clean test-cases test-integrations test-benchmarks
|
||||
|
||||
.PHONY: test-cases
|
||||
test-cases:
|
||||
|
||||
22
repl/main.c
22
repl/main.c
@@ -263,18 +263,6 @@ int repl(const char* filepath) {
|
||||
//free the bytecode, and leave the VM ready for the next loop
|
||||
Toy_resetVM(&vm);
|
||||
|
||||
//count the bucket memory - hang on, this this garbage collection??
|
||||
Toy_Bucket* iter = bucket;
|
||||
int depth = 0;
|
||||
while (iter->next) {
|
||||
iter = iter->next;
|
||||
if (++depth >= 7) {
|
||||
Toy_freeBucket(&bucket);
|
||||
bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s> ", prompt); //shows the terminal prompt
|
||||
}
|
||||
|
||||
@@ -331,9 +319,12 @@ static void debugStackPrint(Toy_Stack* stack) {
|
||||
}
|
||||
|
||||
case TOY_VALUE_ARRAY:
|
||||
case TOY_VALUE_DICTIONARY:
|
||||
case TOY_VALUE_TABLE:
|
||||
case TOY_VALUE_FUNCTION:
|
||||
case TOY_VALUE_OPAQUE:
|
||||
case TOY_VALUE_TYPE:
|
||||
case TOY_VALUE_ANY:
|
||||
case TOY_VALUE_UNKNOWN:
|
||||
printf("???");
|
||||
break;
|
||||
}
|
||||
@@ -393,9 +384,12 @@ static void debugScopePrint(Toy_Scope* scope, int depth) {
|
||||
}
|
||||
|
||||
case TOY_VALUE_ARRAY:
|
||||
case TOY_VALUE_DICTIONARY:
|
||||
case TOY_VALUE_TABLE:
|
||||
case TOY_VALUE_FUNCTION:
|
||||
case TOY_VALUE_OPAQUE:
|
||||
case TOY_VALUE_TYPE:
|
||||
case TOY_VALUE_ANY:
|
||||
case TOY_VALUE_UNKNOWN:
|
||||
printf("???");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,17 @@ void Toy_private_emitAstBinary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, T
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstCompare(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag, Toy_Ast* right) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
tmp->type = TOY_AST_COMPARE;
|
||||
tmp->compare.flag = flag;
|
||||
tmp->compare.left = *astHandle; //left-recursive
|
||||
tmp->compare.right = right;
|
||||
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
@@ -91,6 +102,17 @@ void Toy_private_emitAstVariableDeclaration(Toy_Bucket** bucketHandle, Toy_Ast**
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstVariableAssignment(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_AstFlag flag, Toy_Ast* expr) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
tmp->type = TOY_AST_VAR_ASSIGN;
|
||||
tmp->varAssign.flag = flag;
|
||||
tmp->varAssign.name = name;
|
||||
tmp->varAssign.expr = expr;
|
||||
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
|
||||
@@ -13,11 +13,13 @@ typedef enum Toy_AstType {
|
||||
TOY_AST_VALUE,
|
||||
TOY_AST_UNARY,
|
||||
TOY_AST_BINARY,
|
||||
TOY_AST_COMPARE,
|
||||
TOY_AST_GROUP,
|
||||
|
||||
TOY_AST_PRINT,
|
||||
|
||||
TOY_AST_VAR_DECLARE,
|
||||
TOY_AST_VAR_ASSIGN,
|
||||
|
||||
TOY_AST_PASS,
|
||||
TOY_AST_ERROR,
|
||||
@@ -26,34 +28,37 @@ typedef enum Toy_AstType {
|
||||
|
||||
//flags are handled differently by different types
|
||||
typedef enum Toy_AstFlag {
|
||||
TOY_AST_FLAG_NONE,
|
||||
TOY_AST_FLAG_NONE = 0,
|
||||
|
||||
//binary flags
|
||||
TOY_AST_FLAG_ADD,
|
||||
TOY_AST_FLAG_SUBTRACT,
|
||||
TOY_AST_FLAG_MULTIPLY,
|
||||
TOY_AST_FLAG_DIVIDE,
|
||||
TOY_AST_FLAG_MODULO,
|
||||
TOY_AST_FLAG_ASSIGN,
|
||||
TOY_AST_FLAG_ADD_ASSIGN,
|
||||
TOY_AST_FLAG_SUBTRACT_ASSIGN,
|
||||
TOY_AST_FLAG_MULTIPLY_ASSIGN,
|
||||
TOY_AST_FLAG_DIVIDE_ASSIGN,
|
||||
TOY_AST_FLAG_MODULO_ASSIGN,
|
||||
TOY_AST_FLAG_COMPARE_EQUAL,
|
||||
TOY_AST_FLAG_COMPARE_NOT,
|
||||
TOY_AST_FLAG_COMPARE_LESS,
|
||||
TOY_AST_FLAG_COMPARE_LESS_EQUAL,
|
||||
TOY_AST_FLAG_COMPARE_GREATER,
|
||||
TOY_AST_FLAG_COMPARE_GREATER_EQUAL,
|
||||
TOY_AST_FLAG_AND,
|
||||
TOY_AST_FLAG_OR,
|
||||
TOY_AST_FLAG_CONCAT,
|
||||
TOY_AST_FLAG_ADD = 1,
|
||||
TOY_AST_FLAG_SUBTRACT = 2,
|
||||
TOY_AST_FLAG_MULTIPLY = 3,
|
||||
TOY_AST_FLAG_DIVIDE = 4,
|
||||
TOY_AST_FLAG_MODULO = 5,
|
||||
|
||||
TOY_AST_FLAG_ASSIGN = 10,
|
||||
TOY_AST_FLAG_ADD_ASSIGN = 11,
|
||||
TOY_AST_FLAG_SUBTRACT_ASSIGN = 12,
|
||||
TOY_AST_FLAG_MULTIPLY_ASSIGN = 13,
|
||||
TOY_AST_FLAG_DIVIDE_ASSIGN = 14,
|
||||
TOY_AST_FLAG_MODULO_ASSIGN = 15,
|
||||
|
||||
TOY_AST_FLAG_COMPARE_EQUAL = 20,
|
||||
TOY_AST_FLAG_COMPARE_NOT = 21,
|
||||
TOY_AST_FLAG_COMPARE_LESS = 22,
|
||||
TOY_AST_FLAG_COMPARE_LESS_EQUAL = 23,
|
||||
TOY_AST_FLAG_COMPARE_GREATER = 24,
|
||||
TOY_AST_FLAG_COMPARE_GREATER_EQUAL = 25,
|
||||
|
||||
TOY_AST_FLAG_AND = 30,
|
||||
TOY_AST_FLAG_OR = 31,
|
||||
TOY_AST_FLAG_CONCAT = 32,
|
||||
|
||||
//unary flags
|
||||
TOY_AST_FLAG_NEGATE,
|
||||
TOY_AST_FLAG_INCREMENT,
|
||||
TOY_AST_FLAG_DECREMENT,
|
||||
TOY_AST_FLAG_NEGATE = 33,
|
||||
TOY_AST_FLAG_INCREMENT = 34,
|
||||
TOY_AST_FLAG_DECREMENT = 35,
|
||||
|
||||
// TOY_AST_FLAG_TERNARY,
|
||||
} Toy_AstFlag;
|
||||
@@ -86,6 +91,13 @@ typedef struct Toy_AstBinary {
|
||||
Toy_Ast* right;
|
||||
} Toy_AstBinary;
|
||||
|
||||
typedef struct Toy_AstCompare {
|
||||
Toy_AstType type;
|
||||
Toy_AstFlag flag;
|
||||
Toy_Ast* left;
|
||||
Toy_Ast* right;
|
||||
} Toy_AstCompare;
|
||||
|
||||
typedef struct Toy_AstGroup {
|
||||
Toy_AstType type;
|
||||
Toy_Ast* child;
|
||||
@@ -102,6 +114,13 @@ typedef struct Toy_AstVarDeclare {
|
||||
Toy_Ast* expr;
|
||||
} Toy_AstVarDeclare;
|
||||
|
||||
typedef struct Toy_AstVarAssign {
|
||||
Toy_AstType type;
|
||||
Toy_AstFlag flag;
|
||||
Toy_String* name;
|
||||
Toy_Ast* expr;
|
||||
} Toy_AstVarAssign;
|
||||
|
||||
typedef struct Toy_AstPass {
|
||||
Toy_AstType type;
|
||||
} Toy_AstPass;
|
||||
@@ -120,9 +139,11 @@ union Toy_Ast { //32 | 64 BITNESS
|
||||
Toy_AstValue value; //12 | 24
|
||||
Toy_AstUnary unary; //12 | 16
|
||||
Toy_AstBinary binary; //16 | 24
|
||||
Toy_AstCompare compare; //16 | 24
|
||||
Toy_AstGroup group; //8 | 16
|
||||
Toy_AstPrint print; //8 | 16
|
||||
Toy_AstVarDeclare varDeclare; //16 | 24
|
||||
Toy_AstVarAssign varAssign; //16 | 24
|
||||
Toy_AstPass pass; //4 | 4
|
||||
Toy_AstError error; //4 | 4
|
||||
Toy_AstEnd end; //4 | 4
|
||||
@@ -134,11 +155,13 @@ void Toy_private_appendAstBlock(Toy_Bucket** bucketHandle, Toy_Ast* block, Toy_A
|
||||
void Toy_private_emitAstValue(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Value value);
|
||||
void Toy_private_emitAstUnary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag);
|
||||
void Toy_private_emitAstBinary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
||||
void Toy_private_emitAstCompare(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
||||
void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
|
||||
void Toy_private_emitAstPrint(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
|
||||
void Toy_private_emitAstVariableDeclaration(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_Ast* expr);
|
||||
void Toy_private_emitAstVariableAssignment(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_AstFlag flag, Toy_Ast* expr);
|
||||
|
||||
void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
void Toy_private_emitAstError(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
|
||||
@@ -7,6 +7,8 @@ typedef enum Toy_OpcodeType {
|
||||
TOY_OPCODE_ASSIGN,
|
||||
TOY_OPCODE_ACCESS,
|
||||
|
||||
TOY_OPCODE_DUPLICATE, //duplicate the top of the stack
|
||||
|
||||
//arithmetic instructions
|
||||
TOY_OPCODE_ADD,
|
||||
TOY_OPCODE_SUBTRACT,
|
||||
|
||||
@@ -110,6 +110,7 @@ typedef struct ParsingTuple {
|
||||
|
||||
static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle, ParsingPrecedence precRule);
|
||||
|
||||
static Toy_AstFlag nameString(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 binary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||
@@ -119,8 +120,8 @@ static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast*
|
||||
static ParsingTuple parsingRulesetTable[] = {
|
||||
{PREC_PRIMARY,literal,NULL},// TOY_TOKEN_NULL,
|
||||
|
||||
//variable names
|
||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_NAME,
|
||||
//variable names (initially handled as a string)
|
||||
{PREC_NONE,nameString,NULL},// TOY_TOKEN_NAME,
|
||||
|
||||
//types
|
||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_TYPE_TYPE,
|
||||
@@ -221,6 +222,44 @@ static ParsingTuple parsingRulesetTable[] = {
|
||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_EOF,
|
||||
};
|
||||
|
||||
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_AstFlag flag = TOY_AST_FLAG_NONE;
|
||||
|
||||
if (match(parser, TOY_TOKEN_OPERATOR_ASSIGN)) {
|
||||
flag = TOY_AST_FLAG_ASSIGN;
|
||||
}
|
||||
else if (match(parser, TOY_TOKEN_OPERATOR_ADD_ASSIGN)) {
|
||||
flag = TOY_AST_FLAG_ADD_ASSIGN;
|
||||
}
|
||||
else if (match(parser, TOY_TOKEN_OPERATOR_SUBTRACT_ASSIGN)) {
|
||||
flag = TOY_AST_FLAG_SUBTRACT_ASSIGN;
|
||||
}
|
||||
else if (match(parser, TOY_TOKEN_OPERATOR_MULTIPLY_ASSIGN)) {
|
||||
flag = TOY_AST_FLAG_MULTIPLY_ASSIGN;
|
||||
}
|
||||
else if (match(parser, TOY_TOKEN_OPERATOR_DIVIDE_ASSIGN)) {
|
||||
flag = TOY_AST_FLAG_DIVIDE_ASSIGN;
|
||||
}
|
||||
else if (match(parser, TOY_TOKEN_OPERATOR_MODULO_ASSIGN)) {
|
||||
flag = TOY_AST_FLAG_MODULO_ASSIGN;
|
||||
}
|
||||
|
||||
//assignment
|
||||
if (flag != TOY_AST_FLAG_NONE) {
|
||||
Toy_Ast* expr = NULL;
|
||||
parsePrecedence(bucketHandle, parser, &expr, PREC_ASSIGNMENT); //this makes chained assignment possible, I think
|
||||
Toy_private_emitAstVariableAssignment(bucketHandle, rootHandle, name, flag, expr);
|
||||
return TOY_AST_FLAG_NONE;
|
||||
}
|
||||
|
||||
//access
|
||||
printError(parser, parser->previous, "Unexpectedly found a variable access; this is not yet implemented");
|
||||
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||
return TOY_AST_FLAG_NONE;
|
||||
}
|
||||
|
||||
static Toy_AstFlag literal(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||
switch(parser->previous.type) {
|
||||
case TOY_TOKEN_NULL:
|
||||
@@ -494,6 +533,9 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
|
||||
return;
|
||||
}
|
||||
|
||||
//grab this for name storage
|
||||
Toy_Token prevToken = parser->previous;
|
||||
|
||||
Toy_Ast* ptr = NULL;
|
||||
Toy_AstFlag flag = infix(bucketHandle, parser, &ptr);
|
||||
|
||||
@@ -502,8 +544,16 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
|
||||
(*rootHandle) = ptr;
|
||||
return;
|
||||
}
|
||||
|
||||
Toy_private_emitAstBinary(bucketHandle, rootHandle, flag, ptr);
|
||||
else if (flag >= 10 && flag <= 19) {
|
||||
Toy_String* name = Toy_createNameStringLength(bucketHandle, prevToken.lexeme, prevToken.length, TOY_VALUE_UNKNOWN);
|
||||
Toy_private_emitAstVariableAssignment(bucketHandle, rootHandle, name, flag, ptr);
|
||||
}
|
||||
else if (flag >= 20 && flag <= 29) {
|
||||
Toy_private_emitAstCompare(bucketHandle, rootHandle, flag, ptr);
|
||||
}
|
||||
else {
|
||||
Toy_private_emitAstBinary(bucketHandle, rootHandle, flag, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
//can't assign below a certain precedence
|
||||
@@ -531,8 +581,8 @@ static void makeExprStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast*
|
||||
static void makeVariableDeclarationStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||
consume(parser, TOY_TOKEN_NAME, "Expected variable name after 'var' keyword");
|
||||
|
||||
if (parser->previous.length > 256) {
|
||||
printError(parser, parser->previous, "Can't have a variable name longer than 256 characters");
|
||||
if (parser->previous.length > 255) {
|
||||
printError(parser, parser->previous, "Can't have a variable name longer than 255 characters");
|
||||
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ static void emitString(Toy_Routine** rt, Toy_String* str) {
|
||||
unsigned int startAddr = (*rt)->dataCount;
|
||||
|
||||
//move the string into the data section
|
||||
expand((void**)(&((*rt)->data)), &((*rt)->dataCapacity), &((*rt)->dataCount), (*rt)->dataCount + length);
|
||||
expand((void**)(&((*rt)->data)), &((*rt)->dataCapacity), &((*rt)->dataCount), length);
|
||||
|
||||
if (str->type == TOY_STRING_NODE) {
|
||||
char* buffer = Toy_getStringRawBuffer(str);
|
||||
@@ -125,8 +125,8 @@ static void writeInstructionValue(Toy_Routine** rt, Toy_AstValue ast) {
|
||||
}
|
||||
else if (TOY_VALUE_IS_STRING(ast.value)) {
|
||||
//4-byte alignment
|
||||
EMIT_BYTE(rt, code, 0);
|
||||
EMIT_BYTE(rt, code, 0);
|
||||
EMIT_BYTE(rt, code, TOY_STRING_LEAF); //normal string
|
||||
EMIT_BYTE(rt, code, 0); //can't store the length
|
||||
|
||||
emitString(rt, TOY_VALUE_AS_STRING(ast.value));
|
||||
}
|
||||
@@ -175,42 +175,153 @@ static void writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) {
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_MODULO);
|
||||
}
|
||||
|
||||
// else if (ast.flag == TOY_AST_FLAG_ASSIGN) {
|
||||
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||
// //TODO: emit the env symbol to store TOP(S) within
|
||||
// }
|
||||
// else if (ast.flag == TOY_AST_FLAG_ADD_ASSIGN) {
|
||||
// EMIT_BYTE(rt, code,TOY_OPCODE_ADD);
|
||||
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||
// //TODO: emit the env symbol to store TOP(S) within
|
||||
// }
|
||||
// else if (ast.flag == TOY_AST_FLAG_SUBTRACT_ASSIGN) {
|
||||
// EMIT_BYTE(rt, code,TOY_OPCODE_SUBTRACT);
|
||||
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||
// //TODO: emit the env symbol to store TOP(S) within
|
||||
// }
|
||||
// else if (ast.flag == TOY_AST_FLAG_MULTIPLY_ASSIGN) {
|
||||
// EMIT_BYTE(rt, code,TOY_OPCODE_MULTIPLY);
|
||||
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||
// //TODO: emit the env symbol to store TOP(S) within
|
||||
// }
|
||||
// else if (ast.flag == TOY_AST_FLAG_DIVIDE_ASSIGN) {
|
||||
// EMIT_BYTE(rt, code,TOY_OPCODE_DIVIDE);
|
||||
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||
// //TODO: emit the env symbol to store TOP(S) within
|
||||
// }
|
||||
// else if (ast.flag == TOY_AST_FLAG_MODULO_ASSIGN) {
|
||||
// EMIT_BYTE(rt, code,TOY_OPCODE_MODULO);
|
||||
// EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN);
|
||||
// //TODO: emit the env symbol to store TOP(S) within
|
||||
// }
|
||||
//nowhere to really put these for now
|
||||
else if (ast.flag == TOY_AST_FLAG_AND) {
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_AND);
|
||||
}
|
||||
else if (ast.flag == TOY_AST_FLAG_OR) {
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_OR);
|
||||
}
|
||||
else if (ast.flag == TOY_AST_FLAG_CONCAT) {
|
||||
EMIT_BYTE(rt, code, TOY_OPCODE_CONCAT);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST binary flag found\n" TOY_CC_RESET);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
else if (ast.flag == TOY_AST_FLAG_COMPARE_EQUAL) {
|
||||
//4-byte alignment
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_PASS); //checked in compound assignments
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
}
|
||||
|
||||
static void writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) {
|
||||
//name, duplicate, right, opcode
|
||||
if (ast.flag == TOY_AST_FLAG_ASSIGN) {
|
||||
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
|
||||
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
|
||||
EMIT_BYTE(rt, code, TOY_STRING_NAME);
|
||||
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)
|
||||
|
||||
emitString(rt, ast.name);
|
||||
writeRoutineCode(rt, ast.expr);
|
||||
|
||||
EMIT_BYTE(rt, code, TOY_OPCODE_ASSIGN);
|
||||
EMIT_BYTE(rt, code, 0);
|
||||
}
|
||||
else if (ast.flag == TOY_AST_FLAG_ADD_ASSIGN) {
|
||||
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
|
||||
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
|
||||
EMIT_BYTE(rt, code, TOY_STRING_NAME);
|
||||
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)
|
||||
|
||||
emitString(rt, ast.name);
|
||||
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
|
||||
writeRoutineCode(rt, ast.expr);
|
||||
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_ADD);
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed
|
||||
}
|
||||
else if (ast.flag == TOY_AST_FLAG_SUBTRACT_ASSIGN) {
|
||||
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
|
||||
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
|
||||
EMIT_BYTE(rt, code, TOY_STRING_NAME);
|
||||
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)
|
||||
|
||||
emitString(rt, ast.name);
|
||||
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
|
||||
writeRoutineCode(rt, ast.expr);
|
||||
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_SUBTRACT);
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed
|
||||
}
|
||||
else if (ast.flag == TOY_AST_FLAG_MULTIPLY_ASSIGN) {
|
||||
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
|
||||
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
|
||||
EMIT_BYTE(rt, code, TOY_STRING_NAME);
|
||||
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)
|
||||
|
||||
emitString(rt, ast.name);
|
||||
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
|
||||
writeRoutineCode(rt, ast.expr);
|
||||
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_MULTIPLY);
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed
|
||||
}
|
||||
else if (ast.flag == TOY_AST_FLAG_DIVIDE_ASSIGN) {
|
||||
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
|
||||
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
|
||||
EMIT_BYTE(rt, code, TOY_STRING_NAME);
|
||||
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)
|
||||
|
||||
emitString(rt, ast.name);
|
||||
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
|
||||
writeRoutineCode(rt, ast.expr);
|
||||
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_DIVIDE);
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed
|
||||
}
|
||||
else if (ast.flag == TOY_AST_FLAG_MODULO_ASSIGN) {
|
||||
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
|
||||
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
|
||||
EMIT_BYTE(rt, code, TOY_STRING_NAME);
|
||||
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)
|
||||
|
||||
emitString(rt, ast.name);
|
||||
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
|
||||
writeRoutineCode(rt, ast.expr);
|
||||
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_MODULO);
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed
|
||||
}
|
||||
|
||||
else {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST assign flag found\n" TOY_CC_RESET);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
//4-byte alignment
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
}
|
||||
|
||||
static void writeInstructionCompare(Toy_Routine** rt, Toy_AstCompare ast) {
|
||||
//left, then right, then the compare's operation
|
||||
writeRoutineCode(rt, ast.left);
|
||||
writeRoutineCode(rt, ast.right);
|
||||
|
||||
if (ast.flag == TOY_AST_FLAG_COMPARE_EQUAL) {
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_COMPARE_EQUAL);
|
||||
}
|
||||
else if (ast.flag == TOY_AST_FLAG_COMPARE_NOT) {
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_COMPARE_EQUAL);
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_NEGATE); //squeezed into one word
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_NEGATE); //squeezed
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
|
||||
@@ -229,17 +340,8 @@ static void writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) {
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_COMPARE_GREATER_EQUAL);
|
||||
}
|
||||
|
||||
else if (ast.flag == TOY_AST_FLAG_AND) {
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_AND);
|
||||
}
|
||||
else if (ast.flag == TOY_AST_FLAG_OR) {
|
||||
EMIT_BYTE(rt, code,TOY_OPCODE_OR);
|
||||
}
|
||||
else if (ast.flag == TOY_AST_FLAG_CONCAT) {
|
||||
EMIT_BYTE(rt, code, TOY_OPCODE_CONCAT);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST binary flag found\n" TOY_CC_RESET);
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST compare flag found\n" TOY_CC_RESET);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@@ -308,6 +410,14 @@ static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
|
||||
writeInstructionBinary(rt, ast->binary);
|
||||
break;
|
||||
|
||||
case TOY_AST_VAR_ASSIGN:
|
||||
writeInstructionAssign(rt, ast->varAssign);
|
||||
break;
|
||||
|
||||
case TOY_AST_COMPARE:
|
||||
writeInstructionCompare(rt, ast->compare);
|
||||
break;
|
||||
|
||||
case TOY_AST_GROUP:
|
||||
writeInstructionGroup(rt, ast->group);
|
||||
break;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
typedef struct Toy_Stack { //32 | 64 BITNESS
|
||||
unsigned int capacity; //4 | 4
|
||||
unsigned int count; //4 | 4
|
||||
char data[]; //- | -
|
||||
Toy_Value data[]; //- | -
|
||||
} Toy_Stack; //8 | 8
|
||||
|
||||
TOY_API Toy_Stack* Toy_allocateStack();
|
||||
|
||||
@@ -60,11 +60,13 @@ bool Toy_private_isEqual(Toy_Value left, Toy_Value right) {
|
||||
return false;
|
||||
|
||||
case TOY_VALUE_ARRAY:
|
||||
case TOY_VALUE_DICTIONARY:
|
||||
case TOY_VALUE_TABLE:
|
||||
case TOY_VALUE_FUNCTION:
|
||||
case TOY_VALUE_OPAQUE:
|
||||
default:
|
||||
Toy_error(TOY_CC_ERROR "ERROR: Unknown types in value equality comparison\n" TOY_CC_RESET);
|
||||
case TOY_VALUE_TYPE:
|
||||
case TOY_VALUE_ANY:
|
||||
case TOY_VALUE_UNKNOWN:
|
||||
Toy_error(TOY_CC_ERROR "ERROR: Unknown types in value equality comparison\n" TOY_CC_RESET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -96,12 +98,66 @@ unsigned int Toy_hashValue(Toy_Value value) {
|
||||
return Toy_hashString(TOY_VALUE_AS_STRING(value));
|
||||
|
||||
case TOY_VALUE_ARRAY:
|
||||
case TOY_VALUE_DICTIONARY:
|
||||
case TOY_VALUE_TABLE:
|
||||
case TOY_VALUE_FUNCTION:
|
||||
case TOY_VALUE_OPAQUE:
|
||||
default:
|
||||
case TOY_VALUE_TYPE:
|
||||
case TOY_VALUE_ANY:
|
||||
case TOY_VALUE_UNKNOWN:
|
||||
Toy_error(TOY_CC_ERROR "ERROR: Can't hash an unknown type\n" TOY_CC_RESET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Toy_Value Toy_copyValue(Toy_Value value) {
|
||||
switch(value.type) {
|
||||
case TOY_VALUE_NULL:
|
||||
case TOY_VALUE_BOOLEAN:
|
||||
case TOY_VALUE_INTEGER:
|
||||
case TOY_VALUE_FLOAT:
|
||||
return value;
|
||||
|
||||
case TOY_VALUE_STRING: {
|
||||
Toy_String* string = TOY_VALUE_AS_STRING(value);
|
||||
return TOY_VALUE_FROM_STRING(Toy_copyString(string));
|
||||
}
|
||||
|
||||
case TOY_VALUE_ARRAY:
|
||||
case TOY_VALUE_TABLE:
|
||||
case TOY_VALUE_FUNCTION:
|
||||
case TOY_VALUE_OPAQUE:
|
||||
case TOY_VALUE_TYPE:
|
||||
case TOY_VALUE_ANY:
|
||||
case TOY_VALUE_UNKNOWN:
|
||||
Toy_error(TOY_CC_ERROR "ERROR: Can't copy an unknown type\n" TOY_CC_RESET);
|
||||
}
|
||||
|
||||
//dummy return
|
||||
return TOY_VALUE_FROM_NULL();
|
||||
}
|
||||
|
||||
void Toy_freeValue(Toy_Value value) {
|
||||
switch(value.type) {
|
||||
case TOY_VALUE_NULL:
|
||||
case TOY_VALUE_BOOLEAN:
|
||||
case TOY_VALUE_INTEGER:
|
||||
case TOY_VALUE_FLOAT:
|
||||
break;
|
||||
|
||||
case TOY_VALUE_STRING: {
|
||||
Toy_String* string = TOY_VALUE_AS_STRING(value);
|
||||
Toy_freeString(string);
|
||||
break;
|
||||
}
|
||||
|
||||
case TOY_VALUE_ARRAY:
|
||||
case TOY_VALUE_TABLE:
|
||||
case TOY_VALUE_FUNCTION:
|
||||
case TOY_VALUE_OPAQUE:
|
||||
case TOY_VALUE_TYPE:
|
||||
case TOY_VALUE_ANY:
|
||||
case TOY_VALUE_UNKNOWN:
|
||||
Toy_error(TOY_CC_ERROR "ERROR: Can't free an unknown type\n" TOY_CC_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,12 @@ typedef enum Toy_ValueType {
|
||||
TOY_VALUE_FLOAT,
|
||||
TOY_VALUE_STRING,
|
||||
TOY_VALUE_ARRAY,
|
||||
TOY_VALUE_DICTIONARY,
|
||||
TOY_VALUE_TABLE,
|
||||
TOY_VALUE_FUNCTION,
|
||||
TOY_VALUE_OPAQUE,
|
||||
|
||||
//TODO: type, any, consider 'stack' as a possible addition
|
||||
TOY_VALUE_TYPE,
|
||||
TOY_VALUE_ANY,
|
||||
TOY_VALUE_UNKNOWN, //The correct value is unknown, but will be determined later
|
||||
} Toy_ValueType;
|
||||
|
||||
//8 bytes in size
|
||||
@@ -26,10 +27,8 @@ typedef struct Toy_Value { //32 | 64 BITNESS
|
||||
int integer; //4 | 4
|
||||
float number; //4 | 4
|
||||
struct Toy_String* string; //4 | 8
|
||||
//TODO: arrays
|
||||
//TODO: dictonaries
|
||||
//TODO: functions
|
||||
//TODO: opaque
|
||||
//TODO: more types go here
|
||||
//TODO: consider 'stack' as a possible addition
|
||||
} as; //4 | 8
|
||||
|
||||
Toy_ValueType type; //4 | 4
|
||||
@@ -41,7 +40,7 @@ typedef struct Toy_Value { //32 | 64 BITNESS
|
||||
#define TOY_VALUE_IS_FLOAT(value) ((value).type == TOY_VALUE_FLOAT)
|
||||
#define TOY_VALUE_IS_STRING(value) ((value).type == TOY_VALUE_STRING)
|
||||
#define TOY_VALUE_IS_ARRAY(value) ((value).type == TOY_VALUE_ARRAY)
|
||||
#define TOY_VALUE_IS_DICTIONARY(value) ((value).type == TOY_VALUE_DICTIONARY)
|
||||
#define TOY_VALUE_IS_TABLE(value) ((value).type == TOY_VALUE_TABLE)
|
||||
#define TOY_VALUE_IS_FUNCTION(value) ((value).type == TOY_VALUE_FUNCTION)
|
||||
#define TOY_VALUE_IS_OPAQUE(value) ((value).type == TOY_VALUE_OPAQUE)
|
||||
|
||||
@@ -66,3 +65,5 @@ TOY_API bool Toy_private_isEqual(Toy_Value left, Toy_Value right);
|
||||
|
||||
unsigned int Toy_hashValue(Toy_Value value);
|
||||
|
||||
TOY_API Toy_Value Toy_copyValue(Toy_Value value);
|
||||
TOY_API void Toy_freeValue(Toy_Value value);
|
||||
|
||||
@@ -64,15 +64,27 @@ static void processRead(Toy_VM* vm) {
|
||||
}
|
||||
|
||||
case TOY_VALUE_STRING: {
|
||||
fixAlignment(vm);
|
||||
enum Toy_StringType stringType = READ_BYTE(vm);
|
||||
int len = (int)READ_BYTE(vm);
|
||||
|
||||
//grab the jump as an integer
|
||||
unsigned int jump = *(unsigned int*)(vm->routine + vm->jumpsAddr + READ_INT(vm));
|
||||
unsigned int jump = 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));
|
||||
if (stringType == TOY_STRING_LEAF) {
|
||||
value = TOY_VALUE_FROM_STRING(Toy_createString(&vm->stringBucket, cstring));
|
||||
}
|
||||
else if (stringType == TOY_STRING_NAME) {
|
||||
Toy_ValueType valueType = TOY_VALUE_UNKNOWN;
|
||||
|
||||
value = TOY_VALUE_FROM_STRING(Toy_createNameStringLength(&vm->stringBucket, cstring, len, valueType));
|
||||
}
|
||||
else {
|
||||
Toy_error("Invalid string type found");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -82,7 +94,7 @@ static void processRead(Toy_VM* vm) {
|
||||
// break;
|
||||
}
|
||||
|
||||
case TOY_VALUE_DICTIONARY: {
|
||||
case TOY_VALUE_TABLE: {
|
||||
//
|
||||
// break;
|
||||
}
|
||||
@@ -97,6 +109,21 @@ static void processRead(Toy_VM* vm) {
|
||||
// break;
|
||||
}
|
||||
|
||||
case TOY_VALUE_TYPE: {
|
||||
//
|
||||
// break;
|
||||
}
|
||||
|
||||
case TOY_VALUE_ANY: {
|
||||
//
|
||||
// break;
|
||||
}
|
||||
|
||||
case TOY_VALUE_UNKNOWN: {
|
||||
//
|
||||
// break;
|
||||
}
|
||||
|
||||
default:
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid value type %d found, exiting\n" TOY_CC_RESET, type);
|
||||
exit(-1);
|
||||
@@ -133,6 +160,24 @@ static void processDeclare(Toy_VM* vm) {
|
||||
Toy_freeString(name);
|
||||
}
|
||||
|
||||
static void processAssign(Toy_VM* vm) {
|
||||
//get the value & name
|
||||
Toy_Value value = Toy_popStack(&vm->stack);
|
||||
Toy_Value name = Toy_popStack(&vm->stack);
|
||||
|
||||
//check string type
|
||||
if (!TOY_VALUE_IS_STRING(name) && TOY_VALUE_AS_STRING(name)->type != TOY_STRING_NAME) {
|
||||
Toy_error("Invalid assignment target");
|
||||
return;
|
||||
}
|
||||
|
||||
//assign it
|
||||
Toy_assignScope(vm->scope, TOY_VALUE_AS_STRING(name), value);
|
||||
|
||||
//cleanup
|
||||
Toy_freeValue(name);
|
||||
}
|
||||
|
||||
static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
|
||||
Toy_Value right = Toy_popStack(&vm->stack);
|
||||
Toy_Value left = Toy_popStack(&vm->stack);
|
||||
@@ -191,6 +236,18 @@ static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
|
||||
|
||||
//finally
|
||||
Toy_pushStack(&vm->stack, result);
|
||||
|
||||
//check for compound assignments
|
||||
Toy_OpcodeType squeezed = READ_BYTE(vm);
|
||||
if (squeezed == TOY_OPCODE_ASSIGN) {
|
||||
processAssign(vm);
|
||||
}
|
||||
}
|
||||
|
||||
static void processDuplicate(Toy_VM* vm) {
|
||||
Toy_Value value = Toy_copyValue(Toy_peekStack(&vm->stack));
|
||||
Toy_pushStack(&vm->stack, value);
|
||||
Toy_freeValue(value);
|
||||
}
|
||||
|
||||
static void processComparison(Toy_VM* vm, Toy_OpcodeType opcode) {
|
||||
@@ -316,9 +373,12 @@ static void processPrint(Toy_VM* vm) {
|
||||
}
|
||||
|
||||
case TOY_VALUE_ARRAY:
|
||||
case TOY_VALUE_DICTIONARY:
|
||||
case TOY_VALUE_TABLE:
|
||||
case TOY_VALUE_FUNCTION:
|
||||
case TOY_VALUE_OPAQUE:
|
||||
case TOY_VALUE_TYPE:
|
||||
case TOY_VALUE_ANY:
|
||||
case TOY_VALUE_UNKNOWN:
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown value type %d passed to processPrint, exiting\n" TOY_CC_RESET, value.type);
|
||||
exit(-1);
|
||||
}
|
||||
@@ -357,6 +417,14 @@ static void process(Toy_VM* vm) {
|
||||
processDeclare(vm);
|
||||
break;
|
||||
|
||||
case TOY_OPCODE_ASSIGN:
|
||||
processAssign(vm);
|
||||
break;
|
||||
|
||||
case TOY_OPCODE_DUPLICATE:
|
||||
processDuplicate(vm);
|
||||
break;
|
||||
|
||||
//arithmetic instructions
|
||||
case TOY_OPCODE_ADD:
|
||||
case TOY_OPCODE_SUBTRACT:
|
||||
@@ -398,7 +466,6 @@ static void process(Toy_VM* vm) {
|
||||
break;
|
||||
|
||||
//not yet implemented
|
||||
case TOY_OPCODE_ASSIGN:
|
||||
case TOY_OPCODE_ACCESS:
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Incomplete opcode %d found, exiting\n" TOY_CC_RESET, opcode);
|
||||
exit(-1);
|
||||
@@ -486,7 +553,10 @@ void Toy_bindVMToRoutine(Toy_VM* vm, unsigned char* routine) {
|
||||
vm->stringBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
vm->scopeBucket = Toy_allocateBucket(TOY_BUCKET_SMALL);
|
||||
vm->stack = Toy_allocateStack();
|
||||
vm->scope = Toy_pushScope(&vm->scopeBucket, NULL);
|
||||
if (vm->scope == NULL) {
|
||||
//only allocate a new top-level scope when needed, otherwise REPL will break
|
||||
vm->scope = Toy_pushScope(&vm->scopeBucket, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void Toy_runVM(Toy_VM* vm) {
|
||||
|
||||
@@ -21,6 +21,8 @@ int test_sizeof_ast_64bit() {
|
||||
TEST_SIZEOF(Toy_AstValue, 24);
|
||||
TEST_SIZEOF(Toy_AstUnary, 16);
|
||||
TEST_SIZEOF(Toy_AstBinary, 24);
|
||||
TEST_SIZEOF(Toy_AstVarAssign, 24);
|
||||
TEST_SIZEOF(Toy_AstCompare, 24);
|
||||
TEST_SIZEOF(Toy_AstGroup, 16);
|
||||
TEST_SIZEOF(Toy_AstPrint, 16);
|
||||
TEST_SIZEOF(Toy_AstPass, 4);
|
||||
@@ -50,6 +52,8 @@ int test_sizeof_ast_32bit() {
|
||||
TEST_SIZEOF(Toy_AstValue, 12);
|
||||
TEST_SIZEOF(Toy_AstUnary, 12);
|
||||
TEST_SIZEOF(Toy_AstBinary, 16);
|
||||
TEST_SIZEOF(Toy_AstVarAssign, 16);
|
||||
TEST_SIZEOF(Toy_AstCompare, 16);
|
||||
TEST_SIZEOF(Toy_AstGroup, 8);
|
||||
TEST_SIZEOF(Toy_AstPrint, 8);
|
||||
TEST_SIZEOF(Toy_AstPass, 4);
|
||||
@@ -124,6 +128,56 @@ int test_type_emission(Toy_Bucket** bucketHandle) {
|
||||
}
|
||||
}
|
||||
|
||||
//emit assign
|
||||
{
|
||||
//build the AST
|
||||
Toy_Ast* ast = NULL;
|
||||
Toy_Ast* right = NULL;
|
||||
Toy_String* name = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_INTEGER);
|
||||
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_FROM_INTEGER(69));
|
||||
Toy_private_emitAstVariableAssignment(bucketHandle, &ast, name, TOY_AST_FLAG_ASSIGN, right);
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_VAR_ASSIGN ||
|
||||
ast->varAssign.flag != TOY_AST_FLAG_ASSIGN ||
|
||||
ast->varAssign.name == NULL ||
|
||||
ast->varAssign.name->type != TOY_STRING_NAME ||
|
||||
strcmp(ast->varAssign.name->as.name.data, "foobar") != 0 ||
|
||||
ast->varAssign.name->as.name.type != TOY_VALUE_INTEGER ||
|
||||
ast->varAssign.expr->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_AS_INTEGER(ast->varAssign.expr->value.value) != 69)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit an assign as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//emit compare
|
||||
{
|
||||
//build the AST
|
||||
Toy_Ast* ast = NULL;
|
||||
Toy_Ast* right = NULL;
|
||||
Toy_private_emitAstValue(bucketHandle, &ast, TOY_VALUE_FROM_INTEGER(42)); //technically, not a valid value
|
||||
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_FROM_INTEGER(69));
|
||||
Toy_private_emitAstCompare(bucketHandle, &ast, TOY_AST_FLAG_ADD, right);
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_COMPARE ||
|
||||
ast->compare.flag != TOY_AST_FLAG_ADD ||
|
||||
ast->compare.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_AS_INTEGER(ast->compare.left->value.value) != 42 ||
|
||||
ast->compare.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_AS_INTEGER(ast->compare.right->value.value) != 69)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a compare as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//emit group
|
||||
{
|
||||
//build the AST
|
||||
|
||||
@@ -122,7 +122,7 @@ int test_bytecode_from_source(Toy_Bucket** bucketHandle) {
|
||||
*(int*)(offset + bc.ptr + 36) != 2 ||
|
||||
|
||||
*((unsigned char*)(offset + bc.ptr + 40)) != TOY_OPCODE_ADD ||
|
||||
*((unsigned char*)(offset + bc.ptr + 41)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 41)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(offset + bc.ptr + 42)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 43)) != 0 ||
|
||||
|
||||
@@ -140,13 +140,13 @@ int test_bytecode_from_source(Toy_Bucket** bucketHandle) {
|
||||
*(int*)(offset + bc.ptr + 56) != 4 ||
|
||||
|
||||
*((unsigned char*)(offset + bc.ptr + 60)) != TOY_OPCODE_ADD ||
|
||||
*((unsigned char*)(offset + bc.ptr + 61)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 61)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(offset + bc.ptr + 62)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 63)) != 0 ||
|
||||
|
||||
//multiply the two values
|
||||
*((unsigned char*)(offset + bc.ptr + 64)) != TOY_OPCODE_MULTIPLY ||
|
||||
*((unsigned char*)(offset + bc.ptr + 65)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 65)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(offset + bc.ptr + 66)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 67)) != 0 ||
|
||||
|
||||
|
||||
@@ -100,6 +100,100 @@ int test_simple_empty_parsers(Toy_Bucket** bucketHandle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_var_declare(Toy_Bucket** bucketHandle) {
|
||||
//declare with an initial value
|
||||
{
|
||||
const char* source = "var answer = 42;";
|
||||
Toy_Ast* ast = makeAstFromSource(bucketHandle, source);
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VAR_DECLARE ||
|
||||
|
||||
ast->block.child->varDeclare.name == NULL ||
|
||||
ast->block.child->varDeclare.name->type != TOY_STRING_NAME ||
|
||||
strcmp(ast->block.child->varDeclare.name->as.name.data, "answer") != 0 ||
|
||||
|
||||
ast->block.child->varDeclare.expr == NULL ||
|
||||
ast->block.child->varDeclare.expr->type != TOY_AST_VALUE ||
|
||||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->varDeclare.expr->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->varDeclare.expr->value.value) != 42)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Declare AST failed, source: %s\n" TOY_CC_RESET, source);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//declare without an initial value
|
||||
{
|
||||
const char* source = "var empty;";
|
||||
Toy_Ast* ast = makeAstFromSource(bucketHandle, source);
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VAR_DECLARE ||
|
||||
|
||||
ast->block.child->varDeclare.name == NULL ||
|
||||
ast->block.child->varDeclare.name->type != TOY_STRING_NAME ||
|
||||
strcmp(ast->block.child->varDeclare.name->as.name.data, "empty") != 0 ||
|
||||
|
||||
ast->block.child->varDeclare.expr == NULL ||
|
||||
ast->block.child->varDeclare.expr->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_NULL(ast->block.child->varDeclare.expr->value.value) == false ||
|
||||
|
||||
false)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Declare AST failed, source: %s\n" TOY_CC_RESET, source);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_var_assign(Toy_Bucket** bucketHandle) {
|
||||
//macro templates
|
||||
#define TEST_VAR_ASSIGN(ARG_SOURCE, ARG_FLAG, ARG_NAME, ARG_VALUE) \
|
||||
{ \
|
||||
const char* source = ARG_SOURCE; \
|
||||
Toy_Ast* ast = makeAstFromSource(bucketHandle, source); \
|
||||
if ( \
|
||||
ast == NULL || \
|
||||
ast->type != TOY_AST_BLOCK || \
|
||||
ast->block.child == NULL || \
|
||||
ast->block.child->type != TOY_AST_VAR_ASSIGN || \
|
||||
ast->block.child->varAssign.flag != ARG_FLAG || \
|
||||
ast->block.child->varAssign.name == NULL || \
|
||||
ast->block.child->varAssign.name->type != TOY_STRING_NAME || \
|
||||
strcmp(ast->block.child->varAssign.name->as.name.data, ARG_NAME) != 0 || \
|
||||
ast->block.child->varAssign.expr == NULL || \
|
||||
ast->block.child->varAssign.expr->type != TOY_AST_VALUE || \
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->varAssign.expr->value.value) == false || \
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->varAssign.expr->value.value) != ARG_VALUE) \
|
||||
{ \
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Assign AST failed, source: %s\n" TOY_CC_RESET, source); \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
//run tests
|
||||
TEST_VAR_ASSIGN("answer = 42;", TOY_AST_FLAG_ASSIGN, "answer", 42);
|
||||
TEST_VAR_ASSIGN("answer += 42;", TOY_AST_FLAG_ADD_ASSIGN, "answer", 42);
|
||||
TEST_VAR_ASSIGN("answer -= 42;", TOY_AST_FLAG_SUBTRACT_ASSIGN, "answer", 42);
|
||||
TEST_VAR_ASSIGN("answer *= 42;", TOY_AST_FLAG_MULTIPLY_ASSIGN, "answer", 42);
|
||||
TEST_VAR_ASSIGN("answer /= 42;", TOY_AST_FLAG_DIVIDE_ASSIGN, "answer", 42);
|
||||
TEST_VAR_ASSIGN("answer %= 42;", TOY_AST_FLAG_MODULO_ASSIGN, "answer", 42);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_values(Toy_Bucket** bucketHandle) {
|
||||
//test boolean true
|
||||
{
|
||||
@@ -358,60 +452,6 @@ int test_binary(Toy_Bucket** bucketHandle) {
|
||||
}
|
||||
}
|
||||
|
||||
//test binary assign (using numbers for now, as identifiers aren't coded yet)
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(bucketHandle, "1 = 2;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.flag != TOY_AST_FLAG_ASSIGN ||
|
||||
|
||||
ast->block.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->value.value) != 1 ||
|
||||
|
||||
ast->block.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->value.value) != 2)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with binary assign '1 = 2'\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test binary compare (equality)
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(bucketHandle, "42 == 69;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.flag != TOY_AST_FLAG_COMPARE_EQUAL ||
|
||||
|
||||
ast->block.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->value.value) != 42 ||
|
||||
|
||||
ast->block.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->value.value) != 69)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with binary compare '42 == 69'\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -574,15 +614,17 @@ int main() {
|
||||
total += res;
|
||||
}
|
||||
|
||||
// { //TODO: test_parser.c: test_var_declare()
|
||||
// Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
// res = test_var_declare(&bucket);
|
||||
// Toy_freeBucket(&bucket);
|
||||
// if (res == 0) {
|
||||
// printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
// }
|
||||
// total += res;
|
||||
// }
|
||||
{
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
res = test_var_declare(&bucket);
|
||||
Toy_freeBucket(&bucket);
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
total += res;
|
||||
}
|
||||
|
||||
//TODO: assign & compare?
|
||||
|
||||
{
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
|
||||
@@ -364,7 +364,7 @@ int test_routine_expressions(Toy_Bucket** bucketHandle) {
|
||||
//code start
|
||||
*((unsigned char*)(code + 0)) != TOY_OPCODE_READ ||
|
||||
*((unsigned char*)(code + 1)) != TOY_VALUE_STRING ||
|
||||
*((unsigned char*)(code + 2)) != 0 ||
|
||||
*((unsigned char*)(code + 2)) != TOY_STRING_LEAF ||
|
||||
*((unsigned char*)(code + 3)) != 0 ||
|
||||
*(unsigned int*)(code + 4) != 0 || //the jump index
|
||||
*((unsigned char*)(code + 8)) != TOY_OPCODE_RETURN ||
|
||||
@@ -470,7 +470,7 @@ int test_routine_binary(Toy_Bucket** bucketHandle) {
|
||||
*(int*)(buffer + 36) != 5 ||
|
||||
|
||||
*((unsigned char*)(buffer + 40)) != TOY_OPCODE_ADD ||
|
||||
*((unsigned char*)(buffer + 41)) != 0 ||
|
||||
*((unsigned char*)(buffer + 41)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(buffer + 42)) != 0 ||
|
||||
*((unsigned char*)(buffer + 43)) != 0 ||
|
||||
|
||||
@@ -670,7 +670,7 @@ int test_routine_binary(Toy_Bucket** bucketHandle) {
|
||||
*(int*)(buffer + 36) != 2 ||
|
||||
|
||||
*((unsigned char*)(buffer + 40)) != TOY_OPCODE_ADD ||
|
||||
*((unsigned char*)(buffer + 41)) != 0 ||
|
||||
*((unsigned char*)(buffer + 41)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(buffer + 42)) != 0 ||
|
||||
*((unsigned char*)(buffer + 43)) != 0 ||
|
||||
|
||||
@@ -688,13 +688,13 @@ int test_routine_binary(Toy_Bucket** bucketHandle) {
|
||||
*(int*)(buffer + 56) != 4 ||
|
||||
|
||||
*((unsigned char*)(buffer + 60)) != TOY_OPCODE_ADD ||
|
||||
*((unsigned char*)(buffer + 61)) != 0 ||
|
||||
*((unsigned char*)(buffer + 61)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(buffer + 62)) != 0 ||
|
||||
*((unsigned char*)(buffer + 63)) != 0 ||
|
||||
|
||||
//multiply the two values
|
||||
*((unsigned char*)(buffer + 64)) != TOY_OPCODE_MULTIPLY ||
|
||||
*((unsigned char*)(buffer + 65)) != 0 ||
|
||||
*((unsigned char*)(buffer + 65)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(buffer + 66)) != 0 ||
|
||||
*((unsigned char*)(buffer + 67)) != 0 ||
|
||||
|
||||
@@ -912,7 +912,7 @@ int main() {
|
||||
total += res;
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
res = test_routine_keywords(&bucket);
|
||||
Toy_freeBucket(&bucket);
|
||||
|
||||
@@ -4,3 +4,19 @@ var answer = 42;
|
||||
//declare a variable without an initial value
|
||||
var empty;
|
||||
|
||||
//assign a previously existing variable
|
||||
answer = 6 * 9;
|
||||
|
||||
|
||||
/* TODO: implement compound assignments
|
||||
answer += 5;
|
||||
|
||||
answer -= 5;
|
||||
|
||||
answer *= 9;
|
||||
|
||||
answer /= 2;
|
||||
|
||||
answer %= 10;
|
||||
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user