whole_func_string: function() {
      const result = this.node("trait");
      // graceful mode : ignore token & go next
      if (this.token !== this.tok.T_TRAIT) {
        this.error(this.tok.T_TRAIT);
        this.next();
        return null;
      }
      this.next().expect(this.tok.T_STRING);
      let propName = this.node("identifier");
      const name = this.text();
      this.next();
      propName = propName(name);
      this.expect("{");
      const body = this.next().read_class_body();
      return result(propName, body);
    }
func_code_string: function() {
      const result = this.node("trait");
      // graceful mode : ignore token & go next
      if (this.token !== this.tok.T_TRAIT) {
        this.error(this.tok.T_TRAIT);
        this.next();
        return null;
      }
      this.next().expect(this.tok.T_STRING);
      let propName = this.node("identifier");
      const name = this.text();
      this.next();
      propName = propName(name);
      this.expect("{");
      const body = this.next().read_class_body();
      return result(propName, body);
    }
func_documentation_string: reading a trait
  ```ebnf
  trait ::= T_TRAIT T_STRING (T_EXTENDS (NAMESPACE_NAME ',')* NAMESPACE_NAME)? '{' FUNCTION* '}'
  ```