whole_func_string: function(byref) {
      let result = this.node("variable");
      let name;
      if (
        this.expect([this.tok.T_VARIABLE, "$"]) &&
        this.token === this.tok.T_VARIABLE
      ) {
        // plain variable name
        name = this.text().substring(1);
        this.next();
        result = result(name, byref, false);
      } else {
        if (this.token === "$") this.next();
        // dynamic variable name
        switch (this.token) {
          case "{": {
            const expr = this.next().read_expr();
            this.expect("}") && this.next();
            result = result(expr, byref, true);
            break;
          }
          case "$": // $$$var
            // @fixme check coverage here
            result = result(this.read_simple_variable(false), byref, false);
            break;
          case this.tok.T_VARIABLE: {
            // $$var
            name = this.text().substring(1);
            const node = this.node("variable");
            this.next();
            result = result(node(name, false, false), byref, false);
            break;
          }
          default:
            this.error(["{", "$", this.tok.T_VARIABLE]);
            // graceful mode
            name = this.text();
            this.next();
            result = result(name, byref, false);
        }
      }
      return result;
    }
func_code_string: function(byref) {
      let result = this.node("variable");
      let name;
      if (
        this.expect([this.tok.T_VARIABLE, "$"]) &&
        this.token === this.tok.T_VARIABLE
      ) {
        // plain variable name
        name = this.text().substring(1);
        this.next();
        result = result(name, byref, false);
      } else {
        if (this.token === "$") this.next();
        // dynamic variable name
        switch (this.token) {
          case "{": {
            const expr = this.next().read_expr();
            this.expect("}") && this.next();
            result = result(expr, byref, true);
            break;
          }
          case "$": // $$$var
            // @fixme check coverage here
            result = result(this.read_simple_variable(false), byref, false);
            break;
          case this.tok.T_VARIABLE: {
            // $$var
            name = this.text().substring(1);
            const node = this.node("variable");
            this.next();
            result = result(node(name, false, false), byref, false);
            break;
          }
          default:
            this.error(["{", "$", this.tok.T_VARIABLE]);
            // graceful mode
            name = this.text();
            this.next();
            result = result(name, byref, false);
        }
      }
      return result;
    }
func_documentation_string: ```ebnf
  simple_variable ::= T_VARIABLE | '$' '{' expr '}' | '$' simple_variable
  ```