Use tree-sitter-php from crates.io

pull/795/head
Wilfred Hughes 2024-12-20 08:36:36 +07:00
parent f9d663ea9f
commit eb0b47d403
52 changed files with 18 additions and 156674 deletions

@ -11,7 +11,7 @@ with YAML.
Improved language detection when one argument is a named pipe.
Updated to the latest tree-sitter parser for Bash, C, C++, C#, Go,
Haskell, Java, JavaScript, Julia, Objective-C, OCaml, Python, Ruby,
Haskell, Java, JavaScript, Julia, Objective-C, OCaml, PHP, Python, Ruby,
Scala and TypeScript.
### Syntax Highlighting

11
Cargo.lock generated

@ -261,6 +261,7 @@ dependencies = [
"tree-sitter-language",
"tree-sitter-objc",
"tree-sitter-ocaml",
"tree-sitter-php",
"tree-sitter-python",
"tree-sitter-ruby",
"tree-sitter-scala",
@ -1132,6 +1133,16 @@ dependencies = [
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-php"
version = "0.23.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f066e94e9272cfe4f1dcb07a1c50c66097eca648f2d7233d299c8ae9ed8c130c"
dependencies = [
"cc",
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-python"
version = "0.23.5"

@ -93,6 +93,7 @@ tree-sitter-java = "0.23.4"
tree-sitter-julia = "0.23.1"
tree-sitter-go = "0.23.4"
tree-sitter-bash = "0.23.3"
tree-sitter-php = "0.23.11"
[dev-dependencies]
# assert_cmd 2.0.10 requires predicates 3.

@ -209,11 +209,6 @@ fn main() {
src_dir: "vendored_parsers/tree-sitter-perl-src",
extra_files: vec!["scanner.c"],
},
TreeSitterParser {
name: "tree-sitter-php",
src_dir: "vendored_parsers/tree-sitter-php-src",
extra_files: vec!["scanner.cc"],
},
TreeSitterParser {
name: "tree-sitter-qmljs",
src_dir: "vendored_parsers/tree-sitter-qmljs-src",

@ -89,7 +89,6 @@ extern "C" {
fn tree_sitter_newick() -> ts::Language;
fn tree_sitter_nix() -> ts::Language;
fn tree_sitter_pascal() -> ts::Language;
fn tree_sitter_php() -> ts::Language;
fn tree_sitter_perl() -> ts::Language;
fn tree_sitter_qmljs() -> ts::Language;
fn tree_sitter_r() -> ts::Language;
@ -837,16 +836,15 @@ pub(crate) fn from_language(language: guess::Language) -> TreeSitterConfig {
}
}
Php => {
let language = unsafe { tree_sitter_php() };
let language_fn = tree_sitter_php::LANGUAGE_PHP;
let language = tree_sitter::Language::new(language_fn);
TreeSitterConfig {
language: language.clone(),
atom_nodes: vec!["string", "encapsed_string"].into_iter().collect(),
delimiter_tokens: vec![("(", ")"), ("[", "]"), ("{", "}")],
highlight_query: ts::Query::new(
&language,
include_str!("../../vendored_parsers/highlights/php.scm"),
)
.unwrap(),
highlight_query: ts::Query::new(&language, tree_sitter_php::HIGHLIGHTS_QUERY)
.unwrap(),
sub_languages: vec![],
}
}

@ -1 +0,0 @@
../tree-sitter-php/queries/highlights.scm

@ -1 +0,0 @@
tree-sitter-php/src

@ -1,3 +0,0 @@
/src/** linguist-vendored
/examples/* linguist-vendored
/corpus/* linguist-vendored

@ -1,8 +0,0 @@
Checklist:
- [ ] All tests pass in CI
- [ ] There are sufficient tests for the new fix/feature
- [ ] Grammar rules have not been renamed unless absolutely necessary (x rules renamed)
- [ ] The conflicts section hasn't grown too much (x new conflicts)
- [ ] The parser size hasn't grown too much (master: STATE_COUNT, PR: STATE_COUNT) (check the value of STATE_COUNT in src/parser.c)

@ -1,22 +0,0 @@
name: Build/test
on:
pull_request:
branches:
- "**"
push:
branches:
- "master"
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16
- run: npm install
- run: npm test

@ -1,14 +0,0 @@
package-lock.json
node_modules
build
*.log
.DS_Store
examples
*.a
*.dylib
*.so
*.o
bindings/c/*.h
bindings/c/tree-sitter-*.pc
.build/

@ -1,5 +0,0 @@
test
build
script
examples
target

@ -1,59 +0,0 @@
# 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,25 +0,0 @@
[package]
name = "tree-sitter-php"
description = "php grammar for the tree-sitter parsing library"
version = "0.19.1"
keywords = ["incremental", "parsing", "php"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/tree-sitter/tree-sitter-php"
edition = "2018"
build = "bindings/rust/build.rs"
include = [
"bindings/rust/*",
"grammar.js",
"queries/*",
"src/*",
]
[lib]
path = "bindings/rust/lib.rs"
[dependencies]
tree-sitter = ">= 0.19, < 0.21"
[build-dependencies]
cc = "1.0"

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2017 Josh Vera, GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -1,114 +0,0 @@
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

@ -1,37 +0,0 @@
// 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")])
]
)

@ -1,9 +0,0 @@
tree-sitter-php
==================
[![Build/test](https://github.com/tree-sitter/tree-sitter-php/actions/workflows/ci.yml/badge.svg)](https://github.com/tree-sitter/tree-sitter-php/actions/workflows/ci.yml)
PHP grammar for [tree-sitter][].
[tree-sitter]: https://github.com/tree-sitter/tree-sitter

@ -1,19 +0,0 @@
{
"targets": [
{
"target_name": "tree_sitter_php_binding",
"include_dirs": [
"<!(node -e \"require('nan')\")",
"src"
],
"sources": [
"src/parser.c",
"src/scanner.cc",
"bindings/node/binding.cc"
],
"cflags_c": [
"-std=c99"
]
}
]
}

@ -1,16 +0,0 @@
#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_

@ -1,11 +0,0 @@
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}

@ -1,28 +0,0 @@
#include "tree_sitter/parser.h"
#include <node.h>
#include "nan.h"
using namespace v8;
extern "C" TSLanguage * tree_sitter_php();
namespace {
NAN_METHOD(New) {}
void Init(Local<Object> exports, Local<Object> module) {
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
tpl->SetClassName(Nan::New("Language").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Local<Function> constructor = Nan::GetFunction(tpl).ToLocalChecked();
Local<Object> instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked();
Nan::SetInternalFieldPointer(instance, 0, tree_sitter_php());
Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("php").ToLocalChecked());
Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance);
}
NODE_MODULE(tree_sitter_php_binding, Init)
} // namespace

@ -1,19 +0,0 @@
try {
module.exports = require("../../build/Release/tree_sitter_php_binding");
} catch (error1) {
if (error1.code !== 'MODULE_NOT_FOUND') {
throw error1;
}
try {
module.exports = require("../../build/Debug/tree_sitter_php_binding");
} catch (error2) {
if (error2.code !== 'MODULE_NOT_FOUND') {
throw error2;
}
throw error1
}
}
try {
module.exports.nodeTypeInfo = require("../../src/node-types.json");
} catch (_) {}

@ -1,48 +0,0 @@
# tree-sitter-php
This crate provides support of the PHP language for the [tree-sitter][] parsing library. To use this crate, add it to
the `[dependencies]` section of your
`Cargo.toml` file. As this crate is not (yet) published to the central registry, you will have to specify it as a git
dependency, currently we suggest using the `master` branch.
You will also need the [tree-sitter crate][] to do the actual parsing here.
``` toml
[dependencies]
tree-sitter = "0.19"
tree-sitter-php = { git = "https://github.com/tree-sitter/tree-sitter-php.git", branch = "master" }
```
To you the parser, you need to obtain an instance of a [`tree_sitter::Language`][Language] struct for php.
The `language()` function provides this.
Passing this struct to a [`tree_sitter::Parser`][Parser] will enable it to parse PHP.
``` rust
use tree_sitter::Parser;
fn main() {
let code = r#"
function double(int $x) {
return $x * 2;
}
"#;
let mut parser = Parser::new();
parser
.set_language(tree_sitter_php::language())
.expect("Error loading PHP parsing support");
let parsed = parser.parse(code, None);
println!("{:#?}", parsed);
}
```
If you have any questions, please reach out to us in the [tree-sitter discussions] page.
[Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
[Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
[tree-sitter]: https://tree-sitter.github.io/
[tree-sitter crate]: https://crates.io/crates/tree-sitter
[tree-sitter discussions]: https://github.com/tree-sitter/tree-sitter/discussions

@ -1,29 +0,0 @@
fn main() {
let src_dir = std::path::Path::new("src");
let mut c_config = cc::Build::new();
c_config.include(&src_dir);
c_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable")
.flag_if_supported("-Wno-trigraphs");
let parser_path = src_dir.join("parser.c");
c_config.file(&parser_path);
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
c_config.compile("parser");
// If your language uses an external scanner written in C++,
// then include this block of code:
let mut cpp_config = cc::Build::new();
cpp_config.cpp(true);
cpp_config.include(&src_dir);
cpp_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable");
let scanner_path = src_dir.join("scanner.cc");
cpp_config.file(&scanner_path);
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
cpp_config.compile("scanner");
}

@ -1,52 +0,0 @@
//! This crate provides php language support for the [tree-sitter][] parsing library.
//!
//! Typically, you will use the [language][language func] function to add this language to a
//! tree-sitter [Parser][], and then use the parser to parse some code:
//!
//! ```
//! let code = "";
//! let mut parser = tree_sitter::Parser::new();
//! parser.set_language(tree_sitter_php::language()).expect("Error loading php grammar");
//! let tree = parser.parse(code, None).unwrap();
//! ```
//!
//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
//! [language func]: fn.language.html
//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
//! [tree-sitter]: https://tree-sitter.github.io/
use tree_sitter::Language;
extern "C" {
fn tree_sitter_php() -> Language;
}
/// Get the tree-sitter [Language][] for this grammar.
///
/// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
pub fn language() -> Language {
unsafe { tree_sitter_php() }
}
/// The content of the [`node-types.json`][] file for this grammar.
///
/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json");
// Uncomment these to include any queries that this grammar contains
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");
#[cfg(test)]
mod tests {
#[test]
fn test_can_load_grammar() {
let mut parser = tree_sitter::Parser::new();
parser
.set_language(super::language())
.expect("Error loading php language");
}
}

@ -1,16 +0,0 @@
#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_

File diff suppressed because it is too large Load Diff

@ -1,40 +0,0 @@
{
"name": "tree-sitter-php",
"version": "0.19.0",
"description": "PHP grammar for tree-sitter",
"main": "bindings/node",
"keywords": [
"parser",
"php"
],
"author": "Josh Vera",
"license": "MIT",
"bugs": {
"url": "https://github.com/tree-sitter/tree-sitter-php/issues"
},
"homepage": "https://github.com/tree-sitter/tree-sitter-php#readme",
"dependencies": {
"nan": "^2.14.0"
},
"devDependencies": {
"tree-sitter-cli": "^0.19.1",
"shelljs": "^0.8.4"
},
"scripts": {
"build": "tree-sitter generate && node-gyp build",
"test": "tree-sitter test && node script/parse-examples.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tree-sitter/tree-sitter-php.git"
},
"tree-sitter": [
{
"scope": "source.php",
"file-types": [
"php"
],
"highlights": "queries/highlights.scm"
}
]
}

@ -1,115 +0,0 @@
(php_tag) @tag
"?>" @tag
; Types
(primitive_type) @type.builtin
(cast_type) @type.builtin
(named_type (name) @type) @type
(named_type (qualified_name) @type) @type
; Functions
(array_creation_expression "array" @function.builtin)
(list_literal "list" @function.builtin)
(method_declaration
name: (name) @function.method)
(function_call_expression
function: (qualified_name (name)) @function)
(scoped_call_expression
name: (name) @function)
(member_call_expression
name: (name) @function.method)
(function_definition
name: (name) @function)
; Member
(property_element
(variable_name) @property)
(member_access_expression
name: (variable_name (name)) @property)
(member_access_expression
name: (name) @property)
; Variables
(relative_scope) @variable.builtin
((name) @constant
(#match? @constant "^_?[A-Z][A-Z\\d_]+$"))
((name) @constructor
(#match? @constructor "^[A-Z]"))
((name) @variable.builtin
(#eq? @variable.builtin "this"))
(variable_name) @variable
; Basic tokens
(string) @string
(heredoc) @string
(boolean) @constant.builtin
(null) @constant.builtin
(integer) @number
(float) @number
(comment) @comment
"$" @operator
; Keywords
"abstract" @keyword
"as" @keyword
"break" @keyword
"case" @keyword
"catch" @keyword
"class" @keyword
"const" @keyword
"continue" @keyword
"declare" @keyword
"default" @keyword
"do" @keyword
"echo" @keyword
"else" @keyword
"elseif" @keyword
"enddeclare" @keyword
"endforeach" @keyword
"endif" @keyword
"endswitch" @keyword
"endwhile" @keyword
"extends" @keyword
"final" @keyword
"finally" @keyword
"foreach" @keyword
"function" @keyword
"global" @keyword
"if" @keyword
"implements" @keyword
"include_once" @keyword
"include" @keyword
"insteadof" @keyword
"interface" @keyword
"namespace" @keyword
"new" @keyword
"private" @keyword
"protected" @keyword
"public" @keyword
"require_once" @keyword
"require" @keyword
"return" @keyword
"static" @keyword
"switch" @keyword
"throw" @keyword
"trait" @keyword
"try" @keyword
"use" @keyword
"while" @keyword

@ -1,3 +0,0 @@
((text) @injection.content
(#set! injection.language "html")
(#set! injection.combined))

@ -1,26 +0,0 @@
(class_declaration
name: (name) @name) @definition.class
(function_definition
name: (name) @name) @definition.function
(method_declaration
name: (name) @name) @definition.function
(object_creation_expression
[
(qualified_name (name) @name)
(variable_name (name) @name)
]) @reference.class
(function_call_expression
function: [
(qualified_name (name) @name)
(variable_name (name)) @name
]) @reference.call
(scoped_call_expression
name: (name) @name) @reference.call
(member_call_expression
name: (name) @name) @reference.call

@ -1,39 +0,0 @@
#!/bin/bash
set -e
cd "$(dirname "$0")/.."
function checkout_at() {
path="examples/$1"
url=$2
sha=$3
if [ ! -d "$path" ]; then
git clone "https://github.com/$url" "$path"
fi
pushd "$path"
git fetch && git reset --hard "$sha"
popd
}
checkout_at "laravel" "laravel/laravel" "9d0862b3340c8243ee072afc181e315ffa35e110"
checkout_at "phabricator" "phacility/phabricator" "d0b01a41f2498fb2a6487c2d6704dc7acfd4675f"
checkout_at "phpunit" "sebastianbergmann/phpunit" "5e523bdc7dd4d90fed9fb29d1df05347b3e7eaba"
checkout_at "WordPress" "WordPress/WordPress" "45286c5bb3f6fe5005567903ec858d87077eae2c"
known_failures="$(cat script/known-failures.txt)"
tree-sitter parse -q \
'examples/**/*.php' \
$(for file in $known_failures; do echo "!${file}"; done)
example_count=$(find examples -name '*.php' | wc -l)
failure_count=$(wc -w <<< "$known_failures")
success_count=$(( $example_count - $failure_count ))
success_percent=$(bc -l <<< "100*${success_count}/${example_count}")
printf \
"Successfully parsed %d of %d example files (%.1f%%)\n" \
$success_count $example_count $success_percent

@ -1,102 +0,0 @@
const fs = require('fs')
const os = require('os')
const util = require('util');
const { exec, execSync } = require('child_process')
const shell = require('shelljs')
function main() {
checkoutExampleProjects([
{ dir: 'laravel', repository: 'https://github.com/laravel/laravel', sha: '9d0862b3340c8243ee072afc181e315ffa35e110' },
{ dir: 'framework', repository: 'https://github.com/laravel/framework', sha: '45d439e98a6b14afde8911f7d22a265948adbf72' },
{ dir: 'phabricator', repository: 'https://github.com/phacility/phabricator', sha: 'd0b01a41f2498fb2a6487c2d6704dc7acfd4675f' },
{ dir: 'phpunit', repository: 'https://github.com/sebastianbergmann/phpunit', sha: '5e523bdc7dd4d90fed9fb29d1df05347b3e7eaba' },
{ dir: 'WordPress', repository: 'https://github.com/WordPress/WordPress', sha: '45286c5bb3f6fe5005567903ec858d87077eae2c' },
{ dir: 'mediawiki', repository: 'https://github.com/wikimedia/mediawiki', sha: 'b6b88cbf98fb0c7891324709a85eabc290ed28b4' },
])
parseExamples()
}
function parseExamples() {
const knownFailures = loadKnownFailures().split(/\r\n|\n/).filter(line => line.length > 0)
let excludeString = knownFailures.join(" !")
if (knownFailures.length > 0) {
excludeString = "!" + excludeString
}
if (os.platform == 'win32') {
excludeString = convertToWindowsPath(excludeString)
}
exec('"./node_modules/.bin/tree-sitter" parse -q examples/**/*.php ' + excludeString, (err, stdout) => {
const failures = extractFailureFilePaths(stdout)
failures.forEach(failure => {
if (!knownFailures.includes(failure)) {
console.error(`Unknown failure occurred: ${failure}`)
}
})
const failureCount = failures.length + knownFailures.length
const exampleCount = countExampleFiles()
const successCount = exampleCount - failureCount;
const successPercent = 100 * successCount / exampleCount
console.log(`Successfully parsed ${successCount} of ${exampleCount} example files (${successPercent.toFixed(2)}%)`)
})
}
function extractFailureFilePaths(stdout) {
return stdout.split(/\r\n|\n/).filter(line => line.length > 0).map(line => convertToUnixPath(line.substring(0, line.indexOf(" "))))
}
function convertToUnixPath(filePathString) {
return filePathString.split("\\").join("/")
}
function convertToWindowsPath(filePathString) {
return filePathString.split("/").join("\\")
}
function countExampleFiles() {
return shell.find('./examples').filter((file) => { return file.match(/\.php$/) }).length
}
function createExamplesDirectoryIfNotExists() {
const dir = './examples'
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir)
}
}
function checkoutExampleProjects(projects) {
createExamplesDirectoryIfNotExists()
checkoutPromise = util.promisify(checkoutExampleProject)
Promise.all(projects.map((project) => checkoutPromise(project)))
}
function checkoutExampleProject(project) {
const projectDir = './examples/' + project.dir
if (!fs.existsSync(projectDir)) {
cloneRepository(project)
}
checkoutCommit(project)
}
function cloneRepository(project) {
execSync('cd examples && git clone --quiet ' + project.repository + ' ' + project.dir + ' && cd ..')
}
function checkoutCommit(project) {
execSync('cd examples/' + project.dir + ' && git fetch --quiet && git reset --quiet --hard "' + project.sha + '" && cd ../..')
}
function loadKnownFailures() {
return fs.readFileSync('./script/known-failures.txt').toString()
}
main()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,465 +0,0 @@
#include <tree_sitter/parser.h>
#include <vector>
#include <string>
#include <cwctype>
namespace {
using std::vector;
using std::string;
enum TokenType {
AUTOMATIC_SEMICOLON,
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
};
struct Heredoc {
Heredoc() : end_word_indentation_allowed(false) {}
string word;
bool end_word_indentation_allowed;
};
struct Scanner {
bool has_leading_whitespace;
vector<Heredoc> open_heredocs;
Scanner() : has_leading_whitespace(false) {}
void reset() {
open_heredocs.clear();
}
enum ScanContentResult {
Error,
End
};
unsigned serialize(char *buffer) {
unsigned i = 0;
buffer[i++] = open_heredocs.size();
for (
vector<Heredoc>::iterator iter = open_heredocs.begin(),
end = open_heredocs.end();
iter != end;
++iter
) {
if (i + 2 + iter->word.size() >= TREE_SITTER_SERIALIZATION_BUFFER_SIZE) return 0;
buffer[i++] = iter->end_word_indentation_allowed;
buffer[i++] = iter->word.size();
iter->word.copy(&buffer[i], iter->word.size());
i += iter->word.size();
}
return i;
}
void deserialize(const char *buffer, unsigned length) {
unsigned i = 0;
has_leading_whitespace = false;
open_heredocs.clear();
if (length == 0) return;
uint8_t open_heredoc_count = buffer[i++];
for (unsigned j = 0; j < open_heredoc_count; j++) {
Heredoc heredoc;
heredoc.end_word_indentation_allowed = buffer[i++];
uint8_t word_length = buffer[i++];
heredoc.word.assign(buffer + i, buffer + i + word_length);
i += word_length;
open_heredocs.push_back(heredoc);
}
// assert(i == length);
}
void skip(TSLexer *lexer) {
has_leading_whitespace = true;
lexer->advance(lexer, true);
}
static void advance(TSLexer *lexer) {
lexer->advance(lexer, false);
}
bool scan_whitespace(TSLexer *lexer) {
for (;;) {
while (iswspace(lexer->lookahead)) {
advance(lexer);
}
if (lexer->lookahead == '/') {
advance(lexer);
if (lexer->lookahead == '/') {
advance(lexer);
while (lexer->lookahead != 0 && lexer->lookahead != '\n') {
advance(lexer);
}
} else {
return false;
}
} else {
return true;
}
}
}
static bool is_valid_name_char(TSLexer *lexer) {
return iswalpha(lexer->lookahead) || lexer->lookahead == '_';
}
static bool is_escapable_sequence(TSLexer *lexer) {
// Note: remember to also update the escape_sequence rule in the
// main grammar whenever changing this method
int32_t letter = lexer->lookahead;
if (letter == 'n' ||
letter == 'r' ||
letter == 't' ||
letter == 'v' ||
letter == 'e' ||
letter == 'f' ||
letter == '\\' ||
letter == '$' ||
letter == '"') {
return true;
}
// Hex
if (letter == 'x') {
advance(lexer);
return isxdigit(lexer->lookahead);
}
// Unicode
if (letter == 'u') {
return true; // We handle the case where this is not really an escape sequence in grammar.js - this is needed to support the edge case "\u{$a}" in which case "\u" is to be interprented as characters and {$a} as a variable
}
// Octal
return iswdigit(lexer->lookahead) && lexer->lookahead >= '0' && lexer->lookahead <= '7';
}
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;
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 '\n':
case '\r':
return has_content;
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);
// \{ should not be interprented as an escape sequence, but both
// should be consumed as normal characters
if (lexer->lookahead == '{') {
advance(lexer);
break;
}
if (is_heredoc && lexer->lookahead == '\\') {
advance(lexer);
break;
}
if (is_escapable_sequence(lexer)) {
return has_content;
}
break;
case '$':
advance(lexer);
if (is_valid_name_char(lexer) || lexer->lookahead == '{') {
return has_content;
}
break;
case '-':
if (is_after_variable) {
advance(lexer);
if (lexer->lookahead == '>') {
advance(lexer);
if (is_valid_name_char(lexer)) {
return has_content;
}
break;
}
break;
}
case '[':
if (is_after_variable) {
return has_content;
}
advance(lexer);
break;
case '{':
advance(lexer);
if (lexer->lookahead == '$') {
return has_content;
}
break;
default:
if (lexer->eof(lexer)) return false;
advance(lexer);
}
is_after_variable = false;
}
return false;
}
string scan_heredoc_word(TSLexer *lexer) {
string result;
while (is_valid_name_char(lexer)) {
result += lexer->lookahead;
advance(lexer);
}
return result;
}
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;
}
has_leading_whitespace = false;
lexer->mark_end(lexer);
if (valid_symbols[ENCAPSED_STRING_CHARS_AFTER_VARIABLE]) {
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]) {
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;
if (valid_symbols[EOF_TOKEN] && lexer->eof(lexer)) {
lexer->result_symbol = EOF_TOKEN;
return true;
}
if (valid_symbols[HEREDOC_START]) {
lexer->result_symbol = HEREDOC_START;
Heredoc heredoc;
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]) {
lexer->result_symbol = AUTOMATIC_SEMICOLON;
if (lexer->lookahead != '?') return false;
advance(lexer);
return lexer->lookahead == '>';
}
return false;
}
};
}
extern "C" {
void *tree_sitter_php_external_scanner_create() {
return new Scanner();
}
unsigned tree_sitter_php_external_scanner_serialize(void *payload, char *buffer) {
Scanner *scanner = static_cast<Scanner *>(payload);
return scanner->serialize(buffer);
}
void tree_sitter_php_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
Scanner *scanner = static_cast<Scanner *>(payload);
scanner->deserialize(buffer, length);
}
void tree_sitter_php_external_scanner_destroy(void *payload) {
Scanner *scanner = static_cast<Scanner *>(payload);
delete scanner;
}
bool tree_sitter_php_external_scanner_scan(void *payload, TSLexer *lexer,
const bool *valid_symbols) {
Scanner *scanner = static_cast<Scanner *>(payload);
return scanner->scan(lexer, valid_symbols);
}
void tree_sitter_php_external_scanner_reset(void *p) {}
}

