diff --git a/source/toy_ast.c b/source/toy_ast.c index 8eb3b69..540463f 100644 --- a/source/toy_ast.c +++ b/source/toy_ast.c @@ -84,6 +84,17 @@ void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) { (*astHandle) = tmp; } +void Toy_private_emitAstCompound(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_COMPOUND; + tmp->compound.flag = flag; + tmp->compound.left = *astHandle; //left-recursive + tmp->compound.right = right; + + (*astHandle) = tmp; +} + void Toy_private_emitAstPrint(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) { Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast)); diff --git a/source/toy_ast.h b/source/toy_ast.h index 91cc055..296ad9a 100644 --- a/source/toy_ast.h +++ b/source/toy_ast.h @@ -15,6 +15,7 @@ typedef enum Toy_AstType { TOY_AST_BINARY, TOY_AST_COMPARE, TOY_AST_GROUP, + TOY_AST_COMPOUND, TOY_AST_PRINT, @@ -52,14 +53,17 @@ typedef enum Toy_AstFlag { 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, + TOY_AST_FLAG_COMPOUND_COLLECTION = 30, + TOY_AST_FLAG_COMPOUND_INDEX = 31, + + TOY_AST_FLAG_AND = 40, + TOY_AST_FLAG_OR = 41, + TOY_AST_FLAG_CONCAT = 42, //unary flags - TOY_AST_FLAG_NEGATE = 33, - TOY_AST_FLAG_INCREMENT = 34, - TOY_AST_FLAG_DECREMENT = 35, + TOY_AST_FLAG_NEGATE = 43, + TOY_AST_FLAG_INCREMENT = 44, + TOY_AST_FLAG_DECREMENT = 45, // TOY_AST_FLAG_TERNARY, } Toy_AstFlag; @@ -105,6 +109,13 @@ typedef struct Toy_AstGroup { Toy_Ast* child; } Toy_AstGroup; +typedef struct Toy_AstCompound { + Toy_AstType type; + Toy_AstFlag flag; + Toy_Ast* left; + Toy_Ast* right; +} Toy_AstCompound; + typedef struct Toy_AstPrint { Toy_AstType type; Toy_Ast* child; @@ -148,6 +159,7 @@ union Toy_Ast { //32 | 64 BITNESS Toy_AstBinary binary; //16 | 24 Toy_AstCompare compare; //16 | 24 Toy_AstGroup group; //8 | 16 + Toy_AstCompound compound; //16 | 24 Toy_AstPrint print; //8 | 16 Toy_AstVarDeclare varDeclare; //16 | 24 Toy_AstVarAssign varAssign; //16 | 24 @@ -165,6 +177,7 @@ void Toy_private_emitAstUnary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, To 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_emitAstCompound(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right); void Toy_private_emitAstPrint(Toy_Bucket** bucketHandle, Toy_Ast** astHandle); diff --git a/source/toy_opcodes.h b/source/toy_opcodes.h index 9e9c205..66f9f69 100644 --- a/source/toy_opcodes.h +++ b/source/toy_opcodes.h @@ -39,6 +39,7 @@ typedef enum Toy_OpcodeType { //various action instructions TOY_OPCODE_PRINT, TOY_OPCODE_CONCAT, + TOY_OPCODE_INDEX, //TODO: clear the program stack? //meta instructions diff --git a/source/toy_parser.c b/source/toy_parser.c index f3c43e1..5c1f959 100644 --- a/source/toy_parser.c +++ b/source/toy_parser.c @@ -116,6 +116,7 @@ static Toy_AstFlag literal(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_As 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); static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle); +static Toy_AstFlag compound(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle); //precedence definitions static ParsingTuple parsingRulesetTable[] = { @@ -194,7 +195,7 @@ static ParsingTuple parsingRulesetTable[] = { //structural operators {PREC_NONE,group,NULL},// TOY_TOKEN_OPERATOR_PAREN_LEFT, {PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_PAREN_RIGHT, - {PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACKET_LEFT, + {PREC_CALL,NULL,compound},// TOY_TOKEN_OPERATOR_BRACKET_LEFT, {PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACKET_RIGHT, {PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_LEFT, {PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_RIGHT, @@ -207,7 +208,7 @@ static ParsingTuple parsingRulesetTable[] = { {PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_COLON, {PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_SEMICOLON, // ; - {PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_COMMA, // , + {PREC_CALL,NULL,compound},// TOY_TOKEN_OPERATOR_COMMA, // , {PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_DOT, // . {PREC_CALL,NULL,binary},// TOY_TOKEN_OPERATOR_CONCAT, // .. @@ -557,6 +558,26 @@ static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast* return TOY_AST_FLAG_NONE; } +static Toy_AstFlag compound(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) { + //infix must advance + advance(parser); + + if (parser->previous.type == TOY_TOKEN_OPERATOR_COMMA) { + parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT + 1); + return TOY_AST_FLAG_COMPOUND_COLLECTION; + } + else if (parser->previous.type == TOY_TOKEN_OPERATOR_BRACKET_LEFT) { + parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT + 1); + consume(parser, TOY_TOKEN_OPERATOR_BRACKET_RIGHT, "Expected ']' at the end of index expression"); + return TOY_AST_FLAG_COMPOUND_INDEX; + } + else { + printError(parser, parser->previous, "Unexpected token passed to compound precedence rule"); + Toy_private_emitAstError(bucketHandle, rootHandle); + return TOY_AST_FLAG_NONE; + } +} + static ParsingTuple* getParsingRule(Toy_TokenType type) { return &parsingRulesetTable[type]; } @@ -605,6 +626,7 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A (*rootHandle) = ptr; return; } + //eww, gross else if (flag >= 10 && flag <= 19) { Toy_String* name = Toy_createNameStringLength(bucketHandle, prevToken.lexeme, prevToken.length, TOY_VALUE_UNKNOWN, false); Toy_private_emitAstVariableAssignment(bucketHandle, rootHandle, name, flag, ptr); @@ -612,6 +634,9 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A else if (flag >= 20 && flag <= 29) { Toy_private_emitAstCompare(bucketHandle, rootHandle, flag, ptr); } + else if (flag >= 30 && flag <= 39) { + Toy_private_emitAstCompound(bucketHandle, rootHandle, flag, ptr); + } else { Toy_private_emitAstBinary(bucketHandle, rootHandle, flag, ptr); } diff --git a/source/toy_routine.c b/source/toy_routine.c index 3b375ee..9ff1297 100644 --- a/source/toy_routine.c +++ b/source/toy_routine.c @@ -58,7 +58,7 @@ static void emitToJumpTable(Toy_Routine** rt, unsigned int startAddr) { EMIT_INT(rt, jumps, startAddr); //save address at the jump index } -static void emitString(Toy_Routine** rt, Toy_String* str) { +static unsigned int emitString(Toy_Routine** rt, Toy_String* str) { //4-byte alignment unsigned int length = str->length + 1; if (length % 4 != 0) { @@ -87,11 +87,13 @@ static void emitString(Toy_Routine** rt, Toy_String* str) { //mark the jump position emitToJumpTable(rt, startAddr); + + return 1; } -static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast); //forward declare for recursion +static unsigned int writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast); //forward declare for recursion -static void writeInstructionValue(Toy_Routine** rt, Toy_AstValue ast) { +static unsigned int writeInstructionValue(Toy_Routine** rt, Toy_AstValue ast) { EMIT_BYTE(rt, code, TOY_OPCODE_READ); EMIT_BYTE(rt, code, ast.value.type); @@ -128,17 +130,19 @@ static void writeInstructionValue(Toy_Routine** rt, Toy_AstValue ast) { 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)); + return emitString(rt, TOY_VALUE_AS_STRING(ast.value)); } else { fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST type found: Unknown value type\n" TOY_CC_RESET); exit(-1); } + + return 1; } -static void writeInstructionUnary(Toy_Routine** rt, Toy_AstUnary ast) { +static unsigned int writeInstructionUnary(Toy_Routine** rt, Toy_AstUnary ast) { //working with a stack means the child gets placed first - writeRoutineCode(rt, ast.child); + unsigned int result = writeRoutineCode(rt, ast.child); if (ast.flag == TOY_AST_FLAG_NEGATE) { EMIT_BYTE(rt, code, TOY_OPCODE_NEGATE); @@ -152,9 +156,11 @@ static void writeInstructionUnary(Toy_Routine** rt, Toy_AstUnary ast) { fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST unary flag found\n" TOY_CC_RESET); exit(-1); } + + return result; } -static void writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) { +static unsigned int writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) { //left, then right, then the binary's operation writeRoutineCode(rt, ast.left); writeRoutineCode(rt, ast.right); @@ -194,9 +200,11 @@ static void writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) { EMIT_BYTE(rt, code,TOY_OPCODE_PASS); //checked in compound assignments EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); + + return 1; //leaves only 1 value on the stack } -static void writeInstructionCompare(Toy_Routine** rt, Toy_AstCompare ast) { +static unsigned int writeInstructionCompare(Toy_Routine** rt, Toy_AstCompare ast) { //left, then right, then the compare's operation writeRoutineCode(rt, ast.left); writeRoutineCode(rt, ast.right); @@ -210,7 +218,7 @@ static void writeInstructionCompare(Toy_Routine** rt, Toy_AstCompare ast) { EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); - return; + return 1; } else if (ast.flag == TOY_AST_FLAG_COMPARE_LESS) { EMIT_BYTE(rt, code,TOY_OPCODE_COMPARE_LESS); @@ -234,13 +242,45 @@ static void writeInstructionCompare(Toy_Routine** rt, Toy_AstCompare ast) { EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); + + return 1; //leaves only 1 value on the stack } -static void writeInstructionGroup(Toy_Routine** rt, Toy_AstGroup ast) { - writeRoutineCode(rt, ast.child); +static unsigned int writeInstructionGroup(Toy_Routine** rt, Toy_AstGroup ast) { + //not certain what this leaves + return writeRoutineCode(rt, ast.child); } -static void writeInstructionPrint(Toy_Routine** rt, Toy_AstPrint ast) { +static unsigned int writeInstructionCompound(Toy_Routine** rt, Toy_AstCompound ast) { + unsigned int result = 0; + + //left, then right + result += writeRoutineCode(rt, ast.left); + result += writeRoutineCode(rt, ast.right); + + if (ast.flag == TOY_AST_FLAG_COMPOUND_COLLECTION) { + //collections are handled above + return result; + } + else if (ast.flag == TOY_AST_FLAG_COMPOUND_INDEX) { + //value[index, length] + EMIT_BYTE(rt, code, TOY_OPCODE_INDEX); + EMIT_BYTE(rt, code, result); + + //4-byte alignment + EMIT_BYTE(rt, code,0); + EMIT_BYTE(rt, code,0); + + return 1; //leaves only 1 value on the stack + } + else { + fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST compound flag found\n" TOY_CC_RESET); + exit(-1); + return 0; + } +} + +static unsigned int writeInstructionPrint(Toy_Routine** rt, Toy_AstPrint ast) { //the thing to print writeRoutineCode(rt, ast.child); @@ -251,9 +291,11 @@ static void writeInstructionPrint(Toy_Routine** rt, Toy_AstPrint ast) { EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); + + return 0; } -static void writeInstructionVarDeclare(Toy_Routine** rt, Toy_AstVarDeclare ast) { +static unsigned int writeInstructionVarDeclare(Toy_Routine** rt, Toy_AstVarDeclare ast) { //initial value writeRoutineCode(rt, ast.expr); @@ -264,9 +306,13 @@ static void writeInstructionVarDeclare(Toy_Routine** rt, Toy_AstVarDeclare ast) EMIT_BYTE(rt, code, Toy_getNameStringConstant(ast.name) ? 1 : 0); //check for constness emitString(rt, ast.name); + + return 0; } -static void writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) { +static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) { + unsigned int result = 0; + //name, duplicate, right, opcode if (ast.flag == TOY_AST_FLAG_ASSIGN) { EMIT_BYTE(rt, code, TOY_OPCODE_READ); @@ -275,7 +321,7 @@ static void writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) { EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255) emitString(rt, ast.name); - writeRoutineCode(rt, ast.expr); + result += writeRoutineCode(rt, ast.expr); EMIT_BYTE(rt, code, TOY_OPCODE_ASSIGN); EMIT_BYTE(rt, code, 0); @@ -293,7 +339,7 @@ static void writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) { EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); - writeRoutineCode(rt, ast.expr); + result += writeRoutineCode(rt, ast.expr); EMIT_BYTE(rt, code,TOY_OPCODE_ADD); EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed @@ -311,7 +357,7 @@ static void writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) { EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); - writeRoutineCode(rt, ast.expr); + result += writeRoutineCode(rt, ast.expr); EMIT_BYTE(rt, code,TOY_OPCODE_SUBTRACT); EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed @@ -329,7 +375,7 @@ static void writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) { EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); - writeRoutineCode(rt, ast.expr); + result += writeRoutineCode(rt, ast.expr); EMIT_BYTE(rt, code,TOY_OPCODE_MULTIPLY); EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed @@ -347,7 +393,7 @@ static void writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) { EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); - writeRoutineCode(rt, ast.expr); + result += writeRoutineCode(rt, ast.expr); EMIT_BYTE(rt, code,TOY_OPCODE_DIVIDE); EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed @@ -365,7 +411,7 @@ static void writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) { EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); - writeRoutineCode(rt, ast.expr); + result += writeRoutineCode(rt, ast.expr); EMIT_BYTE(rt, code,TOY_OPCODE_MODULO); EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed @@ -379,9 +425,11 @@ static void writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) { //4-byte alignment EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); + + return result; } -static void writeInstructionAccess(Toy_Routine** rt, Toy_AstVarAccess ast) { +static unsigned int writeInstructionAccess(Toy_Routine** rt, Toy_AstVarAccess ast) { //push the name EMIT_BYTE(rt, code, TOY_OPCODE_READ); EMIT_BYTE(rt, code, TOY_VALUE_STRING); @@ -395,6 +443,8 @@ static void writeInstructionAccess(Toy_Routine** rt, Toy_AstVarAccess ast) { EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); EMIT_BYTE(rt, code,0); + + return 1; } //routine structure @@ -402,11 +452,13 @@ static void writeInstructionAccess(Toy_Routine** rt, Toy_AstVarAccess ast) { // // // } -static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) { +static unsigned int writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) { if (ast == NULL) { - return; + return 0; } + unsigned int result = 0; + //determine how to write each instruction based on the Ast switch(ast->type) { case TOY_AST_BLOCK: @@ -417,8 +469,8 @@ static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) { EMIT_BYTE(rt, code, 0); } - writeRoutineCode(rt, ast->block.child); - writeRoutineCode(rt, ast->block.next); + result += writeRoutineCode(rt, ast->block.child); + result += writeRoutineCode(rt, ast->block.next); if (ast->block.innerScope) { EMIT_BYTE(rt, code, TOY_OPCODE_SCOPE_POP); @@ -429,39 +481,43 @@ static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) { break; case TOY_AST_VALUE: - writeInstructionValue(rt, ast->value); + result += writeInstructionValue(rt, ast->value); break; case TOY_AST_UNARY: - writeInstructionUnary(rt, ast->unary); + result += writeInstructionUnary(rt, ast->unary); break; case TOY_AST_BINARY: - writeInstructionBinary(rt, ast->binary); + result += writeInstructionBinary(rt, ast->binary); break; case TOY_AST_COMPARE: - writeInstructionCompare(rt, ast->compare); + result += writeInstructionCompare(rt, ast->compare); break; case TOY_AST_GROUP: - writeInstructionGroup(rt, ast->group); + result += writeInstructionGroup(rt, ast->group); + break; + + case TOY_AST_COMPOUND: + result += writeInstructionCompound(rt, ast->compound); break; case TOY_AST_PRINT: - writeInstructionPrint(rt, ast->print); + result += writeInstructionPrint(rt, ast->print); break; case TOY_AST_VAR_DECLARE: - writeInstructionVarDeclare(rt, ast->varDeclare); + result += writeInstructionVarDeclare(rt, ast->varDeclare); break; case TOY_AST_VAR_ASSIGN: - writeInstructionAssign(rt, ast->varAssign); + result += writeInstructionAssign(rt, ast->varAssign); break; case TOY_AST_VAR_ACCESS: - writeInstructionAccess(rt, ast->varAccess); + result += writeInstructionAccess(rt, ast->varAccess); break; //meta instructions are disallowed @@ -481,6 +537,8 @@ static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) { exit(-1); break; } + + return result; } static void* writeRoutine(Toy_Routine* rt, Toy_Ast* ast) { diff --git a/source/toy_vm.c b/source/toy_vm.c index 95206d8..a0d5f44 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -420,6 +420,74 @@ static void processConcat(Toy_VM* vm) { Toy_pushStack(&vm->stack, TOY_VALUE_FROM_STRING(result)); } +static void processIndex(Toy_VM* vm) { + unsigned char count = READ_BYTE(vm); //value[index, length] ; 1[2, 3] + + Toy_Value value = TOY_VALUE_FROM_NULL(); + Toy_Value index = TOY_VALUE_FROM_NULL(); + Toy_Value length = TOY_VALUE_FROM_NULL(); + + if (count == 3) { + length = Toy_popStack(&vm->stack); + index = Toy_popStack(&vm->stack); + value = Toy_popStack(&vm->stack); + } + else if (count == 2) { + index = Toy_popStack(&vm->stack); + value = Toy_popStack(&vm->stack); + } + else { + Toy_error("Incorrect number of elements found in index"); + //TODO: clear stack + return; + } + + //process based on value's type + if (TOY_VALUE_IS_STRING(value)) { + //type checks + if (!TOY_VALUE_IS_INTEGER(index)) { + Toy_error("Failed to index a string"); + return; + } + + if (!(TOY_VALUE_IS_NULL(length) || TOY_VALUE_IS_INTEGER(length))) { + Toy_error("Failed to index-length a string"); + return; + } + + //extract values + int i = TOY_VALUE_AS_INTEGER(index); + int l = TOY_VALUE_IS_INTEGER(length) ? TOY_VALUE_AS_INTEGER(length) : 1; + + //extract string + Toy_String* str = TOY_VALUE_AS_STRING(value); + Toy_String* result = NULL; + + //extract cstring, based on type + if (str->type == TOY_STRING_LEAF) { + const char* cstr = str->as.leaf.data; + result = Toy_createStringLength(&vm->stringBucket, cstr + i, l); + } + else if (str->type == TOY_STRING_NODE) { + char* cstr = Toy_getStringRawBuffer(str); + result = Toy_createStringLength(&vm->stringBucket, cstr + i, l); + free(cstr); + } + else { + fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown string type found in processIndex, exiting\n" TOY_CC_RESET); + exit(-1); + } + + //finally + Toy_pushStack(&vm->stack, TOY_VALUE_FROM_STRING(result)); + } + + else { + fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown value type %d found in processIndex, exiting\n" TOY_CC_RESET, value.type); + exit(-1); + } +} + static void process(Toy_VM* vm) { while(true) { Toy_OpcodeType opcode = READ_BYTE(vm); @@ -494,6 +562,10 @@ static void process(Toy_VM* vm) { processConcat(vm); break; + case TOY_OPCODE_INDEX: + processIndex(vm); + break; + case TOY_OPCODE_PASS: case TOY_OPCODE_ERROR: case TOY_OPCODE_EOF: diff --git a/tests/cases/test_ast.c b/tests/cases/test_ast.c index 903a1a4..7b76119 100644 --- a/tests/cases/test_ast.c +++ b/tests/cases/test_ast.c @@ -22,6 +22,7 @@ int test_sizeof_ast_64bit() { TEST_SIZEOF(Toy_AstBinary, 24); TEST_SIZEOF(Toy_AstCompare, 24); TEST_SIZEOF(Toy_AstGroup, 16); + TEST_SIZEOF(Toy_AstCompound, 24); TEST_SIZEOF(Toy_AstPrint, 16); TEST_SIZEOF(Toy_AstVarDeclare, 24); TEST_SIZEOF(Toy_AstVarAssign, 24); @@ -54,6 +55,7 @@ int test_sizeof_ast_32bit() { TEST_SIZEOF(Toy_AstBinary, 16); TEST_SIZEOF(Toy_AstCompare, 16); TEST_SIZEOF(Toy_AstGroup, 8); + TEST_SIZEOF(Toy_AstCompound, 16); TEST_SIZEOF(Toy_AstPrint, 8); TEST_SIZEOF(Toy_AstVarDeclare, 12); TEST_SIZEOF(Toy_AstVarAssign, 16); diff --git a/tests/integrations/test_print.toy b/tests/integrations/test_print.toy index e89846c..bd887dd 100644 --- a/tests/integrations/test_print.toy +++ b/tests/integrations/test_print.toy @@ -13,6 +13,11 @@ print "Hello" .. "world!"; //print with escaped characters print "\tHello\nworld"; +//print from a leaf string +print "Hello world"[0,5]; + +print ("hello" .. "world")[2,6]; + //TODO: in the repl, -s to supress output, or -d to print debugging info //TODO: the `assert` keyword will be useful for these