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 or_(int canAssign);
static void ternary(int canAssign); static void ternary(int canAssign);
static void and_(int canAssign); static void and_(int canAssign);
static void classDeclaration(); static KrkToken classDeclaration();
static void declareVariable(); static void declareVariable();
static void namedVariable(KrkToken name, int canAssign); static void namedVariable(KrkToken name, int canAssign);
static void addLocal(KrkToken name); static void addLocal(KrkToken name);
@ -761,7 +761,11 @@ static void declaration() {
} else if (match(TOKEN_LET)) { } else if (match(TOKEN_LET)) {
letDeclaration(); letDeclaration();
} else if (check(TOKEN_CLASS)) { } 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)) { } else if (check(TOKEN_AT)) {
decorator(0, TYPE_FUNCTION); decorator(0, TYPE_FUNCTION);
} else if (match(TOKEN_EOL) || match(TOKEN_EOF)) { } 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; size_t blockWidth = (parser.previous.type == TOKEN_INDENTATION) ? parser.previous.length : 0;
advance(); /* Collect the `class` */ advance(); /* Collect the `class` */
consume(TOKEN_IDENTIFIER, "Expected class name."); 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; KrkToken className = parser.previous;
size_t constInd = identifierConstant(&parser.previous); size_t constInd = identifierConstant(&parser.previous);
declareVariable(); declareVariable();
@ -1094,8 +1104,15 @@ static void classDeclaration() {
} /* else empty class (and at end of file?) we'll allow it for now... */ } /* else empty class (and at end of file?) we'll allow it for now... */
_pop_class: _pop_class:
emitByte(OP_FINALIZE); emitByte(OP_FINALIZE);
endScope();
currentClass = currentClass->enclosing; 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() { static void markInitialized() {
@ -1187,6 +1204,12 @@ static KrkToken decorator(size_t level, FunctionType type) {
function(type, blockWidth); function(type, blockWidth);
} else if (check(TOKEN_AT)) { } else if (check(TOKEN_AT)) {
funcName = decorator(level+1, type); 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 { } else {
error("Expected a function declaration or another decorator."); error("Expected a function declaration or another decorator.");
return funcName; return funcName;

View File

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