Postfix '++' & '--' works (prefix & postfix are both tested)

This commit is contained in:
2025-01-09 18:33:10 +11:00
parent 6f16c31f24
commit 14696833fd
6 changed files with 140 additions and 16 deletions

View File

@@ -1,8 +1,8 @@
//standard example, using 'while' instead of 'for', because it's not ready yet
var counter: int = 1;
var counter: int = 0;
while (counter <= 100) {
while (++counter <= 100) {
var result: string = "";
if (counter % 3 == 0) {
@@ -20,7 +20,5 @@ while (counter <= 100) {
else {
print counter;
}
counter += 1;
}

View File

@@ -9,5 +9,18 @@
assert --a == 42;
assert a == 42;
print a;
}
//increment & decrement (postfix)
{
var a = 42;
assert a == 42;
assert a++ == 42;
assert a == 43;
assert a-- == 43;
assert a == 42;
print a;
}

View File

@@ -46,6 +46,10 @@ typedef enum Toy_AstFlag {
TOY_AST_FLAG_DIVIDE = 4,
TOY_AST_FLAG_MODULO = 5,
TOY_AST_FLAG_AND = 6,
TOY_AST_FLAG_OR = 7,
TOY_AST_FLAG_CONCAT = 8,
TOY_AST_FLAG_ASSIGN = 10,
TOY_AST_FLAG_ADD_ASSIGN = 11,
TOY_AST_FLAG_SUBTRACT_ASSIGN = 12,
@@ -66,14 +70,12 @@ typedef enum Toy_AstFlag {
TOY_AST_FLAG_PAIR = 33,
TOY_AST_FLAG_INDEX = 34,
TOY_AST_FLAG_AND = 40,
TOY_AST_FLAG_OR = 41,
TOY_AST_FLAG_CONCAT = 42,
//unary flags
TOY_AST_FLAG_NEGATE = 43,
TOY_AST_FLAG_PREFIX_INCREMENT = 44,
TOY_AST_FLAG_PREFIX_DECREMENT = 45,
TOY_AST_FLAG_NEGATE = 40,
TOY_AST_FLAG_PREFIX_INCREMENT = 41,
TOY_AST_FLAG_PREFIX_DECREMENT = 42,
TOY_AST_FLAG_POSTFIX_INCREMENT = 43,
TOY_AST_FLAG_POSTFIX_DECREMENT = 44,
// TOY_AST_FLAG_TERNARY,
} Toy_AstFlag;

View File

@@ -119,6 +119,7 @@ static Toy_AstFlag binary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
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);
static Toy_AstFlag aggregate(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
static Toy_AstFlag unaryPostfix(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
//precedence definitions
static ParsingTuple parsingRulesetTable[] = {
@@ -180,8 +181,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_CALL,unary,NULL},// TOY_TOKEN_OPERATOR_INCREMENT,
{PREC_CALL,unary,NULL},// TOY_TOKEN_OPERATOR_DECREMENT,
{PREC_CALL,unary,unaryPostfix},// TOY_TOKEN_OPERATOR_INCREMENT,
{PREC_CALL,unary,unaryPostfix},// TOY_TOKEN_OPERATOR_DECREMENT,
{PREC_ASSIGNMENT,NULL,binary},// TOY_TOKEN_OPERATOR_ASSIGN,
//comparator operators
@@ -223,6 +224,10 @@ static ParsingTuple parsingRulesetTable[] = {
{PREC_NONE,NULL,NULL},// TOY_TOKEN_EOF,
};
static ParsingTuple* getParsingRule(Toy_TokenType type) {
return &parsingRulesetTable[type];
}
static Toy_ValueType readType(Toy_Parser* parser) {
advance(parser);
@@ -429,7 +434,7 @@ static Toy_AstFlag unary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast*
//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");
printError(parser, parser->previous, "Unexpected non-name-string token in unary-prefix operator precedence rule");
Toy_private_emitAstError(bucketHandle, rootHandle);
}
else {
@@ -666,8 +671,41 @@ static Toy_AstFlag aggregate(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_
}
}
static ParsingTuple* getParsingRule(Toy_TokenType type) {
return &parsingRulesetTable[type];
static Toy_AstFlag unaryPostfix(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
//grab the var name, rejecting any other token types
if (parser->previous.type != TOY_TOKEN_NAME) {
printError(parser, parser->previous, "Unexpected parameter passed to unary-postfix precedence rule");
Toy_private_emitAstError(bucketHandle, rootHandle);
return TOY_AST_FLAG_NONE;
}
Toy_Ast* primary = NULL;
ParsingRule nameRule = getParsingRule(parser->previous.type)->prefix;
nameRule(bucketHandle, parser, &primary); //this is to skip the call to advance() at the beginning of parsePrecedence()
//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-postfix operator precedence rule");
Toy_private_emitAstError(bucketHandle, rootHandle);
return TOY_AST_FLAG_NONE;
}
(*rootHandle) = primary->varAccess.child;
//output the postfix AST
if (match(parser, TOY_TOKEN_OPERATOR_INCREMENT)) {
Toy_private_emitAstUnary(bucketHandle, rootHandle, TOY_AST_FLAG_POSTFIX_INCREMENT);
return TOY_AST_FLAG_POSTFIX_INCREMENT;
}
else if (match(parser, TOY_TOKEN_OPERATOR_DECREMENT)) {
Toy_private_emitAstUnary(bucketHandle, rootHandle, TOY_AST_FLAG_POSTFIX_DECREMENT);
return TOY_AST_FLAG_POSTFIX_DECREMENT;
}
else {
printError(parser, parser->previous, "Unexpected token passed to unary-postfix precedence rule");
Toy_private_emitAstError(bucketHandle, rootHandle);
return TOY_AST_FLAG_NONE;
}
}
//grammar rules
@@ -721,6 +759,10 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
else if (flag >= 30 && flag <= 39) {
Toy_private_emitAstAggregate(bucketHandle, rootHandle, flag, ptr);
}
else if (flag >= 40 && flag <= 49) {
(*rootHandle) = ptr;
continue;
}
else {
//BUGFIX: '&&' and '||' are special cases, with short-circuit logic
if (flag == TOY_AST_FLAG_AND || flag == TOY_AST_FLAG_OR) {

View File

@@ -224,6 +224,63 @@ static unsigned int writeInstructionUnary(Toy_Routine** rt, Toy_AstUnary ast) {
result = 1;
}
else if (ast.flag == TOY_AST_FLAG_POSTFIX_INCREMENT || ast.flag == TOY_AST_FLAG_POSTFIX_DECREMENT) { //NOTE: ditto
//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);
//access the value (postfix++ and postfix--)
EMIT_BYTE(rt, code, TOY_OPCODE_ACCESS);
EMIT_BYTE(rt, code,0);
EMIT_BYTE(rt, code,0);
EMIT_BYTE(rt, code,0);
//read the var name onto the stack (again)
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_POSTFIX_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);
//remove the lingering value (yep, this is UGLY)
EMIT_BYTE(rt, code, TOY_OPCODE_ELIMINATE);
EMIT_BYTE(rt, code,0);
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);

View File

@@ -145,4 +145,16 @@ print !false; //true
assert a == 42, "prefix increment & decrement 1.5";
}
//increment & decrement (postfix)
{
var a = 42;
assert a == 42, "postfix increment & decrement 1.1";
assert a++ == 42, "postfix increment & decrement 1.2";
assert a == 43, "postfix increment & decrement 1.3";
assert a-- == 43, "postfix increment & decrement 1.4";
assert a == 42, "postfix increment & decrement 1.5";
print a;
}
//TODO: type casting