Merge commit 'ece74b20942a5b23acaf3622512c6d0db1491a7e'

pull/315/head
Wilfred Hughes 2022-07-10 23:22:23 +07:00
commit 0aea8019db
24 changed files with 92685 additions and 78954 deletions

@ -17,6 +17,6 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 14
node-version: 16
- run: npm install
- run: npm test

@ -4,3 +4,11 @@ build
*.log
.DS_Store
examples
*.a
*.dylib
*.so
*.o
bindings/c/*.h
bindings/c/tree-sitter-*.pc
.build/

59
vendor/tree-sitter-php/Cargo.lock generated vendored

@ -0,0 +1,59 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "regex"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "tree-sitter"
version = "0.20.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09b3b781640108d29892e8b9684642d2cda5ea05951fd58f0fea1db9edeb9b71"
dependencies = [
"cc",
"regex",
]
[[package]]
name = "tree-sitter-php"
version = "0.19.1"
dependencies = [
"cc",
"tree-sitter",
]

@ -1,10 +1,10 @@
[package]
name = "tree-sitter-php"
description = "php grammar for the tree-sitter parsing library"
version = "0.19.0"
version = "0.19.1"
keywords = ["incremental", "parsing", "php"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/tree-sitter/tree-sitter-javascript"
repository = "https://github.com/tree-sitter/tree-sitter-php"
edition = "2018"
build = "bindings/rust/build.rs"
@ -19,7 +19,7 @@ include = [
path = "bindings/rust/lib.rs"
[dependencies]
tree-sitter = "0.19"
tree-sitter = ">= 0.19, < 0.21"
[build-dependencies]
cc = "1.0"

@ -0,0 +1,114 @@
VERSION := 0.19.0
# Repository
SRC_DIR := src
PARSER_REPO_URL := $(shell git -C $(SRC_DIR) remote get-url origin )
ifeq (, $(PARSER_NAME))
PARSER_NAME := $(shell basename $(PARSER_REPO_URL))
PARSER_NAME := $(subst tree-sitter-,,$(PARSER_NAME))
PARSER_NAME := $(subst .git,,$(PARSER_NAME))
endif
ifeq (, $(PARSER_URL))
PARSER_URL := $(subst :,/,$(PARSER_REPO_URL))
PARSER_URL := $(subst git@,https://,$(PARSER_URL))
PARSER_URL := $(subst .git,,$(PARSER_URL))
endif
UPPER_PARSER_NAME := $(shell echo $(PARSER_NAME) | tr a-z A-Z )
# install directory layout
PREFIX ?= /usr/local
INCLUDEDIR ?= $(PREFIX)/include
LIBDIR ?= $(PREFIX)/lib
PCLIBDIR ?= $(LIBDIR)/pkgconfig
# collect C++ sources, and link if necessary
CPPSRC := $(wildcard $(SRC_DIR)/*.cc)
ifeq (, $(CPPSRC))
ADDITIONALLIBS :=
else
ADDITIONALLIBS := -lc++
endif
# collect sources
SRC := $(wildcard $(SRC_DIR)/*.c)
SRC += $(CPPSRC)
OBJ := $(addsuffix .o,$(basename $(SRC)))
# ABI versioning
SONAME_MAJOR := 0
SONAME_MINOR := 0
CFLAGS ?= -O3 -Wall -Wextra -I$(SRC_DIR)
CXXFLAGS ?= -O3 -Wall -Wextra -I$(SRC_DIR)
override CFLAGS += -std=gnu99 -fPIC
override CXXFLAGS += -fPIC
# OS-specific bits
ifeq ($(shell uname),Darwin)
SOEXT = dylib
SOEXTVER_MAJOR = $(SONAME_MAJOR).dylib
SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).dylib
LINKSHARED := $(LINKSHARED)-dynamiclib -Wl,
ifneq ($(ADDITIONALLIBS),)
LINKSHARED := $(LINKSHARED)$(ADDITIONALLIBS),
endif
LINKSHARED := $(LINKSHARED)-install_name,$(LIBDIR)/libtree-sitter-$(PARSER_NAME).$(SONAME_MAJOR).dylib,-rpath,@executable_path/../Frameworks
else
SOEXT = so
SOEXTVER_MAJOR = so.$(SONAME_MAJOR)
SOEXTVER = so.$(SONAME_MAJOR).$(SONAME_MINOR)
LINKSHARED := $(LINKSHARED)-shared -Wl,
ifneq ($(ADDITIONALLIBS),)
LINKSHARED := $(LINKSHARED)$(ADDITIONALLIBS)
endif
LINKSHARED := $(LINKSHARED)-soname,libtree-sitter-$(PARSER_NAME).so.$(SONAME_MAJOR)
endif
ifneq (,$(filter $(shell uname),FreeBSD NetBSD DragonFly))
PCLIBDIR := $(PREFIX)/libdata/pkgconfig
endif
all: libtree-sitter-$(PARSER_NAME).a libtree-sitter-$(PARSER_NAME).$(SOEXTVER) bindings/c/$(PARSER_NAME).h bindings/c/tree-sitter-$(PARSER_NAME).pc
libtree-sitter-$(PARSER_NAME).a: $(OBJ)
$(AR) rcs $@ $^
libtree-sitter-$(PARSER_NAME).$(SOEXTVER): $(OBJ)
$(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@
ln -sf $@ libtree-sitter-$(PARSER_NAME).$(SOEXT)
ln -sf $@ libtree-sitter-$(PARSER_NAME).$(SOEXTVER_MAJOR)
bindings/c/$(PARSER_NAME).h:
sed -e 's|@UPPER_PARSERNAME@|$(UPPER_PARSER_NAME)|' \
-e 's|@PARSERNAME@|$(PARSER_NAME)|' \
bindings/c/tree-sitter.h.in > $@
bindings/c/tree-sitter-$(PARSER_NAME).pc:
sed -e 's|@LIBDIR@|$(LIBDIR)|;s|@INCLUDEDIR@|$(INCLUDEDIR)|;s|@VERSION@|$(VERSION)|' \
-e 's|=$(PREFIX)|=$${prefix}|' \
-e 's|@PREFIX@|$(PREFIX)|' \
-e 's|@ADDITIONALLIBS@|$(ADDITIONALLIBS)|' \
-e 's|@PARSERNAME@|$(PARSER_NAME)|' \
-e 's|@PARSERURL@|$(PARSER_URL)|' \
bindings/c/tree-sitter.pc.in > $@
install: all
install -d '$(DESTDIR)$(LIBDIR)'
install -m755 libtree-sitter-$(PARSER_NAME).a '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).a
install -m755 libtree-sitter-$(PARSER_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).$(SOEXTVER)
ln -sf libtree-sitter-$(PARSER_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).$(SOEXTVER_MAJOR)
ln -sf libtree-sitter-$(PARSER_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).$(SOEXT)
install -d '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter
install -m644 bindings/c/$(PARSER_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/
install -d '$(DESTDIR)$(PCLIBDIR)'
install -m644 bindings/c/tree-sitter-$(PARSER_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/
clean:
rm -f $(OBJ) libtree-sitter-$(PARSER_NAME).a libtree-sitter-$(PARSER_NAME).$(SOEXT) libtree-sitter-$(PARSER_NAME).$(SOEXTVER_MAJOR) libtree-sitter-$(PARSER_NAME).$(SOEXTVER)
rm -f bindings/c/$(PARSER_NAME).h bindings/c/tree-sitter-$(PARSER_NAME).pc
.PHONY: all install clean

@ -0,0 +1,37 @@
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "TreeSitterPHP",
products: [
.library(name: "TreeSitterPHP", targets: ["TreeSitterPHP"]),
],
dependencies: [],
targets: [
.target(name: "TreeSitterPHP",
path: ".",
exclude: [
"binding.gyp",
"bindings",
"Cargo.toml",
"corpus",
"grammar.js",
"LICENSE",
"Makefile",
"package.json",
"README.md",
"script",
"src/grammar.json",
"src/node-types.json",
],
sources: [
"src/parser.c",
"src/scanner.cc",
],
resources: [
.copy("queries")
],
publicHeadersPath: "bindings/swift",
cSettings: [.headerSearchPath("src")])
]
)

@ -0,0 +1,16 @@
#ifndef TREE_SITTER_@UPPER_PARSERNAME@_H_
#define TREE_SITTER_@UPPER_PARSERNAME@_H_
#include <tree_sitter/parser.h>
#ifdef __cplusplus
extern "C" {
#endif
extern TSLanguage *tree_sitter_@PARSERNAME@();
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_@UPPER_PARSERNAME@_H_

@ -0,0 +1,11 @@
prefix=@PREFIX@
libdir=@LIBDIR@
includedir=@INCLUDEDIR@
additionallibs=@ADDITIONALLIBS@
Name: tree-sitter-@PARSERNAME@
Description: A tree-sitter grammar for the @PARSERNAME@ programming language.
URL: @PARSERURL@
Version: @VERSION@
Libs: -L${libdir} ${additionallibs} -ltree-sitter-@PARSERNAME@
Cflags: -I${includedir}

@ -35,10 +35,10 @@ pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json");
// Uncomment these to include any queries that this grammar contains
// pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm");
// pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm");
pub const HIGHLIGHT_QUERY: &'static str = include_str!("../../queries/highlights.scm");
pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm");
// pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm");
// pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm");
pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm");
#[cfg(test)]
mod tests {

@ -0,0 +1,16 @@
#ifndef TREE_SITTER_PHP_H_
#define TREE_SITTER_PHP_H_
typedef struct TSLanguage TSLanguage;
#ifdef __cplusplus
extern "C" {
#endif
extern TSLanguage *tree_sitter_php();
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_PHP_H_

@ -34,10 +34,14 @@ module.exports = grammar({
externals: $ => [
$._automatic_semicolon,
$.heredoc,
$.encapsed_string_chars,
$.encapsed_string_chars_after_variable,
$.encapsed_string_chars_heredoc,
$.encapsed_string_chars_after_variable_heredoc,
$._eof,
$.heredoc_start,
$.heredoc_end,
$.nowdoc_string,
$.sentinel_error, // Unused token used to indicate error recovery mode
],
@ -64,6 +68,7 @@ module.exports = grammar({
[$.if_statement],
[$.namespace_name],
[$.heredoc_body],
[$.namespace_name_as_prefix],
[$.namespace_use_declaration, $.namespace_name_as_prefix]
@ -298,6 +303,7 @@ module.exports = grammar({
final_modifier: $ => keyword('final'),
abstract_modifier: $ => keyword('abstract'),
readonly_modifier: $ => keyword('readonly'),
class_interface_clause: $ => seq(
keyword('implements'),
@ -339,7 +345,8 @@ module.exports = grammar({
$.visibility_modifier,
$.static_modifier,
$.final_modifier,
$.abstract_modifier
$.abstract_modifier,
$.readonly_modifier
)),
property_element: $ => seq(
@ -446,6 +453,7 @@ module.exports = grammar({
property_promotion_parameter: $ => seq(
field('visibility', $.visibility_modifier),
field('readonly', optional($.readonly_modifier)),
field('type', optional($._type)), // Note: callable is not a valid type here, but instead of complicating the parser, we defer this checking to any intelligence using the parser
field('name', $.variable_name),
optional(seq(
@ -491,6 +499,8 @@ module.exports = grammar({
)
),
bottom_type: $ => 'never',
union_type: $ => prec.right(pipeSep1($._types)),
primitive_type: $ => choice(
@ -523,7 +533,7 @@ module.exports = grammar({
keyword('unset', false)
),
_return_type: $ => seq(':', field('return_type', $._type)),
_return_type: $ => seq(':', field('return_type', choice($._type, $.bottom_type))),
const_element: $ => seq(
choice($.name, alias($._reserved_identifier, $.name)), '=', $._expression
@ -845,7 +855,7 @@ module.exports = grammar({
),
unary_op_expression: $ => choice(
seq('@', $._expression),
prec(PREC.INC, seq('@', $._expression)),
prec.left(PREC.NEG, seq(choice('+', '-', '~', '!'), $._expression))
),
@ -1097,17 +1107,24 @@ module.exports = grammar({
keyword('static')
)),
variadic_placeholder: $ => token('...'),
arguments: $ => seq(
'(',
commaSep($.argument),
optional(','),
')'
choice(
seq(
commaSep($.argument),
optional(','),
),
$.variadic_placeholder,
),
')',
),
argument: $ => seq(
optional(seq(field('name', $.name), ':')),
optional(field('reference_modifier', $.reference_modifier)),
choice($.variadic_unpacking, $._expression)
choice(alias($._reserved_identifier, $.name), $.variadic_unpacking, $._expression)
),
member_call_expression: $ => prec(PREC.CALL, seq(
@ -1163,11 +1180,14 @@ module.exports = grammar({
seq('[', commaSep($.array_element_initializer), optional(','), ']')
),
attribute_list: $ => repeat1(seq(
attribute_group: $ => seq(
'#[',
commaSep1($.attribute),
optional(','),
']',
)),
),
attribute_list: $ => repeat1($.attribute_group),
attribute: $ => seq(
choice($.name, alias($._reserved_identifier, $.name), $.qualified_name),
@ -1226,22 +1246,38 @@ module.exports = grammar({
)
)),
_interpolated_string_body: $ => repeat1(
choice(
$.escape_sequence,
seq($.variable_name, alias($.encapsed_string_chars_after_variable, $.string_value)),
alias($.encapsed_string_chars, $.string_value),
$._simple_string_part,
$._complex_string_part,
alias('\\u', $.string_value),
alias("'", $.string_value) // Needed to avoid the edge case "$b'" from breaking parsing by trying to apply the $.string rule for some reason
),
),
_interpolated_string_body_heredoc: $ => repeat1(
choice(
$.escape_sequence,
seq($.variable_name, alias($.encapsed_string_chars_after_variable_heredoc, $.string_value)),
alias($.encapsed_string_chars_heredoc, $.string_value),
$._simple_string_part,
$._complex_string_part,
alias('\\u', $.string_value),
alias("'", $.string_value), // Needed to avoid the edge case "$b'" from breaking parsing by trying to apply the $.string rule for some reason
alias('<?', $.string_value),
alias(token(prec(1, '?>')), $.string_value),
),
),
encapsed_string: $ => prec.right(seq(
choice(
/[bB]"/,
'"',
),
repeat(
choice(
$.escape_sequence,
seq($.variable_name, alias($.encapsed_string_chars_after_variable, $.string)),
alias($.encapsed_string_chars, $.string),
$._simple_string_part,
$._complex_string_part,
alias('\\u', $.string),
alias("'", $.string) // Needed to avoid the edge case "$b'" from breaking parsing by trying to apply the $.string rule for some reason
),
),
optional($._interpolated_string_body),
'"',
)),
@ -1250,15 +1286,71 @@ module.exports = grammar({
/[bB]'/,
"'"
),
token(prec(1, repeat(/\\'|\\\\|\\?[^'\\]/))), // prec(1, ...) is needed to avoid conflict with $.comment
$.string_value,
"'",
),
string_value: $ => token(prec(1, repeat(/\\'|\\\\|\\?[^'\\]/))), // prec(1, ...) is needed to avoid conflict with $.comment
heredoc_body: $ => seq($._new_line,
repeat1(prec.right(
seq(optional($._new_line), $._interpolated_string_body_heredoc),
)),
),
heredoc: $ => seq(
token('<<<'),
field('identifier', choice(
$.heredoc_start,
seq('"', $.heredoc_start, token.immediate('"'))
)),
choice(
seq(
field('value', $.heredoc_body),
$._new_line,
field('end_tag', $.heredoc_end),
),
seq(
field('value', optional($.heredoc_body)),
field('end_tag', $.heredoc_end),
)
),
),
_new_line: $ => choice(token(/\r?\n/), token(/\r/)),
nowdoc_body: $ => seq($._new_line,
choice(
repeat1(
$.nowdoc_string
),
alias("", $.nowdoc_string)
)
),
nowdoc: $ => seq(
token('<<<'),
"'",
field('identifier', $.heredoc_start),
token.immediate("'"),
choice(
seq(
field('value', $.nowdoc_body),
$._new_line,
field('end_tag', $.heredoc_end),
),
seq(
field('value', optional($.nowdoc_body)),
field('end_tag', $.heredoc_end),
)
),
),
boolean: $ => /[Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee]/,
null: $ => keyword('null', false),
_string: $ => choice($.encapsed_string, $.string, $.heredoc),
_string: $ => choice($.encapsed_string, $.string, $.heredoc, $.nowdoc),
dynamic_variable_name: $ => choice(
seq('$', $._variable_name),
@ -1299,7 +1391,11 @@ module.exports = grammar({
field('operator', keyword('instanceof')),
field('right', $._class_type_designator)
)),
prec.right(PREC.NULL_COALESCE, seq($._expression, '??', $._expression)),
prec.right(PREC.NULL_COALESCE, seq(
field('left', $._expression),
field('operator', '??'),
field('right', $._expression)
)),
...[
[keyword('and'), PREC.LOGICAL_AND_2],
[keyword('or'), PREC.LOGICAL_OR_2],

@ -1298,6 +1298,15 @@
"named": false,
"value": "abstract"
},
"readonly_modifier": {
"type": "ALIAS",
"content": {
"type": "PATTERN",
"value": "[rR][eE][aA][dD][oO][nN][lL][yY]"
},
"named": false,
"value": "readonly"
},
"class_interface_clause": {
"type": "SEQ",
"members": [
@ -1597,6 +1606,10 @@
{
"type": "SYMBOL",
"name": "abstract_modifier"
},
{
"type": "SYMBOL",
"name": "readonly_modifier"
}
]
}
@ -2263,6 +2276,22 @@
"name": "visibility_modifier"
}
},
{
"type": "FIELD",
"name": "readonly",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "readonly_modifier"
},
{
"type": "BLANK"
}
]
}
},
{
"type": "FIELD",
"name": "type",
@ -2521,6 +2550,10 @@
}
]
},
"bottom_type": {
"type": "STRING",
"value": "never"
},
"union_type": {
"type": "PREC_RIGHT",
"value": 0,
@ -2672,8 +2705,17 @@
"type": "FIELD",
"name": "return_type",
"content": {
"type": "SYMBOL",
"name": "_type"
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_type"
},
{
"type": "SYMBOL",
"name": "bottom_type"
}
]
}
}
]
@ -4316,17 +4358,21 @@
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "@"
},
{
"type": "SYMBOL",
"name": "_expression"
}
]
"type": "PREC",
"value": 21,
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "@"
},
{
"type": "SYMBOL",
"name": "_expression"
}
]
}
},
{
"type": "PREC_LEFT",
@ -6019,6 +6065,13 @@
]
}
},
"variadic_placeholder": {
"type": "TOKEN",
"content": {
"type": "STRING",
"value": "..."
}
},
"arguments": {
"type": "SEQ",
"members": [
@ -6033,41 +6086,55 @@
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "argument"
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "argument"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "argument"
}
]
}
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "argument"
}
]
}
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
"type": "SYMBOL",
"name": "variadic_placeholder"
}
]
},
@ -6124,6 +6191,15 @@
{
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_reserved_identifier"
},
"named": true,
"value": "name"
},
{
"type": "SYMBOL",
"name": "variadic_unpacking"
@ -6499,45 +6575,61 @@
}
]
},
"attribute_group": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "#["
},
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "attribute"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "attribute"
}
]
}
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": "]"
}
]
},
"attribute_list": {
"type": "REPEAT1",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "#["
},
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "attribute"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "attribute"
}
]
}
}
]
},
{
"type": "STRING",
"value": "]"
}
]
"type": "SYMBOL",
"name": "attribute_group"
}
},
"attribute": {
@ -6794,130 +6886,516 @@
]
}
},
"encapsed_string": {
"type": "PREC_RIGHT",
"value": 0,
"_interpolated_string_body": {
"type": "REPEAT1",
"content": {
"type": "SEQ",
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"type": "SYMBOL",
"name": "escape_sequence"
},
{
"type": "SEQ",
"members": [
{
"type": "PATTERN",
"value": "[bB]\""
"type": "SYMBOL",
"name": "variable_name"
},
{
"type": "STRING",
"value": "\""
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "encapsed_string_chars_after_variable"
},
"named": true,
"value": "string_value"
}
]
},
{
"type": "REPEAT",
"type": "ALIAS",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "escape_sequence"
},
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "variable_name"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "encapsed_string_chars_after_variable"
},
"named": true,
"value": "string"
"type": "SYMBOL",
"name": "encapsed_string_chars"
},
"named": true,
"value": "string_value"
},
{
"type": "SYMBOL",
"name": "_simple_string_part"
},
{
"type": "SYMBOL",
"name": "_complex_string_part"
},
{
"type": "ALIAS",
"content": {
"type": "STRING",
"value": "\\u"
},
"named": true,
"value": "string_value"
},
{
"type": "ALIAS",
"content": {
"type": "STRING",
"value": "'"
},
"named": true,
"value": "string_value"
}
]
}
},
"_interpolated_string_body_heredoc": {
"type": "REPEAT1",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "escape_sequence"
},
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "variable_name"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "encapsed_string_chars_after_variable_heredoc"
},
"named": true,
"value": "string_value"
}
]
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "encapsed_string_chars_heredoc"
},
"named": true,
"value": "string_value"
},
{
"type": "SYMBOL",
"name": "_simple_string_part"
},
{
"type": "SYMBOL",
"name": "_complex_string_part"
},
{
"type": "ALIAS",
"content": {
"type": "STRING",
"value": "\\u"
},
"named": true,
"value": "string_value"
},
{
"type": "ALIAS",
"content": {
"type": "STRING",
"value": "'"
},
"named": true,
"value": "string_value"
},
{
"type": "ALIAS",
"content": {
"type": "STRING",
"value": "<?"
},
"named": true,
"value": "string_value"
},
{
"type": "ALIAS",
"content": {
"type": "TOKEN",
"content": {
"type": "PREC",
"value": 1,
"content": {
"type": "STRING",
"value": "?>"
}
}
},
"named": true,
"value": "string_value"
}
]
}
},
"encapsed_string": {
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "PATTERN",
"value": "[bB]\""
},
{
"type": "STRING",
"value": "\""
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_interpolated_string_body"
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": "\""
}
]
}
},
"string": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "PATTERN",
"value": "[bB]'"
},
{
"type": "STRING",
"value": "'"
}
]
},
{
"type": "SYMBOL",
"name": "string_value"
},
{
"type": "STRING",
"value": "'"
}
]
},
"string_value": {
"type": "TOKEN",
"content": {
"type": "PREC",
"value": 1,
"content": {
"type": "REPEAT",
"content": {
"type": "PATTERN",
"value": "\\\\'|\\\\\\\\|\\\\?[^'\\\\]"
}
}
}
},
"heredoc_body": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_new_line"
},
{
"type": "REPEAT1",
"content": {
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_new_line"
},
{
"type": "BLANK"
}
]
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_interpolated_string_body_heredoc"
}
]
}
}
}
]
},
"heredoc": {
"type": "SEQ",
"members": [
{
"type": "TOKEN",
"content": {
"type": "STRING",
"value": "<<<"
}
},
{
"type": "FIELD",
"name": "identifier",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "heredoc_start"
},
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "\""
},
{
"type": "SYMBOL",
"name": "encapsed_string_chars"
"name": "heredoc_start"
},
"named": true,
"value": "string"
},
{
"type": "IMMEDIATE_TOKEN",
"content": {
"type": "STRING",
"value": "\""
}
}
]
}
]
}
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_simple_string_part"
"type": "FIELD",
"name": "value",
"content": {
"type": "SYMBOL",
"name": "heredoc_body"
}
},
{
"type": "SYMBOL",
"name": "_complex_string_part"
"name": "_new_line"
},
{
"type": "ALIAS",
"type": "FIELD",
"name": "end_tag",
"content": {
"type": "STRING",
"value": "\\u"
},
"named": true,
"value": "string"
"type": "SYMBOL",
"name": "heredoc_end"
}
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "value",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "heredoc_body"
},
{
"type": "BLANK"
}
]
}
},
{
"type": "ALIAS",
"type": "FIELD",
"name": "end_tag",
"content": {
"type": "STRING",
"value": "'"
},
"named": true,
"value": "string"
"type": "SYMBOL",
"name": "heredoc_end"
}
}
]
}
},
{
"type": "STRING",
"value": "\""
]
}
]
},
"_new_line": {
"type": "CHOICE",
"members": [
{
"type": "TOKEN",
"content": {
"type": "PATTERN",
"value": "\\r?\\n"
}
]
}
},
{
"type": "TOKEN",
"content": {
"type": "PATTERN",
"value": "\\r"
}
}
]
},
"string": {
"nowdoc_body": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_new_line"
},
{
"type": "CHOICE",
"members": [
{
"type": "PATTERN",
"value": "[bB]'"
"type": "REPEAT1",
"content": {
"type": "SYMBOL",
"name": "nowdoc_string"
}
},
{
"type": "STRING",
"value": "'"
"type": "ALIAS",
"content": {
"type": "STRING",
"value": ""
},
"named": true,
"value": "nowdoc_string"
}
]
},
}
]
},
"nowdoc": {
"type": "SEQ",
"members": [
{
"type": "TOKEN",
"content": {
"type": "PREC",
"value": 1,
"content": {
"type": "REPEAT",
"content": {
"type": "PATTERN",
"value": "\\\\'|\\\\\\\\|\\\\?[^'\\\\]"
}
}
"type": "STRING",
"value": "<<<"
}
},
{
"type": "STRING",
"value": "'"
},
{
"type": "FIELD",
"name": "identifier",
"content": {
"type": "SYMBOL",
"name": "heredoc_start"
}
},
{
"type": "IMMEDIATE_TOKEN",
"content": {
"type": "STRING",
"value": "'"
}
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "value",
"content": {
"type": "SYMBOL",
"name": "nowdoc_body"
}
},
{
"type": "SYMBOL",
"name": "_new_line"
},
{
"type": "FIELD",
"name": "end_tag",
"content": {
"type": "SYMBOL",
"name": "heredoc_end"
}
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "value",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "nowdoc_body"
},
{
"type": "BLANK"
}
]
}
},
{
"type": "FIELD",
"name": "end_tag",
"content": {
"type": "SYMBOL",
"name": "heredoc_end"
}
}
]
}
]
}
]
},
@ -6943,6 +7421,10 @@
{
"type": "SYMBOL",
"name": "heredoc"
},
{
"type": "SYMBOL",
"name": "nowdoc"
}
]
},
@ -7203,16 +7685,28 @@
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_expression"
"type": "FIELD",
"name": "left",
"content": {
"type": "SYMBOL",
"name": "_expression"
}
},
{
"type": "STRING",
"value": "??"
"type": "FIELD",
"name": "operator",
"content": {
"type": "STRING",
"value": "??"
}
},
{
"type": "SYMBOL",
"name": "_expression"
"type": "FIELD",
"name": "right",
"content": {
"type": "SYMBOL",
"name": "_expression"
}
}
]
}
@ -8319,6 +8813,9 @@
[
"namespace_name"
],
[
"heredoc_body"
],
[
"namespace_name_as_prefix"
],
@ -8335,20 +8832,36 @@
},
{
"type": "SYMBOL",
"name": "heredoc"
"name": "encapsed_string_chars"
},
{
"type": "SYMBOL",
"name": "encapsed_string_chars"
"name": "encapsed_string_chars_after_variable"
},
{
"type": "SYMBOL",
"name": "encapsed_string_chars_after_variable"
"name": "encapsed_string_chars_heredoc"
},
{
"type": "SYMBOL",
"name": "encapsed_string_chars_after_variable_heredoc"
},
{
"type": "SYMBOL",
"name": "_eof"
},
{
"type": "SYMBOL",
"name": "heredoc_start"
},
{
"type": "SYMBOL",
"name": "heredoc_end"
},
{
"type": "SYMBOL",
"name": "nowdoc_string"
},
{
"type": "SYMBOL",
"name": "sentinel_error"

@ -93,6 +93,10 @@
"type": "integer",
"named": true
},
{
"type": "nowdoc",
"named": true
},
{
"type": "null",
"named": true
@ -389,6 +393,10 @@
{
"type": "_type",
"named": true
},
{
"type": "bottom_type",
"named": true
}
]
}
@ -456,6 +464,10 @@
"type": "_expression",
"named": true
},
{
"type": "name",
"named": true
},
{
"type": "variadic_unpacking",
"named": true
@ -474,6 +486,10 @@
{
"type": "argument",
"named": true
},
{
"type": "variadic_placeholder",
"named": true
}
]
}
@ -567,6 +583,10 @@
{
"type": "_type",
"named": true
},
{
"type": "bottom_type",
"named": true
}
]
}
@ -683,7 +703,7 @@
}
},
{
"type": "attribute_list",
"type": "attribute_group",
"named": true,
"fields": {},
"children": {
@ -697,6 +717,21 @@
]
}
},
{
"type": "attribute_list",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "attribute_group",
"named": true
}
]
}
},
{
"type": "augmented_assignment_expression",
"named": true,
@ -846,7 +881,7 @@
"fields": {
"left": {
"multiple": false,
"required": false,
"required": true,
"types": [
{
"type": "_expression",
@ -856,7 +891,7 @@
},
"operator": {
"multiple": false,
"required": false,
"required": true,
"types": [
{
"type": "!=",
@ -938,6 +973,10 @@
"type": ">>",
"named": false
},
{
"type": "??",
"named": false
},
{
"type": "^",
"named": false
@ -970,7 +1009,7 @@
},
"right": {
"multiple": false,
"required": false,
"required": true,
"types": [
{
"type": "_expression",
@ -1010,16 +1049,6 @@
}
]
}
},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "_expression",
"named": true
}
]
}
},
{
@ -1245,6 +1274,10 @@
"type": "name",
"named": true
},
{
"type": "nowdoc",
"named": true
},
{
"type": "nullsafe_member_access_expression",
"named": true
@ -1750,7 +1783,7 @@
"named": true
},
{
"type": "string",
"type": "string_value",
"named": true
},
{
@ -2109,6 +2142,10 @@
"type": "name",
"named": true
},
{
"type": "nowdoc",
"named": true
},
{
"type": "nullsafe_member_call_expression",
"named": true
@ -2202,6 +2239,10 @@
{
"type": "_type",
"named": true
},
{
"type": "bottom_type",
"named": true
}
]
}
@ -2256,6 +2297,85 @@
]
}
},
{
"type": "heredoc",
"named": true,
"fields": {
"end_tag": {
"multiple": false,
"required": true,
"types": [
{
"type": "heredoc_end",
"named": true
}
]
},
"identifier": {
"multiple": true,
"required": true,
"types": [
{
"type": "\"",
"named": false
},
{
"type": "heredoc_start",
"named": true
}
]
},
"value": {
"multiple": false,
"required": false,
"types": [
{
"type": "heredoc_body",
"named": true
}
]
}
}
},
{
"type": "heredoc_body",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "_expression",
"named": true
},
{
"type": "dynamic_variable_name",
"named": true
},
{
"type": "escape_sequence",
"named": true
},
{
"type": "member_access_expression",
"named": true
},
{
"type": "string_value",
"named": true
},
{
"type": "subscript_expression",
"named": true
},
{
"type": "variable_name",
"named": true
}
]
}
},
{
"type": "if_statement",
"named": true,
@ -2601,6 +2721,10 @@
"type": "name",
"named": true
},
{
"type": "nowdoc",
"named": true
},
{
"type": "nullsafe_member_access_expression",
"named": true
@ -2721,6 +2845,10 @@
"type": "name",
"named": true
},
{
"type": "nowdoc",
"named": true
},
{
"type": "nullsafe_member_access_expression",
"named": true
@ -2822,6 +2950,10 @@
{
"type": "_type",
"named": true
},
{
"type": "bottom_type",
"named": true
}
]
}
@ -2838,6 +2970,10 @@
"type": "final_modifier",
"named": true
},
{
"type": "readonly_modifier",
"named": true
},
{
"type": "static_modifier",
"named": true
@ -3043,6 +3179,57 @@
]
}
},
{
"type": "nowdoc",
"named": true,
"fields": {
"end_tag": {
"multiple": false,
"required": true,
"types": [
{
"type": "heredoc_end",
"named": true
}
]
},
"identifier": {
"multiple": false,
"required": true,
"types": [
{
"type": "heredoc_start",
"named": true
}
]
},
"value": {
"multiple": false,
"required": false,
"types": [
{
"type": "nowdoc_body",
"named": true
}
]
}
}
},
{
"type": "nowdoc_body",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "nowdoc_string",
"named": true
}
]
}
},
{
"type": "nullsafe_member_access_expression",
"named": true,
@ -3113,6 +3300,10 @@
"type": "name",
"named": true
},
{
"type": "nowdoc",
"named": true
},
{
"type": "nullsafe_member_access_expression",
"named": true
@ -3233,6 +3424,10 @@
"type": "name",
"named": true
},
{
"type": "nowdoc",
"named": true
},
{
"type": "nullsafe_member_access_expression",
"named": true
@ -3484,6 +3679,10 @@
"type": "property_element",
"named": true
},
{
"type": "readonly_modifier",
"named": true
},
{
"type": "static_modifier",
"named": true
@ -3557,6 +3756,16 @@
}
]
},
"readonly": {
"multiple": false,
"required": false,
"types": [
{
"type": "readonly_modifier",
"named": true
}
]
},
"type": {
"multiple": false,
"required": false,
@ -3598,6 +3807,11 @@
]
}
},
{
"type": "readonly_modifier",
"named": true,
"fields": {}
},
{
"type": "reference_assignment_expression",
"named": true,
@ -3803,6 +4017,10 @@
"type": "name",
"named": true
},
{
"type": "nowdoc",
"named": true
},
{
"type": "nullsafe_member_access_expression",
"named": true
@ -3909,6 +4127,10 @@
"type": "name",
"named": true
},
{
"type": "nowdoc",
"named": true
},
{
"type": "nullsafe_member_access_expression",
"named": true
@ -4062,7 +4284,17 @@
{
"type": "string",
"named": true,
"fields": {}
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "string_value",
"named": true
}
]
}
},
{
"type": "subscript_expression",
@ -4116,6 +4348,10 @@
"type": "name",
"named": true
},
{
"type": "nowdoc",
"named": true
},
{
"type": "nullsafe_member_access_expression",
"named": true
@ -4607,6 +4843,11 @@
}
}
},
{
"type": "variadic_placeholder",
"named": true,
"fields": {}
},
{
"type": "variadic_unpacking",
"named": true,
@ -4820,6 +5061,10 @@
"type": "<<",
"named": false
},
{
"type": "<<<",
"named": false
},
{
"type": "<<=",
"named": false
@ -4936,6 +5181,10 @@
"type": "boolean",
"named": true
},
{
"type": "bottom_type",
"named": true
},
{
"type": "break",
"named": false
@ -5050,11 +5299,11 @@
},
{
"type": "float",
"named": false
"named": true
},
{
"type": "float",
"named": true
"named": false
},
{
"type": "fn",
@ -5085,7 +5334,11 @@
"named": false
},
{
"type": "heredoc",
"type": "heredoc_end",
"named": true
},
{
"type": "heredoc_start",
"named": true
},
{
@ -5149,13 +5402,17 @@
"named": false
},
{
"type": "null",
"named": false
"type": "nowdoc_string",
"named": true
},
{
"type": "null",
"named": true
},
{
"type": "null",
"named": false
},
{
"type": "or",
"named": false
@ -5184,6 +5441,10 @@
"type": "public",
"named": false
},
{
"type": "readonly",
"named": false
},
{
"type": "require",
"named": false
@ -5216,6 +5477,10 @@
"type": "string",
"named": false
},
{
"type": "string_value",
"named": true
},
{
"type": "switch",
"named": false

File diff suppressed because it is too large Load Diff

@ -10,10 +10,14 @@ using std::string;
enum TokenType {
AUTOMATIC_SEMICOLON,
HEREDOC,
ENCAPSED_STRING_CHARS,
ENCAPSED_STRING_CHARS_AFTER_VARIABLE,
ENCAPSED_STRING_CHARS_HEREDOC,
ENCAPSED_STRING_CHARS_AFTER_VARIABLE_HEREDOC,
EOF_TOKEN,
HEREDOC_START,
HEREDOC_END,
NOWDOC_STRING,
SENTINEL_ERROR, // Unused token used to indicate error recovery mode
};
@ -118,7 +122,7 @@ struct Scanner {
static bool is_escapable_sequence(TSLexer *lexer) {
// Note: remember to also update the escape_sequence rule in the
// main grammar whenever changing this method
auto letter = lexer->lookahead;
int32_t letter = lexer->lookahead;
if (letter == 'n' ||
letter == 'r' ||
@ -147,17 +151,118 @@ struct Scanner {
return iswdigit(lexer->lookahead) && lexer->lookahead >= '0' && lexer->lookahead <= '7';
}
bool scan_encapsed_part_string(TSLexer *lexer, bool is_after_variable) {
lexer->result_symbol = ENCAPSED_STRING_CHARS;
bool scan_nowdoc_string(TSLexer *lexer) {
bool has_consumed_content = false;
if (open_heredocs.empty()) {
return false;
}
// While PHP requires the nowdoc end tag to be the very first on a new line, there may be an
// arbitrary amount of whitespace before the closing token
while (iswspace(lexer->lookahead)) {
advance(lexer);
has_consumed_content = true;
}
string heredoc_tag = open_heredocs.back().word;
bool end_tag_matched = false;
for (int i = 0; i < heredoc_tag.length(); i++) {
if (lexer->lookahead != heredoc_tag[i]) break;
advance(lexer);
has_consumed_content = true;
for (bool has_content = false;; has_content = true) {
end_tag_matched = (i == heredoc_tag.length() - 1 && (iswspace(lexer->lookahead) || lexer->lookahead == ';' || lexer->lookahead == ',' || lexer->lookahead == ')'));
}
if (end_tag_matched) {
// There may be an arbitrary amount of white space after the end tag
while (iswspace(lexer->lookahead) && lexer->lookahead != '\r' && lexer->lookahead != '\n') {
advance(lexer);
has_consumed_content = true;
}
// Return to allow the end tag parsing if we've encountered an end tag at a valid position
if (lexer->lookahead == ';' || lexer->lookahead == ',' || lexer->lookahead == ')' || lexer->lookahead == '\n' || lexer->lookahead == '\r') {
// , and ) is needed to support heredoc in function arguments
return false;
}
}
for (bool has_content = has_consumed_content;; has_content = true) {
lexer->mark_end(lexer);
switch (lexer->lookahead) {
case '"':
case '\n':
case '\r':
return has_content;
case '\0':
default:
if (lexer->eof(lexer)) return false;
advance(lexer);
}
}
return false;
}
bool scan_encapsed_part_string(TSLexer *lexer, bool is_after_variable, bool is_heredoc) {
bool has_consumed_content = false;
if (is_heredoc && !open_heredocs.empty()) {
// While PHP requires the heredoc end tag to be the very first on a new line, there may be an
// arbitrary amount of whitespace before the closing token
// However, we should not consume \r or \n
while (iswspace(lexer->lookahead) && lexer->lookahead != '\r' && lexer->lookahead != '\n') {
advance(lexer);
has_consumed_content = true;
}
string heredoc_tag = open_heredocs.back().word;
bool end_tag_matched = false;
for (int i = 0; i < heredoc_tag.length(); i++) {
if (lexer->lookahead != heredoc_tag[i]) break;
has_consumed_content = true;
advance(lexer);
end_tag_matched = (i == heredoc_tag.length() - 1 && (iswspace(lexer->lookahead) || lexer->lookahead == ';' || lexer->lookahead == ',' || lexer->lookahead == ')'));
}
if (end_tag_matched) {
// There may be an arbitrary amount of white space after the end tag
// However, we should not consume \r or \n
while (iswspace(lexer->lookahead) && lexer->lookahead != '\r' && lexer->lookahead != '\n') {
advance(lexer);
has_consumed_content = true;
}
// Return to allow the end tag parsing if we've encountered an end tag at a valid position
if (lexer->lookahead == ';' || lexer->lookahead == ',' || lexer->lookahead == ')' || lexer->lookahead == '\n' || lexer->lookahead == '\r') {
// , and ) is needed to support heredoc in function arguments
return false;
}
}
}
for (bool has_content = has_consumed_content;; has_content = true) {
lexer->mark_end(lexer);
switch (lexer->lookahead) {
case '"':
if (!is_heredoc) {
return has_content;
}
advance(lexer);
break;
case '\n':
case '\r':
if (is_heredoc) {
return has_content;
}
advance(lexer);
break;
case '\\':
advance(lexer);
@ -168,6 +273,11 @@ struct Scanner {
break;
}
if (is_heredoc && lexer->lookahead == '\\') {
advance(lexer);
break;
}
if (is_escapable_sequence(lexer)) {
return has_content;
}
@ -204,84 +314,33 @@ struct Scanner {
}
break;
default:
if (lexer->eof(lexer)) return false;
advance(lexer);
}
is_after_variable = false;
}
return false;
}
string scan_heredoc_word(TSLexer *lexer) {
string result;
int32_t quote;
switch (lexer->lookahead) {
case '\'':
quote = lexer->lookahead;
advance(lexer);
while (lexer->lookahead != quote && lexer->lookahead != 0) {
result += lexer->lookahead;
advance(lexer);
}
advance(lexer);
break;
default:
if (iswalnum(lexer->lookahead) || lexer->lookahead == '_') {
result += lexer->lookahead;
advance(lexer);
while (iswalnum(lexer->lookahead) || lexer->lookahead == '_') {
result += lexer->lookahead;
advance(lexer);
}
}
break;
while (is_valid_name_char(lexer)) {
result += lexer->lookahead;
advance(lexer);
}
return result;
}
ScanContentResult scan_heredoc_content(TSLexer *lexer) {
if (open_heredocs.empty()) return Error;
Heredoc heredoc = open_heredocs.front();
size_t position_in_word = 0;
for (;;) {
if (position_in_word == heredoc.word.size()) {
// While PHP requires the heredoc end tag to be the very first on a new line, there may be an
// arbitrary amount of whitespace before the closing token
while (lexer->lookahead == ' ') {
advance(lexer);
}
// , and ) is needed to support heredoc in function arguments
if (lexer->lookahead == ';' || lexer->lookahead == ',' || lexer->lookahead == ')' || lexer->lookahead == '\n' || lexer->lookahead == '\r') {
open_heredocs.erase(open_heredocs.begin());
return End;
}
position_in_word = 0;
}
if (lexer->lookahead == 0) {
open_heredocs.erase(open_heredocs.begin());
return Error;
}
if (lexer->lookahead == heredoc.word[position_in_word]) {
advance(lexer);
position_in_word++;
} else {
position_in_word = 0;
advance(lexer);
}
}
}
bool scan(TSLexer *lexer, const bool *valid_symbols) {
const bool is_error_recovery = valid_symbols[SENTINEL_ERROR];
if (is_error_recovery) {
// Consider if we should clear the heredoc list on error
return false;
}
@ -290,11 +349,47 @@ struct Scanner {
lexer->mark_end(lexer);
if (valid_symbols[ENCAPSED_STRING_CHARS_AFTER_VARIABLE]) {
return scan_encapsed_part_string(lexer, true);
lexer->result_symbol = ENCAPSED_STRING_CHARS_AFTER_VARIABLE;
return scan_encapsed_part_string(lexer, /* is_after_variable */ true, /* is_heredoc */ false);
}
if (valid_symbols[ENCAPSED_STRING_CHARS]) {
return scan_encapsed_part_string(lexer, false);
lexer->result_symbol = ENCAPSED_STRING_CHARS;
return scan_encapsed_part_string(lexer, /* is_after_variable */ false, /* is_heredoc */ false);
}
if (valid_symbols[ENCAPSED_STRING_CHARS_AFTER_VARIABLE_HEREDOC]) {
lexer->result_symbol = ENCAPSED_STRING_CHARS_AFTER_VARIABLE_HEREDOC;
return scan_encapsed_part_string(lexer, /* is_after_variable */ true, /* is_heredoc */ true);
}
if (valid_symbols[ENCAPSED_STRING_CHARS_HEREDOC]) {
lexer->result_symbol = ENCAPSED_STRING_CHARS_HEREDOC;
return scan_encapsed_part_string(lexer, /* is_after_variable */ false, /* is_heredoc */ true);
}
if (valid_symbols[NOWDOC_STRING]) {
lexer->result_symbol = NOWDOC_STRING;
return scan_nowdoc_string(lexer);
}
if (valid_symbols[HEREDOC_END]) {
lexer->result_symbol = HEREDOC_END;
if (open_heredocs.empty()) return false;
Heredoc heredoc = open_heredocs.back();
while (iswspace(lexer->lookahead)) {
advance(lexer);
}
if (heredoc.word != scan_heredoc_word(lexer)) {
return false;
}
lexer->mark_end(lexer);
open_heredocs.pop_back();
return true;
}
if (!scan_whitespace(lexer)) return false;
@ -305,31 +400,20 @@ struct Scanner {
}
if (valid_symbols[HEREDOC]) {
if (lexer->lookahead == '<') {
advance(lexer);
if (lexer->lookahead != '<') return false;
advance(lexer);
if (lexer->lookahead != '<') return false;
advance(lexer);
if (valid_symbols[HEREDOC_START]) {
lexer->result_symbol = HEREDOC_START;
Heredoc heredoc;
if (!scan_whitespace(lexer)) return false;
// Found a heredoc
Heredoc heredoc;
heredoc.word = scan_heredoc_word(lexer);
if (heredoc.word.empty()) return false;
open_heredocs.push_back(heredoc);
switch (scan_heredoc_content(lexer)) {
case Error:
return false;
case End:
lexer->result_symbol = HEREDOC;
lexer->mark_end(lexer);
return true;
}
while (iswspace(lexer->lookahead)) {
skip(lexer);
}
heredoc.word = scan_heredoc_word(lexer);
if (heredoc.word.empty()) return false;
lexer->mark_end(lexer);
open_heredocs.push_back(heredoc);
return true;
}
if (valid_symbols[AUTOMATIC_SEMICOLON]) {

@ -0,0 +1,67 @@
=========================================
#131: Parse error when using self as constant
=========================================
<?php
define('self', 'value');
var_dump(self);
---
(program
(php_tag)
(expression_statement
(function_call_expression
function: (name)
arguments: (arguments
(argument (string (string_value)))
(argument (string (string_value)))
)
)
)
(expression_statement
(function_call_expression
function: (name)
arguments: (arguments (argument (name)))
)
)
)
=========================================
#133: Incorrect precedence for error supression operator
=========================================
<?php
@trigger_error("a") && trigger_error("b");
---
(program
(php_tag)
(expression_statement
(binary_expression
left: (unary_op_expression
(function_call_expression
function: (name)
arguments: (arguments
(argument
(encapsed_string
(string_value)
)
)
)
)
)
right: (function_call_expression
function: (name)
arguments: (arguments
(argument
(encapsed_string
(string_value)
)
)
)
)
)
)
)

@ -134,7 +134,7 @@ class A {
(base_clause (name))
(declaration_list
(const_declaration
(const_element (name) (string))
(const_element (name) (string (string_value)))
)
)
)
@ -393,4 +393,378 @@ class Point {
)
)
)
)
)
================================================================================
Readonly properties
================================================================================
<?php
class A {
private readonly int $pria;
private readonly float $prfa;
private readonly mixed $prma;
private readonly string $prsa;
private readonly object $proa;
readonly private int $rpia;
readonly private float $rpfa;
readonly private mixed $rpma;
readonly private string $rpsa;
readonly private object $rpoa;
protected readonly int $oria;
protected readonly float $orfa;
protected readonly mixed $orma;
protected readonly string $orsa;
protected readonly object $oroa;
readonly protected int $roia;
readonly protected float $rofa;
readonly protected mixed $roma;
readonly protected string $rosa;
readonly protected object $rooa;
public readonly int $uria;
public readonly float $urfa;
public readonly mixed $urma;
public readonly string $ursa;
public readonly object $uroa;
readonly public int $ruia;
readonly public float $rufa;
readonly public mixed $ruma;
readonly public string $rusa;
readonly public object $ruoa;
readonly int $ria;
readonly float $rfa;
readonly mixed $rma;
ReAdOnLy string $rsa;
READONLY object $roa;
}
--------------------------------------------------------------------------------
(program
(php_tag)
(class_declaration
(name)
(declaration_list
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(named_type
(name)))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(named_type
(name)))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(named_type
(name)))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(named_type
(name)))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(visibility_modifier)
(readonly_modifier)
(union_type
(named_type
(name)))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(visibility_modifier)
(union_type
(named_type
(name)))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(union_type
(primitive_type))
(property_element
(variable_name
(name))))
(property_declaration
(readonly_modifier)
(union_type
(named_type
(name)))
(property_element
(variable_name
(name)))))))
================================================================================
Constructor property promotion with readonly modifier
================================================================================
<?php
class Point {
public function __construct(
public $x,
protected readonly $y,
private readonly int $z,
) {}
}
--------------------------------------------------------------------------------
(program
(php_tag)
(class_declaration
name: (name)
body: (declaration_list
(method_declaration
(visibility_modifier)
name: (name)
parameters: (formal_parameters
(property_promotion_parameter
visibility: (visibility_modifier)
name: (variable_name (name)))
(property_promotion_parameter
visibility: (visibility_modifier)
readonly: (readonly_modifier)
name: (variable_name (name)))
(property_promotion_parameter
visibility: (visibility_modifier)
readonly: (readonly_modifier)
type: (union_type (primitive_type))
name: (variable_name (name))))
body: (compound_statement)))))

