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