LARA

package tool.lexer
 
object Tokens {
  /** The info attached to a token (beside the position). For most
      tokens this is just the class information (eg. "it's a colon").
      For literals and identifiers, this also contains the proper
      information (eg. "this number literal represents 42"). */
  sealed trait TokenInfo {
    def tokenClass: TokenClass
  }
 
  /** All tokens have a corresponding token class: for instance,
      all identifiers have the IDCLASS. For "informationless"
      tokens (like COLON), the token class is the token info itself.
      This is why the trait TokenClass is mixed-in with the class in
      that case. This will be useful for the parser, the next lab.
      */
  sealed trait TokenClass {
    self =>
    def tokenClass: self.type = self
  }
 
  case object BAD extends TokenInfo with TokenClass             // represents incorrect tokens.
  case object EOF extends TokenInfo with TokenClass             // represents end of file
  case object COLON extends TokenInfo with TokenClass           // :
 
  // etc.
 
  case object PRINTLN extends TokenInfo with TokenClass
 
  // Identifiers
  case class ID(value: String) extends TokenInfo {
    override def toString: String = "ID"+value
    def tokenClass: TokenClass = IDCLASS
  }
 
  // etc.
 
  // The token class for identifiers
  case object IDCLASS extends TokenClass {
    override def toString: String = "identifier"
  }
 
  // etc.
 
  /** A Token is a positional wrapper around an info.
      You don't have to change anything in that class. */
  class Token(val info: TokenInfo) extends Positional {
    override def toString: String = info.toString
    def tokenClass: TokenClass = info.tokenClass
  }
 
  /** To create tokens and match on them. Nothing to change here. */
  object Token {
    def apply(info: TokenInfo): Token = new Token(info)
    def unapply(token: Token): Option[TokenInfo] = Some(token.info)
  }
}