예제 #1
0
파일: parser.php 프로젝트: jaz303/phpx
 public function parse_class()
 {
     $class_annotation = $this->last_annotation;
     $this->last_annotation = null;
     // abstract class
     $abstract = false;
     $final = false;
     while ($this->at(array(T_ABSTRACT, T_FINAL))) {
         if ($this->at(T_ABSTRACT)) {
             $abstract = true;
         } else {
             $final = true;
         }
         $this->accept();
         $this->s();
     }
     // class
     $this->accept(T_CLASS);
     $this->s();
     $class = new ClassDef($this->parse_ident());
     $class->set_abstract($abstract);
     $class->set_namespace($this->namespace);
     if ($class_annotation) {
         $class->set_annotation($class_annotation);
     }
     $this->s();
     // superclass
     if ($this->at(T_EXTENDS)) {
         $this->accept();
         $this->s();
         $class->extend($this->parse_ident());
         $this->s();
     }
     // interfaces
     $req = T_IMPLEMENTS;
     while ($this->at($req)) {
         $this->accept();
         $this->s();
         $class->implement($this->parse_ident());
         $this->s();
         $req = ',';
     }
     $this->s();
     $this->accept('{');
     // forward declarations: before
     Forward::apply('before', $class);
     // const, var, methods, eval, mixin
     $this->s();
     while ($this->at_class_part()) {
         if ($this->at(T_CONST)) {
             $this->accept();
             $this->s();
             $ident = $this->parse_ident();
             $this->s();
             $this->accept('=');
             $this->s();
             $class->define_constant($ident, $this->parse_value());
             $this->s();
             $this->accept(';');
         } elseif ($this->at_qualifier()) {
             $member_annotation = $this->last_annotation;
             $this->last_annotation = null;
             $access = 'public';
             $static = false;
             $abstract = false;
             $final = false;
             while ($this->at_qualifier()) {
                 switch ($this->current_token()) {
                     case T_PUBLIC:
                         $access = 'public';
                         break;
                     case T_PRIVATE:
                         $access = 'private';
                         break;
                     case T_PROTECTED:
                         $access = 'protected';
                         break;
                     case T_STATIC:
                         $static = true;
                         break;
                     case T_FINAL:
                         $final = true;
                         break;
                     case T_ABSTRACT:
                         $abstract = true;
                         break;
                 }
                 $this->accept();
                 $this->s();
             }
             if ($this->at(T_VARIABLE)) {
                 $variable = $this->parse_variable($access, $static);
                 if ($member_annotation) {
                     $variable->set_annotation($member_annotation);
                 }
                 $class->add_variable($variable);
                 $this->s();
                 if ($this->at(T_IMPLEMENTS)) {
                     $this->accept();
                     $this->s();
                     $this->write_interface_delegate($class, $variable->get_name(), $this->parse_absolute_namespaced_ident());
                     $this->s();
                     while ($this->at(',')) {
                         $this->accept();
                         $this->s();
                         $this->write_interface_delegate($class, $variable->get_name(), $this->parse_absolute_namespaced_ident());
                         $this->s();
                     }
                 } else {
                     while ($this->at(',')) {
                         $this->accept();
                         $this->s();
                         $class->add_variable($this->parse_variable($access, $static));
                         $this->s();
                     }
                 }
                 $this->accept(';');
             } elseif ($this->at(T_FUNCTION)) {
                 $this->accept();
                 $this->s();
                 if ($this->at('&')) {
                     $reference = true;
                     $this->accept();
                     $this->s();
                 } else {
                     $reference = false;
                 }
                 if ($this->at(T_CONSTANT_ENCAPSED_STRING)) {
                     if ($access != 'public') {
                         $this->error("pattern matched methods must be public");
                     }
                     if ($final) {
                         $this->error("pattern matched methods cannot be final");
                     }
                     if ($abstract) {
                         $this->error("pattern matched methods cannot be abstract");
                     }
                     if ($reference) {
                         $this->error("pattern matched methods cannot return by reference");
                     }
                     $pattern = $this->current_text();
                     $this->accept();
                     $this->s();
                     $args = $this->parse_arg_list();
                     $this->s();
                     $body = substr($this->parse_block(), 1, -1);
                     if ($static) {
                         $class->add_static_pattern(new Literal($pattern), $args, $body);
                     } else {
                         $class->add_pattern(new Literal($pattern), $args, $body);
                     }
                 } else {
                     $ident = $this->parse_ident();
                     $this->s();
                     $args = $this->parse_arg_list();
                     $this->s();
                     if ($this->at(';')) {
                         $body = '';
                         $this->accept();
                     } else {
                         $body = substr($this->parse_block(), 1, -1);
                     }
                     $method = new Method($ident);
                     $method->set_access($access);
                     $method->set_static($static);
                     $method->set_final($final);
                     $method->set_abstract($abstract);
                     $method->set_reference_returned($reference);
                     $method->set_arg_list($args);
                     $method->set_body($body);
                     $class->add_method($method);
                     if ($member_annotation) {
                         $method->set_annotation($member_annotation);
                     }
                 }
             }
         } elseif ($this->at(T_EVAL)) {
             $this->accept();
             $this->s();
             $code = $this->parse_block();
             class_eval_without_scope($class, $code);
         } elseif ($this->at(T_INCLUDE)) {
             $this->accept();
             $this->s();
             $mixin_method = 'mixin';
             if ($this->at(T_CONST)) {
                 $mixin_method .= '_constants';
                 $this->accept();
                 $this->s();
             } elseif ($this->at(T_STATIC)) {
                 $mixin_method .= '_static';
                 $this->accept();
                 $this->s();
             }
             $module = $this->parse_absolute_namespaced_ident();
             $this->s();
             $this->accept(';');
             $class->{$mixin_method}($module);
         }
         $this->s();
     }
     $this->s();
     $this->accept('}');
     // forward declarations: after
     Forward::apply('after', $class);
     return $class;
 }