@ -1,223 +0,0 @@
#ifndef TREE_SITTER_PARSER_H_
#define TREE_SITTER_PARSER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#define ts_builtin_sym_error ((TSSymbol)-1)
#define ts_builtin_sym_end 0
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
typedef uint16_t TSStateId;
#ifndef TREE_SITTER_API_H_
typedef uint16_t TSSymbol;
typedef uint16_t TSFieldId;
typedef struct TSLanguage TSLanguage;
#endif
typedef struct {
TSFieldId field_id;
uint8_t child_index;
bool inherited;
} TSFieldMapEntry;
typedef struct {
uint16_t index;
uint16_t length;
} TSFieldMapSlice;
typedef struct {
bool visible;
bool named;
bool supertype;
} TSSymbolMetadata;
typedef struct TSLexer TSLexer;
struct TSLexer {
int32_t lookahead;
TSSymbol result_symbol;
void (*advance)(TSLexer *, bool);
void (*mark_end)(TSLexer *);
uint32_t (*get_column)(TSLexer *);
bool (*is_at_included_range_start)(const TSLexer *);
bool (*eof)(const TSLexer *);
};
typedef enum {
TSParseActionTypeShift,
TSParseActionTypeReduce,
TSParseActionTypeAccept,
TSParseActionTypeRecover,
} TSParseActionType;
typedef union {
struct {
uint8_t type;
TSStateId state;
bool extra;
bool repetition;
} shift;
struct {
uint8_t type;
uint8_t child_count;
TSSymbol symbol;
int16_t dynamic_precedence;
uint16_t production_id;
} reduce;
uint8_t type;
} TSParseAction;
typedef struct {
uint16_t lex_state;
uint16_t external_lex_state;
} TSLexMode;
typedef union {
TSParseAction action;
struct {
uint8_t count;
bool reusable;
} entry;
} TSParseActionEntry;
struct TSLanguage {
uint32_t version;
uint32_t symbol_count;
uint32_t alias_count;
uint32_t token_count;
uint32_t external_token_count;
uint32_t state_count;
uint32_t large_state_count;
uint32_t production_id_count;
uint32_t field_count;
uint16_t max_alias_sequence_length;
const uint16_t *parse_table;
const uint16_t *small_parse_table;
const uint32_t *small_parse_table_map;
const TSParseActionEntry *parse_actions;
const char * const *symbol_names;
const char * const *field_names;
const TSFieldMapSlice *field_map_slices;
const TSFieldMapEntry *field_map_entries;
const TSSymbolMetadata *symbol_metadata;
const TSSymbol *public_symbol_map;
const uint16_t *alias_map;
const TSSymbol *alias_sequences;
const TSLexMode *lex_modes;
bool (*lex_fn)(TSLexer *, TSStateId);
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
TSSymbol keyword_capture_token;
struct {
const bool *states;
const TSSymbol *symbol_map;
void *(*create)(void);
void (*destroy)(void *);
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
unsigned (*serialize)(void *, char *);
void (*deserialize)(void *, const char *, unsigned);
} external_scanner;
};
/*
* Lexer Macros
*/
#define START_LEXER() \
bool result = false; \
bool skip = false; \
bool eof = false; \
int32_t lookahead; \
goto start; \
next_state: \
lexer->advance(lexer, skip); \
start: \
skip = false; \
lookahead = lexer->lookahead;
#define ADVANCE(state_value) \
{ \
state = state_value; \
goto next_state; \
}
#define SKIP(state_value) \
{ \
skip = true; \
state = state_value; \
goto next_state; \
}
#define ACCEPT_TOKEN(symbol_value) \
result = true; \
lexer->result_symbol = symbol_value; \
lexer->mark_end(lexer);
#define END_STATE() return result;
/*
* Parse Table Macros
*/
#define SMALL_STATE(id) id - LARGE_STATE_COUNT
#define STATE(id) id
#define ACTIONS(id) id
#define SHIFT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value \
} \
}}
#define SHIFT_REPEAT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value, \
.repetition = true \
} \
}}
#define SHIFT_EXTRA() \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.extra = true \
} \
}}
#define REDUCE(symbol_val, child_count_val, ...) \
{{ \
.reduce = { \
.type = TSParseActionTypeReduce, \
.symbol = symbol_val, \
.child_count = child_count_val, \
__VA_ARGS__ \
}, \
}}
#define RECOVER() \
{{ \
.type = TSParseActionTypeRecover \
}}
#define ACCEPT_INPUT() \
{{ \
.type = TSParseActionTypeAccept \
}}
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_PARSER_H_