@ -33,7 +33,7 @@ class Exception_foo implements ThrowableInterface {
body: (declaration_list
(property_declaration
(visibility_modifier)
(property_element (variable_name (name)) (property_initializer (encapsed_string (string)))))
(property_element (variable_name (name)) (property_initializer (encapsed_string (string_value)))))
(method_declaration
(visibility_modifier)
name: (name)
@ -141,7 +141,7 @@ class foo {
name: (variable_name (name))))
body: (compound_statement
(expression_statement (reference_assignment_expression
left: (subscript_expression (variable_name (name)) (string))
left: (subscript_expression (variable_name (name)) (string (string_value)))
right: (variable_name (name))))
(expression_statement (assignment_expression
left: (member_access_expression
@ -149,7 +149,7 @@ class foo {
name: (name))
right: (variable_name (name))))
(expression_statement (member_call_expression
object: (subscript_expression (variable_name (name)) (string))
object: (subscript_expression (variable_name (name)) (string (string_value)))
name: (name)
arguments: (arguments)))))
(method_declaration
@ -157,7 +157,7 @@ class foo {
parameters: (formal_parameters)
body: (compound_statement
(expression_statement (assignment_expression
left: (subscript_expression (subscript_expression (variable_name (name)) (string)))
left: (subscript_expression (subscript_expression (variable_name (name)) (string (string_value))))
right: (member_access_expression
object: (variable_name (name))
name: (name)))))))))
@ -271,15 +271,15 @@ define('ANIMALS', array(
(function_call_expression
(name)
(arguments
(argument (encapsed_string (string)))
(argument (encapsed_string (string)))
(argument (encapsed_string (string_value)))
(argument (encapsed_string (string_value)))
)
)
)
(const_declaration
(const_element
(name)
(string)
(string (string_value))
)
)
(const_declaration
@ -287,7 +287,7 @@ define('ANIMALS', array(
(name)
(binary_expression
(name)
(string)
(string (string_value))
)
)
)
@ -295,9 +295,9 @@ define('ANIMALS', array(
(const_element
(name)
(array_creation_expression
(array_element_initializer (string))
(array_element_initializer (string))
(array_element_initializer (string))
(array_element_initializer (string (string_value)))
(array_element_initializer (string (string_value)))
(array_element_initializer (string (string_value)))
)
)
)
@ -305,12 +305,12 @@ define('ANIMALS', array(
(function_call_expression
(name)
(arguments
(argument (string))
(argument (string (string_value)))
(argument
(array_creation_expression
(array_element_initializer (string))
(array_element_initializer (string))
(array_element_initializer (string))
(array_element_initializer (string (string_value)))
(array_element_initializer (string (string_value)))
(array_element_initializer (string (string_value)))
)
)
)
@ -355,17 +355,37 @@ new #[ExampleAttribute] class() {};
#[ExampleAttribute] fn($x) => $x;
$baz = #[ExampleAttribute] function($x) {return $x;};
class A {
#[\Assert\All(
new \Assert\NotNull,
new \Assert\Length(min: 5))
]
public string $name = '';
}
#[
A1,
A2(),
A3(0),
A4(x: 1),
]
function a() {
}
---
(program
(php_tag)
(function_definition
attributes: (attribute_list (attribute (name)))
attributes: (attribute_list (attribute_group (attribute (name))))
name: (name)
parameters: (formal_parameters
(simple_parameter
attributes: (attribute_list (attribute (name)))
attributes: (attribute_list
(attribute_group (attribute (name)))
)
name: (variable_name (name))
)
)
@ -376,27 +396,29 @@ $baz = #[ExampleAttribute] function($x) {return $x;};
name: (name)
body: (declaration_list
(const_declaration
attributes: (attribute_list (attribute (name)))
(const_element (name) (string))
attributes: (attribute_list (attribute_group (attribute (name))))
(const_element (name) (string (string_value)))
)
(property_declaration
attributes: (attribute_list (attribute (name)))
attributes: (attribute_list (attribute_group (attribute (name))))
(visibility_modifier)
type: (union_type (primitive_type))
(property_element (variable_name (name))
(property_initializer (string))
(property_initializer (string (string_value)))
)
)
(method_declaration
attributes: (attribute_list
(attribute
(name)
parameters: (arguments
(argument (encapsed_string (string)))
(argument
(array_creation_expression
(array_element_initializer (encapsed_string (string)))
(attribute_group
(attribute
(name)
parameters: (arguments
(argument (encapsed_string (string_value)))
(argument
(array_creation_expression
(array_element_initializer (encapsed_string (string_value)))
)
)
)
)
@ -406,7 +428,7 @@ $baz = #[ExampleAttribute] function($x) {return $x;};
name: (name)
parameters: (formal_parameters
(simple_parameter
attributes: (attribute_list (attribute (name)))
attributes: (attribute_list (attribute_group (attribute (name))))
name: (variable_name (name))
)
)
@ -416,50 +438,62 @@ $baz = #[ExampleAttribute] function($x) {return $x;};
)
(class_declaration
attributes: (attribute_list
(attribute (name))
(attribute
(qualified_name
(namespace_name_as_prefix
(namespace_name (name))
(attribute_group
(attribute (name))
)
(attribute_group
(attribute
(qualified_name
(namespace_name_as_prefix
(namespace_name (name))
)
(name)
)
(name)
)
)
(attribute
(name)
parameters: (arguments (argument (integer)))
(attribute_group
(attribute
(name)
parameters: (arguments (argument (integer)))
)
)
(attribute
(name)
parameters: (arguments
(argument
(class_constant_access_expression
(name)
(name)
(attribute_group
(attribute
(name)
parameters: (arguments
(argument
(class_constant_access_expression
(name)
(name)
)
)
)
)
)
(attribute
(name)
parameters: (arguments
(argument
(array_creation_expression
(array_element_initializer
(encapsed_string (string))
(encapsed_string (string))
(attribute_group
(attribute
(name)
parameters: (arguments
(argument
(array_creation_expression
(array_element_initializer
(encapsed_string (string_value))
(encapsed_string (string_value))
)
)
)
)
)
)
(attribute
(name)
parameters: (arguments
(argument
(binary_expression
left: (integer)
right: (integer)
(attribute_group
(attribute
(name)
parameters: (arguments
(argument
(binary_expression
left: (integer)
right: (integer)
)
)
)
)
@ -470,14 +504,14 @@ $baz = #[ExampleAttribute] function($x) {return $x;};
)
(expression_statement
(object_creation_expression
attributes: (attribute_list (attribute (name)))
attributes: (attribute_list (attribute_group (attribute (name))))
(arguments)
(declaration_list)
)
)
(expression_statement
(arrow_function
attributes: (attribute_list (attribute (name)))
attributes: (attribute_list (attribute_group (attribute (name))))
parameters: (formal_parameters
(simple_parameter
name: (variable_name (name))
@ -490,7 +524,7 @@ $baz = #[ExampleAttribute] function($x) {return $x;};
(assignment_expression
left: (variable_name (name))
right: (anonymous_function_creation_expression
attributes: (attribute_list (attribute (name)))
attributes: (attribute_list (attribute_group (attribute (name))))
parameters: (formal_parameters
(simple_parameter
name: (variable_name (name))
@ -504,6 +538,75 @@ $baz = #[ExampleAttribute] function($x) {return $x;};
)
)
)
(class_declaration
name: (name)
body: (declaration_list
(property_declaration
attributes: (attribute_list
(attribute_group
(attribute
(qualified_name
(namespace_name_as_prefix (namespace_name (name)))
(name)
)
parameters: (arguments
(argument
(object_creation_expression
(qualified_name
(namespace_name_as_prefix (namespace_name (name)))
(name)
)
)
)
(argument
(object_creation_expression
(qualified_name
(namespace_name_as_prefix (namespace_name (name)))
(name)
)
(arguments
(argument
name: (name)
(integer)
)
)
)
)
)
)
)
)
(visibility_modifier)
type: (union_type (primitive_type))
(property_element
(variable_name (name))
(property_initializer (string (string_value)))
)
)
)
)
(function_definition
attributes: (attribute_list
(attribute_group
(attribute (name))
(attribute
(name)
parameters: (arguments)
)
(attribute
(name)
parameters: (arguments (argument (integer)))
)
(attribute
(name)
parameters: (arguments (argument name: (name) (integer)))
)
)
)
name: (name)
parameters: (formal_parameters)
body: (compound_statement)
)
)
@ -560,10 +663,10 @@ enum Suit: string
(name)
(union_type (primitive_type))
(enum_declaration_list
(enum_case (name) (string))
(enum_case (name) (string (string_value)))
(enum_case (name))
(enum_case (name) (string))
(enum_case (name) (string))
(enum_case (name) (string (string_value)))
(enum_case (name) (string (string_value)))
(comment)
@ -584,14 +687,14 @@ enum Suit: string
(class_constant_access_expression (name) (name))
(class_constant_access_expression (name) (name))
)
(string)
(string (string_value))
)
(match_conditional_expression
(match_condition_list
(class_constant_access_expression (name) (name))
(class_constant_access_expression (name) (name))
)
(string)
(string (string_value))
)
)
)

@ -161,7 +161,7 @@ $a = (array) include 'some.php';
left: (variable_name (name))
right: (cast_expression
type: (cast_type)
value: (include_expression (string))
value: (include_expression (string (string_value)))
)
)
)
@ -244,13 +244,13 @@ list(, $name1) = $data[0];
(array_element_initializer
(array_creation_expression
(array_element_initializer (integer))
(array_element_initializer (string))
(array_element_initializer (string (string_value)))
)
)
(array_element_initializer
(array_creation_expression
(array_element_initializer (integer))
(array_element_initializer (string))
(array_element_initializer (string (string_value)))
)
)
)
@ -414,8 +414,8 @@ true ? false : true ? "a" : "b";
(boolean)
(boolean)
(boolean))
(encapsed_string (string))
(encapsed_string (string))))
(encapsed_string (string_value))
(encapsed_string (string_value))))
(text_interpolation))
=================================================
@ -487,7 +487,7 @@ $i .= "a" . "b";
(assignment_expression
(variable_name
(name))
(encapsed_string (string)))))
(encapsed_string (string_value)))))
(expression_statement
(augmented_assignment_expression
(variable_name
@ -501,15 +501,15 @@ $i .= "a" . "b";
(variable_name
(name))
(binary_expression
(encapsed_string (string))
(encapsed_string (string)))))
(encapsed_string (string_value))
(encapsed_string (string_value)))))
(expression_statement
(binary_expression
(encapsed_string (string))
(encapsed_string (string_value))
(augmented_assignment_expression
(variable_name
(name))
(encapsed_string (string)))))
(encapsed_string (string_value)))))
(text_interpolation))
=======================================
@ -632,9 +632,9 @@ Concatenation precedence
(php_tag)
(expression_statement
(binary_expression
(encapsed_string (string))
(encapsed_string (string_value))
(binary_expression
(encapsed_string (string))
(encapsed_string (string_value))
(integer)
)
)
@ -669,9 +669,9 @@ $a = [...$values];
(arguments
(argument
(array_creation_expression
(array_element_initializer (encapsed_string (string)) (encapsed_string (string)))
(array_element_initializer (encapsed_string (string)) (encapsed_string (string)))
(array_element_initializer (encapsed_string (string)) (encapsed_string (string))))))))
(array_element_initializer (encapsed_string (string_value)) (encapsed_string (string_value)))
(array_element_initializer (encapsed_string (string_value)) (encapsed_string (string_value)))
(array_element_initializer (encapsed_string (string_value)) (encapsed_string (string_value))))))))
(expression_statement
(assignment_expression
(variable_name (name))
@ -710,7 +710,7 @@ ob_start(function($buffer) use (&$storage,) { $storage .= $buffer; }, 20);
(anonymous_function_creation_expression
parameters: (formal_parameters)
body: (compound_statement
(echo_statement (encapsed_string (string)))))))))
(echo_statement (encapsed_string (string_value)))))))))
(expression_statement
(function_call_expression
function: (name)
@ -876,8 +876,8 @@ throw $exception ??= new Exception();
(expression_statement
(throw_expression
(binary_expression
(variable_name (name))
(object_creation_expression
left: (variable_name (name))
right: (object_creation_expression
(name)
(arguments)
)
@ -980,6 +980,71 @@ $country = $session?->user?->getAddress()?->country;
)
)
===============================================
First class callable syntax
===============================================
<?php
foo(...);
$this->foo(...);
A::foo(...);
// These are invalid, but accepted on the parser level.
new Foo(...);
#[Foo(...)]
function foo() {}
---
(program
(php_tag)
(expression_statement
(function_call_expression
(name)
(arguments (variadic_placeholder))
)
)
(expression_statement
(member_call_expression
(variable_name (name))
(name)
(arguments (variadic_placeholder))
)
)
(expression_statement
(scoped_call_expression
(name)
(name)
(arguments (variadic_placeholder))
)
)
(comment)
(expression_statement
(object_creation_expression
(name)
(arguments (variadic_placeholder))
)
)
(function_definition
(attribute_list
(attribute_group
(attribute
(name)
(arguments (variadic_placeholder))
)
)
)
(name)
(formal_parameters)
(compound_statement)
)
)
===============================================
Match expressions
===============================================
@ -1039,7 +1104,7 @@ $statement = match ($a) {
(member_call_expression
(variable_name (name))
(name)
(arguments (argument (string)))
(arguments (argument (string (string_value))))
)
)
)
@ -1372,7 +1437,7 @@ class A {
(subscript_expression
(variable_name (name))
(binary_expression
(string)
(string (string_value))
(function_call_expression
(qualified_name
(namespace_name_as_prefix)
@ -1388,10 +1453,10 @@ class A {
)
(expression_statement
(array_creation_expression
(array_element_initializer (string))
(array_element_initializer (string (string_value)))
(array_element_initializer (by_ref (variable_name (name))))
(array_element_initializer (string) (string))
(array_element_initializer (string) (by_ref (variable_name (name))))
(array_element_initializer (string (string_value)) (string (string_value)))
(array_element_initializer (string (string_value)) (by_ref (variable_name (name))))
)
)
(expression_statement
@ -1412,7 +1477,7 @@ class A {
(expression_statement
(assignment_expression
(list_literal
(string)
(string (string_value))
(by_ref (variable_name (name)))
)
(variable_name (name))
@ -1429,7 +1494,7 @@ class A {
(expression_statement
(assignment_expression
(list_literal
(string)
(string (string_value))
(by_ref (variable_name (name)))
)
(variable_name (name))

@ -8,7 +8,7 @@ echo "hi";
(program
(php_tag)
(echo_statement (encapsed_string (string))))
(echo_statement (encapsed_string (string_value))))
===============================
interpolated text at beginning
@ -22,7 +22,7 @@ echo "hi";
(program
(text)
(php_tag)
(echo_statement (encapsed_string (string))))
(echo_statement (encapsed_string (string_value))))
===============================
interpolated text at end
@ -38,7 +38,7 @@ echo "hi";
(program
(php_tag)
(echo_statement (encapsed_string (string)))
(echo_statement (encapsed_string (string_value)))
(text_interpolation (text)))
===============================
@ -59,11 +59,11 @@ echo "bye";
(program
(php_tag)
(echo_statement (encapsed_string (string)))
(echo_statement (encapsed_string (string_value)))
(text_interpolation
(text)
(php_tag))
(echo_statement (encapsed_string (string)))
(echo_statement (encapsed_string (string_value)))
(text_interpolation))
==============================
@ -79,7 +79,7 @@ Finished
(program
(php_tag)
(echo_statement (encapsed_string (string) (escape_sequence)))
(echo_statement (encapsed_string (string_value) (escape_sequence)))
(text_interpolation (text)))
==============================
@ -109,7 +109,7 @@ $a = 'This gets echoed twice';
(program
(text)
(php_tag)
(expression_statement (assignment_expression (variable_name (name)) (string)))
(expression_statement (assignment_expression (variable_name (name)) (string (string_value))))
(text_interpolation (php_tag))
(expression_statement (variable_name (name)))
(text_interpolation (text) (php_tag))
@ -140,7 +140,7 @@ echo "hi";
(text_interpolation (text) (php_tag))
(comment)
(comment)
(echo_statement (encapsed_string (string))))
(echo_statement (encapsed_string (string_value))))
=======================================
@ -165,7 +165,7 @@ if ( ! function_exists('xml_parser_create') ) {
(unary_op_expression
(function_call_expression
function: (name)
arguments: (arguments (argument (string)))
arguments: (arguments (argument (string (string_value))))
)
)
)

@ -91,7 +91,7 @@ Testing string scanner confirmance
(program
(php_tag)
(echo_statement (binary_expression (encapsed_string (escape_sequence) (escape_sequence) (escape_sequence) (string)) (string)))
(echo_statement (binary_expression (encapsed_string (escape_sequence) (escape_sequence) (escape_sequence) (string_value)) (string (string_value))))
(text_interpolation))
==========================
@ -107,111 +107,3 @@ Shell command
(php_tag)
(expression_statement (shell_command_expression))
(expression_statement (shell_command_expression)))
==========================
Heredocs
==========================
<?php
<<<HERE
foo #{bar} HERE;
<<<HERE
foo #{bar}
HERE;
?>
<?php
<<<HERE
foo #{bar} HERE;
<<<HERE
foo #{bar}
HERE;
<<< HERE
foo #{bar}
HERE;
// Allow Heredoc as function argument
read(<<< HERE
foo #{bar}
HERE);
read(<<< HERE
foo #{bar}
HERE , true);
---
(program
(php_tag)
(expression_statement (heredoc))
(expression_statement (heredoc))
(text_interpolation (php_tag))
(expression_statement (heredoc))
(expression_statement (heredoc))
(expression_statement (heredoc))
(comment)
(expression_statement
(function_call_expression
(name)
(arguments (argument (heredoc)))
)
)
(expression_statement
(function_call_expression
(name)
(arguments
(argument (heredoc))
(argument (boolean))
)
)
)
)
==========================
Nowdocs
==========================
<?php
<<<'PHP'
<?php echo phpversion().PHP_SAPI;
PHP
?>
---
(program
(php_tag)
(expression_statement (heredoc))
(text_interpolation))
==============================
Unicode escape sequences
==============================
<?php
"\u{61}"; // ASCII "a" - characters below U+007F just encode as ASCII, as it's UTF-8
"\u{FF}"; // y with diaeresis
"\u{ff}"; // case-insensitive
"\u{2603}"; // Unicode snowman
"\u{1F602}"; // FACE WITH TEARS OF JOY emoji
"\u{0000001F602}"; // Leading zeroes permitted
---
(program
(php_tag)
(expression_statement (encapsed_string (escape_sequence))) (comment)
(expression_statement (encapsed_string (escape_sequence))) (comment)
(expression_statement (encapsed_string (escape_sequence))) (comment)
(expression_statement (encapsed_string (escape_sequence))) (comment)
(expression_statement (encapsed_string (escape_sequence))) (comment)
(expression_statement (encapsed_string (escape_sequence))) (comment))

@ -30,26 +30,26 @@ if ($a==0) {
condition: (parenthesized_expression (binary_expression
left: (variable_name (name))
right: (integer)))
body: (compound_statement (echo_statement (encapsed_string (string)))))
body: (compound_statement (echo_statement (encapsed_string (string_value)))))
(if_statement
condition: (parenthesized_expression (binary_expression
left: (variable_name (name))
right: (integer)))
body: (compound_statement (echo_statement (encapsed_string (string))))
body: (compound_statement (echo_statement (encapsed_string (string_value))))
alternative: (else_clause
body: (compound_statement (echo_statement (encapsed_string (string))))))
body: (compound_statement (echo_statement (encapsed_string (string_value))))))
(if_statement
condition: (parenthesized_expression (binary_expression
left: (variable_name (name))
right: (integer)))
body: (compound_statement (echo_statement (encapsed_string (string))))
body: (compound_statement (echo_statement (encapsed_string (string_value))))
alternative: (else_if_clause
condition: (parenthesized_expression (binary_expression
left: (variable_name (name))
right: (integer)))
body: (compound_statement (echo_statement (encapsed_string (string)))))
body: (compound_statement (echo_statement (encapsed_string (string_value)))))
alternative: (else_clause
body: (compound_statement (echo_statement (encapsed_string (string)))))))
body: (compound_statement (echo_statement (encapsed_string (string_value)))))))
==============================
Alternative if statements
@ -233,12 +233,12 @@ switch ($a) {
body: (switch_block
(case_statement
value: (integer)
(echo_statement (encapsed_string (string))) (break_statement))
(echo_statement (encapsed_string (string_value))) (break_statement))
(case_statement
value: (integer)
(echo_statement (encapsed_string (string))) (break_statement))
(echo_statement (encapsed_string (string_value))) (break_statement))
(default_statement
(echo_statement (encapsed_string (string))) (break_statement))))
(echo_statement (encapsed_string (string_value))) (break_statement))))
(text_interpolation))
==============================
@ -289,7 +289,7 @@ include "015.inc";
(program
(php_tag)
(expression_statement (include_expression (encapsed_string (string)))))
(expression_statement (include_expression (encapsed_string (string_value)))))
==============================
Do-while statements
@ -364,7 +364,7 @@ try {
name: (variable_name (name))
body: (compound_statement
(expression_statement (print_intrinsic (binary_expression
left: (encapsed_string (string))
left: (encapsed_string (string_value))
right: (member_call_expression
object: (variable_name (name))
name: (name)

File diff suppressed because it is too large Load Diff

@ -29,6 +29,7 @@ Primitive types
function a(): int {}
function b(): callable {}
function c(): iterable {}
function d(): never {}
---
@ -45,6 +46,10 @@ function c(): iterable {}
(function_definition
(name) (formal_parameters)
(union_type (primitive_type))
(compound_statement))
(function_definition
(name) (formal_parameters)
(bottom_type)
(compound_statement)))
=======================