Support arguments to super(), support outside of classes

This commit is contained in:
K. Lange 2021-03-30 13:23:51 +09:00
parent 1c5c2577e9
commit 006119cc1e
4 changed files with 76 additions and 32 deletions

View File

@ -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);
}

View File

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

View 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()

View File

@ -0,0 +1,3 @@
'Bar' object is not an instance of 'Foo'
hello
hi