@ -1,67 +0,0 @@
=========================================
#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)
)
)
)
)
)
)
)

@ -1,770 +0,0 @@
=========================================
Abstract class
=========================================
<?php
abstract class A {
public function a() {}
abstract public function b();
}
---
(program
(php_tag)
(class_declaration
(abstract_modifier)
(name)
(declaration_list
(method_declaration
(visibility_modifier)
(name)
(formal_parameters)
(compound_statement)
)
(method_declaration
(abstract_modifier)
(visibility_modifier)
(name)
(formal_parameters)
)
)
)
)
=========================================
Anonymous classes
=========================================
<?php
new class {
public function test() {}
};
new class extends A implements B, C {};
new class() {
public $foo;
};
new class($a, $b) extends A {
use T;
};
class A {
public function test() {
return new class($this) extends A {
const A = 'B';
};
}
}
---
(program
(php_tag)
(expression_statement
(object_creation_expression
(declaration_list
(method_declaration
(visibility_modifier)
(name)
(formal_parameters)
(compound_statement)
)
)
)
)
(expression_statement
(object_creation_expression
(base_clause
(name)
)
(class_interface_clause
(name)
(name)
)
(declaration_list)
)
)
(expression_statement
(object_creation_expression
(arguments)
(declaration_list
(property_declaration
(visibility_modifier)
(property_element
(variable_name (name))
)
)
)
)
)
(expression_statement
(object_creation_expression
(arguments
(argument
(variable_name (name))
)
(argument
(variable_name (name))
)
)
(base_clause
(name)
)
(declaration_list
(use_declaration
(name)
)
)
)
)
(class_declaration
(name)
(declaration_list
(method_declaration
(visibility_modifier)
(name)
(formal_parameters)
(compound_statement
(return_statement
(object_creation_expression
(arguments (argument (variable_name (name))))
(base_clause (name))
(declaration_list
(const_declaration
(const_element (name) (string (string_value)))
)
)
)
)
)
)
)
)
)
=========================================
Conditional class definition
=========================================
<?php
if (true) {
class A {}
}
---
(program
(php_tag)
(if_statement
(parenthesized_expression (boolean))
(compound_statement
(class_declaration
(name)
(declaration_list)
)
)
)
)
=========================================
Class constant modifiers
=========================================
<?php
class Foo {
const A = 1;
public const B = 2;
protected const C = 3;
private const D = 4;
final const E = 5;
}
---
(program
(php_tag)
(class_declaration
(name)
(declaration_list
(const_declaration
(const_element (name) (integer))
)
(const_declaration
(visibility_modifier)
(const_element (name) (integer))
)
(const_declaration
(visibility_modifier)
(const_element (name) (integer))
)
(const_declaration
(visibility_modifier)
(const_element (name) (integer))
)
(const_declaration
(final_modifier)
(const_element (name) (integer))
)
)
)
)
=========================================
Final class
=========================================
<?php
final class A {}
---
(program
(php_tag)
(class_declaration
(final_modifier)
(name)
(declaration_list)
)
)
=========================================
Implicitly public properties and methods
=========================================
<?php
abstract class A {
var $a;
static $b;
abstract function c();
final function d() {}
static function e() {}
final static function f() {}
function g() {}
}
---
(program
(php_tag)
(class_declaration
(abstract_modifier)
(name)
(declaration_list
(property_declaration
(var_modifier)
(property_element (variable_name (name)))
)
(property_declaration
(static_modifier)
(property_element (variable_name (name)))
)
(method_declaration
(abstract_modifier)
(name)
(formal_parameters)
)
(method_declaration
(final_modifier)
(name)
(formal_parameters)
(compound_statement)
)
(method_declaration
(static_modifier)
(name)
(formal_parameters)
(compound_statement)
)
(method_declaration
(final_modifier)
(static_modifier)
(name)
(formal_parameters)
(compound_statement)
)
(method_declaration
(name)
(formal_parameters)
(compound_statement)
)
)
)
)
=========================================
Property Types
=========================================
<?php
class A {
public string $a;
protected static D $b;
private ?float $c;
private $d;
}
---
(program
(php_tag)
(class_declaration
name: (name)
body: (declaration_list
(property_declaration
(visibility_modifier)
type: (union_type (primitive_type))
(property_element (variable_name (name)))
)
(property_declaration
(visibility_modifier)
(static_modifier)
type: (union_type (named_type (name)))
(property_element (variable_name (name)))
)
(property_declaration
(visibility_modifier)
type: (union_type (optional_type (primitive_type)))
(property_element (variable_name (name)))
)
(property_declaration
(visibility_modifier)
(property_element (variable_name (name)))
)
)
)
)
=========================================
Constructor Property Promotion
=========================================
<?php
class Point {
public function __construct(
public float $x = 0.0,
float $y = 0.0,
private float $z = 0.0
) {}
}
---
(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)
type: (union_type
(primitive_type)
)
name: (variable_name (name))
default_value: (float)
)
(simple_parameter
type: (union_type (primitive_type))
name: (variable_name (name))
default_value: (float)
)
(property_promotion_parameter
visibility: (visibility_modifier)
type: (union_type (primitive_type))
name: (variable_name (name))
default_value: (float)
)
)
body: (compound_statement)
)
)
)
)
================================================================================
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)))))

