private function classDeclaration() {
    $node = new ClassNode();
    $this->matchDocComment($node);
    $this->tryMatch(T_ABSTRACT, $node, 'abstract') || $this->tryMatch(T_FINAL, $node, 'final');
    $this->mustMatch(T_CLASS, $node);
    $name_node = new NameNode();
    $this->mustMatch(T_STRING, $name_node, NULL, TRUE);
    $node->addChild($name_node, 'name');
    if ($this->tryMatch(T_EXTENDS, $node)) {
      $node->addChild($this->name(), 'extends');
    }
    if ($this->tryMatch(T_IMPLEMENTS, $node)) {
      $implements = new CommaListNode();
      do {
        $implements->addChild($this->name());
      } while ($this->tryMatch(',', $implements));
      $node->addChild($implements, 'implements');
    }
    $this->matchHidden($node);
    $statement_block = new StatementBlockNode();
    $this->mustMatch('{', $statement_block, NULL, FALSE, TRUE);
    $is_abstract = $node->getAbstract() !== NULL;
    while ($this->currentType !== NULL && $this->currentType !== '}') {
      $this->matchHidden($statement_block);
      $statement_block->addChild($this->classStatement($is_abstract));
    }
    $this->mustMatch('}', $statement_block, NULL, TRUE, TRUE);
    $node->addChild($statement_block, 'statements');
    return $node;
  }