munificent / craftinginterpreters

Repository for the book "Crafting Interpreters"
http://www.craftinginterpreters.com/
Other
8.75k stars 1.03k forks source link

Implementation of postfix operators in clox #992

Closed SjVer closed 3 years ago

SjVer commented 3 years ago

After I finished the (absolute masterpiece of a) book I decided to build upon my implementation of clox. One of the things I want to do with it is implementing the postfix in- and decrement operators ++ and --.
I have however stumbled upon the following issue: how do I let the compiler or vm know if, and how to store the incremented value?
If the incremented thing is a variable (e.g. var a = 1; a++; where a should end up being 2 and keep that 2 on the stack to allow stuff like print a++;) I have no clue how to let the compiler or vm figure out how to store the incremented value again correctly.
And if the incremented thing is a number (e.g. print 3++; which should print 4) how do I let the compiler know that it's incrementing a number since the parser.previous variable then points to the ++ token?
This are the changes I've made to compiler.c so far:

[TOKEN_MINUS_MINUS]     = {NULL, postfix, PREC_CALL},
[TOKEN_PLUS_PLUS]   = {NULL, postfix, PREC_CALL},
// in the parserules
static void postfix(bool canAssign)
{
    switch (parser.previous.type)
    {
    case TOKEN_PLUS_PLUS:
        emitByte(OP_INCREMENT);
        break;
    case TOKEN_MINUS_MINUS:
        emitByte(OP_DECREMENT);
        break;
    default:
        return;
    }
}
// as a new function

and to vm.c:

        case OP_INCREMENT:
        {
            if(!IS_NUMBER(peek(0)))
            {
                runtimeError("Cannot increment non-numerical value '%s'.", valueToString(peek(0)));
                return INTERPRET_RUNTIME_ERROR;
            }
            push(NUMBER_VAL(AS_NUMBER(pop())+1));
            break;
        }
        case OP_DECREMENT:
        {
            if (!IS_NUMBER(peek(0)))
            {
                runtimeError("Cannot decrement non-numerical value '%s'.", valueToString(peek(0)));
                return INTERPRET_RUNTIME_ERROR;
            }
            push(NUMBER_VAL(AS_NUMBER(pop()) - 1));
            break;
        }
// in run()


Sadly I couldn't find much help online so I'd love to hear how I could tackle/approach this problem!
Thanks!

PS: Don't mind that valueToString() function, I've added it myself as well.

SjVer commented 3 years ago

nm i got it :)

mcfriend99 commented 3 years ago

While this doesn't look too bad, an edge case I am yet to see a clean and not so hacky solution is incrementing properties such as this.prop++ or instance.prop++. How do you plan to handle this?? The moment you add that consideration into the problem, this simple solution no longer suffice.

SjVer commented 3 years ago

I already found a different solution :)