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) {
|
static void block(size_t indentation, const char * blockName) {
|
||||||
if (match(TOKEN_EOL)) {
|
if (match(TOKEN_EOL)) {
|
||||||
if (check(TOKEN_INDENTATION)) {
|
if (check(TOKEN_INDENTATION)) {
|
||||||
@ -1259,43 +1264,28 @@ static KrkToken classDeclaration() {
|
|||||||
|
|
||||||
beginScope();
|
beginScope();
|
||||||
|
|
||||||
KrkToken className = parser.previous;
|
|
||||||
size_t constInd = identifierConstant(&parser.previous);
|
size_t constInd = identifierConstant(&parser.previous);
|
||||||
declareVariable();
|
declareVariable();
|
||||||
|
|
||||||
EMIT_CONSTANT_OP(OP_CLASS, constInd);
|
EMIT_CONSTANT_OP(OP_CLASS, constInd);
|
||||||
defineVariable(constInd);
|
markInitialized();
|
||||||
|
|
||||||
ClassCompiler classCompiler;
|
ClassCompiler classCompiler;
|
||||||
classCompiler.name = parser.previous;
|
classCompiler.name = parser.previous;
|
||||||
classCompiler.enclosing = currentClass;
|
classCompiler.enclosing = currentClass;
|
||||||
currentClass = &classCompiler;
|
currentClass = &classCompiler;
|
||||||
int hasSuperclass = 0;
|
|
||||||
classCompiler.hasAnnotations = 0;
|
classCompiler.hasAnnotations = 0;
|
||||||
|
|
||||||
if (match(TOKEN_LEFT_PAREN)) {
|
if (match(TOKEN_LEFT_PAREN)) {
|
||||||
startEatingWhitespace();
|
startEatingWhitespace();
|
||||||
if (!check(TOKEN_RIGHT_PAREN)) {
|
if (!check(TOKEN_RIGHT_PAREN)) {
|
||||||
expression();
|
expression();
|
||||||
hasSuperclass = 1;
|
emitByte(OP_INHERIT);
|
||||||
}
|
}
|
||||||
stopEatingWhitespace();
|
stopEatingWhitespace();
|
||||||
consume(TOKEN_RIGHT_PAREN, "Expected ) after superclass.");
|
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();
|
beginScope();
|
||||||
addLocal(syntheticToken("super"));
|
|
||||||
defineVariable(0);
|
|
||||||
|
|
||||||
namedVariable(className, 0);
|
|
||||||
|
|
||||||
emitByte(OP_INHERIT);
|
|
||||||
|
|
||||||
consume(TOKEN_COLON, "Expected colon after class");
|
consume(TOKEN_COLON, "Expected colon after class");
|
||||||
|
|
||||||
@ -1342,12 +1332,7 @@ _pop_class:
|
|||||||
freeCompiler(&subcompiler);
|
freeCompiler(&subcompiler);
|
||||||
emitBytes(OP_CALL, 0);
|
emitBytes(OP_CALL, 0);
|
||||||
|
|
||||||
return className;
|
return classCompiler.name;
|
||||||
}
|
|
||||||
|
|
||||||
static void markInitialized() {
|
|
||||||
if (current->scopeDepth == 0) return;
|
|
||||||
current->locals[current->localCount - 1].depth = current->scopeDepth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lambda(int canAssign) {
|
static void lambda(int canAssign) {
|
||||||
@ -2366,16 +2351,28 @@ static void variable(int canAssign) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void super_(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_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_DOT, "Expected a field of `super()` to be referenced.");
|
||||||
consume(TOKEN_IDENTIFIER, "Expected a field name.");
|
consume(TOKEN_IDENTIFIER, "Expected a field name.");
|
||||||
size_t ind = identifierConstant(&parser.previous);
|
size_t ind = identifierConstant(&parser.previous);
|
||||||
EMIT_CONSTANT_OP(OP_GET_LOCAL, 0);
|
|
||||||
namedVariable(syntheticToken("super"), 0);
|
|
||||||
EMIT_CONSTANT_OP(OP_GET_SUPER, ind);
|
EMIT_CONSTANT_OP(OP_GET_SUPER, ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
src/vm.c
28
src/vm.c
@ -2261,17 +2261,18 @@ _finishReturn: (void)0;
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_INHERIT: {
|
case OP_INHERIT: {
|
||||||
KrkValue superclass = krk_peek(1);
|
KrkValue superclass = krk_peek(0);
|
||||||
if (unlikely(!IS_CLASS(superclass))) {
|
if (unlikely(!IS_CLASS(superclass))) {
|
||||||
krk_runtimeError(vm.exceptions->typeError, "Superclass must be a class, not '%s'",
|
krk_runtimeError(vm.exceptions->typeError, "Superclass must be a class, not '%s'",
|
||||||
krk_typeName(superclass));
|
krk_typeName(superclass));
|
||||||
goto _finishException;
|
goto _finishException;
|
||||||
}
|
}
|
||||||
KrkClass * subclass = AS_CLASS(krk_peek(0));
|
KrkClass * subclass = AS_CLASS(krk_peek(1));
|
||||||
subclass->base = AS_CLASS(superclass);
|
subclass->base = AS_CLASS(superclass);
|
||||||
subclass->allocSize = AS_CLASS(superclass)->allocSize;
|
subclass->allocSize = AS_CLASS(superclass)->allocSize;
|
||||||
subclass->_ongcsweep = AS_CLASS(superclass)->_ongcsweep;
|
subclass->_ongcsweep = AS_CLASS(superclass)->_ongcsweep;
|
||||||
subclass->_ongcscan = AS_CLASS(superclass)->_ongcscan;
|
subclass->_ongcscan = AS_CLASS(superclass)->_ongcscan;
|
||||||
|
krk_pop(); /* Super class */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_DOCSTRING: {
|
case OP_DOCSTRING: {
|
||||||
@ -2627,12 +2628,33 @@ _finishReturn: (void)0;
|
|||||||
case OP_GET_SUPER_LONG:
|
case OP_GET_SUPER_LONG:
|
||||||
case OP_GET_SUPER: {
|
case OP_GET_SUPER: {
|
||||||
KrkString * name = READ_STRING(OPERAND);
|
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)) {
|
if (!krk_bindMethod(superclass, name)) {
|
||||||
krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'",
|
krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'",
|
||||||
superclass->name->chars, name->chars);
|
superclass->name->chars, name->chars);
|
||||||
goto _finishException;
|
goto _finishException;
|
||||||
}
|
}
|
||||||
|
/* Swap bind and superclass */
|
||||||
|
krk_swap(1);
|
||||||
|
/* Pop super class */
|
||||||
|
krk_pop();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_DUP_LONG:
|
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