From 6f16c31f248c9a0579bd9d2e1fbe615d7e83e1b5 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Thu, 9 Jan 2025 16:45:48 +1100 Subject: [PATCH] Prefix '++' working (postfix is next) --- .notes/misc.txt | 3 ++ scripts/valgrind.toy | 71 ++++----------------------- source/toy_ast.h | 4 +- source/toy_parser.c | 24 ++++++++- source/toy_routine.c | 41 +++++++++++++++- source/toy_vm.c | 2 +- tests/integrations/test_variables.toy | 36 +++++++++----- 7 files changed, 102 insertions(+), 79 deletions(-) create mode 100644 .notes/misc.txt diff --git a/.notes/misc.txt b/.notes/misc.txt new file mode 100644 index 0000000..2185392 --- /dev/null +++ b/.notes/misc.txt @@ -0,0 +1,3 @@ +type coercion +permanent strings? +concat & free? (strings) diff --git a/scripts/valgrind.toy b/scripts/valgrind.toy index 3342a26..6c056d3 100644 --- a/scripts/valgrind.toy +++ b/scripts/valgrind.toy @@ -1,64 +1,13 @@ -//logical short-circuits and chained assignments -//logical AND + +//increment & decrement (prefix) { - var a = 1; - var b = 2; - var c = a + 1 && b + 2; + var a = 42; + assert a == 42; + assert ++a == 43; + assert a == 43; + assert --a == 42; + assert a == 42; - assert a == 1, "short circuit 1.1"; - assert b == 2, "short circuit 1.2"; - assert c == 4, "short circuit 1.3"; -} - -{ - var a = 1; - var b = 2; - var c = a = (a + 1) && b + 2; - - assert a == 4, "short circuit 2.1"; - assert b == 2, "short circuit 2.2"; - assert c == 4, "short circuit 2.3"; -} - -{ - var a = 1; - var b = 2; - var c = a = a + 1 && b + 2; - - assert a == 4, "short circuit 3.1"; - assert b == 2, "short circuit 3.2"; - assert c == 4, "short circuit 3.3"; -} - - -//logical OR -{ - var a = 1; - var b = 2; - var c = a + 1 || b + 2; - - assert a == 1, "short circuit 4.1"; - assert b == 2, "short circuit 4.2"; - assert c == 2, "short circuit 4.3"; -} - -{ - var a = 1; - var b = 2; - var c = a = (a + 1) || b + 2; - - assert a == 2, "short circuit 5.1"; - assert b == 2, "short circuit 5.2"; - assert c == 2, "short circuit 5.3"; -} - -{ - var a = 1; - var b = 2; - var c = a = a + 1 || b + 2; - - assert a == 2, "short circuit 6.1"; - assert b == 2, "short circuit 6.2"; - assert c == 2, "short circuit 6.3"; -} + print a; +} \ No newline at end of file diff --git a/source/toy_ast.h b/source/toy_ast.h index 3b371af..5a1fd83 100644 --- a/source/toy_ast.h +++ b/source/toy_ast.h @@ -72,8 +72,8 @@ typedef enum Toy_AstFlag { //unary flags TOY_AST_FLAG_NEGATE = 43, - TOY_AST_FLAG_INCREMENT = 44, - TOY_AST_FLAG_DECREMENT = 45, + TOY_AST_FLAG_PREFIX_INCREMENT = 44, + TOY_AST_FLAG_PREFIX_DECREMENT = 45, // TOY_AST_FLAG_TERNARY, } Toy_AstFlag; diff --git a/source/toy_parser.c b/source/toy_parser.c index 0f90a73..cccbf6f 100644 --- a/source/toy_parser.c +++ b/source/toy_parser.c @@ -180,8 +180,8 @@ static ParsingTuple parsingRulesetTable[] = { {PREC_ASSIGNMENT,NULL,binary},// TOY_TOKEN_OPERATOR_MULTIPLY_ASSIGN, {PREC_ASSIGNMENT,NULL,binary},// TOY_TOKEN_OPERATOR_DIVIDE_ASSIGN, {PREC_ASSIGNMENT,NULL,binary},// TOY_TOKEN_OPERATOR_MODULO_ASSIGN, - {PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_INCREMENT, - {PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_DECREMENT, + {PREC_CALL,unary,NULL},// TOY_TOKEN_OPERATOR_INCREMENT, + {PREC_CALL,unary,NULL},// TOY_TOKEN_OPERATOR_DECREMENT, {PREC_ASSIGNMENT,NULL,binary},// TOY_TOKEN_OPERATOR_ASSIGN, //comparator operators @@ -419,6 +419,26 @@ static Toy_AstFlag unary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast* Toy_private_emitAstUnary(bucketHandle, rootHandle, TOY_AST_FLAG_NEGATE); } + else if (parser->previous.type == TOY_TOKEN_OPERATOR_INCREMENT || parser->previous.type == TOY_TOKEN_OPERATOR_DECREMENT) { + Toy_AstFlag flag = parser->previous.type == TOY_TOKEN_OPERATOR_INCREMENT ? TOY_AST_FLAG_PREFIX_INCREMENT : TOY_AST_FLAG_PREFIX_DECREMENT; + + //grab the info below + Toy_Ast* primary = NULL; + + parsePrecedence(bucketHandle, parser, &primary, PREC_PRIMARY); + + //double check it's a name string within an access NOTE: doing some fiddling with the existing AST here + if (primary->type != TOY_AST_VAR_ACCESS || primary->varAccess.child->type != TOY_AST_VALUE || TOY_VALUE_IS_STRING(primary->varAccess.child->value.value) != true || TOY_VALUE_AS_STRING(primary->varAccess.child->value.value)->info.type != TOY_STRING_NAME) { + printError(parser, parser->previous, "Unexpected non-name-string token in unary operator increment precedence rule"); + Toy_private_emitAstError(bucketHandle, rootHandle); + } + else { + //swap the varAccess for a unary prefix, as the latter leaves the value on the stack + *rootHandle = primary->varAccess.child; + Toy_private_emitAstUnary(bucketHandle, rootHandle, flag); + } + } + else { printError(parser, parser->previous, "Unexpected token passed to unary precedence rule"); Toy_private_emitAstError(bucketHandle, rootHandle); diff --git a/source/toy_routine.c b/source/toy_routine.c index 82d5eb3..4cd46e8 100644 --- a/source/toy_routine.c +++ b/source/toy_routine.c @@ -176,10 +176,11 @@ static unsigned int writeInstructionValue(Toy_Routine** rt, Toy_AstValue ast) { } static unsigned int writeInstructionUnary(Toy_Routine** rt, Toy_AstUnary ast) { - //working with a stack means the child gets placed first - unsigned int result = writeRoutineCode(rt, ast.child); + unsigned int result = 0; if (ast.flag == TOY_AST_FLAG_NEGATE) { + result = writeRoutineCode(rt, ast.child); + EMIT_BYTE(rt, code, TOY_OPCODE_NEGATE); //4-byte alignment @@ -187,6 +188,42 @@ static unsigned int writeInstructionUnary(Toy_Routine** rt, Toy_AstUnary ast) { EMIT_BYTE(rt, code, 0); EMIT_BYTE(rt, code, 0); } + + else if (ast.flag == TOY_AST_FLAG_PREFIX_INCREMENT || ast.flag == TOY_AST_FLAG_PREFIX_DECREMENT) { //NOTE: tightly coupled to the parser's logic, and somewhat duplicates ACCESS + //read the var name onto the stack + Toy_String* name = TOY_VALUE_AS_STRING(ast.child->value.value); + + 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, name->info.length); //store the length (max 255) + + emitString(rt, name); + + //duplicate the var name, then get the value + EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE); + EMIT_BYTE(rt, code, TOY_OPCODE_ACCESS); //squeezed + EMIT_BYTE(rt, code, 0); + EMIT_BYTE(rt, code, 0); + + //read the integer '1' + EMIT_BYTE(rt, code, TOY_OPCODE_READ); + EMIT_BYTE(rt, code, TOY_VALUE_INTEGER); + EMIT_BYTE(rt, code, 0); + EMIT_BYTE(rt, code, 0); + + EMIT_INT(rt, code, 1); + + //add (or subtract) the two values, then assign (pops the second duplicate, and leaves value on the stack) + EMIT_BYTE(rt, code, ast.flag == TOY_AST_FLAG_PREFIX_INCREMENT ? TOY_OPCODE_ADD : TOY_OPCODE_SUBTRACT); + EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed + EMIT_BYTE(rt, code,0); + EMIT_BYTE(rt, code,0); + + //leaves one value on the stack + result = 1; + } + else { fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST unary flag found\n" TOY_CC_RESET); exit(-1); diff --git a/source/toy_vm.c b/source/toy_vm.c index b89666b..974b4d5 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -307,7 +307,7 @@ static void processAccess(Toy_VM* vm) { Toy_Value name = Toy_popStack(&vm->stack); //check name string type - if (!TOY_VALUE_IS_STRING(name) && TOY_VALUE_AS_STRING(name)->info.type != TOY_STRING_NAME) { + if (!TOY_VALUE_IS_STRING(name) || TOY_VALUE_AS_STRING(name)->info.type != TOY_STRING_NAME) { Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL()); Toy_error("Invalid access target"); return; diff --git a/tests/integrations/test_variables.toy b/tests/integrations/test_variables.toy index 6d5ea30..f434ffe 100644 --- a/tests/integrations/test_variables.toy +++ b/tests/integrations/test_variables.toy @@ -112,23 +112,37 @@ print !false; //true } //types -var a: int; -var b: int = 42; +{ + var a: int; + var b: int = 42; -a = 69; -b = 8891; + a = 69; + b = 8891; -print a; -print b; + print a; + print b; +} //constants -var c: int const = 42; - -print c; +{ + var c: int const = 42; + print c; +} //indexing -var s = "Hello" .. "world!"; +{ + var s = "Hello" .. "world!"; + print s[3, 3]; +} -print s[3, 3]; +//increment & decrement (prefix) +{ + var a = 42; + assert a == 42, "prefix increment & decrement 1.1"; + assert ++a == 43, "prefix increment & decrement 1.2"; + assert a == 43, "prefix increment & decrement 1.3"; + assert --a == 42, "prefix increment & decrement 1.4"; + assert a == 42, "prefix increment & decrement 1.5"; +} //TODO: type casting