Example #1
0
        /// <summary>
        /// classDecl   → "class" IDENTIFIER ( "&lt;" 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;
        }
Example #2
0
 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);
     }
 }
Example #3
0
 public LoxCompilerClass(Token name, LoxCompilerClass enclosing = null)
 {
     Name      = name;
     Enclosing = enclosing;
 }