public object visitClassStmt(Stmt.Class stmt) { object superclass = null; if (stmt.superclass != null) { superclass = Evaluate(stmt.superclass); if (!(superclass is LoxClass)) { throw new RuntimeError(stmt.superclass.name, "Superclass must be a class."); } } int classIndex = environment.Define(null); if (stmt.superclass != null) { environment = new Environment(enclosing: environment); environment.Define(superclass); } Dictionary <string, LoxFunction> methods = new Dictionary <string, LoxFunction>(); foreach (Stmt.Function method in stmt.methods) { LoxFunction loxFunc = new LoxFunction(method, closure: environment, method.name.lexeme == "init"); methods.Add(method.name.lexeme, loxFunc); } Dictionary <string, LoxFunction> staticMethods = new Dictionary <string, LoxFunction>(); foreach (Stmt.Function method in stmt.staticMethods) { LoxFunction loxFunc = new LoxFunction(method, closure: environment, false); staticMethods.Add(method.name.lexeme, loxFunc); } LoxClass loxClass = new LoxClass(stmt.name.lexeme, (LoxClass)superclass, staticMethods, methods); if (stmt.superclass != null) { environment = environment.enclosing; } environment.Assign(classIndex, loxClass); return(null); }
public object visitClassStmt(Stmt.Class stmt) { ClassType enclosingClass = currentClass; currentClass = ClassType.CLASS; Declare(stmt.name); Define(stmt.name); MarkUnused(stmt.name); if (stmt.superclass != null) { if (stmt.superclass.name.lexeme == stmt.name.lexeme) { Lox.ReportError(stmt.superclass.name, "Class cannot inherit from itself."); } else { currentClass = ClassType.SUBCLASS; Resolve(stmt.superclass); BeginScope(); Peek(scopes)["super"] = true; Peek(varIndices)["super"] = GetNextIndex(); } } BeginScope(); // "this" is the only variable we declare at class scope. That means that when ResolveLocal() // is called on "this" in the methods, the resolver will compute depth = 1, index = 0. // In LoxFunction.Bind(), we create a new function with a closure whose only variable is "this" (at index 0) // and since it's a closure, it has a depth of 1 from the function body. Peek(scopes)["this"] = true; Peek(varIndices)["this"] = GetNextIndex(); // TODO maybe change to 0 foreach (Stmt.Function method in stmt.staticMethods) { Declare(method.name); Define(method.name); ResolveFunction(method.parameters, method.body, FunctionType.STATIC); } foreach (Stmt.Function method in stmt.methods) { Declare(method.name); Define(method.name); FunctionType declaration = FunctionType.METHOD; if (method.name.lexeme == "init") { declaration = FunctionType.INITIALIZER; } ResolveFunction(method.parameters, method.body, declaration); } EndScope(); if (stmt.superclass != null) { EndScope(); } currentClass = enclosingClass; return(null); }