src/parser/scalar.js
function() {
    if (this.is("T_MAGIC_CONST")) {
      return this.get_magic_constant();
    } else {
      let value, node;
      switch (this.token) {
        // TEXTS
        case this.tok.T_CONSTANT_ENCAPSED_STRING: {
          value = this.node("string");
          const text = this.text();
          let offset = 0;
          if (text[0] === "b" || text[0] === "B") {
            offset = 1;
          }
          const isDoubleQuote = text[offset] === '"';
          this.next();
          value = value(
            isDoubleQuote,
            this.resolve_special_chars(
              text.substring(offset + 1, text.length - 1),
              isDoubleQuote
            ),
            offset === 1, // unicode flag
            text
          );
          if (this.token === this.tok.T_DOUBLE_COLON) {
            // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1151
            return this.read_static_getter(value);
          } else {
            // dirrect string
            return value;
          }
        }
        case this.tok.T_START_HEREDOC:
          if (this.lexer.curCondition === "ST_NOWDOC") {
            const start = this.lexer.yylloc.first_offset;
            node = this.node("nowdoc");
            value = this.next().text();
            // strip the last line return char
            const lastCh = value[value.length - 1];
            if (lastCh === "\n") {
              if (value[value.length - 2] === "\r") {
                // windows style
                value = value.substring(0, value.length - 2);
              } else {
                // linux style
                value = value.substring(0, value.length - 1);
              }
            } else if (lastCh === "\r") {
              // mac style
              value = value.substring(0, value.length - 1);
            }
            this.expect(this.tok.T_ENCAPSED_AND_WHITESPACE) && this.next();
            const raw = this.lexer._input.substring(
              start,
              this.lexer.yylloc.last_offset
            );
            this.expect(this.tok.T_END_HEREDOC) && this.next();
            node = node(
              value,
              raw,
              this.lexer.heredoc_label,
              raw[3] === '"' || raw[3] === "'"
            );
            return node;
          } else {
            return this.read_encapsed_string(this.tok.T_END_HEREDOC);
          }

        case '"':
          return this.read_encapsed_string('"');

        case 'b"':
        case 'B"': {
          return this.read_encapsed_string('"', true);
        }

        // NUMERIC
        case this.tok.T_LNUMBER: // long
        case this.tok.T_DNUMBER: {
          // double
          const result = this.node("number");
          value = this.text();
          this.next();
          return result(value, null);
        }

        // ARRAYS
        case this.tok.T_ARRAY: // array parser
          return this.read_array();
        case "[": // short array format
          return this.read_array();
        default: {
          const err = this.error("SCALAR");
          // graceful mode : ignore token & return error node
          this.next();
          return err;
        }
      }
    }
  }
function() {
    if (this.is("T_MAGIC_CONST")) {
      return this.get_magic_constant();
    } else {
      let value, node;
      switch (this.token) {
        // TEXTS
        case this.tok.T_CONSTANT_ENCAPSED_STRING: {
          value = this.node("string");
          const text = this.text();
          let offset = 0;
          if (text[0] === "b" || text[0] === "B") {
            offset = 1;
          }
          const isDoubleQuote = text[offset] === '"';
          this.next();
          value = value(
            isDoubleQuote,
            this.resolve_special_chars(
              text.substring(offset + 1, text.length - 1),
              isDoubleQuote
            ),
            offset === 1, // unicode flag
            text
          );
          if (this.token === this.tok.T_DOUBLE_COLON) {
            // https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y#L1151
            return this.read_static_getter(value);
          } else {
            // dirrect string
            return value;
          }
        }
        case this.tok.T_START_HEREDOC:
          if (this.lexer.curCondition === "ST_NOWDOC") {
            const start = this.lexer.yylloc.first_offset;
            node = this.node("nowdoc");
            value = this.next().text();
            // strip the last line return char
            const lastCh = value[value.length - 1];
            if (lastCh === "\n") {
              if (value[value.length - 2] === "\r") {
                // windows style
                value = value.substring(0, value.length - 2);
              } else {
                // linux style
                value = value.substring(0, value.length - 1);
              }
            } else if (lastCh === "\r") {
              // mac style
              value = value.substring(0, value.length - 1);
            }
            this.expect(this.tok.T_ENCAPSED_AND_WHITESPACE) && this.next();
            const raw = this.lexer._input.substring(
              start,
              this.lexer.yylloc.last_offset
            );
            this.expect(this.tok.T_END_HEREDOC) && this.next();
            node = node(
              value,
              raw,
              this.lexer.heredoc_label,
              raw[3] === '"' || raw[3] === "'"
            );
            return node;
          } else {
            return this.read_encapsed_string(this.tok.T_END_HEREDOC);
          }

        case '"':
          return this.read_encapsed_string('"');

        case 'b"':
        case 'B"': {
          return this.read_encapsed_string('"', true);
        }

        // NUMERIC
        case this.tok.T_LNUMBER: // long
        case this.tok.T_DNUMBER: {
          // double
          const result = this.node("number");
          value = this.text();
          this.next();
          return result(value, null);
        }

        // ARRAYS
        case this.tok.T_ARRAY: // array parser
          return this.read_array();
        case "[": // short array format
          return this.read_array();
        default: {
          const err = this.error("SCALAR");
          // graceful mode : ignore token & return error node
          this.next();
          return err;
        }
      }
    }
  }
```ebnf
scalar ::= T_MAGIC_CONST
| T_LNUMBER | T_DNUMBER
| T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE? T_END_HEREDOC
| '"' encaps_list '"'
| T_START_HEREDOC encaps_list T_END_HEREDOC
| namespace_name (T_DOUBLE_COLON T_STRING)?
```