whole_func_string: function() {
      let result = [];
  
      while (this.token !== this.EOF && this.token !== "}") {
        if (this.token === this.tok.T_COMMENT) {
          result.push(this.read_comment());
          continue;
        }
  
        if (this.token === this.tok.T_DOC_COMMENT) {
          result.push(this.read_doc_comment());
          continue;
        }
  
        // check T_USE trait
        if (this.token === this.tok.T_USE) {
          result = result.concat(this.read_trait_use_statement());
          continue;
        }
  
        // read member flags
        const flags = this.read_member_flags(false);
  
        // check constant
        if (this.token === this.tok.T_CONST) {
          const constants = this.read_constant_list(flags);
          if (this.expect(";")) {
            this.next();
          }
          result = result.concat(constants);
          continue;
        }
  
        // jump over T_VAR then land on T_VARIABLE
        if (this.token === this.tok.T_VAR) {
          this.next().expect(this.tok.T_VARIABLE);
          flags[0] = null; // public (as null)
          flags[1] = 0; // non static var
        }
  
        if (this.token === this.tok.T_VARIABLE) {
          // reads a variable
          const variables = this.read_variable_list(flags);
          this.expect(";");
          this.next();
          result = result.concat(variables);
        } else if (this.token === this.tok.T_FUNCTION) {
          // reads a function
          result.push(this.read_function(false, flags));
        } else {
          // raise an error
          this.error([
            this.tok.T_CONST,
            this.tok.T_VARIABLE,
            this.tok.T_FUNCTION
          ]);
          // ignore token
          this.next();
        }
      }
      this.expect("}");
      this.next();
      return result;
    }
func_code_string: function() {
      let result = [];
  
      while (this.token !== this.EOF && this.token !== "}") {
        if (this.token === this.tok.T_COMMENT) {
          result.push(this.read_comment());
          continue;
        }
  
        if (this.token === this.tok.T_DOC_COMMENT) {
          result.push(this.read_doc_comment());
          continue;
        }
  
        // check T_USE trait
        if (this.token === this.tok.T_USE) {
          result = result.concat(this.read_trait_use_statement());
          continue;
        }
  
        // read member flags
        const flags = this.read_member_flags(false);
  
        // check constant
        if (this.token === this.tok.T_CONST) {
          const constants = this.read_constant_list(flags);
          if (this.expect(";")) {
            this.next();
          }
          result = result.concat(constants);
          continue;
        }
  
        // jump over T_VAR then land on T_VARIABLE
        if (this.token === this.tok.T_VAR) {
          this.next().expect(this.tok.T_VARIABLE);
          flags[0] = null; // public (as null)
          flags[1] = 0; // non static var
        }
  
        if (this.token === this.tok.T_VARIABLE) {
          // reads a variable
          const variables = this.read_variable_list(flags);
          this.expect(";");
          this.next();
          result = result.concat(variables);
        } else if (this.token === this.tok.T_FUNCTION) {
          // reads a function
          result.push(this.read_function(false, flags));
        } else {
          // raise an error
          this.error([
            this.tok.T_CONST,
            this.tok.T_VARIABLE,
            this.tok.T_FUNCTION
          ]);
          // ignore token
          this.next();
        }
      }
      this.expect("}");
      this.next();
      return result;
    }
func_documentation_string: Reads a class body
  ```ebnf
  class_body ::= (member_flags? (T_VAR | T_STRING | T_FUNCTION))*
  ```