mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Postfix '++' & '--' works (prefix & postfix are both tested)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user