@ -1,706 +0,0 @@
=========================================
Interface declarations
=========================================
<?php
interface ThrowableInterface {
public function getMessage();
}
class Exception_foo implements ThrowableInterface {
public $foo = "foo";
public function getMessage() {
return $this->foo;
}
}
---
(program
(php_tag)
(interface_declaration
name: (name)
body: (declaration_list
(method_declaration
(visibility_modifier)
name: (name)
parameters: (formal_parameters))))
(class_declaration
name: (name)
(class_interface_clause (name))
body: (declaration_list
(property_declaration
(visibility_modifier)
(property_element (variable_name (name)) (property_initializer (encapsed_string (string_value)))))
(method_declaration
(visibility_modifier)
name: (name)
parameters: (formal_parameters)
body: (compound_statement
(return_statement (member_access_expression
object: (variable_name (name))
name: (name))))))))
==========================
Use declarations
==========================
<?php
trait AbstractTrait
{
use LoggerAwareTrait;
use LoggerAwareTrait, OtherTrait {}
use LoggerAwareTrait, OtherTrait;
}
class AbstractCache
{
use AbstractTrait {
deleteItems as private;
AbstractTrait::deleteItem as delete;
AbstractTrait::hasItem as has;
}
}
---
(program
(php_tag)
(trait_declaration
(name)
(declaration_list
(use_declaration (name))
(use_declaration (name) (name) (use_list))
(use_declaration (name) (name))))
(class_declaration
(name)
(declaration_list
(use_declaration
(name)
(use_list
(use_as_clause (name) (visibility_modifier))
(use_as_clause (class_constant_access_expression (name) (name)) (name))
(use_as_clause (class_constant_access_expression (name) (name)) (name)))))))
==========================
Namespace names in namespaces
==========================
<?php
namespace Be \ ta {
class A {}
class B {}
}
---
(program
(php_tag)
(namespace_definition
name: (namespace_name (name) (name))
body: (compound_statement
(class_declaration
name: (name)
body: (declaration_list))
(class_declaration
name: (name)
body: (declaration_list)))))
==============================
Class declarations
==============================
<?php
class foo {
function __construct($name) {
$GLOBALS['List']= &$this;
$this->Name = $name;
$GLOBALS['List']->echoName();
}
function echoName() {
$GLOBALS['names'][]=$this->Name;
}
}
---
(program
(php_tag)
(class_declaration
name: (name)
body: (declaration_list
(method_declaration
name: (name)
parameters: (formal_parameters
(simple_parameter
name: (variable_name (name))))
body: (compound_statement
(expression_statement (reference_assignment_expression
left: (subscript_expression (variable_name (name)) (string (string_value)))
right: (variable_name (name))))
(expression_statement (assignment_expression
left: (member_access_expression
object: (variable_name (name))
name: (name))
right: (variable_name (name))))
(expression_statement (member_call_expression
object: (subscript_expression (variable_name (name)) (string (string_value)))
name: (name)
arguments: (arguments)))))
(method_declaration
name: (name)
parameters: (formal_parameters)
body: (compound_statement
(expression_statement (assignment_expression
left: (subscript_expression (subscript_expression (variable_name (name)) (string (string_value))))
right: (member_access_expression
object: (variable_name (name))
name: (name)))))))))
========================================
Class declarations with base classes
========================================
<?php
class A extends B {
}
---
(program
(php_tag)
(class_declaration
name: (name)
(base_clause (name))
body: (declaration_list)))
==========================
Function parameters
==========================
<?php
function test(int $a, string ...$b)
{
}
---
(program
(php_tag)
(function_definition
name: (name)
parameters: (formal_parameters
(simple_parameter
type: (union_type (primitive_type))
name: (variable_name (name)))
(variadic_parameter
type: (union_type (primitive_type))
name: (variable_name (name))))
body: (compound_statement)))
====================================
Functions with default parameters
====================================
<?php
function a($arg = self::bar) {
echo $arg;
}
---
(program
(php_tag)
(function_definition
(name)
(formal_parameters
(simple_parameter
(variable_name (name))
(class_constant_access_expression (relative_scope) (name))))
(compound_statement (echo_statement (variable_name (name))))))
========================================================================
Static variables in functions
========================================================================
<?php
function blah()
{
static $hey=0, $yo=0;
}
---
(program
(php_tag)
(function_definition
(name)
(formal_parameters)
(compound_statement
(function_static_declaration
(static_variable_declaration (variable_name (name)) (integer))
(static_variable_declaration (variable_name (name)) (integer))))))
=========================================
Defining Constants
=========================================
<?php
define("CONSTANT", "Hello world.");
const CONSTANT = 'Hello World';
const ANOTHER_CONST = CONSTANT.'; Goodbye World';
const ANIMALS = array('dog', 'cat', 'bird');
define('ANIMALS', array(
'dog',
'cat',
'bird'
));
---
(program
(php_tag)
(expression_statement
(function_call_expression
(name)
(arguments
(argument (encapsed_string (string_value)))
(argument (encapsed_string (string_value)))
)
)
)
(const_declaration
(const_element
(name)
(string (string_value))
)
)
(const_declaration
(const_element
(name)
(binary_expression
(name)
(string (string_value))
)
)
)
(const_declaration
(const_element
(name)
(array_creation_expression
(array_element_initializer (string (string_value)))
(array_element_initializer (string (string_value)))
(array_element_initializer (string (string_value)))
)
)
)
(expression_statement
(function_call_expression
(name)
(arguments
(argument (string (string_value)))
(argument
(array_creation_expression
(array_element_initializer (string (string_value)))
(array_element_initializer (string (string_value)))
(array_element_initializer (string (string_value)))
)
)
)
)
)
)
=======================================
Attributes
=======================================
<?php
#[Test]
function a(#[Test] $a) {
$c;
}
class PostsController
{
#[Test]
const CONSTANT = 'constant value';
#[Test]
private string $a = '';
#[Route("/api/posts/{id}", ["GET"])]
public function get(#[Test] $id) { /* ... */ }
}
#[MyAttribute]
#[\MyExample\MyAttribute]
#[MyAttribute(1234)]
#[MyAttribute(MyAttribute::VALUE)]
#[MyAttribute(array("key" => "value"))]
#[MyAttribute(100 + 200)]
class Thing
{
}
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_group (attribute (name))))
name: (name)
parameters: (formal_parameters
(simple_parameter
attributes: (attribute_list
(attribute_group (attribute (name)))
)
name: (variable_name (name))
)
)
body: (compound_statement (expression_statement (variable_name (name))))
)
(class_declaration
name: (name)
body: (declaration_list
(const_declaration
attributes: (attribute_list (attribute_group (attribute (name))))
(const_element (name) (string (string_value)))
)
(property_declaration
attributes: (attribute_list (attribute_group (attribute (name))))
(visibility_modifier)
type: (union_type (primitive_type))
(property_element (variable_name (name))
(property_initializer (string (string_value)))
)
)
(method_declaration
attributes: (attribute_list
(attribute_group
(attribute
(name)
parameters: (arguments
(argument (encapsed_string (string_value)))
(argument
(array_creation_expression
(array_element_initializer (encapsed_string (string_value)))
)
)
)
)
)
)
(visibility_modifier)
name: (name)
parameters: (formal_parameters
(simple_parameter
attributes: (attribute_list (attribute_group (attribute (name))))
name: (variable_name (name))
)
)
body: (compound_statement (comment))
)
)
)
(class_declaration
attributes: (attribute_list
(attribute_group
(attribute (name))
)
(attribute_group
(attribute
(qualified_name
(namespace_name_as_prefix
(namespace_name (name))
)
(name)
)
)
)
(attribute_group
(attribute
(name)
parameters: (arguments (argument (integer)))
)
)
(attribute_group
(attribute
(name)
parameters: (arguments
(argument
(class_constant_access_expression
(name)
(name)
)
)
)
)
)
(attribute_group
(attribute
(name)
parameters: (arguments
(argument
(array_creation_expression
(array_element_initializer
(encapsed_string (string_value))
(encapsed_string (string_value))
)
)
)
)
)
)
(attribute_group
(attribute
(name)
parameters: (arguments
(argument
(binary_expression
left: (integer)
right: (integer)
)
)
)
)
)
)
name: (name)
body: (declaration_list)
)
(expression_statement
(object_creation_expression
attributes: (attribute_list (attribute_group (attribute (name))))
(arguments)
(declaration_list)
)
)
(expression_statement
(arrow_function
attributes: (attribute_list (attribute_group (attribute (name))))
parameters: (formal_parameters
(simple_parameter
name: (variable_name (name))
)
)
body: (variable_name (name))
)
)
(expression_statement
(assignment_expression
left: (variable_name (name))
right: (anonymous_function_creation_expression
attributes: (attribute_list (attribute_group (attribute (name))))
parameters: (formal_parameters
(simple_parameter
name: (variable_name (name))
)
)
body: (compound_statement
(return_statement
(variable_name (name))
)
)
)
)
)
(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)
)
)
=======================================
Enums
=======================================
<?php
enum A {}
enum B implements Bar, Baz {
}
enum C: int implements Bar {}
enum Suit: string
{
case Hearts = 'H';
case Diamonds;
case Clubs = 'C';
case Spades = 'S';
// Fulfills the interface contract.
public function color(): string {
return match($this) {
Suit::Hearts, Suit::Diamonds => 'Red',
Suit::Clubs, Suit::Spades => 'Black',
};
}
}
---
(program
(php_tag)
(enum_declaration
(name)
(enum_declaration_list)
)
(enum_declaration
(name)
(class_interface_clause
(name)
(name)
)
(enum_declaration_list)
)
(enum_declaration
(name)
(union_type (primitive_type))
(class_interface_clause (name))
(enum_declaration_list)
)
(enum_declaration
(name)
(union_type (primitive_type))
(enum_declaration_list
(enum_case (name) (string (string_value)))
(enum_case (name))
(enum_case (name) (string (string_value)))
(enum_case (name) (string (string_value)))
(comment)
(method_declaration
(visibility_modifier)
(name)
(formal_parameters)
(union_type (primitive_type))
(compound_statement
(return_statement
(match_expression
(parenthesized_expression
(variable_name (name))
)
(match_block
(match_conditional_expression
(match_condition_list
(class_constant_access_expression (name) (name))
(class_constant_access_expression (name) (name))
)
(string (string_value))
)
(match_conditional_expression
(match_condition_list
(class_constant_access_expression (name) (name))
(class_constant_access_expression (name) (name))
)
(string (string_value))
)
)
)
)
)
)
)
)
)

