// anche questa classe va nel package, anche se non estende
// la classe Istruzione

package linguaggio;

// una variabile non e' una istruzione, quindi questa classe
// non deve estendere Istruzione

// deve pero' avere il metodo clone, per cui bisogna
// implementare l'interfaccia cloneable

public class Variabile implements Cloneable {

// componente nome privata, costruttore e metodo get
// pubblici; in questo modo, il nome della variabile non si
// puo' cambiare dopo la creazione

  private String nome;

// costruttore con controllo valore null (non ammesso, anche
// se nel testo non c'era scritto: come potrebbe una
// variabile non avere nome?); notare che la stringa
// fornisce una indicazione utile a capire perche' si e'
// verificato l'errore; usare una stringa come "errore",
// e' invece uno sbaglio, perche' non permette di capire
// dove e perche' l'errore si e' verificato

  public Variabile(String n) {
    if(n==null)
      throw new RuntimeException(
        "Tentativo di creare una variabile con nome nullo");
    nome=n;
  }

  public String getNome() {
    return nome;
  }

// la specifica dice che servono toString, equals, hashCode,
// e clone e noi ce li mettiamo; sono i metodi standard
// tranne toString, che in questo caso restituisce il nome
// della variabile invece di qualcosa del tipo [nome]

  public String toString() {
    return nome;
  }

// solito metodo equals; notare che non serve controllare se
// this.nome e' null, dato che questo valore valore puo'
// essere modificato solo dal costruttore, che lancia una
// eccezione se si cerca di inserire un valore null

  public boolean equals(Object o) {
    if(o==null)
      return false;

    if(o.getClass()!=this.getClass())
      return false;

    String s=(String) o;

    return this.nome.equals(s);
  }

  public int hashCode() {
    return nome.hashCode();
  }

// dato che questa e' una sottoclasse diretta di Object, il
// metodo clone e' quello complicato; serve anche la parte
// "implements Cloneable" nella dichiarazione della classe

// dato che la componente String non e' clonabile, non la
// cloniamo, per cui la clonazione profonda in questo caso
// coincide con quella superficiale

  public Object clone() {
    try {
      return super.clone();
    }
    catch(CloneNotSupportedException e) {
      return null;
    }
  }
}
