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:
2024-10-25 22:48:24 +11:00
parent 5b17c5e1e9
commit 3148a56ce0
17 changed files with 653 additions and 182 deletions

View 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

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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));

View File

@@ -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);

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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

View File

@@ -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 ||

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
*/