visitClassStmt method
Defines a class.
Implementation
@override
void visitClassStmt(ClassStmt stmt) {
PyClass? superclassValue;
Object? evaluatedSuper; // Temporary variable
if (stmt.superclass != null) {
evaluatedSuper = evaluate(stmt.superclass!);
if (evaluatedSuper is! PyClass) {
throw RuntimeError(
stmt.superclass!.name,
"Superclass must be a class.",
);
}
superclassValue = evaluatedSuper;
}
// 1. Define class in current scope (for references within methods)
_environment.define(stmt.name.lexeme, null); //temporary
// 2. create environment for class body
Environment classEnvironment =
_environment; // default: enclosing environment
if (superclassValue != null) {
// If super class exists, create a new environment containing the current one
// and defining "super".
classEnvironment = Environment(enclosing: _environment);
classEnvironment.define("super", superclassValue);
}
// 3. Process methods in class environment
Map<String, PyFunction> methods = {};
// Switch to class environment temporarily for setting up method closures correctly
Environment previousEnv = _environment;
_environment = classEnvironment;
for (FunctionStmt methodStmt in stmt.methods) {
// The closure of the methode *must* be the class environment, so that 'super' can be found
PyFunction method = PyFunction.fromDef(
methodStmt,
classEnvironment, // Closure is the class environment
isInitializer: methodStmt.name.lexeme == "__init__",
);
methods[methodStmt.name.lexeme] = method;
// The method need not be defined in classEnvironment,
// because it can be found via self.method or Class.method.
}
// Back to enclosing environment
_environment = previousEnv;
// 4. Create PyClass object
PyClass thisClass = PyClass(stmt.name.lexeme, superclassValue, methods);
// 5. Define class in original scope, overwriting temporary null
_environment.assign(stmt.name, thisClass);
}