mirror of https://github.com/Wilfred/difftastic/
Add 'vendor/tree-sitter-php/' from commit '0ce134234214427b6aeb2735e93a307881c6cd6f'
git-subtree-dir: vendor/tree-sitter-php git-subtree-mainline:pull/297/head020983cd85git-subtree-split:0ce1342342
commit
51a4da6d7c
@ -0,0 +1,3 @@
|
||||
/src/** linguist-vendored
|
||||
/examples/* linguist-vendored
|
||||
/corpus/* linguist-vendored
|
||||
@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
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)
|
||||
@ -0,0 +1,22 @@
|
||||
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: 14
|
||||
- run: npm install
|
||||
- run: npm test
|
||||
@ -0,0 +1,6 @@
|
||||
package-lock.json
|
||||
node_modules
|
||||
build
|
||||
*.log
|
||||
.DS_Store
|
||||
examples
|
||||
@ -0,0 +1,5 @@
|
||||
test
|
||||
build
|
||||
script
|
||||
examples
|
||||
target
|
||||
@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "tree-sitter-php"
|
||||
description = "php grammar for the tree-sitter parsing library"
|
||||
version = "0.19.0"
|
||||
keywords = ["incremental", "parsing", "php"]
|
||||
categories = ["parsing", "text-editors"]
|
||||
repository = "https://github.com/tree-sitter/tree-sitter-javascript"
|
||||
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"
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
@ -0,0 +1,21 @@
|
||||
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.
|
||||
@ -0,0 +1,9 @@
|
||||
tree-sitter-php
|
||||
==================
|
||||
|
||||
[](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
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
#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
|
||||
@ -0,0 +1,19 @@
|
||||
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 (_) {}
|
||||
@ -0,0 +1,48 @@
|
||||
# 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
|
||||
@ -0,0 +1,29 @@
|
||||
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");
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
//! 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 HIGHLIGHTS_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");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,40 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,115 @@
|
||||
(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
|
||||
@ -0,0 +1,3 @@
|
||||
((text) @injection.content
|
||||
(#set! injection.language "html")
|
||||
(#set! injection.combined))
|
||||
@ -0,0 +1,26 @@
|
||||
(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
|
||||
@ -0,0 +1 @@
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
#!/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
|
||||
@ -0,0 +1,102 @@
|
||||
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
@ -0,0 +1,381 @@
|
||||
#include <tree_sitter/parser.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cwctype>
|
||||
|
||||
namespace {
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
enum TokenType {
|
||||
AUTOMATIC_SEMICOLON,
|
||||
HEREDOC,
|
||||
ENCAPSED_STRING_CHARS,
|
||||
ENCAPSED_STRING_CHARS_AFTER_VARIABLE,
|
||||
EOF_TOKEN,
|
||||
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
|
||||
auto 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_encapsed_part_string(TSLexer *lexer, bool is_after_variable) {
|
||||
lexer->result_symbol = ENCAPSED_STRING_CHARS;
|
||||
|
||||
for (bool has_content = false;; has_content = true) {
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
switch (lexer->lookahead) {
|
||||
case '"':
|
||||
return has_content;
|
||||
case '\0':
|
||||
return false;
|
||||
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_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:
|
||||
advance(lexer);
|
||||
}
|
||||
|
||||
is_after_variable = 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
has_leading_whitespace = false;
|
||||
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
if (valid_symbols[ENCAPSED_STRING_CHARS_AFTER_VARIABLE]) {
|
||||
return scan_encapsed_part_string(lexer, true);
|
||||
}
|
||||
|
||||
if (valid_symbols[ENCAPSED_STRING_CHARS]) {
|
||||
return scan_encapsed_part_string(lexer, false);
|
||||
}
|
||||
|
||||
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]) {
|
||||
if (lexer->lookahead == '<') {
|
||||
advance(lexer);
|
||||
if (lexer->lookahead != '<') return false;
|
||||
advance(lexer);
|
||||
if (lexer->lookahead != '<') return false;
|
||||
advance(lexer);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {}
|
||||
|
||||
}
|
||||
@ -0,0 +1,223 @@
|
||||
#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_
|
||||
@ -0,0 +1,396 @@
|
||||
=========================================
|
||||
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))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
=========================================
|
||||
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)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -0,0 +1,603 @@
|
||||
=========================================
|
||||
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)))))
|
||||
(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))
|
||||
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))
|
||||
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)))
|
||||
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)))
|
||||
(argument (encapsed_string (string)))
|
||||
)
|
||||
)
|
||||
)
|
||||
(const_declaration
|
||||
(const_element
|
||||
(name)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(const_declaration
|
||||
(const_element
|
||||
(name)
|
||||
(binary_expression
|
||||
(name)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
)
|
||||
(const_declaration
|
||||
(const_element
|
||||
(name)
|
||||
(array_creation_expression
|
||||
(array_element_initializer (string))
|
||||
(array_element_initializer (string))
|
||||
(array_element_initializer (string))
|
||||
)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(function_call_expression
|
||||
(name)
|
||||
(arguments
|
||||
(argument (string))
|
||||
(argument
|
||||
(array_creation_expression
|
||||
(array_element_initializer (string))
|
||||
(array_element_initializer (string))
|
||||
(array_element_initializer (string))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
=======================================
|
||||
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;};
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
|
||||
(function_definition
|
||||
attributes: (attribute_list (attribute (name)))
|
||||
name: (name)
|
||||
parameters: (formal_parameters
|
||||
(simple_parameter
|
||||
attributes: (attribute_list (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 (name)))
|
||||
(const_element (name) (string))
|
||||
)
|
||||
|
||||
(property_declaration
|
||||
attributes: (attribute_list (attribute (name)))
|
||||
(visibility_modifier)
|
||||
type: (union_type (primitive_type))
|
||||
(property_element (variable_name (name))
|
||||
(property_initializer (string))
|
||||
)
|
||||
)
|
||||
(method_declaration
|
||||
attributes: (attribute_list
|
||||
(attribute
|
||||
(name)
|
||||
parameters: (arguments
|
||||
(argument (encapsed_string (string)))
|
||||
(argument
|
||||
(array_creation_expression
|
||||
(array_element_initializer (encapsed_string (string)))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(visibility_modifier)
|
||||
name: (name)
|
||||
parameters: (formal_parameters
|
||||
(simple_parameter
|
||||
attributes: (attribute_list (attribute (name)))
|
||||
name: (variable_name (name))
|
||||
)
|
||||
)
|
||||
body: (compound_statement (comment))
|
||||
)
|
||||
)
|
||||
)
|
||||
(class_declaration
|
||||
attributes: (attribute_list
|
||||
(attribute (name))
|
||||
(attribute
|
||||
(qualified_name
|
||||
(namespace_name_as_prefix
|
||||
(namespace_name (name))
|
||||
)
|
||||
(name)
|
||||
)
|
||||
)
|
||||
(attribute
|
||||
(name)
|
||||
parameters: (arguments (argument (integer)))
|
||||
)
|
||||
(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
|
||||
(name)
|
||||
parameters: (arguments
|
||||
(argument
|
||||
(binary_expression
|
||||
left: (integer)
|
||||
right: (integer)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
name: (name)
|
||||
body: (declaration_list)
|
||||
)
|
||||
(expression_statement
|
||||
(object_creation_expression
|
||||
attributes: (attribute_list (attribute (name)))
|
||||
(arguments)
|
||||
(declaration_list)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(arrow_function
|
||||
attributes: (attribute_list (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 (name)))
|
||||
parameters: (formal_parameters
|
||||
(simple_parameter
|
||||
name: (variable_name (name))
|
||||
)
|
||||
)
|
||||
body: (compound_statement
|
||||
(return_statement
|
||||
(variable_name (name))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
=======================================
|
||||
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))
|
||||
(enum_case (name))
|
||||
(enum_case (name) (string))
|
||||
(enum_case (name) (string))
|
||||
|
||||
(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)
|
||||
)
|
||||
(match_conditional_expression
|
||||
(match_condition_list
|
||||
(class_constant_access_expression (name) (name))
|
||||
(class_constant_access_expression (name) (name))
|
||||
)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,188 @@
|
||||
====================
|
||||
no interpolated text
|
||||
====================
|
||||
|
||||
<?php
|
||||
echo "hi";
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(echo_statement (encapsed_string (string))))
|
||||
|
||||
===============================
|
||||
interpolated text at beginning
|
||||
===============================
|
||||
|
||||
<div>
|
||||
<?php
|
||||
echo "hi";
|
||||
---
|
||||
|
||||
(program
|
||||
(text)
|
||||
(php_tag)
|
||||
(echo_statement (encapsed_string (string))))
|
||||
|
||||
===============================
|
||||
interpolated text at end
|
||||
===============================
|
||||
|
||||
<?php
|
||||
echo "hi";
|
||||
?>
|
||||
|
||||
<div>
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(echo_statement (encapsed_string (string)))
|
||||
(text_interpolation (text)))
|
||||
|
||||
===============================
|
||||
interpolated text in middle
|
||||
===============================
|
||||
|
||||
<?php
|
||||
echo "hi";
|
||||
?>
|
||||
|
||||
<div>
|
||||
|
||||
<?php
|
||||
echo "bye";
|
||||
?>
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(echo_statement (encapsed_string (string)))
|
||||
(text_interpolation
|
||||
(text)
|
||||
(php_tag))
|
||||
(echo_statement (encapsed_string (string)))
|
||||
(text_interpolation))
|
||||
|
||||
==============================
|
||||
short open tag: On
|
||||
==============================
|
||||
|
||||
<?
|
||||
echo "Used a short tag\n";
|
||||
?>
|
||||
Finished
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(echo_statement (encapsed_string (string) (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)))
|
||||
(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))))
|
||||
|
||||
|
||||
=======================================
|
||||
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)))
|
||||
)
|
||||
)
|
||||
)
|
||||
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)))
|
||||
@ -0,0 +1,217 @@
|
||||
========================
|
||||
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)) (string)))
|
||||
(text_interpolation))
|
||||
|
||||
==========================
|
||||
Shell command
|
||||
==========================
|
||||
<?php
|
||||
`ls -la`;
|
||||
`ls`;
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(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))
|
||||
@ -0,0 +1,469 @@
|
||||
==============================
|
||||
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)))))
|
||||
(if_statement
|
||||
condition: (parenthesized_expression (binary_expression
|
||||
left: (variable_name (name))
|
||||
right: (integer)))
|
||||
body: (compound_statement (echo_statement (encapsed_string (string))))
|
||||
alternative: (else_clause
|
||||
body: (compound_statement (echo_statement (encapsed_string (string))))))
|
||||
(if_statement
|
||||
condition: (parenthesized_expression (binary_expression
|
||||
left: (variable_name (name))
|
||||
right: (integer)))
|
||||
body: (compound_statement (echo_statement (encapsed_string (string))))
|
||||
alternative: (else_if_clause
|
||||
condition: (parenthesized_expression (binary_expression
|
||||
left: (variable_name (name))
|
||||
right: (integer)))
|
||||
body: (compound_statement (echo_statement (encapsed_string (string)))))
|
||||
alternative: (else_clause
|
||||
body: (compound_statement (echo_statement (encapsed_string (string)))))))
|
||||
|
||||
==============================
|
||||
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))) (break_statement))
|
||||
(case_statement
|
||||
value: (integer)
|
||||
(echo_statement (encapsed_string (string))) (break_statement))
|
||||
(default_statement
|
||||
(echo_statement (encapsed_string (string))) (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)))))
|
||||
|
||||
==============================
|
||||
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))
|
||||
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)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -0,0 +1,655 @@
|
||||
=======================================
|
||||
Complex: Variable access
|
||||
=======================================
|
||||
|
||||
<?php
|
||||
|
||||
"{$test}";
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(variable_name (name))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
=======================================
|
||||
Complex: Disallow space between { and $
|
||||
=======================================
|
||||
|
||||
<?php
|
||||
|
||||
"{ $test}";
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(variable_name (name))
|
||||
(string)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
=========================================
|
||||
Complex: PHP documentation tests
|
||||
=========================================
|
||||
<?php
|
||||
|
||||
"This is {$great}";
|
||||
"This square is {$square->width}00 centimeters broad.";
|
||||
|
||||
// Works, quoted keys only work using the curly brace syntax
|
||||
"This works: {$arr['key']}";
|
||||
"This works: {$arr[4][3]}";
|
||||
|
||||
// Works. When using multi-dimensional arrays, always use braces around arrays
|
||||
// when inside of strings
|
||||
"This works: {$arr['foo'][3]}";
|
||||
|
||||
"This works: " . $arr['foo'][3];
|
||||
|
||||
"This works too: {$obj->values[3]->name}";
|
||||
|
||||
"This is the value of the var named $name: {${$name}}";
|
||||
|
||||
"This is the value of the var named by the return value of getName(): {${getName()}}";
|
||||
|
||||
"This is the value of the var named by the return value of \$object->getName(): {${$object->getName()}}";
|
||||
|
||||
// Won't work, outputs: This is the return value of getName(): {getName()}
|
||||
"This is the return value of getName(): {getName()}";
|
||||
|
||||
"{$foo->$bar}\n";
|
||||
|
||||
"{$foo->{$baz[1]}}\n";
|
||||
|
||||
"I'd like an {${beers::softdrink}}\n";
|
||||
|
||||
"I'd like an {${beers::$ale}}\n";
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(variable_name (name))
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(member_access_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(comment)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(subscript_expression
|
||||
(variable_name (name))
|
||||
(string)
|
||||
)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(subscript_expression
|
||||
(subscript_expression
|
||||
(variable_name (name))
|
||||
(integer)
|
||||
)
|
||||
(integer)
|
||||
)
|
||||
)
|
||||
)
|
||||
(comment)
|
||||
(comment)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(subscript_expression
|
||||
(subscript_expression
|
||||
(variable_name (name))
|
||||
(string)
|
||||
)
|
||||
(integer)
|
||||
)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(binary_expression
|
||||
(encapsed_string
|
||||
(string)
|
||||
)
|
||||
(subscript_expression
|
||||
(subscript_expression
|
||||
(variable_name (name))
|
||||
(string)
|
||||
)
|
||||
(integer)
|
||||
)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(member_access_expression
|
||||
(subscript_expression
|
||||
(member_access_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
)
|
||||
(integer)
|
||||
)
|
||||
(name)
|
||||
)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(variable_name (name))
|
||||
(string)
|
||||
(dynamic_variable_name
|
||||
(variable_name (name))
|
||||
)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(dynamic_variable_name
|
||||
(function_call_expression
|
||||
(name)
|
||||
(arguments)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(escape_sequence)
|
||||
(string)
|
||||
(dynamic_variable_name
|
||||
(member_call_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
(arguments)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(comment)
|
||||
(expression_statement
|
||||
(encapsed_string (string))
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(member_access_expression
|
||||
(variable_name (name))
|
||||
(variable_name (name))
|
||||
)
|
||||
(escape_sequence)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(member_access_expression
|
||||
(variable_name (name))
|
||||
(subscript_expression
|
||||
(variable_name (name))
|
||||
(integer)
|
||||
)
|
||||
)
|
||||
(escape_sequence)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(dynamic_variable_name
|
||||
(class_constant_access_expression
|
||||
(name)
|
||||
(name)
|
||||
)
|
||||
)
|
||||
(escape_sequence)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(dynamic_variable_name
|
||||
(scoped_property_access_expression
|
||||
(name)
|
||||
(variable_name (name))
|
||||
)
|
||||
)
|
||||
(escape_sequence)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
=======================================
|
||||
Simple: Variable access
|
||||
=======================================
|
||||
|
||||
<?php
|
||||
|
||||
"Hello $people, you're awesome!";
|
||||
"hello ${a} world";
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(variable_name (name))
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(dynamic_variable_name (name))
|
||||
(string)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
=========================================
|
||||
Simple: Member and array access
|
||||
=========================================
|
||||
<?php
|
||||
|
||||
"$people->john drank some $juices[0] juice.".PHP_EOL;
|
||||
"$people->john then said hello to $people->jane.".PHP_EOL;
|
||||
"$people->john's wife greeted $people->robert.";
|
||||
"The character at index -2 is $string[-2].";
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(expression_statement
|
||||
(binary_expression
|
||||
(encapsed_string
|
||||
(member_access_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
)
|
||||
(string)
|
||||
(subscript_expression
|
||||
(variable_name (name))
|
||||
(integer)
|
||||
)
|
||||
(string)
|
||||
)
|
||||
(name)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(binary_expression
|
||||
(encapsed_string
|
||||
(member_access_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
)
|
||||
(string)
|
||||
(member_access_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
)
|
||||
(string)
|
||||
)
|
||||
(name)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(member_access_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
)
|
||||
(string)
|
||||
(member_access_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(subscript_expression
|
||||
(variable_name (name))
|
||||
(unary_op_expression (integer))
|
||||
)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
=========================================
|
||||
Corner cases
|
||||
=========================================
|
||||
|
||||
<?php
|
||||
|
||||
"{";
|
||||
"{\$";
|
||||
"{ $";
|
||||
"/a";
|
||||
"#";
|
||||
"//";
|
||||
"/*";
|
||||
"/* text *#//";
|
||||
"/**/";
|
||||
"// # /**/";
|
||||
"\\";
|
||||
"\{";
|
||||
"";
|
||||
"\$notavar";
|
||||
"\\\\\$notavar";
|
||||
"\\\{$embedexp}";
|
||||
"#x$var";
|
||||
" # x $var#x";
|
||||
"sometext$var";
|
||||
"{$var::get()}";
|
||||
"Test $var->tester- Hello";
|
||||
" # x {$var->prop["key:"."key: {$var->func("arg")}"]}# x";
|
||||
"hello \0 world";
|
||||
"hello ${"a"."b"} world";
|
||||
"$$$$$$$$$$$$$a";
|
||||
"{$$$$$$$$b}";
|
||||
"\{$";
|
||||
"${a}[";
|
||||
"\u{$a}";
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(escape_sequence)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string (string))
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string (string))
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string (string))
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string (string))
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string (string))
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string (string))
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string (string))
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string (escape_sequence))
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string (string))
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(escape_sequence)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(escape_sequence)
|
||||
(escape_sequence)
|
||||
(escape_sequence)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(escape_sequence)
|
||||
(string)
|
||||
(variable_name (name))
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(variable_name (name))
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(variable_name (name))
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(variable_name (name))
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(scoped_call_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
(arguments)
|
||||
)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(member_access_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(subscript_expression
|
||||
(member_access_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
)
|
||||
(binary_expression
|
||||
(encapsed_string (string))
|
||||
(encapsed_string
|
||||
(string)
|
||||
(member_call_expression
|
||||
(variable_name (name))
|
||||
(name)
|
||||
(arguments
|
||||
(argument
|
||||
(encapsed_string (string))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(escape_sequence)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(dynamic_variable_name
|
||||
(binary_expression
|
||||
(encapsed_string (string))
|
||||
(encapsed_string (string))
|
||||
)
|
||||
)
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(variable_name (name))
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(dynamic_variable_name
|
||||
(dynamic_variable_name
|
||||
(dynamic_variable_name
|
||||
(dynamic_variable_name
|
||||
(dynamic_variable_name
|
||||
(dynamic_variable_name
|
||||
(dynamic_variable_name
|
||||
(variable_name (name))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(dynamic_variable_name (name))
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
(variable_name (name))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
=========================================
|
||||
Single quoted
|
||||
=========================================
|
||||
|
||||
<?php
|
||||
|
||||
'this is a simple string';
|
||||
'You can also have embedded newlines in
|
||||
strings this way as it is
|
||||
okay to do';
|
||||
'Arnold once said: "I\'ll be back"';
|
||||
'You deleted C:\\*.*?';
|
||||
'You deleted C:\*.*?';
|
||||
'This will not expand: \n a newline';
|
||||
'Variables do not $expand $either';
|
||||
'socket://';
|
||||
'#valid regexp#';
|
||||
'hello#world';
|
||||
'hello//world';
|
||||
'/*valid regexp*/';
|
||||
'/*valid regexp';
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
)
|
||||
|
||||
=========================================
|
||||
Bug: #113
|
||||
=========================================
|
||||
|
||||
<?php
|
||||
"$b'";
|
||||
"'";
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(php_tag)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(variable_name (name))
|
||||
(string)
|
||||
)
|
||||
)
|
||||
(expression_statement
|
||||
(encapsed_string
|
||||
(string)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@ -0,0 +1,166 @@
|
||||
=========================
|
||||
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 {}
|
||||
|
||||
---
|
||||
|
||||
(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)))
|
||||
|
||||
=======================
|
||||
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)
|
||||
)
|
||||
)
|
||||
@ -0,0 +1,47 @@
|
||||
<?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
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
|
||||
echo <<<OMG
|
||||
something
|
||||
OMG
|
||||
// <- string
|
||||
|
||||
echo true, TRUE, false, FALSE
|
||||
// ^ constant.builtin
|
||||
// ^ constant.builtin
|
||||
// ^ constant.builtin
|
||||
// ^ constant.builtin
|
||||
|
||||
echo PI_314
|
||||
// ^ constant
|
||||
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
|
||||
function a(array $b, Something $c) {
|
||||
// ^ type.builtin
|
||||
// ^ type
|
||||
echo (int) $foo;
|
||||
// ^ type.builtin
|
||||
}
|
||||
Loading…
Reference in New Issue