Support arguments to super(), support outside of classes
This commit is contained in:
parent
1c5c2577e9
commit
006119cc1e
@ -964,6 +964,11 @@ static void endScope() {
|
||||
}
|
||||
}
|
||||
|
||||
static void markInitialized() {
|
||||
if (current->scopeDepth == 0) return;
|
||||
current->locals[current->localCount - 1].depth = current->scopeDepth;
|
||||
}
|
||||
|
||||
static void block(size_t indentation, const char * blockName) {
|
||||
if (match(TOKEN_EOL)) {
|
||||
if (check(TOKEN_INDENTATION)) {
|
||||
@ -1259,43 +1264,28 @@ static KrkToken classDeclaration() {
|
||||
|
||||
beginScope();
|
||||
|
||||
KrkToken className = parser.previous;
|
||||
size_t constInd = identifierConstant(&parser.previous);
|
||||
declareVariable();
|
||||
|
||||
EMIT_CONSTANT_OP(OP_CLASS, constInd);
|
||||
defineVariable(constInd);
|
||||
markInitialized();
|
||||
|
||||
ClassCompiler classCompiler;
|
||||
classCompiler.name = parser.previous;
|
||||
classCompiler.enclosing = currentClass;
|
||||
currentClass = &classCompiler;
|
||||
int hasSuperclass = 0;
|
||||
classCompiler.hasAnnotations = 0;
|
||||
|
||||
if (match(TOKEN_LEFT_PAREN)) {
|
||||
startEatingWhitespace();
|
||||
if (!check(TOKEN_RIGHT_PAREN)) {
|
||||
expression();
|
||||
hasSuperclass = 1;
|
||||
emitByte(OP_INHERIT);
|
||||
}
|
||||
stopEatingWhitespace();
|
||||
consume(TOKEN_RIGHT_PAREN, "Expected ) after superclass.");
|
||||
}
|
||||
|
||||
if (!hasSuperclass) {
|
||||
KrkToken Object = syntheticToken("object");
|
||||
size_t ind = identifierConstant(&Object);
|
||||
EMIT_CONSTANT_OP(OP_GET_GLOBAL, ind);
|
||||
}
|
||||
|
||||
beginScope();
|
||||
addLocal(syntheticToken("super"));
|
||||
defineVariable(0);
|
||||
|
||||
namedVariable(className, 0);
|
||||
|
||||
emitByte(OP_INHERIT);
|
||||
|
||||
consume(TOKEN_COLON, "Expected colon after class");
|
||||
|
||||
@ -1342,12 +1332,7 @@ _pop_class:
|
||||
freeCompiler(&subcompiler);
|
||||
emitBytes(OP_CALL, 0);
|
||||
|
||||
return className;
|
||||
}
|
||||
|
||||
static void markInitialized() {
|
||||
if (current->scopeDepth == 0) return;
|
||||
current->locals[current->localCount - 1].depth = current->scopeDepth;
|
||||
return classCompiler.name;
|
||||
}
|
||||
|
||||
static void lambda(int canAssign) {
|
||||
@ -2366,16 +2351,28 @@ static void variable(int canAssign) {
|
||||
}
|
||||
|
||||
static void super_(int canAssign) {
|
||||
if (currentClass == NULL) {
|
||||
error("Invalid reference to `super` outside of a class.");
|
||||
}
|
||||
consume(TOKEN_LEFT_PAREN, "Expected `super` to be called.");
|
||||
consume(TOKEN_RIGHT_PAREN, "`super` can not take arguments.");
|
||||
|
||||
/* Argument time */
|
||||
if (match(TOKEN_RIGHT_PAREN)) {
|
||||
if (!isMethod(current->type)) {
|
||||
error("super() outside of a method body requires arguments");
|
||||
return;
|
||||
}
|
||||
namedVariable(currentClass->name, 0);
|
||||
EMIT_CONSTANT_OP(OP_GET_LOCAL, 0);
|
||||
} else {
|
||||
expression();
|
||||
if (match(TOKEN_COMMA)) {
|
||||
expression();
|
||||
} else {
|
||||
emitConstant(KWARGS_VAL(0));
|
||||
}
|
||||
consume(TOKEN_RIGHT_PAREN, "Expected ')' after argument list");
|
||||
}
|
||||
consume(TOKEN_DOT, "Expected a field of `super()` to be referenced.");
|
||||
consume(TOKEN_IDENTIFIER, "Expected a field name.");
|
||||
size_t ind = identifierConstant(&parser.previous);
|
||||
EMIT_CONSTANT_OP(OP_GET_LOCAL, 0);
|
||||
namedVariable(syntheticToken("super"), 0);
|
||||
EMIT_CONSTANT_OP(OP_GET_SUPER, ind);
|
||||
}
|
||||
|
||||
|
28
src/vm.c
28
src/vm.c
@ -2261,17 +2261,18 @@ _finishReturn: (void)0;
|
||||
break;
|
||||
}
|
||||
case OP_INHERIT: {
|
||||
KrkValue superclass = krk_peek(1);
|
||||
KrkValue superclass = krk_peek(0);
|
||||
if (unlikely(!IS_CLASS(superclass))) {
|
||||
krk_runtimeError(vm.exceptions->typeError, "Superclass must be a class, not '%s'",
|
||||
krk_typeName(superclass));
|
||||
goto _finishException;
|
||||
}
|
||||
KrkClass * subclass = AS_CLASS(krk_peek(0));
|
||||
KrkClass * subclass = AS_CLASS(krk_peek(1));
|
||||
subclass->base = AS_CLASS(superclass);
|
||||
subclass->allocSize = AS_CLASS(superclass)->allocSize;
|
||||
subclass->_ongcsweep = AS_CLASS(superclass)->_ongcsweep;
|
||||
subclass->_ongcscan = AS_CLASS(superclass)->_ongcscan;
|
||||
krk_pop(); /* Super class */
|
||||
break;
|
||||
}
|
||||
case OP_DOCSTRING: {
|
||||
@ -2627,12 +2628,33 @@ _finishReturn: (void)0;
|
||||
case OP_GET_SUPER_LONG:
|
||||
case OP_GET_SUPER: {
|
||||
KrkString * name = READ_STRING(OPERAND);
|
||||
KrkClass * superclass = AS_CLASS(krk_pop());
|
||||
KrkValue baseClass = krk_peek(1);
|
||||
if (!IS_CLASS(baseClass)) {
|
||||
krk_runtimeError(vm.exceptions->typeError,
|
||||
"super() argument 1 must be class, not %s", krk_typeName(baseClass));
|
||||
goto _finishException;
|
||||
}
|
||||
if (IS_KWARGS(krk_peek(0))) {
|
||||
krk_runtimeError(vm.exceptions->notImplementedError,
|
||||
"Unbound super() reference not supported");
|
||||
goto _finishException;
|
||||
}
|
||||
if (!krk_isInstanceOf(krk_peek(0), AS_CLASS(baseClass))) {
|
||||
krk_runtimeError(vm.exceptions->typeError,
|
||||
"'%s' object is not an instance of '%s'",
|
||||
krk_typeName(krk_peek(0)), AS_CLASS(baseClass)->name->chars);
|
||||
goto _finishException;
|
||||
}
|
||||
KrkClass * superclass = AS_CLASS(baseClass)->base ? AS_CLASS(baseClass)->base : vm.baseClasses->objectClass;
|
||||
if (!krk_bindMethod(superclass, name)) {
|
||||
krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'",
|
||||
superclass->name->chars, name->chars);
|
||||
goto _finishException;
|
||||
}
|
||||
/* Swap bind and superclass */
|
||||
krk_swap(1);
|
||||
/* Pop super class */
|
||||
krk_pop();
|
||||
break;
|
||||
}
|
||||
case OP_DUP_LONG:
|
||||
|
22
test/testSuperArguments.krk
Normal file
22
test/testSuperArguments.krk
Normal file
@ -0,0 +1,22 @@
|
||||
class Foo:
|
||||
def method():
|
||||
print("hi")
|
||||
|
||||
class Bar:
|
||||
pass
|
||||
|
||||
try:
|
||||
super(Foo,Bar()).test
|
||||
except TypeError as e:
|
||||
print(str(e))
|
||||
|
||||
class Baz(Foo):
|
||||
def method():
|
||||
print("hello")
|
||||
|
||||
class Qux(Baz):
|
||||
def method():
|
||||
super().method()
|
||||
super(Baz,self).method()
|
||||
|
||||
Qux().method()
|
3
test/testSuperArguments.krk.expect
Normal file
3
test/testSuperArguments.krk.expect
Normal file
@ -0,0 +1,3 @@
|
||||
'Bar' object is not an instance of 'Foo'
|
||||
hello
|
||||
hi
|
Loading…
Reference in New Issue
Block a user