Como Acrescentar Métodos a uma Classe

 

 

Suponha que você queira acrescentar a todas as classes do programa em Simples sendo compilado um método

 

       proc getClassName() : String

          begin

          return “A”;  // esta é a classe A

          end

 

que retorna uma String com o nome da classe. Exemplo:

 

class Store

   private:

      var n : integer;

   public:

      proc get() : integer

         begin

         return self.n;

         end

      proc set( n : integer )

         begin

         self.n = n;

         end

end

 

class SubStore subclassOf Store

end  // sem nenhum método

 

class Program

   public:

      proc run()

            var s : Store;

         begin

         s = Store.new();

         write( s.getClassName() ); // imprime "Store"

         s = SubStore.new();

         write( s.getClassName() ); // imprime "SubStore"

         end

end        

     

 

Como fazer isto ?  Será que é suficiente gerar o código em C para o método getClassName ? Claramente não, pois não poderíamos conferir se os envios de mensagem, comos.getClassName()”, estão corretos. Então temos que acrescentar o método getClassName no objeto da ASA que representa cada classe. Para simplificar, vamos assumir que é proibido uma classe declarar um método chamado getClassName. Modificaremos o método classDec da classe Compiler.

 

   private void classDec() {

      if ( lexer.token != Symbol.CLASS )

         error.show("'class' expected");

      lexer.nextToken();

      if ( lexer.token != Symbol.IDENT )

         error.show(CompilerError.identifier_expected);

      String className = lexer.getStringValue();

      lexer.nextToken();

      currentClass = new ClassDec(className);

         // note que colocamos os comentários três colunas à direita do código.

         // Assim, os comentários não atrapalham a leitura do programa.

         // cria o novo método getClassName

      MethodDec m = new MethodDec("getClassName");

         // getClassName não tem parâmetros

      m.setParameterList(null);

         // getClassName retorna uma string

      m.setReturnType(Type.stringType);

      StatementList sl = new StatementList();

         // cria um comando return com o nome da classe sendo compilada, className

      st.addStatement( new ReturnStatement( new LiteralStringExp(className) ) );

      m.setStatementList(st);

         // getClassName não tem variáveis locais

      m.setLocalVarList(null);

     

         // adiciona getClassName na lista de métodos públicos da classe corrente.

      currentClass.addPublicMethod( m );

 

         // continua a análise da classe corrente.

      ...

   }

 

 

Veja que não é uma operação complexa. Para fazer o get, faça algo assim:

 

   // código que analisa a declaração de uma variável de instância.

   // acabou de encontra o nome da variável

 

instVar = new InstanceVariable(lexer.getStringValue());

instVarList.addElement(instVar);

localList.addElement(instVar);

lexer.nextToken();

 

if ( encontrou o "g" depois do nome da variável de instância )

     // a classe InstanceVariable deve ter uma variável de instância indicando que

     // um método get deve ser criado quando se encontrar o tipo da variável.

     // Isto não é necessário para set.

   instVar.you_should_create_a_get_method();

  

 

  

...

 

   // Quando encontra o tipo da variável, cria o método get

Enumeration e = localList.elements();

while ( e.hasMoreElements() ) {

   p = (InstanceVariable ) e.nextElement();

   p.setType(t);

   if ( p.should_I_create_a_get_method() ) {

         // cria o método get

      String instanceVariableName = p.getName();

      MethodDec m = new MethodDec( "get" +  

          Character.toUpperCase(instanceVariableName.charAt(0)) +

          instanceVariableName.substring(1) );

      m.setParameterList(null);

      m.setReturnType(t);

      StatementList sl = new StatementList();

      st.addStatement( new ReturnStatement(new VariableExpr(p)) );

      m.setStatementList(st);

      m.setLocalVarList(null);

      currentClass.addPublicMethod( m );

   }

}

 

 

A diretiva forwardsTo não deve criar muito mais problemas do que os “getters” e “setters” para a criação dos métodos. Contudo, esta classe possui muito mais conferências semânticas. Bom trabalho, que seja divertido.