diff --git a/README.md b/README.md index 03031bb..6cc5aed 100644 --- a/README.md +++ b/README.md @@ -642,17 +642,20 @@ f.theMethod("the newly required argument") # I also required this extra argument: the newly required argument ``` -Decorators may also take arguments in addition to the function to be wrapped: +Decorators are _expressions_, just like in Python, so to make a decorator with arguments create a function that takes those arguments and returns a decorator: ```py -def requirePassword(func, password): - print "I am wrapping", func, "and attaching",password - def wrapper(secretPassword): - if secretPassword != password: - print "You didn't say the magic word." - return - func() - return wrapper +def requirePassword(password): + print "I am creating a decorator." + def decorator(func): + print "I am wrapping", func, "and attaching",password + def wrapper(secretPassword): + if secretPassword != password: + print "You didn't say the magic word." + return + func() + return wrapper + return decorator @requirePassword("hunter2") def superSecretFunction(): @@ -667,8 +670,6 @@ superSecretFunction("hunter2") # Welcome! ``` -_**NOTE:** Arguments in decorators work differently from Python: In Python, decorators with arguments are functions which return a new decorator and _that_ decorator is applied to the wrapped function; in Kuroko, decorators with arguments are no different from those with out - the additional arguments are appended after the passed function._ - ## About the REPL Kuroko's repl provides an interactive environment for executing code and seeing results. diff --git a/compiler.c b/compiler.c index da8c5c2..7c1a0ed 100644 --- a/compiler.c +++ b/compiler.c @@ -802,20 +802,8 @@ static KrkToken decorator(size_t level, FunctionType type) { size_t blockWidth = (parser.previous.type == TOKEN_INDENTATION) ? parser.previous.length : 0; advance(); /* Collect the `@` */ - beginScope(); - /* Collect an identifier */ - consume(TOKEN_IDENTIFIER,"Expected a decorator name."); - variable(0); - size_t outputLocal = current->localCount; - - emitByte(OP_NONE); /* Space for the function */ - - /* See if we have an argument list */ - size_t argCount = 0; - if (match(TOKEN_LEFT_PAREN)) { - argCount = argumentList(); - } + expression(); consume(TOKEN_EOL, "Expected line feed after decorator."); if (blockWidth) { @@ -839,15 +827,7 @@ static KrkToken decorator(size_t level, FunctionType type) { error("Expected a function declaration or another decorator."); } - /* As a 'declaration' syntax element, we can always guarantee by the time we - * get to this point, we are at the current local level. */ - size_t argumentDestination = (type == TYPE_FUNCTION) ? (outputLocal + 1) : (outputLocal + 2); - EMIT_CONSTANT_OP(OP_SET_LOCAL, argumentDestination); - endScope(); - - emitByte(OP_POP); - - emitBytes(OP_CALL, 1 + argCount); + emitBytes(OP_CALL, 1); if (level == 0) { if (type == TYPE_FUNCTION) { diff --git a/test/testDecorators.krk b/test/testDecorators.krk index 49a52aa..146b650 100644 --- a/test/testDecorators.krk +++ b/test/testDecorators.krk @@ -72,12 +72,14 @@ print "Returned from f.undecorated()" f.decorated("butts") print "Returned from f.decorated()" -def decoratorWithArgument(func, decoratorArg): - print "I am decorating",func,"with this argument:",decoratorArg - def wrapped(): - print "This wrapper captured this decorator arg:", decoratorArg - func() - return wrapped +def decoratorWithArgument(decoratorArg): + def theActualDecorator(func): + print "I am decorating",func,"with this argument:",decoratorArg + def wrapped(): + print "This wrapper captured this decorator arg:", decoratorArg + func() + return wrapped + return theActualDecorator @decoratorWithArgument("foo") def decoratedWithArgument(): @@ -85,13 +87,15 @@ def decoratedWithArgument(): decoratedWithArgument() -def methodDecoratorWithArguments(method, decoratorArgA, decoratorArgB): - print "I am decorating", method, "with these args:", decoratorArgA, decoratorArgB - def wrapped(instance, wrapperArg): - print "I captured these from the decorator:", decoratorArgA, decoratorArgB - print "I also take my own argument:", wrapperArg - method(instance,"and modify this one") - return wrapped +def methodDecoratorWithArguments(decoratorArgA, decoratorArgB): + def theActualDecorator(method): + print "I am decorating", method, "with these args:", decoratorArgA, decoratorArgB + def wrapped(instance, wrapperArg): + print "I captured these from the decorator:", decoratorArgA, decoratorArgB + print "I also take my own argument:", wrapperArg + method(instance,"and modify this one") + return wrapped + return theActualDecorator class Bar(): @methodDecoratorWithArguments("foo","bar")