TMP: Brain broke, I need a break, don't use this commit
This commit is contained in:
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
|
||||||
|
```toy
|
||||||
|
for (var name in array) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
pushStack name
|
||||||
|
pushStack array
|
||||||
|
pushStack counter //tracks the index for each loop
|
||||||
|
|
||||||
|
OPCODE iterable:
|
||||||
|
pushScope
|
||||||
|
declare name = array.next() if next is not null else jump to end
|
||||||
|
|
||||||
|
(user code)
|
||||||
|
|
||||||
|
popScope
|
||||||
|
jump to beginning
|
||||||
|
|
||||||
|
popStack counter, array, name
|
||||||
@@ -1,12 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
var array = ["foo", "bar"];
|
||||||
|
|
||||||
fn a(x) {
|
for (var i in array) {
|
||||||
print x;
|
print i;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn b() {
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
|
|
||||||
a(b(), b());
|
|
||||||
+62
-5
@@ -226,6 +226,7 @@ static unsigned int writeBytecodeFromAst(Toy_Bytecode** mb, Toy_Ast* ast); //for
|
|||||||
static void writeBytecodeBody(Toy_Bytecode* mb, Toy_Ast* ast);
|
static void writeBytecodeBody(Toy_Bytecode* mb, Toy_Ast* ast);
|
||||||
static unsigned char* collateBytecodeBody(Toy_Bytecode* mb);
|
static unsigned char* collateBytecodeBody(Toy_Bytecode* mb);
|
||||||
static unsigned int writeInstructionAssign(Toy_Bytecode** mb, Toy_AstVarAssign ast, bool chainedAssignment); //forward declare for chaining of var declarations
|
static unsigned int writeInstructionAssign(Toy_Bytecode** mb, Toy_AstVarAssign ast, bool chainedAssignment); //forward declare for chaining of var declarations
|
||||||
|
static unsigned int writeInstructionAccess(Toy_Bytecode** mb, Toy_AstVarAccess ast);
|
||||||
static unsigned int writeInstructionFnInvoke(Toy_Bytecode** mb, Toy_AstFnInvoke ast, bool chainedInvoke);
|
static unsigned int writeInstructionFnInvoke(Toy_Bytecode** mb, Toy_AstFnInvoke ast, bool chainedInvoke);
|
||||||
|
|
||||||
static unsigned int writeInstructionValue(Toy_Bytecode** mb, Toy_AstValue ast) {
|
static unsigned int writeInstructionValue(Toy_Bytecode** mb, Toy_AstValue ast) {
|
||||||
@@ -456,7 +457,7 @@ static unsigned int writeInstructionBinaryShortCircuit(Toy_Bytecode** mb, Toy_As
|
|||||||
|
|
||||||
//if the lhs value isn't needed, pop it
|
//if the lhs value isn't needed, pop it
|
||||||
EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE);
|
EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE);
|
||||||
EMIT_BYTE(mb, code, 0);
|
EMIT_BYTE(mb, code, 1);
|
||||||
EMIT_BYTE(mb, code, 0);
|
EMIT_BYTE(mb, code, 0);
|
||||||
EMIT_BYTE(mb, code, 0);
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
|
||||||
@@ -719,9 +720,65 @@ static unsigned int writeInstructionWhileThen(Toy_Bytecode** mb, Toy_AstWhileThe
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int writeInstructionForThen(Toy_Bytecode** mb, Toy_AstForThen ast) {
|
static unsigned int writeInstructionForThen(Toy_Bytecode** mb, Toy_AstForThen ast) {
|
||||||
//URGENT: WIP
|
//check the operands
|
||||||
(void)mb;
|
if (ast.condBranch->type != TOY_AST_ITERABLE || ast.condBranch->iterable.left->type != TOY_AST_VAR_DECLARE || ast.condBranch->iterable.right->type != TOY_AST_VAR_ACCESS) {
|
||||||
(void)ast;
|
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: Invalid conditional found in a 'for' loop\n" TOY_CC_RESET);
|
||||||
|
(*mb)->panic = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//set up the iterable, and the counter
|
||||||
|
writeInstructionAccess(mb, ast.condBranch->iterable.right->varAccess);
|
||||||
|
|
||||||
|
EMIT_BYTE(mb, code, TOY_OPCODE_READ);
|
||||||
|
EMIT_BYTE(mb, code, TOY_VALUE_INTEGER);
|
||||||
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
|
||||||
|
EMIT_INT(mb, code, 0); //start from zero
|
||||||
|
|
||||||
|
//access [-1] from [-2], incrementing [-1] afterwards
|
||||||
|
//then if null, execute relative jump
|
||||||
|
EMIT_BYTE(mb, code, TOY_OPCODE_ITERABLE);
|
||||||
|
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_RELATIVE);
|
||||||
|
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_IF_NULL);
|
||||||
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
|
||||||
|
unsigned int thenParamAddr = SKIP_INT(mb, code); //parameter to be written later
|
||||||
|
|
||||||
|
//push scope (built-into the keyword)
|
||||||
|
EMIT_BYTE(mb, code, TOY_OPCODE_SCOPE_PUSH);
|
||||||
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
(*mb)->currentScopeDepth++;
|
||||||
|
|
||||||
|
//delcare the iterator with the given string
|
||||||
|
EMIT_BYTE(mb, code, TOY_OPCODE_DECLARE);
|
||||||
|
EMIT_BYTE(mb, code, ast.condBranch->iterable.left->varDeclare.valueType);
|
||||||
|
EMIT_BYTE(mb, code, ast.condBranch->iterable.left->varDeclare.name->info.length); //quick optimisation to skip a 'strlen()' call
|
||||||
|
EMIT_BYTE(mb, code, ast.condBranch->iterable.left->varDeclare.constant); //check for constness
|
||||||
|
|
||||||
|
emitString(mb, ast.condBranch->iterable.left->varDeclare.name);
|
||||||
|
|
||||||
|
//write the body
|
||||||
|
writeBytecodeFromAst(mb, ast.thenBranch);
|
||||||
|
|
||||||
|
//pop scope after each iteration
|
||||||
|
EMIT_BYTE(mb, code, TOY_OPCODE_SCOPE_POP);
|
||||||
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
(*mb)->currentScopeDepth--;
|
||||||
|
|
||||||
|
//end of the loop, overwrite the parameter
|
||||||
|
OVERWRITE_INT(mb, code, thenParamAddr, CURRENT_ADDRESS(mb, code) - (thenParamAddr + 4));
|
||||||
|
|
||||||
|
//pop the conditional stuff from the stack
|
||||||
|
EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE);
|
||||||
|
EMIT_BYTE(mb, code, 2);
|
||||||
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
|
||||||
(*mb)->panic = true;
|
(*mb)->panic = true;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1163,7 +1220,7 @@ static unsigned int writeInstructionStackPop(Toy_Bytecode** mb, Toy_AstStackPop
|
|||||||
|
|
||||||
//dead simple
|
//dead simple
|
||||||
EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE);
|
EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE);
|
||||||
EMIT_BYTE(mb, code, 0);
|
EMIT_BYTE(mb, code, 1);
|
||||||
EMIT_BYTE(mb, code, 0);
|
EMIT_BYTE(mb, code, 0);
|
||||||
EMIT_BYTE(mb, code, 0);
|
EMIT_BYTE(mb, code, 0);
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ typedef enum Toy_OpcodeType {
|
|||||||
TOY_OPCODE_ACCESS,
|
TOY_OPCODE_ACCESS,
|
||||||
TOY_OPCODE_INVOKE, //for calling functions
|
TOY_OPCODE_INVOKE, //for calling functions
|
||||||
TOY_OPCODE_ATTRIBUTE, //for accessing parts of compounds
|
TOY_OPCODE_ATTRIBUTE, //for accessing parts of compounds
|
||||||
TOY_OPCODE_ITERABLE, //for operating on all members of a compound
|
|
||||||
TOY_OPCODE_DUPLICATE, //duplicate the top of the stack
|
TOY_OPCODE_DUPLICATE, //duplicate the top of the stack
|
||||||
TOY_OPCODE_ELIMINATE, //remove the top of the stack
|
TOY_OPCODE_ELIMINATE, //remove the top of the stack
|
||||||
|
TOY_OPCODE_ITERABLE, //for operating on all members of a compound
|
||||||
|
|
||||||
//arithmetic instructions
|
//arithmetic instructions
|
||||||
TOY_OPCODE_ADD,
|
TOY_OPCODE_ADD,
|
||||||
@@ -67,5 +67,6 @@ typedef enum Toy_OpParamJumpConditional {
|
|||||||
TOY_OP_PARAM_JUMP_ALWAYS = 0,
|
TOY_OP_PARAM_JUMP_ALWAYS = 0,
|
||||||
TOY_OP_PARAM_JUMP_IF_TRUE = 1,
|
TOY_OP_PARAM_JUMP_IF_TRUE = 1,
|
||||||
TOY_OP_PARAM_JUMP_IF_FALSE = 2,
|
TOY_OP_PARAM_JUMP_IF_FALSE = 2,
|
||||||
|
TOY_OP_PARAM_JUMP_IF_NULL = 3,
|
||||||
} Toy_OpParamJumpConditional;
|
} Toy_OpParamJumpConditional;
|
||||||
|
|
||||||
|
|||||||
+50
-7
@@ -765,11 +765,17 @@ static Toy_AstFlag iterable(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
|
|||||||
//infix must advance
|
//infix must advance
|
||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
Toy_Ast* expr = NULL;
|
//check for the correct operands
|
||||||
parsePrecedence(bucketHandle, parser, &expr, PREC_CALL);
|
if ((*rootHandle)->type != TOY_AST_VAR_DECLARE) {
|
||||||
Toy_private_emitAstIterable(bucketHandle, rootHandle, expr);
|
printError(parser, parser->previous, "Expected iterator name not found");
|
||||||
|
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||||
|
return TOY_AST_FLAG_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: check for var declare without assignment
|
Toy_Ast* expr = NULL;
|
||||||
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_CALL);
|
||||||
|
|
||||||
|
Toy_private_emitAstIterable(bucketHandle, rootHandle, expr);
|
||||||
|
|
||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
}
|
}
|
||||||
@@ -785,7 +791,7 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
|
|||||||
if (prefix == NULL) {
|
if (prefix == NULL) {
|
||||||
//make a nice error message
|
//make a nice error message
|
||||||
if (Toy_private_findKeywordByType(parser->previous.type)) {
|
if (Toy_private_findKeywordByType(parser->previous.type)) {
|
||||||
printError(parser, parser->previous, "Found reserved keyword instead");
|
printError(parser, parser->previous, "Expected expression, found reserved keyword instead");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printError(parser, parser->previous, "Expected expression");
|
printError(parser, parser->previous, "Expected expression");
|
||||||
@@ -909,12 +915,49 @@ static void makeForStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast**
|
|||||||
Toy_Ast* condBranch = NULL;
|
Toy_Ast* condBranch = NULL;
|
||||||
Toy_Ast* thenBranch = NULL;
|
Toy_Ast* thenBranch = NULL;
|
||||||
|
|
||||||
|
//BUG: wtf am I doing here?
|
||||||
|
|
||||||
//for (condBranch)
|
//for (condBranch)
|
||||||
consume(parser, TOY_TOKEN_OPERATOR_PAREN_LEFT, "Expected '(' after 'for' keyword");
|
consume(parser, TOY_TOKEN_OPERATOR_PAREN_LEFT, "Expected '(' after 'for' keyword");
|
||||||
|
consume(parser, TOY_TOKEN_KEYWORD_VAR, "Expected 'var' in 'for' conditional");
|
||||||
|
|
||||||
|
//WARN: duped from var declare
|
||||||
|
consume(parser, TOY_TOKEN_NAME, "Expected variable name after 'var' keyword");
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Token nameToken = parser->previous;
|
||||||
|
|
||||||
|
//read the type specifier if present
|
||||||
|
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 name string & emit a var declare
|
||||||
|
Toy_String* nameStr = Toy_toStringLength(bucketHandle, nameToken.lexeme, nameToken.length);
|
||||||
|
Toy_private_emitAstVariableDeclaration(bucketHandle, &condBranch, nameStr, varType, constant, NULL);
|
||||||
|
|
||||||
|
//continue to the 'in' keyword
|
||||||
|
consume(parser, TOY_TOKEN_KEYWORD_IN, "Expected 'in' inside 'for' condition");
|
||||||
makeExpr(bucketHandle, parser, &condBranch);
|
makeExpr(bucketHandle, parser, &condBranch);
|
||||||
|
|
||||||
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'for' condition");
|
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'for' condition");
|
||||||
|
|
||||||
//TODO: check for an iterable node
|
if (condBranch->type != TOY_AST_ITERABLE) {
|
||||||
|
printError(parser, parser->previous, "Expected 'in' in for condition");
|
||||||
|
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//{ thenBranch }
|
//{ thenBranch }
|
||||||
makeDeclarationStmt(bucketHandle, parser, &thenBranch, true);
|
makeDeclarationStmt(bucketHandle, parser, &thenBranch, true);
|
||||||
@@ -1125,7 +1168,7 @@ static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** ro
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: import
|
//import?
|
||||||
|
|
||||||
//print
|
//print
|
||||||
else if (match(parser, TOY_TOKEN_KEYWORD_PRINT)) {
|
else if (match(parser, TOY_TOKEN_KEYWORD_PRINT)) {
|
||||||
|
|||||||
+66
-2
@@ -33,6 +33,9 @@ static inline void fixAlignment(Toy_VM* vm) {
|
|||||||
vm->programCounter = (vm->programCounter + 3) & ~3;
|
vm->programCounter = (vm->programCounter + 3) & ~3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//forward declarations for delegations
|
||||||
|
static void processJump(Toy_VM* vm);
|
||||||
|
|
||||||
//instruction handlers
|
//instruction handlers
|
||||||
static void processRead(Toy_VM* vm) {
|
static void processRead(Toy_VM* vm) {
|
||||||
Toy_ValueType type = READ_BYTE(vm);
|
Toy_ValueType type = READ_BYTE(vm);
|
||||||
@@ -470,9 +473,56 @@ static void processDuplicate(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void processEliminate(Toy_VM* vm) {
|
static void processEliminate(Toy_VM* vm) {
|
||||||
//discard the stack top
|
//discard the stack top, X times
|
||||||
|
unsigned int x = (unsigned int)READ_BYTE(vm);
|
||||||
|
for (unsigned int i = 0; i < x; i++) {
|
||||||
Toy_Value value = Toy_popStack(&vm->stack);
|
Toy_Value value = Toy_popStack(&vm->stack);
|
||||||
Toy_freeValue(value);
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void processIterable(Toy_VM* vm) {
|
||||||
|
//access [-1] from [-2], incrementing [-1] afterwards
|
||||||
|
//if null, delegate to 'processJump' and exit
|
||||||
|
|
||||||
|
Toy_Value counter = Toy_popStack(&vm->stack);
|
||||||
|
Toy_Value compound = Toy_popStack(&vm->stack);
|
||||||
|
|
||||||
|
if (!TOY_VALUE_IS_INTEGER(counter)) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown counter type '%s' found in for loop, exiting\n" TOY_CC_RESET, Toy_getValueTypeAsCString(counter.type));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_VALUE_IS_ARRAY(compound)) {
|
||||||
|
Toy_Array* array = TOY_VALUE_AS_ARRAY(compound);
|
||||||
|
int index = TOY_VALUE_AS_INTEGER(counter);
|
||||||
|
|
||||||
|
//check out-of-bounds
|
||||||
|
if (index < 0 || (unsigned int)index >= array->count) {
|
||||||
|
Toy_freeValue(counter);
|
||||||
|
Toy_freeValue(compound);
|
||||||
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL());
|
||||||
|
processJump(vm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the desired element
|
||||||
|
Toy_Value value = Toy_copyValue(&vm->memoryBucket, array->data[index]);
|
||||||
|
|
||||||
|
//push everything back onto the stack
|
||||||
|
Toy_pushStack(&vm->stack, compound);
|
||||||
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_INTEGER(index + 1));
|
||||||
|
Toy_pushStack(&vm->stack, value);
|
||||||
|
|
||||||
|
//cleanup & delegate
|
||||||
|
Toy_freeValue(compound);
|
||||||
|
Toy_freeValue(counter);
|
||||||
|
processJump(vm);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown value type '%s' found in for loop, exiting\n" TOY_CC_RESET, Toy_getValueTypeAsCString(compound.type));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
|
static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
|
||||||
@@ -682,6 +732,17 @@ static void processJump(Toy_VM* vm) {
|
|||||||
Toy_freeValue(value);
|
Toy_freeValue(value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case TOY_OP_PARAM_JUMP_IF_NULL: {
|
||||||
|
Toy_Value value = Toy_popStack(&vm->stack);
|
||||||
|
if (TOY_VALUE_IS_NULL(value)) {
|
||||||
|
Toy_freeValue(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_freeValue(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//do the jump
|
//do the jump
|
||||||
@@ -997,6 +1058,10 @@ static unsigned int process(Toy_VM* vm) {
|
|||||||
processEliminate(vm);
|
processEliminate(vm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_ITERABLE:
|
||||||
|
processIterable(vm);
|
||||||
|
break;
|
||||||
|
|
||||||
//arithmetic instructions
|
//arithmetic instructions
|
||||||
case TOY_OPCODE_ADD:
|
case TOY_OPCODE_ADD:
|
||||||
case TOY_OPCODE_SUBTRACT:
|
case TOY_OPCODE_SUBTRACT:
|
||||||
@@ -1060,7 +1125,6 @@ static unsigned int process(Toy_VM* vm) {
|
|||||||
processIndex(vm);
|
processIndex(vm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_OPCODE_ITERABLE: //tmp
|
|
||||||
case TOY_OPCODE_UNUSED:
|
case TOY_OPCODE_UNUSED:
|
||||||
case TOY_OPCODE_PASS:
|
case TOY_OPCODE_PASS:
|
||||||
case TOY_OPCODE_ERROR:
|
case TOY_OPCODE_ERROR:
|
||||||
|
|||||||
Reference in New Issue
Block a user