File diff suppressed because it is too large Load Diff

@ -1,188 +0,0 @@
====================
no interpolated text
====================
<?php
echo "hi";
---
(program
(php_tag)
(echo_statement (encapsed_string (string_value))))
===============================
interpolated text at beginning
===============================
<div>
<?php
echo "hi";
---
(program
(text)
(php_tag)
(echo_statement (encapsed_string (string_value))))
===============================
interpolated text at end
===============================
<?php
echo "hi";
?>
<div>
---
(program
(php_tag)
(echo_statement (encapsed_string (string_value)))
(text_interpolation (text)))
===============================
interpolated text in middle
===============================
<?php
echo "hi";
?>
<div>
<?php
echo "bye";
?>
---
(program
(php_tag)
(echo_statement (encapsed_string (string_value)))
(text_interpolation
(text)
(php_tag))
(echo_statement (encapsed_string (string_value)))
(text_interpolation))
==============================
short open tag: On
==============================
<?
echo "Used a short tag\n";
?>
Finished
---
(program
(php_tag)
(echo_statement (encapsed_string (string_value) (escape_sequence)))
(text_interpolation (text)))
==============================
short open tag: Off
==============================
<div>one</div>
<?php
$a = 'This gets echoed twice';
?>
<?= $a ?>
<div>two</div>
<? $b=3; ?>
<?php
echo "{$b}";
?>
<?= "{$b}" ?>
---
(program
(text)
(php_tag)
(expression_statement (assignment_expression (variable_name (name)) (string (string_value))))
(text_interpolation (php_tag))
(expression_statement (variable_name (name)))
(text_interpolation (text) (php_tag))
(expression_statement (assignment_expression (variable_name (name)) (integer)))
(text_interpolation (php_tag))
(echo_statement (encapsed_string (variable_name (name))))
(text_interpolation (php_tag))
(expression_statement (encapsed_string (variable_name (name))))
(text_interpolation))
======================
Single line php comment
======================
<ul class="foo"><?php // this is a comment ?></ul>
<?php
// foo?
// foo? bar?
echo "hi";
---
(program
(text)
(php_tag)
(comment)
(text_interpolation (text) (php_tag))
(comment)
(comment)
(echo_statement (encapsed_string (string_value))))
=======================================
Singel line comment without any content
=======================================
<?php
# Check if PHP xml isn't compiled
#
if ( ! function_exists('xml_parser_create') ) {
echo $test;
}
---
(program
(php_tag)
(comment)
(comment)
(if_statement
condition: (parenthesized_expression
(unary_op_expression
(function_call_expression
function: (name)
arguments: (arguments (argument (string (string_value))))
)
)
)
body: (compound_statement (echo_statement (variable_name (name))))
)
)
=====================================
Closing tags before the first PHP tag
=====================================
a ?> b <?php c;
---
(program
(text)
(php_tag)
(expression_statement
(name)))

