Implement class decorators and move class definitions into pseudo-functions

This commit is contained in:
K. Lange 2021-02-05 19:54:46 +09:00
parent 930b599e82
commit 19e5beba05
4 changed files with 47 additions and 5 deletions

View File

@ -188,7 +188,7 @@ static void declaration();
static void or_(int canAssign);
static void ternary(int canAssign);
static void and_(int canAssign);
static void classDeclaration();
static KrkToken classDeclaration();
static void declareVariable();
static void namedVariable(KrkToken name, int canAssign);
static void addLocal(KrkToken name);
@ -761,7 +761,11 @@ static void declaration() {
} else if (match(TOKEN_LET)) {
letDeclaration();
} else if (check(TOKEN_CLASS)) {
classDeclaration();
KrkToken className = classDeclaration();
size_t classConst = identifierConstant(&className);
parser.previous = className;
declareVariable();
defineVariable(classConst);
} else if (check(TOKEN_AT)) {
decorator(0, TYPE_FUNCTION);
} else if (match(TOKEN_EOL) || match(TOKEN_EOF)) {
@ -1018,11 +1022,17 @@ static void method(size_t blockWidth) {
}
}
static void classDeclaration() {
static KrkToken classDeclaration() {
size_t blockWidth = (parser.previous.type == TOKEN_INDENTATION) ? parser.previous.length : 0;
advance(); /* Collect the `class` */
consume(TOKEN_IDENTIFIER, "Expected class name.");
Compiler subcompiler;
initCompiler(&subcompiler, TYPE_LAMBDA);
subcompiler.function->chunk.filename = subcompiler.enclosing->function->chunk.filename;
beginScope();
KrkToken className = parser.previous;
size_t constInd = identifierConstant(&parser.previous);
declareVariable();
@ -1094,8 +1104,15 @@ static void classDeclaration() {
} /* else empty class (and at end of file?) we'll allow it for now... */
_pop_class:
emitByte(OP_FINALIZE);
endScope();
currentClass = currentClass->enclosing;
KrkFunction * makeclass = endCompiler();
size_t indFunc = krk_addConstant(currentChunk(), OBJECT_VAL(makeclass));
EMIT_CONSTANT_OP(OP_CLOSURE, indFunc);
doUpvalues(&subcompiler, makeclass);
freeCompiler(&subcompiler);
emitBytes(OP_CALL, 0);
return className;
}
static void markInitialized() {
@ -1187,6 +1204,12 @@ static KrkToken decorator(size_t level, FunctionType type) {
function(type, blockWidth);
} else if (check(TOKEN_AT)) {
funcName = decorator(level+1, type);
} else if (check(TOKEN_CLASS)) {
if (type != TYPE_FUNCTION) {
error("Invalid decorator applied to class");
return funcName;
}
funcName = classDeclaration();
} else {
error("Expected a function declaration or another decorator.");
return funcName;

View File

@ -2066,7 +2066,6 @@ static KrkValue run() {
KrkClass * _class = AS_CLASS(krk_peek(0));
/* Store special methods for quick access */
krk_finalizeClass(_class);
krk_pop(); /* Pop the class as we're done attaching methods */
break;
}
case OP_INHERIT: {

View File

@ -0,0 +1,18 @@
def classDecorator(cls):
class NewClass(cls):
def extraMethod(self):
print("decorator-added method",self.__class__.__name__)
return NewClass
@classDecorator
class FooBar(object):
def __init__(self):
self.bar = "baz"
def myMethod(self):
print(self.bar)
let l = FooBar()
l.extraMethod()
l.myMethod()

View File

@ -0,0 +1,2 @@
decorator-added method NewClass
baz