Quietly pretend we didn't just do that different from Python for no reason

This commit is contained in:
K. Lange 2021-01-03 09:29:09 +09:00
parent 7d8dfa2ffe
commit 93af369b8c
3 changed files with 31 additions and 46 deletions

View File

@ -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.

View File

@ -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) {

View File

@ -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")