@ -1,109 +0,0 @@
========================
Booleans
========================
<?php
True;
true;
TRUE;
false;
False;
FALSE;
?>
---
(program
(php_tag)
(expression_statement (boolean))
(expression_statement (boolean))
(expression_statement (boolean))
(expression_statement (boolean))
(expression_statement (boolean))
(expression_statement (boolean))
(text_interpolation))
==========================
Floats
==========================
<?php
1.0;
1E432;
1.0E-3432;
1423.0E3432;
.5;
6.674_083e11;
107_925_284.88;
---
(program
(php_tag)
(expression_statement (float))
(expression_statement (float))
(expression_statement (float))
(expression_statement (float))
(expression_statement (float))
(expression_statement (float))
(expression_statement (float))
)
==========================
Integers
==========================
<?php
1234;
1_234_456;
0123;
0123_456;
0x1A;
0x1A_2B_3C;
0b111111111;
0b1111_1111_1111;
0o123;
---
(program
(php_tag)
(expression_statement (integer))
(expression_statement (integer))
(expression_statement (integer))
(expression_statement (integer))
(expression_statement (integer))
(expression_statement (integer))
(expression_statement (integer))
(expression_statement (integer))
(expression_statement (integer))
)
============================
Testing string scanner confirmance
==============================
<?php echo "\"\t\\'" . '\n\\\'a\\\b\\' ?>
---
(program
(php_tag)
(echo_statement (binary_expression (encapsed_string (escape_sequence) (escape_sequence) (escape_sequence) (string_value)) (string (string_value))))
(text_interpolation))
==========================
Shell command
==========================
<?php
`ls -la`;
`ls`;
---
(program
(php_tag)
(expression_statement (shell_command_expression))
(expression_statement (shell_command_expression)))

