/// <summary> /// classDecl → "class" IDENTIFIER ( "<" IDENTIFIER )? /// "{" function* "}" ; /// </summary> private void ClassDeclaration() { Token className = Tokens.Consume(IDENTIFIER, "Expect class name."); int nameConstant = MakeStringConstant(className.Lexeme); // no fixup needed DeclareVariable(className); // The class name binds the class object type to a variable of the same name. // todo? make the class declaration an expression, require explicit binding of class to variable (like var Pie = new Pie()); 27.2 EmitOpcode(className.Line, OP_CLASS); EmitConstantIndex(className.Line, nameConstant, _FixupStrings); DefineVariable(className.Line, MakeBitStrConstant(className.Lexeme)); _CurrentClass = new LoxCompilerClass(className, _CurrentClass); // superclass: if (Tokens.Match(LESS)) { Tokens.Consume(IDENTIFIER, "Expect superclass name."); if (Tokens.Previous().Lexeme == className.Lexeme) { throw new CompilerException(Tokens.Previous(), "A class cannot inherit from itself."); } NamedVariable(Tokens.Previous(), false); // push super class onto stack BeginScope(); AddLocal(MakeSyntheticToken(SUPER, "super", LineOfLastToken)); DefineVariable(LineOfLastToken, 0); NamedVariable(className); // push class onto stack EmitOpcode(className.Line, OP_INHERIT); _CurrentClass.HasSuperClass = true; } NamedVariable(className); // push class onto stack // body: Tokens.Consume(LEFT_BRACE, "Expect '{' before class body."); while (!Tokens.Check(RIGHT_BRACE) && !Tokens.IsAtEnd()) { // lox doesn't have field declarations, so anything before the brace that ends the class body must be a method. // initializer is a special method MethodDeclaration("method", ELoxFunctionType.TYPE_METHOD); } Tokens.Consume(RIGHT_BRACE, "Expect '}' after class body."); EmitOpcode(LineOfLastToken, OP_POP); // pop class from stack if (_CurrentClass.HasSuperClass) { EndScope(); } _CurrentClass = _CurrentClass.Enclosing; return; }
private LoxCompiler(TokenList tokens, ELoxFunctionType type, string name, LoxCompiler enclosing, LoxCompilerClass enclosingClass) : base(tokens, name) { _FunctionType = type; Arity = 0; _Chunk = new GearsChunk(name); _Rules = new List <Rule>(); _EnclosingCompiler = enclosing; _CurrentClass = enclosingClass; // stack slot zero is used for 'this' reference in methods, and is empty for script/functions: if (type != ELoxFunctionType.TYPE_FUNCTION) { _LocalVarData[_LocalCount++] = new LoxCompilerLocal("this", 0); } else { _LocalVarData[_LocalCount++] = new LoxCompilerLocal(string.Empty, 0); } }
public LoxCompilerClass(Token name, LoxCompilerClass enclosing = null) { Name = name; Enclosing = enclosing; }