Skip to content

Commit

Permalink
Bind local name for decorated function early so it can be closed
Browse files Browse the repository at this point in the history
  • Loading branch information
klange committed Dec 12, 2023
1 parent 0425bec commit f247bba
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 4 deletions.
22 changes: 18 additions & 4 deletions src/compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -1847,6 +1847,10 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType
if (identifiersEqual(&at_classmethod, &state->parser.current)) type = TYPE_CLASSMETHOD;
}

if (level == 0 && inType == TYPE_FUNCTION && state->current->scopeDepth != 0) {
emitByte(OP_NONE);
}

expression(state);

consume(TOKEN_EOL, "Expected end of line after decorator.");
Expand All @@ -1863,6 +1867,10 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType
if (type == TYPE_METHOD && funcName.length == 8 && !memcmp(funcName.start,"__init__",8)) {
type = TYPE_INIT;
}
if (type == TYPE_FUNCTION && state->current->scopeDepth > 0) {
declareVariable(state);
markInitialized(state);
}
function(state, type, blockWidth);
} else if (match(TOKEN_ASYNC)) {
if (!match(TOKEN_DEF)) {
Expand All @@ -1871,6 +1879,10 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType
}
consume(TOKEN_IDENTIFIER, "Expected coroutine name after 'def'.");
funcName = state->parser.previous;
if (type == TYPE_FUNCTION && state->current->scopeDepth > 0) {
declareVariable(state);
markInitialized(state);
}
function(state, type == TYPE_METHOD ? TYPE_COROUTINE_METHOD : TYPE_COROUTINE, blockWidth);
} else if (check(TOKEN_AT)) {
funcName = decorator(state, level+1, type);
Expand All @@ -1889,10 +1901,12 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType

if (level == 0) {
if (inType == TYPE_FUNCTION) {
state->parser.previous = funcName;
declareVariable(state);
size_t ind = (state->current->scopeDepth > 0) ? 0 : identifierConstant(state, &funcName);
defineVariable(state, ind);
if (state->current->scopeDepth == 0) {
size_t ind = identifierConstant(state, &funcName);
defineVariable(state, ind);
} else {
emitByte(OP_SWAP_POP);
}
} else {
size_t ind = identifierConstant(state, &funcName);
rememberClassProperty(state, ind);
Expand Down
1 change: 1 addition & 0 deletions src/opcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,4 @@ SIMPLE(OP_TUPLE_FROM_LIST)

OPERAND(OP_UNPACK_EX,NOOP)
JUMP(OP_ENTER_EXCEPT,+)
SIMPLE(OP_SWAP_POP)
1 change: 1 addition & 0 deletions src/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2258,6 +2258,7 @@ _finishReturn: (void)0;
case OP_FALSE: krk_push(BOOLEAN_VAL(0)); break;
case OP_UNSET: krk_push(KWARGS_VAL(0)); break;
case OP_NOT: krk_currentThread.stackTop[-1] = BOOLEAN_VAL(krk_isFalsey(krk_peek(0))); break;
case OP_SWAP_POP: krk_swap(1); /* fallthrough */
case OP_POP: krk_pop(); break;

case OP_INPLACE_ADD: INPLACE_BINARY_OP(add)
Expand Down
18 changes: 18 additions & 0 deletions test/testDecoratedRecursiveFunction.krk
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
def decorate(func):
def _inner(a):
print('in')
a = func(a)
print('out')
return a
return _inner

def foo():
@decorate
def bar(a):
if a <= 0:
return 0
return bar(a-1)

bar(2)

foo()
6 changes: 6 additions & 0 deletions test/testDecoratedRecursiveFunction.krk.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
in
in
in
out
out
out

0 comments on commit f247bba

Please sign in to comment.