@ -1,469 +0,0 @@
==============================
If statements
==============================
<?php
if ($a > 0) {
echo "Yes";
}
if ($a==0) {
echo "bad";
} else {
echo "good";
}
if ($a==0) {
echo "bad";
} elseif ($a==3) {
echo "bad";
} else {
echo "good";
}
---
(program
(php_tag)
(if_statement
condition: (parenthesized_expression (binary_expression
left: (variable_name (name))
right: (integer)))
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_value))))
alternative: (else_clause
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_value))))
alternative: (else_if_clause
condition: (parenthesized_expression (binary_expression
left: (variable_name (name))
right: (integer)))
body: (compound_statement (echo_statement (encapsed_string (string_value)))))
alternative: (else_clause
body: (compound_statement (echo_statement (encapsed_string (string_value)))))))
==============================
Alternative if statements
==============================
<?php
if ($a) echo 1; else echo 0;
if ($a):
echo 1;
echo 2;
else:
echo 0;
endif;
---
(program
(php_tag)
(if_statement
condition: (parenthesized_expression (variable_name (name)))
body: (echo_statement (integer))
alternative: (else_clause
body: (echo_statement (integer))))
(if_statement
condition: (parenthesized_expression (variable_name (name)))
body: (colon_block
(echo_statement (integer))
(echo_statement (integer)))
alternative: (else_clause
body: (colon_block
(echo_statement (integer))))))
====================================
Wordpress colon blocks
====================================
<?php
if ($post) :
?>
<?php
if ( $open ) {
$attachment_id;
}
?>
<?php
else :
$post;
endif;
?>
---
(program
(php_tag)
(if_statement
condition: (parenthesized_expression (variable_name (name)))
body: (colon_block
(text_interpolation (php_tag))
(if_statement
condition: (parenthesized_expression (variable_name (name)))
body: (compound_statement (expression_statement (variable_name (name))))
)
)
(text_interpolation (php_tag))
alternative: (else_clause
body: (colon_block
(expression_statement (variable_name (name)))
)
)
)
(text_interpolation)
)
==============================
While statements
==============================
<?php
while ($a < 10) {
echo $a;
$a++;
}
---
(program
(php_tag)
(while_statement
condition: (parenthesized_expression (binary_expression
left: (variable_name (name))
right: (integer)))
body: (compound_statement
(echo_statement (variable_name (name)))
(expression_statement (update_expression (variable_name (name)))))))
==============================
Alternative while statements
==============================
<?php
while ($a<5) echo $a++;
while ($a<9):
echo ++$a;
echo $b;
endwhile;
---
(program
(php_tag)
(while_statement
condition: (parenthesized_expression (binary_expression
left: (variable_name (name))
right: (integer)))
body: (echo_statement (update_expression (variable_name (name)))))
(while_statement
condition: (parenthesized_expression (binary_expression
left: (variable_name (name))
right: (integer)))
body: (colon_block
(echo_statement (update_expression (variable_name (name))))
(echo_statement (variable_name (name))))))
==============================
For statements
==============================
<?php
for($a=0;$a<5;$a++) echo $a;
for($a=0;$a<5;$a++):
echo $a;
endfor;
---
(program
(php_tag)
(for_statement
(assignment_expression (variable_name (name)) (integer))
(binary_expression (variable_name (name)) (integer))
(update_expression (variable_name (name)))
(echo_statement (variable_name (name))))
(for_statement
(assignment_expression (variable_name (name)) (integer))
(binary_expression (variable_name (name)) (integer))
(update_expression (variable_name (name)))
(echo_statement (variable_name (name)))))
==============================
Switch statements
==============================
<?php
switch ($a) {
case 0:
echo "bad";
break;
case 1:
echo "good";
break;
default:
echo "bad";
break;
}
?>
---
(program
(php_tag)
(switch_statement
condition: (parenthesized_expression (variable_name (name)))
body: (switch_block
(case_statement
value: (integer)
(echo_statement (encapsed_string (string_value))) (break_statement))
(case_statement
value: (integer)
(echo_statement (encapsed_string (string_value))) (break_statement))
(default_statement
(echo_statement (encapsed_string (string_value))) (break_statement))))
(text_interpolation))
==============================
Alternative switch statements
==============================
<?php
switch ($a):
case 0;
echo 0;
break;
case 5:
echo 1;
break;
default;
echo 0;
break;
endswitch;
---
(program
(php_tag)
(switch_statement
condition: (parenthesized_expression (variable_name (name)))
body: (switch_block
(case_statement
value: (integer)
(echo_statement (integer))
(break_statement))
(case_statement
value: (integer)
(echo_statement (integer))
(break_statement))
(default_statement
(echo_statement (integer))
(break_statement)))))
==============================
Include statement
==============================
<?php
include "015.inc";
---
(program
(php_tag)
(expression_statement (include_expression (encapsed_string (string_value)))))
==============================
Do-while statements
==============================
<?php
do {
echo $i;
$i--;
} while($i>0);
---
(program
(php_tag)
(do_statement
body: (compound_statement
(echo_statement (variable_name (name)))
(expression_statement (update_expression (variable_name (name)))))
condition: (parenthesized_expression (binary_expression
left: (variable_name (name))
right: (integer)))))
==============================
Try statements
==============================
<?php
try {
} catch (MyException) {
} catch (OtherException|YetAnotherException $e) {
} finally {
}
try {
ThrowException();
} catch (MyException $exception) {
print "There was an exception: " . $exception->getException();
print "\n";
}
---
(program
(php_tag)
(try_statement
body: (compound_statement)
(catch_clause
type: (type_list
(named_type (name))
)
body: (compound_statement))
(catch_clause
type: (type_list
(named_type (name))
(named_type (name))
)
name: (variable_name (name))
body: (compound_statement))
(finally_clause
body: (compound_statement)))
(try_statement
body: (compound_statement
(expression_statement (function_call_expression
function: (name)
arguments: (arguments))))
(catch_clause
type: (type_list
(named_type (name))
)
name: (variable_name (name))
body: (compound_statement
(expression_statement (print_intrinsic (binary_expression
left: (encapsed_string (string_value))
right: (member_call_expression
object: (variable_name (name))
name: (name)
arguments: (arguments)))))
(expression_statement (print_intrinsic (encapsed_string (escape_sequence))))))))
==============================
Foreach statements
==============================
<?php
foreach ($a as $b[0]) {
echo $b[0]."\n";
}
foreach($arr as $key => $value);
foreach($a as $b):
echo $a;
echo $b;
endforeach;
---
(program
(php_tag)
(foreach_statement
(variable_name (name))
(subscript_expression (variable_name (name)) (integer))
body: (compound_statement
(echo_statement (binary_expression
left: (subscript_expression (variable_name (name)) (integer))
right: (encapsed_string (escape_sequence))))))
(foreach_statement
(variable_name (name))
(pair (variable_name (name)) (variable_name (name))))
(foreach_statement
(variable_name (name))
(variable_name (name))
body: (colon_block
(echo_statement (variable_name (name)))
(echo_statement (variable_name (name))))))
=================================
Case insensitive keywords
=================================
<?php
FOREACH ($a AS $b) {
DO {
if ($c) {
d();
} else {
e();
}
} while ($f);
}
---
(program
(php_tag)
(foreach_statement
(variable_name (name))
(variable_name (name))
(compound_statement
(do_statement
(compound_statement
(if_statement
(parenthesized_expression (variable_name (name)))
(compound_statement
(expression_statement (function_call_expression (name) (arguments))))
(else_clause
(compound_statement
(expression_statement (function_call_expression (name) (arguments)))))))
(parenthesized_expression (variable_name (name)))))))
=========================================
Accessing Constants
=========================================
<?php
echo ANOTHER_CONST;
echo ANIMALS[1];
---
(program
(php_tag)
(echo_statement
(name)
)
(echo_statement
(subscript_expression
(name)
(integer)
)
)
)

File diff suppressed because it is too large Load Diff

@ -1,171 +0,0 @@
=========================
Type names
=========================
<?php
function a(): A {}
function b(): A\B {}
---
(program
(php_tag)
(function_definition
(name) (formal_parameters)
(union_type (named_type (name)))
(compound_statement))
(function_definition
(name) (formal_parameters)
(union_type
(named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name)))
)
(compound_statement)))
=========================
Primitive types
=========================
<?php
function a(): int {}
function b(): callable {}
function c(): iterable {}
function d(): never {}
---
(program
(php_tag)
(function_definition
(name) (formal_parameters)
(union_type (primitive_type))
(compound_statement))
(function_definition
(name) (formal_parameters)
(union_type (primitive_type))
(compound_statement))
(function_definition
(name) (formal_parameters)
(union_type (primitive_type))
(compound_statement))
(function_definition
(name) (formal_parameters)
(bottom_type)
(compound_statement)))
=======================
Optional types
=======================
<?php
function a(): ?array {}
function b(): ?Something {}
---
(program
(php_tag)
(function_definition
(name) (formal_parameters)
(union_type
(optional_type (primitive_type))
)
(compound_statement))
(function_definition
(name) (formal_parameters)
(union_type
(optional_type (named_type (name)))
)
(compound_statement)))
==========================
Union types
==========================
<?php
function a(int|string|null $var) : ?int|MyClass {}
---
(program
(php_tag)
(function_definition
name: (name)
parameters: (formal_parameters
(simple_parameter
type: (union_type
(primitive_type)
(primitive_type)
(primitive_type)
)
name: (variable_name (name))
)
)
return_type: (union_type
(optional_type
(primitive_type)
)
(named_type (name))
)
body: (compound_statement)
)
)
==========================
Mixed type
==========================
<?php
function a(mixed|string $var) : mixed {
}
---
(program
(php_tag)
(function_definition
(name)
(formal_parameters
(simple_parameter
(union_type
(primitive_type)
(primitive_type)
)
(variable_name (name))
)
)
(union_type (primitive_type))
(compound_statement)
)
)
==========================
Static type
==========================
<?php
function a(string $var) : static {
}
---
(program
(php_tag)
(function_definition
(name)
(formal_parameters
(simple_parameter
(union_type
(primitive_type)
)
(variable_name (name))
)
)
(union_type (primitive_type))
(compound_statement)
)
)

@ -1,47 +0,0 @@
<?php
// <- tag
if ($a) {}
// <- keyword
while ($b) {}
// <- keyword
WHILE ($b) {}
// <- keyword
do { } while ($c);
// <- keyword
// ^ keyword
try {} catch (Exception $e) {}
// <- keyword
// ^ keyword
function a() {}
// <- keyword
class A {}
// <- keyword
throw new Exception("oh");
// <- keyword
// ^ keyword
function b(
int $a,
// <- type.builtin
string $b,
// <- type.builtin
Person $e
// ^ type
): Dog {}
// ^ type
interface T {}
// ^ keyword
trait T {}
// ^ keyword

@ -1,16 +0,0 @@
<?php
echo <<<OMG
something
OMG
// <- string
echo true, TRUE, false, FALSE
// ^ constant.builtin
// ^ constant.builtin
// ^ constant.builtin
// ^ constant.builtin
echo PI_314
// ^ constant

@ -1,9 +0,0 @@
<?php
function a(array $b, Something $c) {
// ^ type.builtin
// ^ type
echo (int) $foo;
// ^ type.builtin
}