├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── Makefile ├── Package.swift ├── README.md ├── binding.gyp ├── bindings ├── c │ ├── tree-sitter-phpdoc.h │ └── tree-sitter-phpdoc.pc.in ├── go │ ├── binding.go │ ├── binding_test.go │ └── go.mod ├── node │ ├── binding.cc │ ├── index.d.ts │ └── index.js ├── python │ └── tree_sitter_phpdoc │ │ ├── __init__.py │ │ ├── __init__.pyi │ │ ├── binding.c │ │ └── py.typed ├── rust │ ├── build.rs │ └── lib.rs └── swift │ └── TreeSitterPhpdoc │ └── phpdoc.h ├── grammar.js ├── package-lock.json ├── package.json ├── pyproject.toml ├── setup.py ├── src ├── grammar.json ├── node-types.json ├── parser.c ├── scanner.c └── tree_sitter │ ├── alloc.h │ ├── array.h │ └── parser.h └── test └── corpus ├── basic.txt ├── generics.txt ├── incomplete.txt ├── inline.txt ├── phpunit.txt ├── psalm-phpstan.txt ├── references.txt ├── special.txt ├── typed_tags.txt ├── types.txt └── versioning.txt /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*.{json,toml,yml,gyp}] 10 | indent_style = space 11 | indent_size = 2 12 | 13 | [*.js] 14 | indent_style = space 15 | indent_size = 2 16 | 17 | [*.rs] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | [*.{c,cc,h}] 22 | indent_style = space 23 | indent_size = 4 24 | 25 | [*.{py,pyi}] 26 | indent_style = space 27 | indent_size = 4 28 | 29 | [*.swift] 30 | indent_style = space 31 | indent_size = 4 32 | 33 | [*.go] 34 | indent_style = tab 35 | indent_size = 8 36 | 37 | [Makefile] 38 | indent_style = tab 39 | indent_size = 8 40 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | 3 | src/*.json linguist-generated 4 | src/parser.c linguist-generated 5 | src/tree_sitter/* linguist-generated 6 | 7 | bindings/** linguist-generated 8 | binding.gyp linguist-generated 9 | setup.py linguist-generated 10 | Makefile linguist-generated 11 | Package.swift linguist-generated 12 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: build/test 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - '**' 7 | push: 8 | branches: 9 | - 'master' 10 | 11 | jobs: 12 | test: 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | fail-fast: true 16 | matrix: 17 | # os: [macos-latest, ubuntu-latest, windows-latest] 18 | # Disabled windows runs. I pinky swear that this is temporary. 19 | os: [macos-latest, ubuntu-latest] 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: actions/setup-node@v4 23 | with: 24 | node-version: 18 25 | - uses: actions/setup-python@v4 26 | with: 27 | python-version: '3.12' 28 | - run: npm install 29 | - run: ./node_modules/.bin/tree-sitter generate 30 | - run: ./node_modules/.bin/tree-sitter test 31 | 32 | format: 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@v4 36 | - uses: actions/setup-node@v4 37 | with: 38 | node-version: 18 39 | - run: npm install 40 | - run: npm run format-check 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | *.log 4 | .DS_Store 5 | examples 6 | .ccls-cache 7 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tree-sitter-phpdoc" 3 | description = "phpdoc grammar for the tree-sitter parsing library" 4 | version = "0.1.0" 5 | keywords = ["incremental", "parsing", "phpdoc"] 6 | categories = ["parsing", "text-editors"] 7 | repository = "https://github.com/claytonrcarter/tree-sitter-phpdoc" 8 | edition = "2018" 9 | license = "MIT" 10 | 11 | build = "bindings/rust/build.rs" 12 | include = [ 13 | "bindings/rust/*", 14 | "grammar.js", 15 | "queries/*", 16 | "src/*", 17 | ] 18 | 19 | [lib] 20 | path = "bindings/rust/lib.rs" 21 | 22 | [dependencies] 23 | tree-sitter = "~0.20" 24 | 25 | [build-dependencies] 26 | cc = "1.0" 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION := 0.0.1 2 | 3 | LANGUAGE_NAME := tree-sitter-phpdoc 4 | 5 | # repository 6 | SRC_DIR := src 7 | 8 | PARSER_REPO_URL := $(shell git -C $(SRC_DIR) remote get-url origin 2>/dev/null) 9 | 10 | ifeq ($(PARSER_URL),) 11 | PARSER_URL := $(subst .git,,$(PARSER_REPO_URL)) 12 | ifeq ($(shell echo $(PARSER_URL) | grep '^[a-z][-+.0-9a-z]*://'),) 13 | PARSER_URL := $(subst :,/,$(PARSER_URL)) 14 | PARSER_URL := $(subst git@,https://,$(PARSER_URL)) 15 | endif 16 | endif 17 | 18 | TS ?= tree-sitter 19 | 20 | # ABI versioning 21 | SONAME_MAJOR := $(word 1,$(subst ., ,$(VERSION))) 22 | SONAME_MINOR := $(word 2,$(subst ., ,$(VERSION))) 23 | 24 | # install directory layout 25 | PREFIX ?= /usr/local 26 | INCLUDEDIR ?= $(PREFIX)/include 27 | LIBDIR ?= $(PREFIX)/lib 28 | PCLIBDIR ?= $(LIBDIR)/pkgconfig 29 | 30 | # source/object files 31 | PARSER := $(SRC_DIR)/parser.c 32 | EXTRAS := $(filter-out $(PARSER),$(wildcard $(SRC_DIR)/*.c)) 33 | OBJS := $(patsubst %.c,%.o,$(PARSER) $(EXTRAS)) 34 | 35 | # flags 36 | ARFLAGS ?= rcs 37 | override CFLAGS += -I$(SRC_DIR) -std=c11 -fPIC 38 | 39 | # OS-specific bits 40 | ifeq ($(OS),Windows_NT) 41 | $(error "Windows is not supported") 42 | else ifeq ($(shell uname),Darwin) 43 | SOEXT = dylib 44 | SOEXTVER_MAJOR = $(SONAME_MAJOR).dylib 45 | SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).dylib 46 | LINKSHARED := $(LINKSHARED)-dynamiclib -Wl, 47 | ifneq ($(ADDITIONAL_LIBS),) 48 | LINKSHARED := $(LINKSHARED)$(ADDITIONAL_LIBS), 49 | endif 50 | LINKSHARED := $(LINKSHARED)-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SONAME_MAJOR).dylib,-rpath,@executable_path/../Frameworks 51 | else 52 | SOEXT = so 53 | SOEXTVER_MAJOR = so.$(SONAME_MAJOR) 54 | SOEXTVER = so.$(SONAME_MAJOR).$(SONAME_MINOR) 55 | LINKSHARED := $(LINKSHARED)-shared -Wl, 56 | ifneq ($(ADDITIONAL_LIBS),) 57 | LINKSHARED := $(LINKSHARED)$(ADDITIONAL_LIBS) 58 | endif 59 | LINKSHARED := $(LINKSHARED)-soname,lib$(LANGUAGE_NAME).so.$(SONAME_MAJOR) 60 | endif 61 | ifneq ($(filter $(shell uname),FreeBSD NetBSD DragonFly),) 62 | PCLIBDIR := $(PREFIX)/libdata/pkgconfig 63 | endif 64 | 65 | all: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc 66 | 67 | lib$(LANGUAGE_NAME).a: $(OBJS) 68 | $(AR) $(ARFLAGS) $@ $^ 69 | 70 | lib$(LANGUAGE_NAME).$(SOEXT): $(OBJS) 71 | $(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@ 72 | ifneq ($(STRIP),) 73 | $(STRIP) $@ 74 | endif 75 | 76 | $(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in 77 | sed -e 's|@URL@|$(PARSER_URL)|' \ 78 | -e 's|@VERSION@|$(VERSION)|' \ 79 | -e 's|@LIBDIR@|$(LIBDIR)|' \ 80 | -e 's|@INCLUDEDIR@|$(INCLUDEDIR)|' \ 81 | -e 's|@REQUIRES@|$(REQUIRES)|' \ 82 | -e 's|@ADDITIONAL_LIBS@|$(ADDITIONAL_LIBS)|' \ 83 | -e 's|=$(PREFIX)|=$${prefix}|' \ 84 | -e 's|@PREFIX@|$(PREFIX)|' $< > $@ 85 | 86 | $(PARSER): $(SRC_DIR)/grammar.json 87 | $(TS) generate --no-bindings $^ 88 | 89 | install: all 90 | install -d '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)' 91 | install -m644 bindings/c/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h 92 | install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 93 | install -m644 lib$(LANGUAGE_NAME).a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a 94 | install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) 95 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) 96 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) 97 | 98 | uninstall: 99 | $(RM) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a \ 100 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) \ 101 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) \ 102 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) \ 103 | '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h \ 104 | '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 105 | 106 | clean: 107 | $(RM) $(OBJS) $(LANGUAGE_NAME).pc lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) 108 | 109 | test: 110 | $(TS) test 111 | 112 | .PHONY: all install uninstall clean test 113 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "TreeSitterPhpdoc", 6 | products: [ 7 | .library(name: "TreeSitterPhpdoc", targets: ["TreeSitterPhpdoc"]), 8 | ], 9 | dependencies: [], 10 | targets: [ 11 | .target(name: "TreeSitterPhpdoc", 12 | path: ".", 13 | exclude: [ 14 | "Cargo.toml", 15 | "Makefile", 16 | "binding.gyp", 17 | "bindings/c", 18 | "bindings/go", 19 | "bindings/node", 20 | "bindings/python", 21 | "bindings/rust", 22 | "prebuilds", 23 | "grammar.js", 24 | "package.json", 25 | "package-lock.json", 26 | "pyproject.toml", 27 | "setup.py", 28 | "test", 29 | "examples", 30 | ".editorconfig", 31 | ".github", 32 | ".gitignore", 33 | ".gitattributes", 34 | ".gitmodules", 35 | ], 36 | sources: [ 37 | "src/parser.c", 38 | // NOTE: if your language has an external scanner, add it here. 39 | ], 40 | resources: [ 41 | .copy("queries") 42 | ], 43 | publicHeadersPath: "bindings/swift", 44 | cSettings: [.headerSearchPath("src")]) 45 | ], 46 | cLanguageStandard: .c11 47 | ) 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tree-sitter-phpdoc 2 | 3 | PHPDoc grammar for [tree-sitter][]. 4 | 5 | [tree-sitter]: https://github.com/tree-sitter/tree-sitter 6 | 7 | ## Install 8 | 9 | `npm install tree-sitter-phpdoc` 10 | 11 | ## Test 12 | 13 | `npm test` 14 | 15 | If this test script doesn't work for you, you can just run 16 | `./node_modules/.bin/tree-sitter generate` and 17 | `./node_modules/.bin/tree-sitter test` manually. 18 | 19 | #### Thanks 20 | 21 | Originally forked from https://github.com/john-nguyen09/tree-sitter-phpdoc 22 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_phpdoc_binding", 5 | "dependencies": [ 6 | " 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | extern "C" TSLanguage *tree_sitter_phpdoc(); 6 | 7 | // "tree-sitter", "language" hashed with BLAKE2 8 | const napi_type_tag LANGUAGE_TYPE_TAG = { 9 | 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16 10 | }; 11 | 12 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 13 | exports["name"] = Napi::String::New(env, "phpdoc"); 14 | auto language = Napi::External::New(env, tree_sitter_phpdoc()); 15 | language.TypeTag(&LANGUAGE_TYPE_TAG); 16 | exports["language"] = language; 17 | return exports; 18 | } 19 | 20 | NODE_API_MODULE(tree_sitter_phpdoc_binding, Init) 21 | -------------------------------------------------------------------------------- /bindings/node/index.d.ts: -------------------------------------------------------------------------------- 1 | type BaseNode = { 2 | type: string; 3 | named: boolean; 4 | }; 5 | 6 | type ChildNode = { 7 | multiple: boolean; 8 | required: boolean; 9 | types: BaseNode[]; 10 | }; 11 | 12 | type NodeInfo = 13 | | (BaseNode & { 14 | subtypes: BaseNode[]; 15 | }) 16 | | (BaseNode & { 17 | fields: { [name: string]: ChildNode }; 18 | children: ChildNode[]; 19 | }); 20 | 21 | type Language = { 22 | name: string; 23 | language: unknown; 24 | nodeTypeInfo: NodeInfo[]; 25 | }; 26 | 27 | declare const language: Language; 28 | export = language; 29 | -------------------------------------------------------------------------------- /bindings/node/index.js: -------------------------------------------------------------------------------- 1 | const root = require("path").join(__dirname, "..", ".."); 2 | 3 | module.exports = require("node-gyp-build")(root); 4 | 5 | try { 6 | module.exports.nodeTypeInfo = require("../../src/node-types.json"); 7 | } catch (_) {} 8 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_phpdoc/__init__.py: -------------------------------------------------------------------------------- 1 | "Phpdoc grammar for tree-sitter" 2 | 3 | from ._binding import language 4 | 5 | __all__ = ["language"] 6 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_phpdoc/__init__.pyi: -------------------------------------------------------------------------------- 1 | def language() -> int: ... 2 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_phpdoc/binding.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | TSLanguage *tree_sitter_phpdoc(void); 6 | 7 | static PyObject* _binding_language(PyObject *self, PyObject *args) { 8 | return PyLong_FromVoidPtr(tree_sitter_phpdoc()); 9 | } 10 | 11 | static PyMethodDef methods[] = { 12 | {"language", _binding_language, METH_NOARGS, 13 | "Get the tree-sitter language for this grammar."}, 14 | {NULL, NULL, 0, NULL} 15 | }; 16 | 17 | static struct PyModuleDef module = { 18 | .m_base = PyModuleDef_HEAD_INIT, 19 | .m_name = "_binding", 20 | .m_doc = NULL, 21 | .m_size = -1, 22 | .m_methods = methods 23 | }; 24 | 25 | PyMODINIT_FUNC PyInit__binding(void) { 26 | return PyModule_Create(&module); 27 | } 28 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_phpdoc/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claytonrcarter/tree-sitter-phpdoc/03bb10330704b0b371b044e937d5cc7cd40b4999/bindings/python/tree_sitter_phpdoc/py.typed -------------------------------------------------------------------------------- /bindings/rust/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let src_dir = std::path::Path::new("src"); 3 | 4 | let mut c_config = cc::Build::new(); 5 | c_config.include(&src_dir); 6 | c_config 7 | .flag_if_supported("-Wno-unused-parameter") 8 | .flag_if_supported("-Wno-unused-but-set-variable") 9 | .flag_if_supported("-Wno-trigraphs"); 10 | #[cfg(target_env = "msvc")] 11 | c_config.flag("-utf-8"); 12 | 13 | let parser_path = src_dir.join("parser.c"); 14 | c_config.file(&parser_path); 15 | 16 | // If your language uses an external scanner written in C, 17 | // then include this block of code: 18 | let scanner_path = src_dir.join("scanner.c"); 19 | c_config.file(&scanner_path); 20 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 21 | 22 | c_config.compile("parser"); 23 | println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); 24 | 25 | // If your language uses an external scanner written in C++, 26 | // then include this block of code: 27 | 28 | /* 29 | let mut cpp_config = cc::Build::new(); 30 | cpp_config.cpp(true); 31 | cpp_config.include(&src_dir); 32 | cpp_config 33 | .flag_if_supported("-Wno-unused-parameter") 34 | .flag_if_supported("-Wno-unused-but-set-variable"); 35 | let scanner_path = src_dir.join("scanner.cc"); 36 | cpp_config.file(&scanner_path); 37 | cpp_config.compile("scanner"); 38 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 39 | */ 40 | } 41 | -------------------------------------------------------------------------------- /bindings/rust/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate provides phpdoc language support for the [tree-sitter][] parsing library. 2 | //! 3 | //! Typically, you will use the [language][language func] function to add this language to a 4 | //! tree-sitter [Parser][], and then use the parser to parse some code: 5 | //! 6 | //! ``` 7 | //! let code = ""; 8 | //! let mut parser = tree_sitter::Parser::new(); 9 | //! parser.set_language(tree_sitter_phpdoc::language()).expect("Error loading phpdoc grammar"); 10 | //! let tree = parser.parse(code, None).unwrap(); 11 | //! ``` 12 | //! 13 | //! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html 14 | //! [language func]: fn.language.html 15 | //! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html 16 | //! [tree-sitter]: https://tree-sitter.github.io/ 17 | 18 | use tree_sitter::Language; 19 | 20 | extern "C" { 21 | fn tree_sitter_phpdoc() -> Language; 22 | } 23 | 24 | /// Get the tree-sitter [Language][] for this grammar. 25 | /// 26 | /// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html 27 | pub fn language() -> Language { 28 | unsafe { tree_sitter_phpdoc() } 29 | } 30 | 31 | /// The content of the [`node-types.json`][] file for this grammar. 32 | /// 33 | /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types 34 | pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json"); 35 | 36 | // Uncomment these to include any queries that this grammar contains 37 | 38 | // pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm"); 39 | // pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm"); 40 | // pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm"); 41 | // pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm"); 42 | 43 | #[cfg(test)] 44 | mod tests { 45 | #[test] 46 | fn test_can_load_grammar() { 47 | let mut parser = tree_sitter::Parser::new(); 48 | parser 49 | .set_language(super::language()) 50 | .expect("Error loading phpdoc language"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bindings/swift/TreeSitterPhpdoc/phpdoc.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_PHPDOC_H_ 2 | #define TREE_SITTER_PHPDOC_H_ 3 | 4 | typedef struct TSLanguage TSLanguage; 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | const TSLanguage *tree_sitter_phpdoc(void); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif // TREE_SITTER_PHPDOC_H_ 17 | -------------------------------------------------------------------------------- /grammar.js: -------------------------------------------------------------------------------- 1 | const PHP = require('tree-sitter-php/php/grammar').grammar; 2 | 3 | // PHPDoc reference: https://docs.phpdoc.org/3.0/guide/references/phpdoc/index.html 4 | // PHPDoc tags: https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/index.html#tag-reference 5 | // PHPDoc docs appear to use these conventions 6 | // 7 | // TODO array return types https://docs.phpdoc.org/3.0/guide/references/phpdoc/types.html#arrays 8 | // @verbatimElement [required element] [] 9 | 10 | module.exports = grammar({ 11 | name: 'phpdoc', 12 | 13 | extras: ($) => [ 14 | token( 15 | choice( 16 | // Skip over stars at the beginnings of lines 17 | seq(/\r?\n/, /[ \t]*/, repeat(seq('*', /[ \t]*/))), 18 | /\s/, 19 | ), 20 | ), 21 | ], 22 | 23 | conflicts: ($) => [ 24 | [$.primitive_type, $.static], 25 | [$.namespace_name], 26 | [$.namespace_name_as_prefix], 27 | [$.named_type, $.generic_type], 28 | [$._type_argument_list], 29 | [ 30 | $._type, 31 | $.union_type, 32 | $.intersection_type, 33 | $.disjunctive_normal_form_type, 34 | ], 35 | [$.union_type, $.disjunctive_normal_form_type], 36 | ], 37 | 38 | // Note: 39 | // 1. External scanners receive text with `extras` not removed yet. So 40 | // whitespace must be detected and skipped appropriately with lexer->skip(). 41 | // 42 | // 2. External scanners are triggered with highest precedence whenever possible. 43 | // For example a rule like: 44 | // seq( 45 | // optional($.variable_name), 46 | // optional($.text) 47 | // ) 48 | // would not even start scanning for $.variable but immediately call the 49 | // external scanner for $.text, because both tokens are optional. This can't 50 | // be fixed with prec() either. 51 | // 52 | // That's why you see weird looking external tokens like $._text_after_type 53 | // which allows us to restate the above rule like: 54 | // 55 | // choice( 56 | // $._text_after_type, 57 | // seq($.variable, $text) 58 | // ) 59 | externals: ($) => [ 60 | $.text, 61 | 62 | // Must not start with $variable 63 | $._text_after_type, 64 | 65 | // Text ends at } 66 | $._text_in_inline_tag, 67 | 68 | // Must not start with 69 | // \d+\. 70 | // '@package_version@' 71 | // 'git: $Id$' (or any other form of 'name-of-vcs: $vector$') 72 | $._text_not_version, 73 | ], 74 | 75 | word: ($) => $.name, 76 | 77 | rules: { 78 | document: ($) => 79 | seq($._begin, optional($.description), repeat($.tag), $._end), 80 | 81 | _begin: ($) => token(seq('/**', repeat('*'))), 82 | 83 | description: ($) => repeat1(choice($.text, $.inline_tag)), 84 | 85 | _description_after_type: ($) => 86 | alias( 87 | repeat1(choice(alias($._text_after_type, $.text), $.inline_tag)), 88 | $.description, 89 | ), 90 | 91 | _description_not_version: ($) => 92 | alias( 93 | repeat1(choice(alias($._text_not_version, $.text), $.inline_tag)), 94 | $.description, 95 | ), 96 | 97 | _description_in_inline_tag: ($) => 98 | alias(repeat1(alias($._text_in_inline_tag, $.text)), $.description), 99 | 100 | _description_in_inline_tag_with_nesting: ($) => 101 | alias( 102 | repeat1(choice(alias($._text_in_inline_tag, $.text), $.inline_tag)), 103 | $.description, 104 | ), 105 | 106 | tag: ($) => 107 | choice( 108 | $._tag_without_description, 109 | $._tag_with_optional_description, 110 | $._tag_with_required_description, 111 | 112 | $._author_tag, 113 | $._deprecated_tag, 114 | $._global_tag, 115 | $._link_tag, 116 | $._method_tag, 117 | $._param_tag, 118 | $._property_tag, 119 | $._return_tag, 120 | $._see_tag, 121 | $._since_tag, 122 | $._throws_tag, 123 | $._var_tag, 124 | $._version_tag, 125 | 126 | $._phpunit_tag, 127 | 128 | // TODO eliminate this 129 | $._tag_with_incomplete_implementation, 130 | 131 | $._generic_template_tag, 132 | $._generic_implements_tag, 133 | $._generic_extends_tag, 134 | $._generic_use_tag, 135 | 136 | $._psalm_tag, 137 | $._mixin_tag, 138 | ), 139 | 140 | inline_tag: ($) => 141 | seq( 142 | '{', 143 | choice( 144 | alias('@inheritdoc', $.tag_name), 145 | alias('@inheritDoc', $.tag_name), 146 | $._inline_internal_tag, 147 | $._inline_link_tag, 148 | $._inline_see_tag, 149 | ), 150 | '}', 151 | ), 152 | 153 | // @api 154 | // @filesource 155 | // @inheritdoc 156 | // @inheritDoc 157 | _tag_without_description: ($) => 158 | alias( 159 | choice('@api', '@filesource', '@inheritdoc', '@inheritDoc'), 160 | $.tag_name, 161 | ), 162 | 163 | // @ignore [] 164 | // @internal [] 165 | _tag_with_optional_description: ($) => 166 | seq( 167 | alias(choice('@ignore', '@internal'), $.tag_name), 168 | optional($.description), 169 | ), 170 | 171 | // @category [description] 172 | // @copyright [description] 173 | // @todo [description] 174 | _tag_with_required_description: ($) => 175 | seq( 176 | alias(choice('@category', '@copyright', '@todo'), $.tag_name), 177 | $.description, 178 | ), 179 | 180 | // TODO complete implementation for these tags 181 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/subpackage.html 182 | // @subpackage [name] 183 | 184 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/example.html 185 | // @example [location] [ [] ] [] 186 | // (also inline) 187 | 188 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/license.html 189 | // @license [] [name] 190 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/package.html 191 | // @package [level 1]\\[level 2]\\[etc.] 192 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/source.html 193 | // @source [ [] ] [] 194 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/uses.html 195 | // @uses [FQSEN] [] 196 | _tag_with_incomplete_implementation: ($) => 197 | seq( 198 | alias( 199 | choice( 200 | '@example', 201 | '@license', 202 | '@package', 203 | '@source', 204 | '@subpackage', 205 | '@uses', 206 | ), 207 | $.tag_name, 208 | ), 209 | optional($.description), 210 | ), 211 | 212 | // @author [name] [] 213 | // specs require email address to be wrapped in angle brackets 214 | _author_tag: ($) => 215 | seq( 216 | alias('@author', $.tag_name), 217 | $.author_name, 218 | optional(seq('<', $.email_address, '>')), 219 | ), 220 | 221 | // @global [Type] [name] (name w/o $) 222 | // @global [Type] [description] 223 | _global_tag: ($) => 224 | seq(alias('@global', $.tag_name), $._type, $.variable_name), 225 | 226 | // @internal [description] 227 | _inline_internal_tag: ($) => 228 | seq( 229 | alias('@internal', $.tag_name), 230 | optional($._description_in_inline_tag_with_nesting), 231 | ), 232 | 233 | // @link [URI] [] 234 | _link_tag: ($) => 235 | seq(alias('@link', $.tag_name), $.uri, optional($.description)), 236 | _inline_link_tag: ($) => 237 | seq( 238 | alias('@link', $.tag_name), 239 | $.uri, 240 | optional($._description_in_inline_tag), 241 | ), 242 | 243 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/method.html#method 244 | // @method [[static] return type] [name]([[type] [parameter]<, ...>]) [] 245 | _method_tag: ($) => 246 | seq( 247 | alias('@method', $.tag_name), 248 | // `[static]` is interpreted as optional despite not being in [<...>] 249 | optional($.static), 250 | optional($._type), 251 | $.name, 252 | $.parameters, 253 | optional($.description), 254 | ), 255 | 256 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/param.html 257 | // @param [] [name] [] 258 | _param_tag: ($) => 259 | seq( 260 | alias('@param', $.tag_name), 261 | optional($._type), 262 | $.variable_name, 263 | optional($.description), 264 | ), 265 | 266 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/property.html 267 | // @property[<-read|-write>] [Type] [name] [] 268 | _property_tag: ($) => 269 | seq( 270 | alias( 271 | choice('@property', '@property-read', '@property-write'), 272 | $.tag_name, 273 | ), 274 | $._type, 275 | $.variable_name, 276 | optional($.description), 277 | ), 278 | 279 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/return.html 280 | // @return [Type] [] 281 | _return_tag: ($) => 282 | seq( 283 | alias('@return', $.tag_name), 284 | $._type, 285 | optional($._description_after_type), 286 | ), 287 | 288 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/see.html 289 | // @see [URI | FQSEN] [] 290 | // TODO Implement FQSEN support 291 | // Docs on FQSEN are unclear: 292 | // https://docs.phpdoc.org/classes/phpDocumentor-Descriptor-DescriptorAbstract.html#property_fqsen 293 | // "Fully Qualified Structural Element Name; the FQCN including method, property or constant name" 294 | // So FQSEN must always use FQCN (fully qualified class name). But the examples don't: 295 | // @see number_of() 296 | // @see MyClass::$items 297 | // @see MyClass::setItems() 298 | _see_tag: ($) => 299 | seq( 300 | alias('@see', $.tag_name), 301 | choice($.uri, $.fqsen), 302 | optional($.description), 303 | ), 304 | _inline_see_tag: ($) => 305 | seq( 306 | alias('@see', $.tag_name), 307 | choice($.uri, $.fqsen), 308 | optional($._description_in_inline_tag), 309 | ), 310 | 311 | // @throws [Type] [] 312 | _throws_tag: ($) => 313 | seq( 314 | alias('@throws', $.tag_name), 315 | $._type, 316 | optional($._description_after_type), 317 | ), 318 | 319 | // https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/var.html 320 | // @var ["Type"] [element_name] [] 321 | _var_tag: ($) => 322 | seq( 323 | alias('@var', $.tag_name), 324 | $._type, 325 | // for psalm and phpstan, the var name is optional 326 | optional( 327 | choice( 328 | // @var int description 329 | $._description_after_type, 330 | 331 | // @var int $foo 332 | $.variable_name, 333 | 334 | // @var int $foo description 335 | seq($.variable_name, $.description), 336 | ), 337 | ), 338 | ), 339 | 340 | // @deprecated [] [] 341 | _deprecated_tag: ($) => 342 | seq( 343 | alias('@deprecated', $.tag_name), 344 | optional( 345 | choice( 346 | $.version, 347 | $._description_not_version, 348 | seq($.version, $.description), 349 | ), 350 | ), 351 | ), 352 | 353 | // @since [] [] 354 | _since_tag: ($) => 355 | seq( 356 | alias('@since', $.tag_name), 357 | choice( 358 | $.version, 359 | $._description_not_version, 360 | seq($.version, $.description), 361 | ), 362 | ), 363 | 364 | // @version [] [] 365 | _version_tag: ($) => 366 | seq( 367 | alias('@version', $.tag_name), 368 | choice( 369 | $.version, 370 | $._description_not_version, 371 | seq($.version, $.description), 372 | ), 373 | ), 374 | 375 | // @template [Type] 376 | // @psalm-template [Type] 377 | // @phpstan-template [Type] 378 | _generic_template_tag: ($) => 379 | seq( 380 | alias( 381 | choice('@template', '@psalm-template', '@phpstan-template'), 382 | $.tag_name, 383 | ), 384 | choice($._type, seq($._type, 'of', $._type)), 385 | ), 386 | 387 | // @implements [Type] 388 | // @template-implements [Type] 389 | _generic_implements_tag: ($) => 390 | seq( 391 | alias(choice('@implements', '@template-implements'), $.tag_name), 392 | $._type, 393 | ), 394 | 395 | // @extends [Type] 396 | // @template-extends [Type] 397 | _generic_extends_tag: ($) => 398 | seq(alias(choice('@extends', '@template-extends'), $.tag_name), $._type), 399 | 400 | // @use [Type] 401 | // @template-use [Type] 402 | _generic_use_tag: ($) => 403 | seq(alias(choice('@use', '@template-use'), $.tag_name), $._type), 404 | 405 | // partial support for phpunit tags 406 | // TODO id the "core" tags and flesh out their support (ie some tags take 407 | // no text, some take types, etc) 408 | // curl https://phpunit.readthedocs.io/en/9.5/annotations.html | grep '@' | sed 's/@/@/g' | sed -E 's/^.+@/@/' | sed -E 's/<.+$//' | sort | uniq 409 | _phpunit_tag: ($) => 410 | seq( 411 | alias( 412 | choice( 413 | '@after', 414 | '@afterClass', 415 | '@annotation', 416 | // '@author', // already part of phpdoc 417 | '@backupGlobals', 418 | '@backupStaticAttributes', 419 | '@before', 420 | '@beforeClass', 421 | '@codeCoverageIgnore', 422 | '@codeCoverageIgnore*', 423 | '@codeCoverageIgnoreEnd', 424 | '@codeCoverageIgnoreStart', 425 | '@covers', 426 | '@coversDefaultClass', 427 | '@coversDefaultClass to shorten annotations', 428 | '@coversNothing', 429 | '@dataProvider', 430 | '@depends', 431 | '@depends annotation to express dependencies', 432 | '@doesNotPerformAssertions', 433 | '@group', 434 | '@large', 435 | '@medium', 436 | '@preserveGlobalState', 437 | '@requires', 438 | '@requires usages', 439 | '@runInSeparateProcess', 440 | '@runTestsInSeparateProcesses', 441 | '@small', 442 | '@test', 443 | '@testWith', 444 | '@testdox', 445 | '@ticket', 446 | // '@uses', // already part of phpdoc 447 | ), 448 | $.tag_name, 449 | ), 450 | optional($.description), 451 | ), 452 | 453 | _psalm_tag: ($) => 454 | choice( 455 | alias( 456 | choice( 457 | '@psalm-consistent-constructor', 458 | '@psalm-consistent-templates', 459 | '@psalm-var', 460 | '@psalm-param', 461 | '@psalm-return', 462 | '@psalm-property', 463 | '@psalm-property-read', 464 | '@psalm-property-write', 465 | '@psalm-method', 466 | '@psalm-ignore-var', 467 | '@psalm-if-this-is', 468 | '@psalm-this-out', 469 | '@psalm-ignore-nullable-return', 470 | '@psalm-ignore-falsable-return', 471 | '@psalm-seal-properties', 472 | '@psalm-readonly', 473 | '@readonly', 474 | '@psalm-mutation-free', 475 | '@psalm-external-mutation-free', 476 | '@psalm-immutable', 477 | '@psalm-pure', 478 | '@psalm-allow-private-mutation', 479 | '@psalm-readonly-allow-private-mutation', 480 | '@psalm-trace', 481 | '@no-named-arguments', 482 | ), 483 | $.tag_name, 484 | ), 485 | // @psalm-trace [name] 486 | seq(alias(choice('@psalm-trace'), $.tag_name), $.variable_name), 487 | seq( 488 | alias(choice('@param-out', '@psalm-param-out'), $.tag_name), 489 | $._type, 490 | $.variable_name, 491 | ), 492 | // @psalm-asset[<-if-true|-if-false] [Type] [name|expression] 493 | seq( 494 | alias( 495 | choice( 496 | '@psalm-assert', 497 | '@psalm-assert-if-true', 498 | '@psalm-assert-if-false', 499 | ), 500 | $.tag_name, 501 | ), 502 | $._type, 503 | choice( 504 | $.variable_name, 505 | // TODO allow PHP expression 506 | ), 507 | ), 508 | //TODO implement @psalm-taint-* see https://psalm.dev/docs/security_analysis/annotations/ 509 | seq( 510 | alias('@psalm-import-type', $.tag_name), 511 | $.named_type, 512 | 'from', 513 | $.named_type, 514 | optional(PHP.rules.namespace_aliasing_clause), 515 | ), 516 | // @psalm-suppress [Type] 517 | // @psalm-internal [Type] 518 | // @psalm-require-[extends|implements] [Type] 519 | seq( 520 | alias( 521 | choice( 522 | '@psalm-suppress', 523 | '@psalm-internal', 524 | '@psalm-require-extends', 525 | '@psalm-require-implements', 526 | ), 527 | $.tag_name, 528 | ), 529 | $.named_type, 530 | ), 531 | ), 532 | 533 | // https://phpstan.org/writing-php-code/phpdocs-basics#mixins 534 | // https://psalm.dev/docs/annotating_code/supported_annotations/#mixins 535 | // @mixin [Type] 536 | _mixin_tag: ($) => seq(alias('@mixin', $.tag_name), $._type), 537 | 538 | // PHP.rules._type creates an alias for $.type_list 539 | _type: ($) => PHP.rules._type, 540 | // union_type uses _types, so we override it to be "regular" types (which 541 | // aren't grouped under a parent node) or array types (which are) 542 | _types: ($) => 543 | choice( 544 | $._regular_types, 545 | alias($._psalm_scalar_type, $.primitive_type), 546 | alias($._phpdoc_array_types, $.array_type), 547 | alias($._psalm_generic_array_types, $.array_type), 548 | alias($._psalm_list_array_types, $.array_type), 549 | alias($._psalm_shaped_array_types, $.array_type), 550 | ), 551 | _regular_types: ($) => PHP.rules._types, 552 | _phpdoc_array_types: ($) => seq($._regular_types, repeat1('[]')), 553 | _psalm_generic_array_types: ($) => 554 | seq( 555 | field('array', $._regular_types), 556 | '<', 557 | field('key', $._types), 558 | ',', 559 | field('value', $._types), 560 | '>', 561 | ), 562 | _psalm_list_array_types: ($) => 563 | seq( 564 | field( 565 | 'array', 566 | choice(alias('list', $.primitive_type), $._regular_types), 567 | ), 568 | '<', 569 | field('value', $._types), 570 | '>', 571 | ), 572 | 573 | _psalm_shaped_array_types: ($) => 574 | prec( 575 | 2, 576 | seq( 577 | choice('array', 'list'), 578 | '{', 579 | sep1(alias($._shaped_array_element, $.array_element), ','), 580 | '}', 581 | ), 582 | ), 583 | 584 | _shaped_array_element: ($) => 585 | seq( 586 | field( 587 | 'key', 588 | optional( 589 | seq( 590 | choice( 591 | $.name, 592 | seq("'", $.name, "'"), 593 | seq('"', $.name, '"'), 594 | alias(/\d+/, $.name), 595 | ), 596 | optional('?'), 597 | ':', 598 | ), 599 | ), 600 | ), 601 | field('value', $._regular_types), 602 | ), 603 | 604 | _psalm_scalar_type: ($) => 605 | choice( 606 | seq('class-string', optional($._type_argument_named_type)), 607 | 'interface-string', 608 | 'positive-int', 609 | 'trait-string', 610 | 'enum-string', 611 | 'callable-string', 612 | 'numeric-string', 613 | 'literal-string', 614 | 'lowercase-string', 615 | 'non-empty-string', 616 | 'non-empty-lowercase-string', 617 | ), 618 | 619 | generic_type: ($) => seq(PHP.rules.named_type, $._type_argument_list), 620 | 621 | _type_argument_list: ($) => 622 | seq('<', choice(repeat(','), sep(',', $._type)), '>'), 623 | 624 | _type_argument_named_type: ($) => seq('<', $.named_type, '>'), 625 | 626 | name: ($) => PHP.rules.name, 627 | named_type: ($) => choice(PHP.rules.named_type, $.generic_type), 628 | namespace_name: ($) => PHP.rules.namespace_name, 629 | namespace_name_as_prefix: ($) => PHP.rules.namespace_name_as_prefix, 630 | optional_type: ($) => PHP.rules.optional_type, 631 | primitive_type: ($) => PHP.rules.primitive_type, 632 | qualified_name: ($) => PHP.rules.qualified_name, 633 | union_type: ($) => PHP.rules.union_type, 634 | intersection_type: ($) => PHP.rules.intersection_type, 635 | disjunctive_normal_form_type: ($) => PHP.rules.disjunctive_normal_form_type, 636 | variable_name: ($) => PHP.rules.variable_name, 637 | 638 | // Match as many words as possible, where a word is just a sequence of 639 | // non-whitespace and non-< characters, separated by a space. (The non-< 640 | // requirement makes sure this regex doesn't consume the field.) 641 | author_name: ($) => /\S+( [^\s<]+)*/, 642 | 643 | // Simplisitic regex to match anything@anything.anything, where the last 644 | // anything also doesn't include a closing angle bracket 645 | email_address: ($) => /\S+@\S+\.[^\s>]+/, 646 | 647 | version: ($) => 648 | choice( 649 | // phpDoc does only recommend semantic versioning but it's not mandatory. 650 | // So we gracefully accept every word (i.e. no space included) that 651 | // starts with a number + dot as version. 652 | /\d+\.[^\s]+/, 653 | // Version vectors: 654 | // $Id$ 655 | // name-of-vcs: $Id$ 656 | $._version_vector, 657 | seq(/[a-zA-Z-_]+: */, $._version_vector), 658 | // Used by PEAR 659 | '@package_version@', 660 | ), 661 | _version_vector: ($) => /\$[a-zA-Z_][a-zA-Z0-9-_]*\$/, 662 | 663 | uri: ($) => /https?:\/\/[^\s}]+/, 664 | 665 | fqsen: ($) => 666 | choice( 667 | $.named_type, 668 | $.variable_name, 669 | seq($.name, '()'), 670 | seq($.named_type, '::', $.name), 671 | seq($.named_type, '::', $.name, '()'), 672 | seq($.named_type, '::', $.variable_name), 673 | ), 674 | 675 | parameters: ($) => seq('(', sep($.parameter, ','), ')'), 676 | 677 | parameter: ($) => 678 | seq( 679 | optional($._type), 680 | $.variable_name, 681 | optional(seq('=', $.default_value)), 682 | ), 683 | 684 | default_value: ($) => /[^, ][^,)]*/, 685 | 686 | static: ($) => 'static', 687 | 688 | _end: ($) => '*/', 689 | }, 690 | }); 691 | 692 | function sep1(rule, sep) { 693 | return seq(rule, repeat(seq(sep, rule))); 694 | } 695 | 696 | function sep(rule, sep) { 697 | return optional(sep1(rule, sep)); 698 | } 699 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-phpdoc", 3 | "version": "0.1.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "tree-sitter-phpdoc", 9 | "version": "0.1.0", 10 | "hasInstallScript": true, 11 | "license": "MIT", 12 | "dependencies": { 13 | "node-addon-api": "^7.1.0", 14 | "node-gyp-build": "^4.8.0" 15 | }, 16 | "devDependencies": { 17 | "prebuildify": "^6.0.0", 18 | "prettier": "^3.3.3", 19 | "tree-sitter-cli": "^0.22.6", 20 | "tree-sitter-php": "^0.22.2" 21 | }, 22 | "peerDependencies": { 23 | "tree-sitter": "^0.21.0" 24 | }, 25 | "peerDependenciesMeta": { 26 | "tree_sitter": { 27 | "optional": true 28 | } 29 | } 30 | }, 31 | "node_modules/base64-js": { 32 | "version": "1.5.1", 33 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 34 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 35 | "dev": true, 36 | "funding": [ 37 | { 38 | "type": "github", 39 | "url": "https://github.com/sponsors/feross" 40 | }, 41 | { 42 | "type": "patreon", 43 | "url": "https://www.patreon.com/feross" 44 | }, 45 | { 46 | "type": "consulting", 47 | "url": "https://feross.org/support" 48 | } 49 | ] 50 | }, 51 | "node_modules/bl": { 52 | "version": "4.1.0", 53 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", 54 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", 55 | "dev": true, 56 | "dependencies": { 57 | "buffer": "^5.5.0", 58 | "inherits": "^2.0.4", 59 | "readable-stream": "^3.4.0" 60 | } 61 | }, 62 | "node_modules/buffer": { 63 | "version": "5.7.1", 64 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 65 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 66 | "dev": true, 67 | "funding": [ 68 | { 69 | "type": "github", 70 | "url": "https://github.com/sponsors/feross" 71 | }, 72 | { 73 | "type": "patreon", 74 | "url": "https://www.patreon.com/feross" 75 | }, 76 | { 77 | "type": "consulting", 78 | "url": "https://feross.org/support" 79 | } 80 | ], 81 | "dependencies": { 82 | "base64-js": "^1.3.1", 83 | "ieee754": "^1.1.13" 84 | } 85 | }, 86 | "node_modules/chownr": { 87 | "version": "1.1.4", 88 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", 89 | "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", 90 | "dev": true 91 | }, 92 | "node_modules/end-of-stream": { 93 | "version": "1.4.4", 94 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 95 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 96 | "dev": true, 97 | "dependencies": { 98 | "once": "^1.4.0" 99 | } 100 | }, 101 | "node_modules/fs-constants": { 102 | "version": "1.0.0", 103 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", 104 | "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", 105 | "dev": true 106 | }, 107 | "node_modules/ieee754": { 108 | "version": "1.2.1", 109 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 110 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 111 | "dev": true, 112 | "funding": [ 113 | { 114 | "type": "github", 115 | "url": "https://github.com/sponsors/feross" 116 | }, 117 | { 118 | "type": "patreon", 119 | "url": "https://www.patreon.com/feross" 120 | }, 121 | { 122 | "type": "consulting", 123 | "url": "https://feross.org/support" 124 | } 125 | ] 126 | }, 127 | "node_modules/inherits": { 128 | "version": "2.0.4", 129 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 130 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 131 | "dev": true 132 | }, 133 | "node_modules/lru-cache": { 134 | "version": "6.0.0", 135 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 136 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 137 | "dev": true, 138 | "dependencies": { 139 | "yallist": "^4.0.0" 140 | }, 141 | "engines": { 142 | "node": ">=10" 143 | } 144 | }, 145 | "node_modules/minimist": { 146 | "version": "1.2.8", 147 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 148 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 149 | "dev": true, 150 | "funding": { 151 | "url": "https://github.com/sponsors/ljharb" 152 | } 153 | }, 154 | "node_modules/mkdirp-classic": { 155 | "version": "0.5.3", 156 | "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", 157 | "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", 158 | "dev": true 159 | }, 160 | "node_modules/nan": { 161 | "version": "2.18.0", 162 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", 163 | "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", 164 | "dev": true 165 | }, 166 | "node_modules/node-abi": { 167 | "version": "3.62.0", 168 | "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.62.0.tgz", 169 | "integrity": "sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==", 170 | "dev": true, 171 | "dependencies": { 172 | "semver": "^7.3.5" 173 | }, 174 | "engines": { 175 | "node": ">=10" 176 | } 177 | }, 178 | "node_modules/node-addon-api": { 179 | "version": "7.1.0", 180 | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz", 181 | "integrity": "sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==", 182 | "engines": { 183 | "node": "^16 || ^18 || >= 20" 184 | } 185 | }, 186 | "node_modules/node-gyp-build": { 187 | "version": "4.8.1", 188 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", 189 | "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", 190 | "bin": { 191 | "node-gyp-build": "bin.js", 192 | "node-gyp-build-optional": "optional.js", 193 | "node-gyp-build-test": "build-test.js" 194 | } 195 | }, 196 | "node_modules/npm-run-path": { 197 | "version": "3.1.0", 198 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", 199 | "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", 200 | "dev": true, 201 | "dependencies": { 202 | "path-key": "^3.0.0" 203 | }, 204 | "engines": { 205 | "node": ">=8" 206 | } 207 | }, 208 | "node_modules/once": { 209 | "version": "1.4.0", 210 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 211 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 212 | "dev": true, 213 | "dependencies": { 214 | "wrappy": "1" 215 | } 216 | }, 217 | "node_modules/path-key": { 218 | "version": "3.1.1", 219 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 220 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 221 | "dev": true, 222 | "engines": { 223 | "node": ">=8" 224 | } 225 | }, 226 | "node_modules/prebuildify": { 227 | "version": "6.0.1", 228 | "resolved": "https://registry.npmjs.org/prebuildify/-/prebuildify-6.0.1.tgz", 229 | "integrity": "sha512-8Y2oOOateom/s8dNBsGIcnm6AxPmLH4/nanQzL5lQMU+sC0CMhzARZHizwr36pUPLdvBnOkCNQzxg4djuFSgIw==", 230 | "dev": true, 231 | "dependencies": { 232 | "minimist": "^1.2.5", 233 | "mkdirp-classic": "^0.5.3", 234 | "node-abi": "^3.3.0", 235 | "npm-run-path": "^3.1.0", 236 | "pump": "^3.0.0", 237 | "tar-fs": "^2.1.0" 238 | }, 239 | "bin": { 240 | "prebuildify": "bin.js" 241 | } 242 | }, 243 | "node_modules/prettier": { 244 | "version": "3.3.3", 245 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", 246 | "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", 247 | "dev": true, 248 | "bin": { 249 | "prettier": "bin/prettier.cjs" 250 | }, 251 | "engines": { 252 | "node": ">=14" 253 | }, 254 | "funding": { 255 | "url": "https://github.com/prettier/prettier?sponsor=1" 256 | } 257 | }, 258 | "node_modules/pump": { 259 | "version": "3.0.0", 260 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 261 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 262 | "dev": true, 263 | "dependencies": { 264 | "end-of-stream": "^1.1.0", 265 | "once": "^1.3.1" 266 | } 267 | }, 268 | "node_modules/readable-stream": { 269 | "version": "3.6.2", 270 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", 271 | "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", 272 | "dev": true, 273 | "dependencies": { 274 | "inherits": "^2.0.3", 275 | "string_decoder": "^1.1.1", 276 | "util-deprecate": "^1.0.1" 277 | }, 278 | "engines": { 279 | "node": ">= 6" 280 | } 281 | }, 282 | "node_modules/safe-buffer": { 283 | "version": "5.2.1", 284 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 285 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 286 | "dev": true, 287 | "funding": [ 288 | { 289 | "type": "github", 290 | "url": "https://github.com/sponsors/feross" 291 | }, 292 | { 293 | "type": "patreon", 294 | "url": "https://www.patreon.com/feross" 295 | }, 296 | { 297 | "type": "consulting", 298 | "url": "https://feross.org/support" 299 | } 300 | ] 301 | }, 302 | "node_modules/semver": { 303 | "version": "7.6.0", 304 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", 305 | "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", 306 | "dev": true, 307 | "dependencies": { 308 | "lru-cache": "^6.0.0" 309 | }, 310 | "bin": { 311 | "semver": "bin/semver.js" 312 | }, 313 | "engines": { 314 | "node": ">=10" 315 | } 316 | }, 317 | "node_modules/string_decoder": { 318 | "version": "1.3.0", 319 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 320 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 321 | "dev": true, 322 | "dependencies": { 323 | "safe-buffer": "~5.2.0" 324 | } 325 | }, 326 | "node_modules/tar-fs": { 327 | "version": "2.1.1", 328 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", 329 | "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", 330 | "dev": true, 331 | "dependencies": { 332 | "chownr": "^1.1.1", 333 | "mkdirp-classic": "^0.5.2", 334 | "pump": "^3.0.0", 335 | "tar-stream": "^2.1.4" 336 | } 337 | }, 338 | "node_modules/tar-stream": { 339 | "version": "2.2.0", 340 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", 341 | "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", 342 | "dev": true, 343 | "dependencies": { 344 | "bl": "^4.0.3", 345 | "end-of-stream": "^1.4.1", 346 | "fs-constants": "^1.0.0", 347 | "inherits": "^2.0.3", 348 | "readable-stream": "^3.1.1" 349 | }, 350 | "engines": { 351 | "node": ">=6" 352 | } 353 | }, 354 | "node_modules/tree-sitter": { 355 | "version": "0.21.1", 356 | "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.21.1.tgz", 357 | "integrity": "sha512-7dxoA6kYvtgWw80265MyqJlkRl4yawIjO7S5MigytjELkX43fV2WsAXzsNfO7sBpPPCF5Gp0+XzHk0DwLCq3xQ==", 358 | "hasInstallScript": true, 359 | "peer": true, 360 | "dependencies": { 361 | "node-addon-api": "^8.0.0", 362 | "node-gyp-build": "^4.8.0" 363 | } 364 | }, 365 | "node_modules/tree-sitter-cli": { 366 | "version": "0.22.6", 367 | "resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.22.6.tgz", 368 | "integrity": "sha512-s7mYOJXi8sIFkt/nLJSqlYZP96VmKTc3BAwIX0rrrlRxWjWuCwixFqwzxWZBQz4R8Hx01iP7z3cT3ih58BUmZQ==", 369 | "dev": true, 370 | "hasInstallScript": true, 371 | "bin": { 372 | "tree-sitter": "cli.js" 373 | } 374 | }, 375 | "node_modules/tree-sitter-php": { 376 | "version": "0.22.2", 377 | "resolved": "https://registry.npmjs.org/tree-sitter-php/-/tree-sitter-php-0.22.2.tgz", 378 | "integrity": "sha512-DPu8nsFR2q9ocjefP3hhTDa6IDVaCQbPOFi/ElMUGiWvql6k8SKX2DUjzRcfbWNpLDAh30k7oQgC3Gmq3bhlsQ==", 379 | "dev": true, 380 | "hasInstallScript": true, 381 | "dependencies": { 382 | "nan": "^2.18.0" 383 | } 384 | }, 385 | "node_modules/tree-sitter/node_modules/node-addon-api": { 386 | "version": "8.0.0", 387 | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz", 388 | "integrity": "sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw==", 389 | "peer": true, 390 | "engines": { 391 | "node": "^18 || ^20 || >= 21" 392 | } 393 | }, 394 | "node_modules/util-deprecate": { 395 | "version": "1.0.2", 396 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 397 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 398 | "dev": true 399 | }, 400 | "node_modules/wrappy": { 401 | "version": "1.0.2", 402 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 403 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 404 | "dev": true 405 | }, 406 | "node_modules/yallist": { 407 | "version": "4.0.0", 408 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 409 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 410 | "dev": true 411 | } 412 | } 413 | } 414 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-phpdoc", 3 | "version": "0.1.0", 4 | "description": "PHPDoc grammar for tree-sitter", 5 | "main": "bindings/node", 6 | "types": "bindings/node", 7 | "scripts": { 8 | "generate": "./node_modules/.bin/tree-sitter generate", 9 | "test": "if [ $(stat -f %m ./grammar.js) -gt $(stat -f %m ./src/grammar.json) -o $(stat -f %m ./src/scanner.c) -gt $(stat -f %m ./src/parser.c) ]; then echo Regenerating...; ./node_modules/.bin/tree-sitter generate; fi && ./node_modules/.bin/tree-sitter test", 10 | "install": "node-gyp-build", 11 | "prebuildify": "prebuildify --napi --strip", 12 | "format": "./node_modules/.bin/prettier --write grammar.js .github/workflows/ci.yml", 13 | "format-check": "npm run format -- --check" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/claytonrcarter/tree-sitter-phpdoc.git" 18 | }, 19 | "keywords": [ 20 | "parser", 21 | "phpdoc" 22 | ], 23 | "files": [ 24 | "grammar.js", 25 | "binding.gyp", 26 | "prebuilds/**", 27 | "bindings/node/*", 28 | "queries/*", 29 | "src/**" 30 | ], 31 | "author": "John Nguyen", 32 | "contributors": [ 33 | "Clayton Carter " 34 | ], 35 | "license": "MIT", 36 | "bugs": { 37 | "url": "https://github.com/claytonrcarter/tree-sitter-phpdoc/issues" 38 | }, 39 | "homepage": "https://github.com/claytonrcarter/tree-sitter-phpdoc#readme", 40 | "devDependencies": { 41 | "prebuildify": "^6.0.0", 42 | "prettier": "^3.3.3", 43 | "tree-sitter-cli": "^0.22.6", 44 | "tree-sitter-php": "^0.22.2" 45 | }, 46 | "dependencies": { 47 | "node-addon-api": "^7.1.0", 48 | "node-gyp-build": "^4.8.0" 49 | }, 50 | "peerDependencies": { 51 | "tree-sitter": "^0.21.0" 52 | }, 53 | "peerDependenciesMeta": { 54 | "tree_sitter": { 55 | "optional": true 56 | } 57 | }, 58 | "tree-sitter": [ 59 | { 60 | "scope": "comment.block.documentation.phpdoc.php" 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=42", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "tree-sitter-phpdoc" 7 | description = "Phpdoc grammar for tree-sitter" 8 | version = "0.0.1" 9 | keywords = ["incremental", "parsing", "tree-sitter", "phpdoc"] 10 | classifiers = [ 11 | "Intended Audience :: Developers", 12 | "License :: OSI Approved :: MIT License", 13 | "Topic :: Software Development :: Compilers", 14 | "Topic :: Text Processing :: Linguistic", 15 | "Typing :: Typed" 16 | ] 17 | requires-python = ">=3.8" 18 | license.text = "MIT" 19 | readme = "README.md" 20 | 21 | [project.urls] 22 | Homepage = "https://github.com/tree-sitter/tree-sitter-phpdoc" 23 | 24 | [project.optional-dependencies] 25 | core = ["tree-sitter~=0.21"] 26 | 27 | [tool.cibuildwheel] 28 | build = "cp38-*" 29 | build-frontend = "build" 30 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from os.path import isdir, join 2 | from platform import system 3 | 4 | from setuptools import Extension, find_packages, setup 5 | from setuptools.command.build import build 6 | from wheel.bdist_wheel import bdist_wheel 7 | 8 | 9 | class Build(build): 10 | def run(self): 11 | if isdir("queries"): 12 | dest = join(self.build_lib, "tree_sitter_phpdoc", "queries") 13 | self.copy_tree("queries", dest) 14 | super().run() 15 | 16 | 17 | class BdistWheel(bdist_wheel): 18 | def get_tag(self): 19 | python, abi, platform = super().get_tag() 20 | if python.startswith("cp"): 21 | python, abi = "cp38", "abi3" 22 | return python, abi, platform 23 | 24 | 25 | setup( 26 | packages=find_packages("bindings/python"), 27 | package_dir={"": "bindings/python"}, 28 | package_data={ 29 | "tree_sitter_phpdoc": ["*.pyi", "py.typed"], 30 | "tree_sitter_phpdoc.queries": ["*.scm"], 31 | }, 32 | ext_package="tree_sitter_phpdoc", 33 | ext_modules=[ 34 | Extension( 35 | name="_binding", 36 | sources=[ 37 | "bindings/python/tree_sitter_phpdoc/binding.c", 38 | "src/parser.c", 39 | # NOTE: if your language uses an external scanner, add it here. 40 | ], 41 | extra_compile_args=[ 42 | "-std=c11", 43 | ] if system() != "Windows" else [ 44 | "/std:c11", 45 | "/utf-8", 46 | ], 47 | define_macros=[ 48 | ("Py_LIMITED_API", "0x03080000"), 49 | ("PY_SSIZE_T_CLEAN", None) 50 | ], 51 | include_dirs=["src"], 52 | py_limited_api=True, 53 | ) 54 | ], 55 | cmdclass={ 56 | "build": Build, 57 | "bdist_wheel": BdistWheel 58 | }, 59 | zip_safe=False 60 | ) 61 | -------------------------------------------------------------------------------- /src/node-types.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "array_element", 4 | "named": true, 5 | "fields": { 6 | "key": { 7 | "multiple": true, 8 | "required": false, 9 | "types": [ 10 | { 11 | "type": "\"", 12 | "named": false 13 | }, 14 | { 15 | "type": "'", 16 | "named": false 17 | }, 18 | { 19 | "type": ":", 20 | "named": false 21 | }, 22 | { 23 | "type": "?", 24 | "named": false 25 | }, 26 | { 27 | "type": "name", 28 | "named": true 29 | } 30 | ] 31 | }, 32 | "value": { 33 | "multiple": false, 34 | "required": true, 35 | "types": [ 36 | { 37 | "type": "named_type", 38 | "named": true 39 | }, 40 | { 41 | "type": "optional_type", 42 | "named": true 43 | }, 44 | { 45 | "type": "primitive_type", 46 | "named": true 47 | } 48 | ] 49 | } 50 | } 51 | }, 52 | { 53 | "type": "array_type", 54 | "named": true, 55 | "fields": { 56 | "array": { 57 | "multiple": false, 58 | "required": false, 59 | "types": [ 60 | { 61 | "type": "named_type", 62 | "named": true 63 | }, 64 | { 65 | "type": "optional_type", 66 | "named": true 67 | }, 68 | { 69 | "type": "primitive_type", 70 | "named": true 71 | } 72 | ] 73 | }, 74 | "key": { 75 | "multiple": false, 76 | "required": false, 77 | "types": [ 78 | { 79 | "type": "array_type", 80 | "named": true 81 | }, 82 | { 83 | "type": "named_type", 84 | "named": true 85 | }, 86 | { 87 | "type": "optional_type", 88 | "named": true 89 | }, 90 | { 91 | "type": "primitive_type", 92 | "named": true 93 | } 94 | ] 95 | }, 96 | "value": { 97 | "multiple": false, 98 | "required": false, 99 | "types": [ 100 | { 101 | "type": "array_type", 102 | "named": true 103 | }, 104 | { 105 | "type": "named_type", 106 | "named": true 107 | }, 108 | { 109 | "type": "optional_type", 110 | "named": true 111 | }, 112 | { 113 | "type": "primitive_type", 114 | "named": true 115 | } 116 | ] 117 | } 118 | }, 119 | "children": { 120 | "multiple": true, 121 | "required": false, 122 | "types": [ 123 | { 124 | "type": "array_element", 125 | "named": true 126 | }, 127 | { 128 | "type": "named_type", 129 | "named": true 130 | }, 131 | { 132 | "type": "optional_type", 133 | "named": true 134 | }, 135 | { 136 | "type": "primitive_type", 137 | "named": true 138 | } 139 | ] 140 | } 141 | }, 142 | { 143 | "type": "description", 144 | "named": true, 145 | "fields": {}, 146 | "children": { 147 | "multiple": true, 148 | "required": true, 149 | "types": [ 150 | { 151 | "type": "inline_tag", 152 | "named": true 153 | }, 154 | { 155 | "type": "text", 156 | "named": true 157 | } 158 | ] 159 | } 160 | }, 161 | { 162 | "type": "disjunctive_normal_form_type", 163 | "named": true, 164 | "fields": {}, 165 | "children": { 166 | "multiple": true, 167 | "required": true, 168 | "types": [ 169 | { 170 | "type": "array_type", 171 | "named": true 172 | }, 173 | { 174 | "type": "intersection_type", 175 | "named": true 176 | }, 177 | { 178 | "type": "named_type", 179 | "named": true 180 | }, 181 | { 182 | "type": "optional_type", 183 | "named": true 184 | }, 185 | { 186 | "type": "primitive_type", 187 | "named": true 188 | } 189 | ] 190 | } 191 | }, 192 | { 193 | "type": "document", 194 | "named": true, 195 | "fields": {}, 196 | "children": { 197 | "multiple": true, 198 | "required": false, 199 | "types": [ 200 | { 201 | "type": "description", 202 | "named": true 203 | }, 204 | { 205 | "type": "tag", 206 | "named": true 207 | } 208 | ] 209 | } 210 | }, 211 | { 212 | "type": "fqsen", 213 | "named": true, 214 | "fields": {}, 215 | "children": { 216 | "multiple": true, 217 | "required": true, 218 | "types": [ 219 | { 220 | "type": "name", 221 | "named": true 222 | }, 223 | { 224 | "type": "named_type", 225 | "named": true 226 | }, 227 | { 228 | "type": "variable_name", 229 | "named": true 230 | } 231 | ] 232 | } 233 | }, 234 | { 235 | "type": "generic_type", 236 | "named": true, 237 | "fields": {}, 238 | "children": { 239 | "multiple": true, 240 | "required": true, 241 | "types": [ 242 | { 243 | "type": "array_type", 244 | "named": true 245 | }, 246 | { 247 | "type": "disjunctive_normal_form_type", 248 | "named": true 249 | }, 250 | { 251 | "type": "intersection_type", 252 | "named": true 253 | }, 254 | { 255 | "type": "name", 256 | "named": true 257 | }, 258 | { 259 | "type": "named_type", 260 | "named": true 261 | }, 262 | { 263 | "type": "optional_type", 264 | "named": true 265 | }, 266 | { 267 | "type": "primitive_type", 268 | "named": true 269 | }, 270 | { 271 | "type": "qualified_name", 272 | "named": true 273 | }, 274 | { 275 | "type": "union_type", 276 | "named": true 277 | } 278 | ] 279 | } 280 | }, 281 | { 282 | "type": "inline_tag", 283 | "named": true, 284 | "fields": {}, 285 | "children": { 286 | "multiple": true, 287 | "required": true, 288 | "types": [ 289 | { 290 | "type": "description", 291 | "named": true 292 | }, 293 | { 294 | "type": "fqsen", 295 | "named": true 296 | }, 297 | { 298 | "type": "tag_name", 299 | "named": true 300 | }, 301 | { 302 | "type": "uri", 303 | "named": true 304 | } 305 | ] 306 | } 307 | }, 308 | { 309 | "type": "intersection_type", 310 | "named": true, 311 | "fields": {}, 312 | "children": { 313 | "multiple": true, 314 | "required": true, 315 | "types": [ 316 | { 317 | "type": "array_type", 318 | "named": true 319 | }, 320 | { 321 | "type": "named_type", 322 | "named": true 323 | }, 324 | { 325 | "type": "optional_type", 326 | "named": true 327 | }, 328 | { 329 | "type": "primitive_type", 330 | "named": true 331 | } 332 | ] 333 | } 334 | }, 335 | { 336 | "type": "named_type", 337 | "named": true, 338 | "fields": {}, 339 | "children": { 340 | "multiple": false, 341 | "required": true, 342 | "types": [ 343 | { 344 | "type": "generic_type", 345 | "named": true 346 | }, 347 | { 348 | "type": "name", 349 | "named": true 350 | }, 351 | { 352 | "type": "qualified_name", 353 | "named": true 354 | } 355 | ] 356 | } 357 | }, 358 | { 359 | "type": "namespace_name", 360 | "named": true, 361 | "fields": {}, 362 | "children": { 363 | "multiple": true, 364 | "required": true, 365 | "types": [ 366 | { 367 | "type": "name", 368 | "named": true 369 | } 370 | ] 371 | } 372 | }, 373 | { 374 | "type": "namespace_name_as_prefix", 375 | "named": true, 376 | "fields": {}, 377 | "children": { 378 | "multiple": false, 379 | "required": false, 380 | "types": [ 381 | { 382 | "type": "namespace_name", 383 | "named": true 384 | } 385 | ] 386 | } 387 | }, 388 | { 389 | "type": "optional_type", 390 | "named": true, 391 | "fields": {}, 392 | "children": { 393 | "multiple": false, 394 | "required": true, 395 | "types": [ 396 | { 397 | "type": "named_type", 398 | "named": true 399 | }, 400 | { 401 | "type": "primitive_type", 402 | "named": true 403 | } 404 | ] 405 | } 406 | }, 407 | { 408 | "type": "parameter", 409 | "named": true, 410 | "fields": {}, 411 | "children": { 412 | "multiple": true, 413 | "required": true, 414 | "types": [ 415 | { 416 | "type": "array_type", 417 | "named": true 418 | }, 419 | { 420 | "type": "default_value", 421 | "named": true 422 | }, 423 | { 424 | "type": "disjunctive_normal_form_type", 425 | "named": true 426 | }, 427 | { 428 | "type": "intersection_type", 429 | "named": true 430 | }, 431 | { 432 | "type": "named_type", 433 | "named": true 434 | }, 435 | { 436 | "type": "optional_type", 437 | "named": true 438 | }, 439 | { 440 | "type": "primitive_type", 441 | "named": true 442 | }, 443 | { 444 | "type": "union_type", 445 | "named": true 446 | }, 447 | { 448 | "type": "variable_name", 449 | "named": true 450 | } 451 | ] 452 | } 453 | }, 454 | { 455 | "type": "parameters", 456 | "named": true, 457 | "fields": {}, 458 | "children": { 459 | "multiple": true, 460 | "required": false, 461 | "types": [ 462 | { 463 | "type": "parameter", 464 | "named": true 465 | } 466 | ] 467 | } 468 | }, 469 | { 470 | "type": "primitive_type", 471 | "named": true, 472 | "fields": {}, 473 | "children": { 474 | "multiple": false, 475 | "required": false, 476 | "types": [ 477 | { 478 | "type": "named_type", 479 | "named": true 480 | } 481 | ] 482 | } 483 | }, 484 | { 485 | "type": "qualified_name", 486 | "named": true, 487 | "fields": {}, 488 | "children": { 489 | "multiple": true, 490 | "required": true, 491 | "types": [ 492 | { 493 | "type": "name", 494 | "named": true 495 | }, 496 | { 497 | "type": "namespace_name_as_prefix", 498 | "named": true 499 | } 500 | ] 501 | } 502 | }, 503 | { 504 | "type": "static", 505 | "named": true, 506 | "fields": {} 507 | }, 508 | { 509 | "type": "tag", 510 | "named": true, 511 | "fields": {}, 512 | "children": { 513 | "multiple": true, 514 | "required": true, 515 | "types": [ 516 | { 517 | "type": "array_type", 518 | "named": true 519 | }, 520 | { 521 | "type": "author_name", 522 | "named": true 523 | }, 524 | { 525 | "type": "description", 526 | "named": true 527 | }, 528 | { 529 | "type": "disjunctive_normal_form_type", 530 | "named": true 531 | }, 532 | { 533 | "type": "email_address", 534 | "named": true 535 | }, 536 | { 537 | "type": "fqsen", 538 | "named": true 539 | }, 540 | { 541 | "type": "intersection_type", 542 | "named": true 543 | }, 544 | { 545 | "type": "name", 546 | "named": true 547 | }, 548 | { 549 | "type": "named_type", 550 | "named": true 551 | }, 552 | { 553 | "type": "optional_type", 554 | "named": true 555 | }, 556 | { 557 | "type": "parameters", 558 | "named": true 559 | }, 560 | { 561 | "type": "primitive_type", 562 | "named": true 563 | }, 564 | { 565 | "type": "static", 566 | "named": true 567 | }, 568 | { 569 | "type": "tag_name", 570 | "named": true 571 | }, 572 | { 573 | "type": "union_type", 574 | "named": true 575 | }, 576 | { 577 | "type": "uri", 578 | "named": true 579 | }, 580 | { 581 | "type": "variable_name", 582 | "named": true 583 | }, 584 | { 585 | "type": "version", 586 | "named": true 587 | } 588 | ] 589 | } 590 | }, 591 | { 592 | "type": "union_type", 593 | "named": true, 594 | "fields": {}, 595 | "children": { 596 | "multiple": true, 597 | "required": true, 598 | "types": [ 599 | { 600 | "type": "array_type", 601 | "named": true 602 | }, 603 | { 604 | "type": "named_type", 605 | "named": true 606 | }, 607 | { 608 | "type": "optional_type", 609 | "named": true 610 | }, 611 | { 612 | "type": "primitive_type", 613 | "named": true 614 | } 615 | ] 616 | } 617 | }, 618 | { 619 | "type": "variable_name", 620 | "named": true, 621 | "fields": {}, 622 | "children": { 623 | "multiple": false, 624 | "required": true, 625 | "types": [ 626 | { 627 | "type": "name", 628 | "named": true 629 | } 630 | ] 631 | } 632 | }, 633 | { 634 | "type": "version", 635 | "named": true, 636 | "fields": {} 637 | }, 638 | { 639 | "type": "\"", 640 | "named": false 641 | }, 642 | { 643 | "type": "$", 644 | "named": false 645 | }, 646 | { 647 | "type": "&", 648 | "named": false 649 | }, 650 | { 651 | "type": "'", 652 | "named": false 653 | }, 654 | { 655 | "type": "(", 656 | "named": false 657 | }, 658 | { 659 | "type": "()", 660 | "named": false 661 | }, 662 | { 663 | "type": ")", 664 | "named": false 665 | }, 666 | { 667 | "type": ",", 668 | "named": false 669 | }, 670 | { 671 | "type": ":", 672 | "named": false 673 | }, 674 | { 675 | "type": "::", 676 | "named": false 677 | }, 678 | { 679 | "type": "<", 680 | "named": false 681 | }, 682 | { 683 | "type": "=", 684 | "named": false 685 | }, 686 | { 687 | "type": ">", 688 | "named": false 689 | }, 690 | { 691 | "type": "?", 692 | "named": false 693 | }, 694 | { 695 | "type": "@package_version@", 696 | "named": false 697 | }, 698 | { 699 | "type": "[]", 700 | "named": false 701 | }, 702 | { 703 | "type": "\\", 704 | "named": false 705 | }, 706 | { 707 | "type": "array", 708 | "named": false 709 | }, 710 | { 711 | "type": "as", 712 | "named": false 713 | }, 714 | { 715 | "type": "author_name", 716 | "named": true 717 | }, 718 | { 719 | "type": "bool", 720 | "named": false 721 | }, 722 | { 723 | "type": "callable", 724 | "named": false 725 | }, 726 | { 727 | "type": "callable-string", 728 | "named": false 729 | }, 730 | { 731 | "type": "class-string", 732 | "named": false 733 | }, 734 | { 735 | "type": "default_value", 736 | "named": true 737 | }, 738 | { 739 | "type": "email_address", 740 | "named": true 741 | }, 742 | { 743 | "type": "enum-string", 744 | "named": false 745 | }, 746 | { 747 | "type": "false", 748 | "named": false 749 | }, 750 | { 751 | "type": "float", 752 | "named": false 753 | }, 754 | { 755 | "type": "from", 756 | "named": false 757 | }, 758 | { 759 | "type": "int", 760 | "named": false 761 | }, 762 | { 763 | "type": "interface-string", 764 | "named": false 765 | }, 766 | { 767 | "type": "iterable", 768 | "named": false 769 | }, 770 | { 771 | "type": "list", 772 | "named": false 773 | }, 774 | { 775 | "type": "literal-string", 776 | "named": false 777 | }, 778 | { 779 | "type": "lowercase-string", 780 | "named": false 781 | }, 782 | { 783 | "type": "mixed", 784 | "named": false 785 | }, 786 | { 787 | "type": "name", 788 | "named": true 789 | }, 790 | { 791 | "type": "namespace", 792 | "named": false 793 | }, 794 | { 795 | "type": "non-empty-lowercase-string", 796 | "named": false 797 | }, 798 | { 799 | "type": "non-empty-string", 800 | "named": false 801 | }, 802 | { 803 | "type": "null", 804 | "named": false 805 | }, 806 | { 807 | "type": "numeric-string", 808 | "named": false 809 | }, 810 | { 811 | "type": "of", 812 | "named": false 813 | }, 814 | { 815 | "type": "positive-int", 816 | "named": false 817 | }, 818 | { 819 | "type": "static", 820 | "named": false 821 | }, 822 | { 823 | "type": "string", 824 | "named": false 825 | }, 826 | { 827 | "type": "tag_name", 828 | "named": true 829 | }, 830 | { 831 | "type": "text", 832 | "named": true 833 | }, 834 | { 835 | "type": "trait-string", 836 | "named": false 837 | }, 838 | { 839 | "type": "true", 840 | "named": false 841 | }, 842 | { 843 | "type": "uri", 844 | "named": true 845 | }, 846 | { 847 | "type": "void", 848 | "named": false 849 | }, 850 | { 851 | "type": "{", 852 | "named": false 853 | }, 854 | { 855 | "type": "|", 856 | "named": false 857 | }, 858 | { 859 | "type": "}", 860 | "named": false 861 | } 862 | ] -------------------------------------------------------------------------------- /src/scanner.c: -------------------------------------------------------------------------------- 1 | #include "tree_sitter/parser.h" 2 | 3 | #define TSDEBUG 0 4 | 5 | #if TSDEBUG 6 | #include 7 | #define LOG(...) fprintf(stderr, __VA_ARGS__) 8 | #else 9 | #define LOG(...) 10 | #endif 11 | 12 | enum TokenType { 13 | TEXT, 14 | TEXT_AFTER_TYPE, 15 | TEXT_IN_INLINE_TAG, 16 | TEXT_NOT_VERSION, 17 | }; 18 | 19 | // Used as version string for some PEAR packages 20 | static const char* const package_version = "@package_version@"; 21 | 22 | void *tree_sitter_phpdoc_external_scanner_create() { return NULL; } 23 | 24 | void tree_sitter_phpdoc_external_scanner_destroy(void *payload) {} 25 | 26 | unsigned tree_sitter_phpdoc_external_scanner_serialize(void *payload, char *buffer) { return 0; } 27 | 28 | void tree_sitter_phpdoc_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) {} 29 | 30 | static void advance(TSLexer *lexer) { lexer->advance(lexer, false); } 31 | 32 | static void skip(TSLexer *lexer) { lexer->advance(lexer, true); } 33 | 34 | // Skip line prefix: 35 | // 36 | // /**\n <-- lookahead points here 37 | // *\n <-- or here ... 38 | // * bla 39 | // ^ ... and will skip to here 40 | // 41 | // False is returned if other chars than [\n *] appear before '* '. 42 | static bool skip_to_text_start(TSLexer *lexer) { 43 | bool asterisk_found = false; 44 | while (true) { 45 | switch (lexer->lookahead) { 46 | case '\r': 47 | case '\n': 48 | skip(lexer); 49 | asterisk_found = false; 50 | break; 51 | case ' ': 52 | if (asterisk_found) { 53 | // '* ' found: potential start of next content 54 | return true; 55 | } 56 | skip(lexer); 57 | break; 58 | case '*': 59 | skip(lexer); 60 | asterisk_found = true; 61 | break; 62 | default: 63 | return false; 64 | } 65 | } 66 | } 67 | 68 | static bool skip_whitespace(TSLexer *lexer) { 69 | bool skipped = false; 70 | while ( 71 | lexer->lookahead == ' ' || 72 | lexer->lookahead == '\t' || 73 | lexer->lookahead == '\n' || 74 | lexer->lookahead == '\r' 75 | ) { 76 | skip(lexer); 77 | skipped = true; 78 | } 79 | return skipped; 80 | } 81 | 82 | // Returns whether a valid variable name like $ab_cde was detected. 83 | // Preceding whitespace will be skipped. 84 | static bool scan_variable_name(TSLexer *lexer, bool *has_content) { 85 | if (skip_whitespace(lexer)) { 86 | *has_content = true; 87 | } 88 | if (lexer->lookahead != '$') { 89 | return false; 90 | } 91 | advance(lexer); 92 | 93 | // From PHP parser: 94 | // name: /[_a-zA-Z\u00A1-\u00ff][_a-zA-Z\u00A1-\u00ff\d]*/, 95 | while (true) { 96 | if ( 97 | lexer->lookahead == '_' || 98 | (lexer->lookahead >= 'a' && lexer->lookahead <= 'z') || 99 | (lexer->lookahead >= 'A' && lexer->lookahead <= 'Z') || 100 | (lexer->lookahead >= 0x00A1 && lexer->lookahead <= 0x00FF) || 101 | (*has_content && lexer->lookahead >= '0' && lexer->lookahead <= '9') 102 | ) { 103 | *has_content = true; 104 | advance(lexer); 105 | } else { 106 | return *has_content; 107 | } 108 | } 109 | } 110 | 111 | // Returns whether a valid version string was detected: 112 | // 1.2.3 113 | // 1.blabla-x 114 | // vcs: $some_vector$ 115 | // $some_vector$ 116 | // @package_version@ 117 | // Preceding whitespace will be skipped. 118 | static bool scan_version(TSLexer *lexer, bool *has_content) { 119 | skip_whitespace(lexer); 120 | const char* pkg = package_version; 121 | bool numeric_started = false; 122 | bool vcs_started = false; 123 | bool vcs_complete = false; 124 | bool vector_started = false; 125 | while (true) { 126 | switch (lexer->lookahead) { 127 | case '\r': 128 | case '\n': 129 | case '\0': 130 | return false; 131 | 132 | case '.': 133 | if (numeric_started) { 134 | return true; 135 | } 136 | break; 137 | 138 | case ' ': 139 | if (!vcs_complete) { 140 | return false; 141 | } 142 | break; 143 | 144 | case ':': 145 | if (vcs_started) { 146 | vcs_complete = true; 147 | } 148 | break; 149 | 150 | case '@': 151 | while (*pkg != '\0') { 152 | if (*(pkg++) != lexer->lookahead) { 153 | return false; 154 | } 155 | advance(lexer); 156 | } 157 | return true; 158 | break; 159 | 160 | case '$': 161 | if (vector_started) { 162 | return true; 163 | } 164 | if (!*has_content || vcs_complete) { 165 | vector_started = true; 166 | } 167 | 168 | case '0': 169 | case '1': 170 | case '2': 171 | case '3': 172 | case '4': 173 | case '5': 174 | case '6': 175 | case '7': 176 | case '8': 177 | case '9': 178 | if (!*has_content) { 179 | numeric_started = true; 180 | } 181 | break; 182 | 183 | default: 184 | if (!*has_content) { 185 | vcs_started = true; 186 | } 187 | } 188 | advance(lexer); 189 | *has_content = true; 190 | } 191 | } 192 | 193 | static bool scan_text(TSLexer *lexer, bool is_inline, bool has_content) { 194 | while (true) { 195 | lexer->mark_end(lexer); 196 | 197 | switch (lexer->lookahead) { 198 | case '\0': 199 | return false; 200 | 201 | case '\r': 202 | case '\n': 203 | return has_content; 204 | 205 | case '@': 206 | case '\\': 207 | // don't allow @ or \\ at text start to not mess with tags and namespaces 208 | if (!has_content) { 209 | return false; 210 | } 211 | break; 212 | 213 | case '{': 214 | advance(lexer); 215 | if (lexer->lookahead == '@') { 216 | // new inline tag starts, so text node is complete 217 | return has_content; 218 | } 219 | break; 220 | 221 | case '}': 222 | if (is_inline) { 223 | // inline tag ends, so text node is complete 224 | return has_content; 225 | } 226 | break; 227 | 228 | case ' ': 229 | advance(lexer); 230 | switch (lexer->lookahead) { 231 | // check for end of comment: ' */', ' **/', ... 232 | case '*': 233 | while (lexer->lookahead == '*') { 234 | advance(lexer); 235 | } 236 | if (lexer->lookahead == '/') { 237 | return has_content; 238 | } 239 | break; 240 | // check for start of inline tag 241 | case '{': 242 | advance(lexer); 243 | if (lexer->lookahead == '@') { 244 | // new inline tag starts, so text node is complete 245 | return has_content; 246 | } 247 | break; 248 | } 249 | break; 250 | } 251 | has_content = true; 252 | advance(lexer); 253 | } 254 | } 255 | 256 | bool tree_sitter_phpdoc_external_scanner_scan(void *payload, TSLexer *lexer, 257 | const bool *valid_symbols) { 258 | LOG("scanner called text:%d text_after_type:%d text_in_inline_tag:%d text_not_version:%d\n", 259 | valid_symbols[TEXT], 260 | valid_symbols[TEXT_AFTER_TYPE], 261 | valid_symbols[TEXT_IN_INLINE_TAG], 262 | valid_symbols[TEXT_NOT_VERSION]); 263 | 264 | bool skipped_nl = false; 265 | bool has_content = false; 266 | if ( 267 | valid_symbols[TEXT] || 268 | valid_symbols[TEXT_AFTER_TYPE] || 269 | valid_symbols[TEXT_IN_INLINE_TAG] || 270 | valid_symbols[TEXT_NOT_VERSION] 271 | ) { 272 | 273 | if (lexer->lookahead == '\n' || lexer->lookahead == '\r') { 274 | if (!skip_to_text_start(lexer)) { 275 | return false; 276 | } 277 | skipped_nl = true; 278 | } 279 | 280 | // node start must always have a preceding space 281 | if (lexer->lookahead != ' ') { 282 | return false; 283 | } 284 | skip(lexer); 285 | 286 | if (valid_symbols[TEXT] && scan_text(lexer, false, has_content)) { 287 | lexer->result_symbol = TEXT; 288 | LOG(" scanner detected:text return:1\n"); 289 | return true; 290 | } 291 | 292 | if (valid_symbols[TEXT_AFTER_TYPE]) { 293 | lexer->result_symbol = TEXT_AFTER_TYPE; 294 | // Ensure that we have '/** int description' and not '/** int $var description' 295 | if (scan_variable_name(lexer, &has_content)) { 296 | LOG(" scanner detected:variable_name return:0\n"); 297 | return false; 298 | } 299 | skip_whitespace(lexer); 300 | if (scan_text(lexer, false, has_content)) { 301 | LOG(" scanner detected:text_after_type return:1\n"); 302 | return true; 303 | } 304 | } 305 | 306 | if (valid_symbols[TEXT_IN_INLINE_TAG] && scan_text(lexer, true, has_content)) { 307 | lexer->result_symbol = TEXT_IN_INLINE_TAG; 308 | LOG(" scanner detected:text_in_inline_tag return:1\n"); 309 | return true; 310 | } 311 | 312 | if (valid_symbols[TEXT_NOT_VERSION]) { 313 | lexer->result_symbol = TEXT_NOT_VERSION; 314 | // Ensure that node doesn't start with anything that looks like a version 315 | // - but only if we didn't skip a linebreak. Otherwhise the lexer might 316 | // advance over a new tag like '\n * @pa...' to check for 317 | // '@package_version@'. This would result in the tag being parsed as 318 | // valid description. 319 | if (!skipped_nl && scan_version(lexer, &has_content)) { 320 | LOG(" scanner detected:version return:0\n"); 321 | return false; 322 | } 323 | if (scan_text(lexer, false, has_content)) { 324 | LOG(" scanner detected:text_not_version return:1\n"); 325 | return true; 326 | } 327 | } 328 | } 329 | LOG("scanner detected:nothing return:0\n"); 330 | return false; 331 | } 332 | -------------------------------------------------------------------------------- /src/tree_sitter/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_ALLOC_H_ 2 | #define TREE_SITTER_ALLOC_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // Allow clients to override allocation functions 13 | #ifdef TREE_SITTER_REUSE_ALLOCATOR 14 | 15 | extern void *(*ts_current_malloc)(size_t); 16 | extern void *(*ts_current_calloc)(size_t, size_t); 17 | extern void *(*ts_current_realloc)(void *, size_t); 18 | extern void (*ts_current_free)(void *); 19 | 20 | #ifndef ts_malloc 21 | #define ts_malloc ts_current_malloc 22 | #endif 23 | #ifndef ts_calloc 24 | #define ts_calloc ts_current_calloc 25 | #endif 26 | #ifndef ts_realloc 27 | #define ts_realloc ts_current_realloc 28 | #endif 29 | #ifndef ts_free 30 | #define ts_free ts_current_free 31 | #endif 32 | 33 | #else 34 | 35 | #ifndef ts_malloc 36 | #define ts_malloc malloc 37 | #endif 38 | #ifndef ts_calloc 39 | #define ts_calloc calloc 40 | #endif 41 | #ifndef ts_realloc 42 | #define ts_realloc realloc 43 | #endif 44 | #ifndef ts_free 45 | #define ts_free free 46 | #endif 47 | 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif // TREE_SITTER_ALLOC_H_ 55 | -------------------------------------------------------------------------------- /src/tree_sitter/array.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_ARRAY_H_ 2 | #define TREE_SITTER_ARRAY_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "./alloc.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef _MSC_VER 17 | #pragma warning(disable : 4101) 18 | #elif defined(__GNUC__) || defined(__clang__) 19 | #pragma GCC diagnostic push 20 | #pragma GCC diagnostic ignored "-Wunused-variable" 21 | #endif 22 | 23 | #define Array(T) \ 24 | struct { \ 25 | T *contents; \ 26 | uint32_t size; \ 27 | uint32_t capacity; \ 28 | } 29 | 30 | /// Initialize an array. 31 | #define array_init(self) \ 32 | ((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL) 33 | 34 | /// Create an empty array. 35 | #define array_new() \ 36 | { NULL, 0, 0 } 37 | 38 | /// Get a pointer to the element at a given `index` in the array. 39 | #define array_get(self, _index) \ 40 | (assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index]) 41 | 42 | /// Get a pointer to the first element in the array. 43 | #define array_front(self) array_get(self, 0) 44 | 45 | /// Get a pointer to the last element in the array. 46 | #define array_back(self) array_get(self, (self)->size - 1) 47 | 48 | /// Clear the array, setting its size to zero. Note that this does not free any 49 | /// memory allocated for the array's contents. 50 | #define array_clear(self) ((self)->size = 0) 51 | 52 | /// Reserve `new_capacity` elements of space in the array. If `new_capacity` is 53 | /// less than the array's current capacity, this function has no effect. 54 | #define array_reserve(self, new_capacity) \ 55 | _array__reserve((Array *)(self), array_elem_size(self), new_capacity) 56 | 57 | /// Free any memory allocated for this array. Note that this does not free any 58 | /// memory allocated for the array's contents. 59 | #define array_delete(self) _array__delete((Array *)(self)) 60 | 61 | /// Push a new `element` onto the end of the array. 62 | #define array_push(self, element) \ 63 | (_array__grow((Array *)(self), 1, array_elem_size(self)), \ 64 | (self)->contents[(self)->size++] = (element)) 65 | 66 | /// Increase the array's size by `count` elements. 67 | /// New elements are zero-initialized. 68 | #define array_grow_by(self, count) \ 69 | do { \ 70 | if ((count) == 0) break; \ 71 | _array__grow((Array *)(self), count, array_elem_size(self)); \ 72 | memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \ 73 | (self)->size += (count); \ 74 | } while (0) 75 | 76 | /// Append all elements from one array to the end of another. 77 | #define array_push_all(self, other) \ 78 | array_extend((self), (other)->size, (other)->contents) 79 | 80 | /// Append `count` elements to the end of the array, reading their values from the 81 | /// `contents` pointer. 82 | #define array_extend(self, count, contents) \ 83 | _array__splice( \ 84 | (Array *)(self), array_elem_size(self), (self)->size, \ 85 | 0, count, contents \ 86 | ) 87 | 88 | /// Remove `old_count` elements from the array starting at the given `index`. At 89 | /// the same index, insert `new_count` new elements, reading their values from the 90 | /// `new_contents` pointer. 91 | #define array_splice(self, _index, old_count, new_count, new_contents) \ 92 | _array__splice( \ 93 | (Array *)(self), array_elem_size(self), _index, \ 94 | old_count, new_count, new_contents \ 95 | ) 96 | 97 | /// Insert one `element` into the array at the given `index`. 98 | #define array_insert(self, _index, element) \ 99 | _array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element)) 100 | 101 | /// Remove one element from the array at the given `index`. 102 | #define array_erase(self, _index) \ 103 | _array__erase((Array *)(self), array_elem_size(self), _index) 104 | 105 | /// Pop the last element off the array, returning the element by value. 106 | #define array_pop(self) ((self)->contents[--(self)->size]) 107 | 108 | /// Assign the contents of one array to another, reallocating if necessary. 109 | #define array_assign(self, other) \ 110 | _array__assign((Array *)(self), (const Array *)(other), array_elem_size(self)) 111 | 112 | /// Swap one array with another 113 | #define array_swap(self, other) \ 114 | _array__swap((Array *)(self), (Array *)(other)) 115 | 116 | /// Get the size of the array contents 117 | #define array_elem_size(self) (sizeof *(self)->contents) 118 | 119 | /// Search a sorted array for a given `needle` value, using the given `compare` 120 | /// callback to determine the order. 121 | /// 122 | /// If an existing element is found to be equal to `needle`, then the `index` 123 | /// out-parameter is set to the existing value's index, and the `exists` 124 | /// out-parameter is set to true. Otherwise, `index` is set to an index where 125 | /// `needle` should be inserted in order to preserve the sorting, and `exists` 126 | /// is set to false. 127 | #define array_search_sorted_with(self, compare, needle, _index, _exists) \ 128 | _array__search_sorted(self, 0, compare, , needle, _index, _exists) 129 | 130 | /// Search a sorted array for a given `needle` value, using integer comparisons 131 | /// of a given struct field (specified with a leading dot) to determine the order. 132 | /// 133 | /// See also `array_search_sorted_with`. 134 | #define array_search_sorted_by(self, field, needle, _index, _exists) \ 135 | _array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists) 136 | 137 | /// Insert a given `value` into a sorted array, using the given `compare` 138 | /// callback to determine the order. 139 | #define array_insert_sorted_with(self, compare, value) \ 140 | do { \ 141 | unsigned _index, _exists; \ 142 | array_search_sorted_with(self, compare, &(value), &_index, &_exists); \ 143 | if (!_exists) array_insert(self, _index, value); \ 144 | } while (0) 145 | 146 | /// Insert a given `value` into a sorted array, using integer comparisons of 147 | /// a given struct field (specified with a leading dot) to determine the order. 148 | /// 149 | /// See also `array_search_sorted_by`. 150 | #define array_insert_sorted_by(self, field, value) \ 151 | do { \ 152 | unsigned _index, _exists; \ 153 | array_search_sorted_by(self, field, (value) field, &_index, &_exists); \ 154 | if (!_exists) array_insert(self, _index, value); \ 155 | } while (0) 156 | 157 | // Private 158 | 159 | typedef Array(void) Array; 160 | 161 | /// This is not what you're looking for, see `array_delete`. 162 | static inline void _array__delete(Array *self) { 163 | if (self->contents) { 164 | ts_free(self->contents); 165 | self->contents = NULL; 166 | self->size = 0; 167 | self->capacity = 0; 168 | } 169 | } 170 | 171 | /// This is not what you're looking for, see `array_erase`. 172 | static inline void _array__erase(Array *self, size_t element_size, 173 | uint32_t index) { 174 | assert(index < self->size); 175 | char *contents = (char *)self->contents; 176 | memmove(contents + index * element_size, contents + (index + 1) * element_size, 177 | (self->size - index - 1) * element_size); 178 | self->size--; 179 | } 180 | 181 | /// This is not what you're looking for, see `array_reserve`. 182 | static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) { 183 | if (new_capacity > self->capacity) { 184 | if (self->contents) { 185 | self->contents = ts_realloc(self->contents, new_capacity * element_size); 186 | } else { 187 | self->contents = ts_malloc(new_capacity * element_size); 188 | } 189 | self->capacity = new_capacity; 190 | } 191 | } 192 | 193 | /// This is not what you're looking for, see `array_assign`. 194 | static inline void _array__assign(Array *self, const Array *other, size_t element_size) { 195 | _array__reserve(self, element_size, other->size); 196 | self->size = other->size; 197 | memcpy(self->contents, other->contents, self->size * element_size); 198 | } 199 | 200 | /// This is not what you're looking for, see `array_swap`. 201 | static inline void _array__swap(Array *self, Array *other) { 202 | Array swap = *other; 203 | *other = *self; 204 | *self = swap; 205 | } 206 | 207 | /// This is not what you're looking for, see `array_push` or `array_grow_by`. 208 | static inline void _array__grow(Array *self, uint32_t count, size_t element_size) { 209 | uint32_t new_size = self->size + count; 210 | if (new_size > self->capacity) { 211 | uint32_t new_capacity = self->capacity * 2; 212 | if (new_capacity < 8) new_capacity = 8; 213 | if (new_capacity < new_size) new_capacity = new_size; 214 | _array__reserve(self, element_size, new_capacity); 215 | } 216 | } 217 | 218 | /// This is not what you're looking for, see `array_splice`. 219 | static inline void _array__splice(Array *self, size_t element_size, 220 | uint32_t index, uint32_t old_count, 221 | uint32_t new_count, const void *elements) { 222 | uint32_t new_size = self->size + new_count - old_count; 223 | uint32_t old_end = index + old_count; 224 | uint32_t new_end = index + new_count; 225 | assert(old_end <= self->size); 226 | 227 | _array__reserve(self, element_size, new_size); 228 | 229 | char *contents = (char *)self->contents; 230 | if (self->size > old_end) { 231 | memmove( 232 | contents + new_end * element_size, 233 | contents + old_end * element_size, 234 | (self->size - old_end) * element_size 235 | ); 236 | } 237 | if (new_count > 0) { 238 | if (elements) { 239 | memcpy( 240 | (contents + index * element_size), 241 | elements, 242 | new_count * element_size 243 | ); 244 | } else { 245 | memset( 246 | (contents + index * element_size), 247 | 0, 248 | new_count * element_size 249 | ); 250 | } 251 | } 252 | self->size += new_count - old_count; 253 | } 254 | 255 | /// A binary search routine, based on Rust's `std::slice::binary_search_by`. 256 | /// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`. 257 | #define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \ 258 | do { \ 259 | *(_index) = start; \ 260 | *(_exists) = false; \ 261 | uint32_t size = (self)->size - *(_index); \ 262 | if (size == 0) break; \ 263 | int comparison; \ 264 | while (size > 1) { \ 265 | uint32_t half_size = size / 2; \ 266 | uint32_t mid_index = *(_index) + half_size; \ 267 | comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \ 268 | if (comparison <= 0) *(_index) = mid_index; \ 269 | size -= half_size; \ 270 | } \ 271 | comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \ 272 | if (comparison == 0) *(_exists) = true; \ 273 | else if (comparison < 0) *(_index) += 1; \ 274 | } while (0) 275 | 276 | /// Helper macro for the `_sorted_by` routines below. This takes the left (existing) 277 | /// parameter by reference in order to work with the generic sorting function above. 278 | #define _compare_int(a, b) ((int)*(a) - (int)(b)) 279 | 280 | #ifdef _MSC_VER 281 | #pragma warning(default : 4101) 282 | #elif defined(__GNUC__) || defined(__clang__) 283 | #pragma GCC diagnostic pop 284 | #endif 285 | 286 | #ifdef __cplusplus 287 | } 288 | #endif 289 | 290 | #endif // TREE_SITTER_ARRAY_H_ 291 | -------------------------------------------------------------------------------- /src/tree_sitter/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_PARSER_H_ 2 | #define TREE_SITTER_PARSER_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define ts_builtin_sym_error ((TSSymbol)-1) 13 | #define ts_builtin_sym_end 0 14 | #define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024 15 | 16 | #ifndef TREE_SITTER_API_H_ 17 | typedef uint16_t TSStateId; 18 | typedef uint16_t TSSymbol; 19 | typedef uint16_t TSFieldId; 20 | typedef struct TSLanguage TSLanguage; 21 | #endif 22 | 23 | typedef struct { 24 | TSFieldId field_id; 25 | uint8_t child_index; 26 | bool inherited; 27 | } TSFieldMapEntry; 28 | 29 | typedef struct { 30 | uint16_t index; 31 | uint16_t length; 32 | } TSFieldMapSlice; 33 | 34 | typedef struct { 35 | bool visible; 36 | bool named; 37 | bool supertype; 38 | } TSSymbolMetadata; 39 | 40 | typedef struct TSLexer TSLexer; 41 | 42 | struct TSLexer { 43 | int32_t lookahead; 44 | TSSymbol result_symbol; 45 | void (*advance)(TSLexer *, bool); 46 | void (*mark_end)(TSLexer *); 47 | uint32_t (*get_column)(TSLexer *); 48 | bool (*is_at_included_range_start)(const TSLexer *); 49 | bool (*eof)(const TSLexer *); 50 | }; 51 | 52 | typedef enum { 53 | TSParseActionTypeShift, 54 | TSParseActionTypeReduce, 55 | TSParseActionTypeAccept, 56 | TSParseActionTypeRecover, 57 | } TSParseActionType; 58 | 59 | typedef union { 60 | struct { 61 | uint8_t type; 62 | TSStateId state; 63 | bool extra; 64 | bool repetition; 65 | } shift; 66 | struct { 67 | uint8_t type; 68 | uint8_t child_count; 69 | TSSymbol symbol; 70 | int16_t dynamic_precedence; 71 | uint16_t production_id; 72 | } reduce; 73 | uint8_t type; 74 | } TSParseAction; 75 | 76 | typedef struct { 77 | uint16_t lex_state; 78 | uint16_t external_lex_state; 79 | } TSLexMode; 80 | 81 | typedef union { 82 | TSParseAction action; 83 | struct { 84 | uint8_t count; 85 | bool reusable; 86 | } entry; 87 | } TSParseActionEntry; 88 | 89 | typedef struct { 90 | int32_t start; 91 | int32_t end; 92 | } TSCharacterRange; 93 | 94 | struct TSLanguage { 95 | uint32_t version; 96 | uint32_t symbol_count; 97 | uint32_t alias_count; 98 | uint32_t token_count; 99 | uint32_t external_token_count; 100 | uint32_t state_count; 101 | uint32_t large_state_count; 102 | uint32_t production_id_count; 103 | uint32_t field_count; 104 | uint16_t max_alias_sequence_length; 105 | const uint16_t *parse_table; 106 | const uint16_t *small_parse_table; 107 | const uint32_t *small_parse_table_map; 108 | const TSParseActionEntry *parse_actions; 109 | const char * const *symbol_names; 110 | const char * const *field_names; 111 | const TSFieldMapSlice *field_map_slices; 112 | const TSFieldMapEntry *field_map_entries; 113 | const TSSymbolMetadata *symbol_metadata; 114 | const TSSymbol *public_symbol_map; 115 | const uint16_t *alias_map; 116 | const TSSymbol *alias_sequences; 117 | const TSLexMode *lex_modes; 118 | bool (*lex_fn)(TSLexer *, TSStateId); 119 | bool (*keyword_lex_fn)(TSLexer *, TSStateId); 120 | TSSymbol keyword_capture_token; 121 | struct { 122 | const bool *states; 123 | const TSSymbol *symbol_map; 124 | void *(*create)(void); 125 | void (*destroy)(void *); 126 | bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist); 127 | unsigned (*serialize)(void *, char *); 128 | void (*deserialize)(void *, const char *, unsigned); 129 | } external_scanner; 130 | const TSStateId *primary_state_ids; 131 | }; 132 | 133 | static inline bool set_contains(TSCharacterRange *ranges, uint32_t len, int32_t lookahead) { 134 | uint32_t index = 0; 135 | uint32_t size = len - index; 136 | while (size > 1) { 137 | uint32_t half_size = size / 2; 138 | uint32_t mid_index = index + half_size; 139 | TSCharacterRange *range = &ranges[mid_index]; 140 | if (lookahead >= range->start && lookahead <= range->end) { 141 | return true; 142 | } else if (lookahead > range->end) { 143 | index = mid_index; 144 | } 145 | size -= half_size; 146 | } 147 | TSCharacterRange *range = &ranges[index]; 148 | return (lookahead >= range->start && lookahead <= range->end); 149 | } 150 | 151 | /* 152 | * Lexer Macros 153 | */ 154 | 155 | #ifdef _MSC_VER 156 | #define UNUSED __pragma(warning(suppress : 4101)) 157 | #else 158 | #define UNUSED __attribute__((unused)) 159 | #endif 160 | 161 | #define START_LEXER() \ 162 | bool result = false; \ 163 | bool skip = false; \ 164 | UNUSED \ 165 | bool eof = false; \ 166 | int32_t lookahead; \ 167 | goto start; \ 168 | next_state: \ 169 | lexer->advance(lexer, skip); \ 170 | start: \ 171 | skip = false; \ 172 | lookahead = lexer->lookahead; 173 | 174 | #define ADVANCE(state_value) \ 175 | { \ 176 | state = state_value; \ 177 | goto next_state; \ 178 | } 179 | 180 | #define ADVANCE_MAP(...) \ 181 | { \ 182 | static const uint16_t map[] = { __VA_ARGS__ }; \ 183 | for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \ 184 | if (map[i] == lookahead) { \ 185 | state = map[i + 1]; \ 186 | goto next_state; \ 187 | } \ 188 | } \ 189 | } 190 | 191 | #define SKIP(state_value) \ 192 | { \ 193 | skip = true; \ 194 | state = state_value; \ 195 | goto next_state; \ 196 | } 197 | 198 | #define ACCEPT_TOKEN(symbol_value) \ 199 | result = true; \ 200 | lexer->result_symbol = symbol_value; \ 201 | lexer->mark_end(lexer); 202 | 203 | #define END_STATE() return result; 204 | 205 | /* 206 | * Parse Table Macros 207 | */ 208 | 209 | #define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT) 210 | 211 | #define STATE(id) id 212 | 213 | #define ACTIONS(id) id 214 | 215 | #define SHIFT(state_value) \ 216 | {{ \ 217 | .shift = { \ 218 | .type = TSParseActionTypeShift, \ 219 | .state = (state_value) \ 220 | } \ 221 | }} 222 | 223 | #define SHIFT_REPEAT(state_value) \ 224 | {{ \ 225 | .shift = { \ 226 | .type = TSParseActionTypeShift, \ 227 | .state = (state_value), \ 228 | .repetition = true \ 229 | } \ 230 | }} 231 | 232 | #define SHIFT_EXTRA() \ 233 | {{ \ 234 | .shift = { \ 235 | .type = TSParseActionTypeShift, \ 236 | .extra = true \ 237 | } \ 238 | }} 239 | 240 | #define REDUCE(symbol_name, children, precedence, prod_id) \ 241 | {{ \ 242 | .reduce = { \ 243 | .type = TSParseActionTypeReduce, \ 244 | .symbol = symbol_name, \ 245 | .child_count = children, \ 246 | .dynamic_precedence = precedence, \ 247 | .production_id = prod_id \ 248 | }, \ 249 | }} 250 | 251 | #define RECOVER() \ 252 | {{ \ 253 | .type = TSParseActionTypeRecover \ 254 | }} 255 | 256 | #define ACCEPT_INPUT() \ 257 | {{ \ 258 | .type = TSParseActionTypeAccept \ 259 | }} 260 | 261 | #ifdef __cplusplus 262 | } 263 | #endif 264 | 265 | #endif // TREE_SITTER_PARSER_H_ 266 | -------------------------------------------------------------------------------- /test/corpus/basic.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | Empty docblock 3 | ===================== 4 | /** 5 | * 6 | */ 7 | --- 8 | (document) 9 | 10 | ===================== 11 | Docblock w/o tags 12 | ===================== 13 | /** 14 | * Summary text 15 | * 16 | * Description text with 17 | * $variable and special chars: } { @ 18 | * and indented text 19 | * 20 | * New paragraph 21 | */ 22 | --- 23 | (document 24 | (description 25 | (text) 26 | (text) 27 | (text) 28 | (text) 29 | (text))) 30 | 31 | ===================== 32 | Docblock w/ description & tags 33 | ===================== 34 | /** 35 | * Summary text 36 | * 37 | * Description text with 38 | * $variable and special chars: } { @ 39 | * and indented text 40 | * 41 | * @api 42 | * @property int $var description 43 | * continued description 44 | * @property int $var 45 | * description on next line 46 | */ 47 | --- 48 | (document 49 | (description 50 | (text) 51 | (text) 52 | (text) 53 | (text)) 54 | (tag (tag_name)) 55 | (tag 56 | (tag_name) 57 | (primitive_type) 58 | (variable_name (name)) 59 | (description (text) (text))) 60 | (tag 61 | (tag_name) 62 | (primitive_type) 63 | (variable_name (name)) 64 | (description (text)))) 65 | 66 | ===================== 67 | Docblock w/ description & tags w/o separation 68 | ===================== 69 | /** 70 | * Summary text 71 | * more text 72 | * @api 73 | */ 74 | --- 75 | (document 76 | (description 77 | (text) 78 | (text)) 79 | (tag (tag_name))) 80 | 81 | 82 | 83 | ===================== 84 | Single line docblock w/o tag 85 | ===================== 86 | /** Just a comment */ 87 | --- 88 | (document 89 | (description (text))) 90 | 91 | ===================== 92 | Single line docblock w/ tag 93 | ===================== 94 | /** @var int $foo just a comment */ 95 | --- 96 | (document 97 | (tag 98 | (tag_name) 99 | (primitive_type) 100 | (variable_name (name)) 101 | (description (text)))) 102 | 103 | 104 | 105 | ===================== 106 | Tags w/o description 107 | ===================== 108 | /** 109 | * @api 110 | * @filesource 111 | * @inheritdoc 112 | * @inheritDoc 113 | */ 114 | --- 115 | (document 116 | (tag (tag_name)) 117 | (tag (tag_name)) 118 | (tag (tag_name)) 119 | (tag (tag_name))) 120 | 121 | ===================== 122 | Tags w/ optional description 123 | ===================== 124 | /** 125 | * @ignore 126 | * @internal 127 | * @ignore description 128 | * @internal description 129 | */ 130 | --- 131 | (document 132 | (tag (tag_name)) 133 | (tag (tag_name)) 134 | (tag (tag_name) (description (text))) 135 | (tag (tag_name) (description (text)))) 136 | 137 | ===================== 138 | Tags w/ required descriptions 139 | ===================== 140 | /** 141 | * @category description 142 | * @copyright description 143 | * @todo description 144 | */ 145 | --- 146 | (document 147 | (tag (tag_name) (description (text))) 148 | (tag (tag_name) (description (text))) 149 | (tag (tag_name) (description (text)))) 150 | 151 | -------------------------------------------------------------------------------- /test/corpus/generics.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | Generic template 3 | ===================== 4 | /** 5 | * @template T 6 | * @template T of MyNameSpace\MyClass 7 | * @psalm-template T 8 | * @phpstan-template T 9 | */ 10 | --- 11 | (document 12 | (tag 13 | (tag_name) 14 | (named_type (name))) 15 | (tag 16 | (tag_name) 17 | (named_type (name)) 18 | (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name)))) 19 | (tag 20 | (tag_name) 21 | (named_type (name))) 22 | (tag 23 | (tag_name) 24 | (named_type (name)))) 25 | ===================== 26 | Generic template implements interface 27 | ===================== 28 | /** 29 | * @implements MyInterface 30 | * @template-implements MyInterface 31 | * @template-implements MyInterface 32 | */ 33 | --- 34 | (document 35 | (tag 36 | (tag_name) 37 | (array_type (named_type (name)) (primitive_type))) 38 | (tag 39 | (tag_name) 40 | (array_type (named_type (name)) (named_type (name)))) 41 | (tag 42 | (tag_name) 43 | (array_type (named_type (name)) (named_type (name)) (named_type (name))))) 44 | ===================== 45 | Generic template extends class 46 | ===================== 47 | /** 48 | * @extends MyInterface 49 | * @template-extends MyInterface 50 | */ 51 | --- 52 | (document 53 | (tag 54 | (tag_name) 55 | (array_type (named_type (name)) (primitive_type))) 56 | (tag 57 | (tag_name) 58 | (array_type (named_type (name)) (named_type (name))))) 59 | ===================== 60 | Generic template use traits 61 | ===================== 62 | /** 63 | * @use MyTrait 64 | * @template-use MyTrait 65 | */ 66 | --- 67 | (document 68 | (tag 69 | (tag_name) 70 | (array_type (named_type (name)) (primitive_type))) 71 | (tag 72 | (tag_name) 73 | (array_type (named_type (name)) (named_type (name))))) 74 | -------------------------------------------------------------------------------- /test/corpus/incomplete.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | Tags w/ incomplete implementation 3 | ===================== 4 | /** 5 | * @example 6 | * @license 7 | * @package 8 | * @source 9 | * @subpackage 10 | * @uses 11 | * @example description 12 | * @license description 13 | * @package description 14 | * @source description 15 | * @subpackage description 16 | * @subpackage description 17 | */ 18 | --- 19 | (document 20 | (tag (tag_name)) 21 | (tag (tag_name)) 22 | (tag (tag_name)) 23 | (tag (tag_name)) 24 | (tag (tag_name)) 25 | (tag (tag_name)) 26 | (tag (tag_name) (description (text))) 27 | (tag (tag_name) (description (text))) 28 | (tag (tag_name) (description (text))) 29 | (tag (tag_name) (description (text))) 30 | (tag (tag_name) (description (text))) 31 | (tag (tag_name) (description (text)))) 32 | 33 | -------------------------------------------------------------------------------- /test/corpus/inline.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | Inline tags standalone 3 | ===================== 4 | /** 5 | * {@inheritDoc} 6 | * {@internal} 7 | * {@link http://www.example.com} 8 | * {@see http://www.example.com} 9 | */ 10 | --- 11 | (document 12 | (description 13 | (inline_tag (tag_name)) 14 | (inline_tag (tag_name)) 15 | (inline_tag (tag_name) (uri)) 16 | (inline_tag (tag_name) (uri)))) 17 | 18 | 19 | ===================== 20 | Inline tags standalone w/ description 21 | ===================== 22 | /** 23 | * {@internal some description} 24 | * {@link http://www.example.com some description} 25 | * {@see http://www.example.com some description} 26 | */ 27 | --- 28 | (document 29 | (description 30 | (inline_tag (tag_name) (description (text))) 31 | (inline_tag (tag_name) (uri) (description (text))) 32 | (inline_tag (tag_name) (uri) (description (text))))) 33 | 34 | ===================== 35 | Inline tags standalone w/ description w/ linebreaks 36 | ===================== 37 | /** 38 | * {@internal some description 39 | * continued on next line} 40 | * {@link http://www.example.com some description 41 | * continued on next line} 42 | * {@see http://www.example.com some description 43 | * continued on next line} 44 | */ 45 | --- 46 | (document 47 | (description 48 | (inline_tag (tag_name) (description (text) (text))) 49 | (inline_tag (tag_name) (uri) (description (text) (text))) 50 | (inline_tag (tag_name) (uri) (description (text) (text))))) 51 | 52 | 53 | 54 | 55 | 56 | ===================== 57 | Inline tags embedded in description 58 | ===================== 59 | /** 60 | * Some {description {@inheritDoc} more description} 61 | * Some {description {@internal} more description} 62 | * Some {description {@link http://www.example.com} more description} 63 | * Some {description {@see http://www.example.com} more description} 64 | */ 65 | --- 66 | (document 67 | (description 68 | (text) 69 | (inline_tag (tag_name)) 70 | (text) 71 | (text) 72 | (inline_tag (tag_name)) 73 | (text) 74 | (text) 75 | (inline_tag (tag_name) (uri)) 76 | (text) 77 | (text) 78 | (inline_tag (tag_name) (uri)) 79 | (text))) 80 | 81 | 82 | ===================== 83 | Inline tags w/ description embedded in description 84 | ===================== 85 | /** 86 | * Some {description {@internal some description} more description} 87 | * Some {description {@link http://www.example.com some description} more description} 88 | * Some {description {@see http://www.example.com some description} more description} 89 | */ 90 | --- 91 | (document 92 | (description 93 | (text) 94 | (inline_tag (tag_name) (description (text))) 95 | (text) 96 | (text) 97 | (inline_tag (tag_name) (uri) (description (text))) 98 | (text) 99 | (text) 100 | (inline_tag (tag_name) (uri) (description (text))) 101 | (text))) 102 | 103 | ===================== 104 | Inline tags w/ description w/ linebreaks embedded in description 105 | ===================== 106 | /** 107 | * Some {description {@internal some description 108 | * continued on next line} more description} 109 | * Some {description {@link http://www.example.com some description 110 | * continued on next line} more description} 111 | * Some {description {@see http://www.example.com some description 112 | * continued on next line} more description} 113 | */ 114 | --- 115 | (document 116 | (description 117 | (text) 118 | (inline_tag (tag_name) (description (text) (text))) 119 | (text) 120 | (text) 121 | (inline_tag (tag_name) (uri) (description (text) (text))) 122 | (text) 123 | (text) 124 | (inline_tag (tag_name) (uri) (description (text) (text))) 125 | (text))) 126 | 127 | 128 | 129 | ===================== 130 | Inline @internal w/ nested inline tag 131 | ===================== 132 | /** 133 | * Some {description {@internal some description {@see https://www.example.com 134 | * nested see description} continued internal description} outer description 135 | */ 136 | --- 137 | (document 138 | (description 139 | (text) 140 | (inline_tag 141 | (tag_name) 142 | (description 143 | (text) 144 | (inline_tag 145 | (tag_name) 146 | (uri) 147 | (description (text))) 148 | (text))) 149 | (text))) 150 | -------------------------------------------------------------------------------- /test/corpus/phpunit.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | @after 3 | ===================== 4 | /** 5 | * @after 6 | * @after description 7 | */ 8 | --- 9 | (document 10 | (tag (tag_name)) 11 | (tag 12 | (tag_name) 13 | (description (text)))) 14 | 15 | ===================== 16 | @afterClass 17 | ===================== 18 | /** 19 | * @afterClass 20 | * @afterClass description 21 | */ 22 | --- 23 | (document 24 | (tag (tag_name)) 25 | (tag 26 | (tag_name) 27 | (description (text)))) 28 | 29 | ===================== 30 | @annotation 31 | ===================== 32 | /** 33 | * @annotation 34 | * @annotation description 35 | */ 36 | --- 37 | (document 38 | (tag (tag_name)) 39 | (tag 40 | (tag_name) 41 | (description (text)))) 42 | 43 | ===================== 44 | @backupGlobals 45 | ===================== 46 | /** 47 | * @backupGlobals 48 | * @backupGlobals description 49 | */ 50 | --- 51 | (document 52 | (tag (tag_name)) 53 | (tag 54 | (tag_name) 55 | (description (text)))) 56 | 57 | ===================== 58 | @backupStaticAttributes 59 | ===================== 60 | /** 61 | * @backupStaticAttributes 62 | * @backupStaticAttributes description 63 | */ 64 | --- 65 | (document 66 | (tag (tag_name)) 67 | (tag 68 | (tag_name) 69 | (description (text)))) 70 | 71 | ===================== 72 | @before 73 | ===================== 74 | /** 75 | * @before 76 | * @before description 77 | */ 78 | --- 79 | (document 80 | (tag (tag_name)) 81 | (tag 82 | (tag_name) 83 | (description (text)))) 84 | 85 | ===================== 86 | @beforeClass 87 | ===================== 88 | /** 89 | * @beforeClass 90 | * @beforeClass description 91 | */ 92 | --- 93 | (document 94 | (tag (tag_name)) 95 | (tag 96 | (tag_name) 97 | (description (text)))) 98 | 99 | ===================== 100 | @codeCoverageIgnore 101 | ===================== 102 | /** 103 | * @codeCoverageIgnore 104 | * @codeCoverageIgnore description 105 | */ 106 | --- 107 | (document 108 | (tag (tag_name)) 109 | (tag 110 | (tag_name) 111 | (description (text)))) 112 | 113 | ===================== 114 | @codeCoverageIgnore* 115 | ===================== 116 | /** 117 | * @codeCoverageIgnore* 118 | * @codeCoverageIgnore* description 119 | */ 120 | --- 121 | (document 122 | (tag (tag_name)) 123 | (tag 124 | (tag_name) 125 | (description (text)))) 126 | 127 | ===================== 128 | @codeCoverageIgnoreEnd 129 | ===================== 130 | /** 131 | * @codeCoverageIgnoreEnd 132 | * @codeCoverageIgnoreEnd description 133 | */ 134 | --- 135 | (document 136 | (tag (tag_name)) 137 | (tag 138 | (tag_name) 139 | (description (text)))) 140 | 141 | ===================== 142 | @codeCoverageIgnoreStart 143 | ===================== 144 | /** 145 | * @codeCoverageIgnoreStart 146 | * @codeCoverageIgnoreStart description 147 | */ 148 | --- 149 | (document 150 | (tag (tag_name)) 151 | (tag 152 | (tag_name) 153 | (description (text)))) 154 | 155 | ===================== 156 | @covers 157 | ===================== 158 | /** 159 | * @covers 160 | * @covers description 161 | */ 162 | --- 163 | (document 164 | (tag (tag_name)) 165 | (tag 166 | (tag_name) 167 | (description (text)))) 168 | 169 | ===================== 170 | @coversDefaultClass 171 | ===================== 172 | /** 173 | * @coversDefaultClass 174 | * @coversDefaultClass description 175 | */ 176 | --- 177 | (document 178 | (tag (tag_name)) 179 | (tag 180 | (tag_name) 181 | (description (text)))) 182 | 183 | ===================== 184 | @coversDefaultClass to shorten annotations 185 | ===================== 186 | /** 187 | * @coversDefaultClass to shorten annotations 188 | * @coversDefaultClass to shorten annotations description 189 | */ 190 | --- 191 | (document 192 | (tag (tag_name)) 193 | (tag 194 | (tag_name) 195 | (description (text)))) 196 | 197 | ===================== 198 | @coversNothing 199 | ===================== 200 | /** 201 | * @coversNothing 202 | * @coversNothing description 203 | */ 204 | --- 205 | (document 206 | (tag (tag_name)) 207 | (tag 208 | (tag_name) 209 | (description (text)))) 210 | 211 | ===================== 212 | @dataProvider 213 | ===================== 214 | /** 215 | * @dataProvider 216 | * @dataProvider description 217 | */ 218 | --- 219 | (document 220 | (tag (tag_name)) 221 | (tag 222 | (tag_name) 223 | (description (text)))) 224 | 225 | ===================== 226 | @depends 227 | ===================== 228 | /** 229 | * @depends 230 | * @depends description 231 | */ 232 | --- 233 | (document 234 | (tag (tag_name)) 235 | (tag 236 | (tag_name) 237 | (description (text)))) 238 | 239 | ===================== 240 | @depends annotation to express dependencies 241 | ===================== 242 | /** 243 | * @depends annotation to express dependencies 244 | * @depends annotation to express dependencies description 245 | */ 246 | --- 247 | (document 248 | (tag (tag_name)) 249 | (tag 250 | (tag_name) 251 | (description (text)))) 252 | 253 | ===================== 254 | @doesNotPerformAssertions 255 | ===================== 256 | /** 257 | * @doesNotPerformAssertions 258 | * @doesNotPerformAssertions description 259 | */ 260 | --- 261 | (document 262 | (tag (tag_name)) 263 | (tag 264 | (tag_name) 265 | (description (text)))) 266 | 267 | ===================== 268 | @group 269 | ===================== 270 | /** 271 | * @group 272 | * @group description 273 | */ 274 | --- 275 | (document 276 | (tag (tag_name)) 277 | (tag 278 | (tag_name) 279 | (description (text)))) 280 | 281 | ===================== 282 | @large 283 | ===================== 284 | /** 285 | * @large 286 | * @large description 287 | */ 288 | --- 289 | (document 290 | (tag (tag_name)) 291 | (tag 292 | (tag_name) 293 | (description (text)))) 294 | 295 | ===================== 296 | @medium 297 | ===================== 298 | /** 299 | * @medium 300 | * @medium description 301 | */ 302 | --- 303 | (document 304 | (tag (tag_name)) 305 | (tag 306 | (tag_name) 307 | (description (text)))) 308 | 309 | ===================== 310 | @preserveGlobalState 311 | ===================== 312 | /** 313 | * @preserveGlobalState 314 | * @preserveGlobalState description 315 | */ 316 | --- 317 | (document 318 | (tag (tag_name)) 319 | (tag 320 | (tag_name) 321 | (description (text)))) 322 | 323 | ===================== 324 | @requires 325 | ===================== 326 | /** 327 | * @requires 328 | * @requires description 329 | */ 330 | --- 331 | (document 332 | (tag (tag_name)) 333 | (tag 334 | (tag_name) 335 | (description (text)))) 336 | 337 | ===================== 338 | @requires usages 339 | ===================== 340 | /** 341 | * @requires usages 342 | * @requires usages description 343 | */ 344 | --- 345 | (document 346 | (tag (tag_name)) 347 | (tag 348 | (tag_name) 349 | (description (text)))) 350 | 351 | ===================== 352 | @runInSeparateProcess 353 | ===================== 354 | /** 355 | * @runInSeparateProcess 356 | * @runInSeparateProcess description 357 | */ 358 | --- 359 | (document 360 | (tag (tag_name)) 361 | (tag 362 | (tag_name) 363 | (description (text)))) 364 | 365 | ===================== 366 | @runTestsInSeparateProcesses 367 | ===================== 368 | /** 369 | * @runTestsInSeparateProcesses 370 | * @runTestsInSeparateProcesses description 371 | */ 372 | --- 373 | (document 374 | (tag (tag_name)) 375 | (tag 376 | (tag_name) 377 | (description (text)))) 378 | 379 | ===================== 380 | @small 381 | ===================== 382 | /** 383 | * @small 384 | * @small description 385 | */ 386 | --- 387 | (document 388 | (tag (tag_name)) 389 | (tag 390 | (tag_name) 391 | (description (text)))) 392 | 393 | ===================== 394 | @test 395 | ===================== 396 | /** 397 | * @test 398 | * @test description 399 | */ 400 | --- 401 | (document 402 | (tag (tag_name)) 403 | (tag 404 | (tag_name) 405 | (description (text)))) 406 | 407 | ===================== 408 | @testWith 409 | ===================== 410 | /** 411 | * @testWith 412 | * @testWith description 413 | */ 414 | --- 415 | (document 416 | (tag (tag_name)) 417 | (tag 418 | (tag_name) 419 | (description (text)))) 420 | 421 | ===================== 422 | @testdox 423 | ===================== 424 | /** 425 | * @testdox 426 | * @testdox description 427 | */ 428 | --- 429 | (document 430 | (tag (tag_name)) 431 | (tag 432 | (tag_name) 433 | (description (text)))) 434 | 435 | ===================== 436 | @ticket 437 | ===================== 438 | /** 439 | * @ticket 440 | * @ticket description 441 | */ 442 | --- 443 | (document 444 | (tag (tag_name)) 445 | (tag 446 | (tag_name) 447 | (description (text)))) 448 | 449 | -------------------------------------------------------------------------------- /test/corpus/psalm-phpstan.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | Psalm and phpStan allow var tags w/o a variable name 3 | ===================== 4 | /** @var array */ 5 | --- 6 | (document 7 | (tag 8 | (tag_name) 9 | (primitive_type))) 10 | 11 | ===================== 12 | Psalm style array types w/o variable name 13 | ===================== 14 | /** @var array description */ 15 | --- 16 | (document 17 | (tag 18 | (tag_name) 19 | (array_type 20 | array: (primitive_type) 21 | key: (primitive_type) 22 | value: (primitive_type)) 23 | (description (text)))) 24 | 25 | 26 | ===================== 27 | Psalm style array types 28 | ===================== 29 | /** 30 | * @var array $foo 31 | * @var list $foo 32 | * @var MyNameSpace\MyClass $foo 33 | */ 34 | --- 35 | (document 36 | (tag 37 | (tag_name) 38 | (array_type 39 | array: (primitive_type) 40 | key: (primitive_type) 41 | value: (primitive_type)) 42 | (variable_name (name))) 43 | (tag 44 | (tag_name) 45 | (array_type 46 | array: (primitive_type) 47 | value: (primitive_type)) 48 | (variable_name (name))) 49 | (tag 50 | (tag_name) 51 | (array_type 52 | array: (named_type 53 | (qualified_name 54 | (namespace_name_as_prefix (namespace_name (name))) 55 | (name))) 56 | key: (primitive_type) 57 | value: (named_type (name))) 58 | (variable_name (name)))) 59 | 60 | 61 | ===================== 62 | Psalm style array types with nested array values 63 | ===================== 64 | /** 65 | * @var array> 66 | * @var array> 67 | */ 68 | --- 69 | (document 70 | (tag 71 | (tag_name) 72 | (array_type 73 | array: (primitive_type) 74 | key: (primitive_type) 75 | value: (array_type 76 | array: (primitive_type) 77 | key: (primitive_type) 78 | value: (primitive_type)))) 79 | (tag 80 | (tag_name) 81 | (array_type 82 | array: (primitive_type) 83 | key: (primitive_type) 84 | value: (array_type 85 | array: (primitive_type) 86 | key: (primitive_type) 87 | value: (primitive_type))))) 88 | 89 | ===================== 90 | PHPStan style nested array types 91 | ===================== 92 | /** @var array>> $foo */ 93 | --- 94 | (document 95 | (tag 96 | (tag_name) 97 | (array_type 98 | array: (primitive_type) 99 | value: (array_type 100 | array: (primitive_type) 101 | value: (array_type 102 | array: (primitive_type) 103 | value: (primitive_type)))) 104 | (variable_name (name)))) 105 | 106 | 107 | ===================== 108 | Psalm-style array shapes 109 | ===================== 110 | /** 111 | * @var array{foo: string, bar: int} 112 | * @return array{optional?: string, bar: int} 113 | */ 114 | --- 115 | (document 116 | (tag 117 | (tag_name) 118 | (array_type 119 | (array_element 120 | key: (name) 121 | value: (primitive_type)) 122 | (array_element 123 | key: (name) 124 | value: (primitive_type)))) 125 | (tag 126 | (tag_name) 127 | (array_type 128 | (array_element 129 | key: (name) 130 | value: (primitive_type)) 131 | (array_element 132 | key: (name) 133 | value: (primitive_type))))) 134 | 135 | 136 | ===================== 137 | Psalm-style list shapes 138 | ===================== 139 | /** 140 | * @var list{string, int} 141 | * @return list{0: string, 1: int} 142 | * @return list{string, string, stdClass, false} 143 | */ 144 | --- 145 | (document 146 | (tag 147 | (tag_name) 148 | (array_type 149 | (array_element 150 | value: (primitive_type)) 151 | (array_element 152 | value: (primitive_type)))) 153 | (tag 154 | (tag_name) 155 | (array_type 156 | (array_element 157 | key: (name) 158 | value: (primitive_type)) 159 | (array_element 160 | key: (name) 161 | value: (primitive_type)))) 162 | (tag 163 | (tag_name) 164 | (array_type 165 | (array_element 166 | value: (primitive_type)) 167 | (array_element 168 | value: (primitive_type)) 169 | (array_element 170 | value: (named_type 171 | (name))) 172 | (array_element 173 | value: (primitive_type))))) 174 | 175 | ===================== 176 | phpStan-style array shapes 177 | ===================== 178 | /** 179 | * @var array{'foo': int, "bar": string} 180 | * @var array{0: int, 1?: int} 181 | * @var array{int, int} 182 | * @var array{foo: int, bar: string} 183 | */ 184 | --- 185 | (document 186 | (tag 187 | (tag_name) 188 | (array_type 189 | (array_element 190 | key: (name) 191 | value: (primitive_type)) 192 | (array_element 193 | key: (name) 194 | value: (primitive_type)))) 195 | (tag 196 | (tag_name) 197 | (array_type 198 | (array_element 199 | key: (name) 200 | value: (primitive_type)) 201 | (array_element 202 | key: (name) 203 | value: (primitive_type)))) 204 | (tag 205 | (tag_name) 206 | (array_type 207 | (array_element 208 | value: (primitive_type)) 209 | (array_element 210 | value: (primitive_type)))) 211 | (tag 212 | (tag_name) 213 | (array_type 214 | (array_element 215 | key: (name) 216 | value: (primitive_type)) 217 | (array_element 218 | key: (name) 219 | value: (primitive_type))))) 220 | 221 | 222 | ===================== 223 | Psalm scalar class-string type 224 | ===================== 225 | /** 226 | * @var class-string $foo 227 | * @var class-string $foo 228 | */ 229 | --- 230 | (document 231 | (tag 232 | (tag_name) 233 | (primitive_type) (variable_name (name))) 234 | (tag 235 | (tag_name) 236 | (primitive_type (named_type (name))) (variable_name (name)))) 237 | 238 | ===================== 239 | Psalm scalar interface-string type 240 | ===================== 241 | /** 242 | * @var interface-string $foo 243 | */ 244 | --- 245 | (document 246 | (tag 247 | (tag_name) 248 | (primitive_type) (variable_name (name)))) 249 | 250 | ===================== 251 | Psalm scalar positive-int type 252 | ===================== 253 | /** 254 | * @var positive-int $foo 255 | */ 256 | --- 257 | (document 258 | (tag 259 | (tag_name) 260 | (primitive_type) (variable_name (name)))) 261 | 262 | ===================== 263 | Psalm scalar trait-string type 264 | ===================== 265 | /** 266 | * @var trait-string $foo 267 | */ 268 | --- 269 | (document 270 | (tag 271 | (tag_name) 272 | (primitive_type) (variable_name (name)))) 273 | 274 | ===================== 275 | Psalm scalar enum-string type 276 | ===================== 277 | /** 278 | * @var enum-string $foo 279 | */ 280 | --- 281 | (document 282 | (tag 283 | (tag_name) 284 | (primitive_type) (variable_name (name)))) 285 | 286 | ===================== 287 | Psalm scalar callable-string type 288 | ===================== 289 | /** 290 | * @var callable-string $foo 291 | */ 292 | --- 293 | (document 294 | (tag 295 | (tag_name) 296 | (primitive_type) (variable_name (name)))) 297 | 298 | ===================== 299 | Psalm scalar numeric-string type 300 | ===================== 301 | /** 302 | * @var numeric-string $foo 303 | */ 304 | --- 305 | (document 306 | (tag 307 | (tag_name) 308 | (primitive_type) (variable_name (name)))) 309 | 310 | ===================== 311 | Psalm scalar literal-string type 312 | ===================== 313 | /** 314 | * @var literal-string $foo 315 | */ 316 | --- 317 | (document 318 | (tag 319 | (tag_name) 320 | (primitive_type) (variable_name (name)))) 321 | 322 | ===================== 323 | Psalm scalar lowercase-string type 324 | ===================== 325 | /** 326 | * @var lowercase-string $foo 327 | */ 328 | --- 329 | (document 330 | (tag 331 | (tag_name) 332 | (primitive_type) (variable_name (name)))) 333 | 334 | ===================== 335 | Psalm scalar non-empty-string type 336 | ===================== 337 | /** 338 | * @var non-empty-string $foo 339 | */ 340 | --- 341 | (document 342 | (tag 343 | (tag_name) 344 | (primitive_type) (variable_name (name)))) 345 | 346 | ===================== 347 | Psalm scalar non-empty-lowercase-string type 348 | ===================== 349 | /** 350 | * @var non-empty-lowercase-string $foo 351 | */ 352 | --- 353 | (document 354 | (tag 355 | (tag_name) 356 | (primitive_type) (variable_name (name)))) 357 | 358 | ===================== 359 | Psalm @psalm-consistent-constructor tag 360 | ===================== 361 | /** 362 | * @psalm-consistent-constructor 363 | */ 364 | --- 365 | (document 366 | (tag (tag_name))) 367 | 368 | ===================== 369 | Psalm @psalm-consistent-templates tag 370 | ===================== 371 | /** 372 | * @psalm-consistent-templates 373 | */ 374 | --- 375 | (document 376 | (tag (tag_name))) 377 | 378 | ===================== 379 | Psalm @param-out tag 380 | ===================== 381 | /** 382 | * @param-out MyClass $foo 383 | * @param-out int $foo 384 | */ 385 | --- 386 | (document 387 | (tag 388 | (tag_name) 389 | (named_type (name)) (variable_name (name))) 390 | (tag 391 | (tag_name) 392 | (primitive_type) (variable_name (name)))) 393 | 394 | ===================== 395 | Psalm @psalm-param-out tag 396 | ===================== 397 | /** 398 | * @psalm-param-out MyClass $foo 399 | * @psalm-param-out int $foo 400 | */ 401 | --- 402 | (document 403 | (tag 404 | (tag_name) 405 | (named_type (name)) (variable_name (name))) 406 | (tag 407 | (tag_name) 408 | (primitive_type) (variable_name (name)))) 409 | 410 | ===================== 411 | Psalm @psalm-var tag 412 | ===================== 413 | /** 414 | * @psalm-var 415 | */ 416 | --- 417 | (document 418 | (tag (tag_name))) 419 | 420 | ===================== 421 | Psalm @psalm-param tag 422 | ===================== 423 | /** 424 | * @psalm-param 425 | */ 426 | --- 427 | (document 428 | (tag (tag_name))) 429 | 430 | ===================== 431 | Psalm @psalm-param tag 432 | ===================== 433 | /** 434 | * @psalm-return 435 | */ 436 | --- 437 | (document 438 | (tag (tag_name))) 439 | 440 | ===================== 441 | Psalm @psalm-property tag 442 | ===================== 443 | /** 444 | * @psalm-property 445 | */ 446 | --- 447 | (document 448 | (tag (tag_name))) 449 | 450 | ===================== 451 | Psalm @psalm-property-read tag 452 | ===================== 453 | /** 454 | * @psalm-property-read 455 | */ 456 | --- 457 | (document 458 | (tag (tag_name))) 459 | 460 | ===================== 461 | Psalm @psalm-property-write tag 462 | ===================== 463 | /** 464 | * @psalm-property-write 465 | */ 466 | --- 467 | (document 468 | (tag (tag_name))) 469 | 470 | ===================== 471 | Psalm @psalm-method tag 472 | ===================== 473 | /** 474 | * @psalm-method 475 | */ 476 | --- 477 | (document 478 | (tag (tag_name))) 479 | 480 | ===================== 481 | Psalm @psalm-ignore-var tag 482 | ===================== 483 | /** 484 | * @psalm-ignore-var 485 | */ 486 | --- 487 | (document 488 | (tag (tag_name))) 489 | 490 | ===================== 491 | Psalm @psalm-assert tag 492 | ===================== 493 | /** 494 | * @psalm-assert MyClass $foo 495 | * @psalm-assert null $foo 496 | */ 497 | --- 498 | (document 499 | (tag 500 | (tag_name) 501 | (named_type (name)) (variable_name (name))) 502 | (tag 503 | (tag_name) 504 | (primitive_type) (variable_name (name)))) 505 | 506 | ===================== 507 | Psalm @psalm-assert-if-true tag 508 | ===================== 509 | /** 510 | * @psalm-assert-if-true MyClass $foo 511 | * @psalm-assert-if-true int $foo 512 | */ 513 | --- 514 | (document 515 | (tag 516 | (tag_name) 517 | (named_type (name)) (variable_name (name))) 518 | (tag 519 | (tag_name) 520 | (primitive_type) (variable_name (name)))) 521 | 522 | ===================== 523 | Psalm @psalm-assert-if-false tag 524 | ===================== 525 | /** 526 | * @psalm-assert-if-false MyClass $foo 527 | * @psalm-assert-if-false int $foo 528 | */ 529 | --- 530 | (document 531 | (tag 532 | (tag_name) 533 | (named_type (name)) (variable_name (name))) 534 | (tag 535 | (tag_name) 536 | (primitive_type) (variable_name (name)))) 537 | 538 | ===================== 539 | Psalm @psalm-if-this-is tag 540 | ===================== 541 | /** 542 | * @psalm-if-this-is 543 | */ 544 | --- 545 | (document 546 | (tag (tag_name))) 547 | 548 | ===================== 549 | Psalm @psalm-this-out tag 550 | ===================== 551 | /** 552 | * @psalm-this-out 553 | */ 554 | --- 555 | (document 556 | (tag (tag_name))) 557 | 558 | ===================== 559 | Psalm @psalm-ignore-nullable-return tag 560 | ===================== 561 | /** 562 | * @psalm-ignore-nullable-return 563 | */ 564 | --- 565 | (document 566 | (tag (tag_name))) 567 | 568 | ===================== 569 | Psalm @psalm-ignore-falsable-return tag 570 | ===================== 571 | /** 572 | * @psalm-ignore-falsable-return 573 | */ 574 | --- 575 | (document 576 | (tag (tag_name))) 577 | 578 | ===================== 579 | Psalm @psalm-seal-properties tag 580 | ===================== 581 | /** 582 | * @psalm-seal-properties 583 | */ 584 | --- 585 | (document 586 | (tag (tag_name))) 587 | 588 | ===================== 589 | Psalm @psalm-readonly tag 590 | ===================== 591 | /** 592 | * @psalm-readonly 593 | */ 594 | --- 595 | (document 596 | (tag (tag_name))) 597 | 598 | ===================== 599 | Psalm @psalm-mutation-free tag 600 | ===================== 601 | /** 602 | * @psalm-mutation-free 603 | */ 604 | --- 605 | (document 606 | (tag (tag_name))) 607 | 608 | ===================== 609 | Psalm @psalm-external-mutation-free tag 610 | ===================== 611 | /** 612 | * @psalm-external-mutation-free 613 | */ 614 | --- 615 | (document 616 | (tag (tag_name))) 617 | 618 | ===================== 619 | Psalm @psalm-immutable tag 620 | ===================== 621 | /** 622 | * @psalm-immutable 623 | */ 624 | --- 625 | (document 626 | (tag (tag_name))) 627 | 628 | ===================== 629 | Psalm @psalm-pure tag 630 | ===================== 631 | /** 632 | * @psalm-pure 633 | */ 634 | --- 635 | (document 636 | (tag (tag_name))) 637 | 638 | ===================== 639 | Psalm @psalm-allow-private-mutation tag 640 | ===================== 641 | /** 642 | * @psalm-allow-private-mutation 643 | */ 644 | --- 645 | (document 646 | (tag (tag_name))) 647 | 648 | ===================== 649 | Psalm @psalm-readonly-allow-private-mutation tag 650 | ===================== 651 | /** 652 | * @psalm-readonly-allow-private-mutation 653 | */ 654 | --- 655 | (document 656 | (tag (tag_name))) 657 | 658 | ===================== 659 | Psalm @psalm-trace tag 660 | ===================== 661 | /** 662 | * @psalm-trace $variable 663 | */ 664 | --- 665 | (document 666 | (tag (tag_name) (variable_name (name)))) 667 | 668 | ===================== 669 | Psalm @no-named-arguments tag 670 | ===================== 671 | /** 672 | * @no-named-arguments 673 | */ 674 | --- 675 | (document 676 | (tag (tag_name))) 677 | 678 | ===================== 679 | Psalm @psalm-suppress tag 680 | ===================== 681 | /** 682 | * @psalm-suppress SomeIssueName 683 | */ 684 | --- 685 | (document 686 | (tag 687 | (tag_name) 688 | (named_type (name)))) 689 | 690 | ===================== 691 | Psalm @psalm-internal tag 692 | ===================== 693 | /** 694 | * @psalm-internal Foo 695 | * @psalm-internal MyNameSpace\MyClass 696 | */ 697 | --- 698 | (document 699 | (tag 700 | (tag_name) 701 | (named_type (name))) 702 | (tag 703 | (tag_name) 704 | (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 705 | 706 | ===================== 707 | Psalm @psalm-import-type tag 708 | ===================== 709 | /** 710 | * @psalm-import-type MyClass from MyClassBase 711 | * @psalm-import-type MyClass from MyClassBase as MyClassAlias 712 | * @psalm-import-type MyNameSpace\MyClass from MyNameSpace\MyClassBase as MyClassAlias 713 | */ 714 | --- 715 | (document 716 | (tag 717 | (tag_name) 718 | (named_type (name)) 719 | (named_type (name))) 720 | (tag 721 | (tag_name) 722 | (named_type (name)) 723 | (named_type (name)) 724 | (name)) 725 | (tag 726 | (tag_name) 727 | (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))) 728 | (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))) 729 | (name))) 730 | 731 | ===================== 732 | Psalm @psalm-require-implements tag 733 | ===================== 734 | /** 735 | * @psalm-require-implements Foo 736 | * @psalm-require-implements MyNameSpace\MyClass 737 | */ 738 | --- 739 | (document 740 | (tag 741 | (tag_name) 742 | (named_type (name))) 743 | (tag 744 | (tag_name) 745 | (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 746 | 747 | ===================== 748 | Psalm @psalm-require-extends tag 749 | ===================== 750 | /** 751 | * @psalm-require-extends Foo 752 | * @psalm-require-extends MyNameSpace\MyClass 753 | */ 754 | --- 755 | (document 756 | (tag 757 | (tag_name) 758 | (named_type (name))) 759 | (tag 760 | (tag_name) 761 | (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 762 | -------------------------------------------------------------------------------- /test/corpus/references.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | @link w/ URI 3 | ===================== 4 | /** 5 | * @link http://example.com 6 | * @link https://example.com 7 | * @link http://www.example.com 8 | * @link https://www.example.com 9 | */ 10 | --- 11 | (document 12 | (tag (tag_name) (uri)) 13 | (tag (tag_name) (uri)) 14 | (tag (tag_name) (uri)) 15 | (tag (tag_name) (uri))) 16 | 17 | ===================== 18 | @link w/ URI & description 19 | ===================== 20 | /** 21 | * @link http://example.com some description 22 | * @link https://example.com some description 23 | * @link http://www.example.com some description 24 | * @link https://www.example.com some description 25 | */ 26 | --- 27 | (document 28 | (tag (tag_name) (uri) (description (text))) 29 | (tag (tag_name) (uri) (description (text))) 30 | (tag (tag_name) (uri) (description (text))) 31 | (tag (tag_name) (uri) (description (text)))) 32 | 33 | ===================== 34 | @link w/ URI & description on next line 35 | ===================== 36 | /** 37 | * @link http://example.com 38 | * some description 39 | * @link https://example.com 40 | * some description 41 | * @link http://www.example.com 42 | * some description 43 | * @link https://www.example.com 44 | * some description 45 | */ 46 | --- 47 | (document 48 | (tag (tag_name) (uri) (description (text))) 49 | (tag (tag_name) (uri) (description (text))) 50 | (tag (tag_name) (uri) (description (text))) 51 | (tag (tag_name) (uri) (description (text)))) 52 | 53 | ===================== 54 | @link w/ URI & description w/ linebreak 55 | ===================== 56 | /** 57 | * @link http://example.com some description 58 | * more description 59 | * @link https://example.com some description 60 | * more description 61 | * @link http://www.example.com some description 62 | * more description 63 | * @link https://www.example.com some description 64 | * more description 65 | */ 66 | --- 67 | (document 68 | (tag (tag_name) (uri) (description (text) (text))) 69 | (tag (tag_name) (uri) (description (text) (text))) 70 | (tag (tag_name) (uri) (description (text) (text))) 71 | (tag (tag_name) (uri) (description (text) (text)))) 72 | 73 | 74 | 75 | ===================== 76 | @see w/ URI 77 | ===================== 78 | /** 79 | * @see http://example.com 80 | * @see https://example.com 81 | * @see http://www.example.com 82 | * @see https://www.example.com 83 | */ 84 | --- 85 | (document 86 | (tag (tag_name) (uri)) 87 | (tag (tag_name) (uri)) 88 | (tag (tag_name) (uri)) 89 | (tag (tag_name) (uri))) 90 | 91 | ===================== 92 | @see w/ URI & description 93 | ===================== 94 | /** 95 | * @see http://example.com some description 96 | * @see https://example.com some description 97 | * @see http://www.example.com some description 98 | * @see https://www.example.com some description 99 | */ 100 | --- 101 | (document 102 | (tag (tag_name) (uri) (description (text))) 103 | (tag (tag_name) (uri) (description (text))) 104 | (tag (tag_name) (uri) (description (text))) 105 | (tag (tag_name) (uri) (description (text)))) 106 | 107 | ===================== 108 | @see w/ URI & description on next line 109 | ===================== 110 | /** 111 | * @see http://example.com 112 | * some description 113 | * @see https://example.com 114 | * some description 115 | * @see http://www.example.com 116 | * some description 117 | * @see https://www.example.com 118 | * some description 119 | */ 120 | --- 121 | (document 122 | (tag (tag_name) (uri) (description (text))) 123 | (tag (tag_name) (uri) (description (text))) 124 | (tag (tag_name) (uri) (description (text))) 125 | (tag (tag_name) (uri) (description (text)))) 126 | 127 | ===================== 128 | @see w/ URI & description w/ linebreak 129 | ===================== 130 | /** 131 | * @see http://example.com some description 132 | * more description 133 | * @see https://example.com some description 134 | * more description 135 | * @see http://www.example.com some description 136 | * more description 137 | * @see https://www.example.com some description 138 | * more description 139 | */ 140 | --- 141 | (document 142 | (tag (tag_name) (uri) (description (text) (text))) 143 | (tag (tag_name) (uri) (description (text) (text))) 144 | (tag (tag_name) (uri) (description (text) (text))) 145 | (tag (tag_name) (uri) (description (text) (text)))) 146 | 147 | 148 | 149 | ===================== 150 | @see w/ FQSEN for classnames 151 | ===================== 152 | /** 153 | * @see \MyClass 154 | * @see \Vendor\Package\ClassName 155 | * @see MyClass 156 | * @see Vendor\Package\ClassName 157 | */ 158 | --- 159 | (document 160 | (tag 161 | (tag_name) 162 | (fqsen 163 | (named_type 164 | (qualified_name 165 | (namespace_name_as_prefix) 166 | (name))))) 167 | (tag 168 | (tag_name) 169 | (fqsen 170 | (named_type 171 | (qualified_name 172 | (namespace_name_as_prefix 173 | (namespace_name (name) (name))) 174 | (name))))) 175 | (tag 176 | (tag_name) 177 | (fqsen 178 | (named_type (name)))) 179 | (tag 180 | (tag_name) 181 | (fqsen 182 | (named_type 183 | (qualified_name 184 | (namespace_name_as_prefix 185 | (namespace_name (name) (name))) 186 | (name)))))) 187 | 188 | ===================== 189 | @see w/ FQSEN for methods 190 | ===================== 191 | /** 192 | * @see some_function() 193 | * @see \MyClass::some_function() 194 | * @see \Vendor\Package\ClassName::some_function() 195 | * @see MyClass::some_function() 196 | * @see Vendor\Package\ClassName::some_function() 197 | */ 198 | --- 199 | (document 200 | (tag 201 | (tag_name) 202 | (fqsen (name))) 203 | (tag 204 | (tag_name) 205 | (fqsen 206 | (named_type 207 | (qualified_name 208 | (namespace_name_as_prefix) 209 | (name))) 210 | (name))) 211 | (tag 212 | (tag_name) 213 | (fqsen 214 | (named_type 215 | (qualified_name 216 | (namespace_name_as_prefix 217 | (namespace_name (name) (name))) 218 | (name))) 219 | (name))) 220 | (tag 221 | (tag_name) 222 | (fqsen 223 | (named_type (name)) 224 | (name))) 225 | (tag 226 | (tag_name) 227 | (fqsen 228 | (named_type 229 | (qualified_name 230 | (namespace_name_as_prefix 231 | (namespace_name (name) (name))) 232 | (name))) 233 | (name)))) 234 | 235 | ===================== 236 | @see w/ FQSEN for properties 237 | ===================== 238 | /** 239 | * @see $some_variable 240 | * @see \MyClass::$someProp 241 | * @see \Vendor\Package\ClassName::$someProp 242 | * @see MyClass::$someProp 243 | * @see Vendor\Package\ClassName::$someProp 244 | */ 245 | --- 246 | (document 247 | (tag 248 | (tag_name) 249 | (fqsen 250 | (variable_name (name)))) 251 | (tag 252 | (tag_name) 253 | (fqsen 254 | (named_type 255 | (qualified_name 256 | (namespace_name_as_prefix) 257 | (name))) 258 | (variable_name (name)))) 259 | (tag 260 | (tag_name) 261 | (fqsen 262 | (named_type 263 | (qualified_name 264 | (namespace_name_as_prefix 265 | (namespace_name (name) (name))) 266 | (name))) 267 | (variable_name (name)))) 268 | (tag 269 | (tag_name) 270 | (fqsen 271 | (named_type (name)) 272 | (variable_name (name)))) 273 | (tag 274 | (tag_name) 275 | (fqsen 276 | (named_type 277 | (qualified_name 278 | (namespace_name_as_prefix 279 | (namespace_name (name) (name))) 280 | (name))) 281 | (variable_name (name))))) 282 | 283 | ===================== 284 | @see w/ FQSEN for class constants 285 | ===================== 286 | /** 287 | * @see \MyClass::SOME_CONSTANT 288 | * @see \Vendor\Package\ClassName::SOME_CONSTANT 289 | * @see MyClass::SOME_CONSTANT 290 | * @see Vendor\Package\ClassName::SOME_CONSTANT 291 | */ 292 | --- 293 | (document 294 | (tag 295 | (tag_name) 296 | (fqsen 297 | (named_type 298 | (qualified_name 299 | (namespace_name_as_prefix) 300 | (name))) 301 | (name))) 302 | (tag 303 | (tag_name) 304 | (fqsen 305 | (named_type 306 | (qualified_name 307 | (namespace_name_as_prefix 308 | (namespace_name (name) (name))) 309 | (name))) 310 | (name))) 311 | (tag 312 | (tag_name) 313 | (fqsen 314 | (named_type (name)) 315 | (name))) 316 | (tag 317 | (tag_name) 318 | (fqsen 319 | (named_type 320 | (qualified_name 321 | (namespace_name_as_prefix 322 | (namespace_name (name) (name))) 323 | (name))) 324 | (name)))) 325 | 326 | ===================== 327 | @see w/ FQSEN for classnames w/ description 328 | ===================== 329 | /** 330 | * @see \MyClass some description 331 | * @see \Vendor\Package\ClassName some description 332 | * @see MyClass some description 333 | * @see Vendor\Package\ClassName some description 334 | */ 335 | --- 336 | (document 337 | (tag 338 | (tag_name) 339 | (fqsen 340 | (named_type 341 | (qualified_name 342 | (namespace_name_as_prefix) 343 | (name)))) 344 | (description (text))) 345 | (tag 346 | (tag_name) 347 | (fqsen 348 | (named_type 349 | (qualified_name 350 | (namespace_name_as_prefix 351 | (namespace_name (name) (name))) 352 | (name)))) 353 | (description (text))) 354 | (tag 355 | (tag_name) 356 | (fqsen 357 | (named_type (name))) 358 | (description (text))) 359 | (tag 360 | (tag_name) 361 | (fqsen 362 | (named_type 363 | (qualified_name 364 | (namespace_name_as_prefix 365 | (namespace_name (name) (name))) 366 | (name)))) 367 | (description (text)))) 368 | 369 | ===================== 370 | @see w/ FQSEN for methods w/ description 371 | ===================== 372 | /** 373 | * @see some_function() some description 374 | * @see \MyClass::some_function() some description 375 | * @see \Vendor\Package\ClassName::some_function() some description 376 | * @see MyClass::some_function() some description 377 | * @see Vendor\Package\ClassName::some_function() some description 378 | */ 379 | --- 380 | (document 381 | (tag 382 | (tag_name) 383 | (fqsen (name)) 384 | (description (text))) 385 | (tag 386 | (tag_name) 387 | (fqsen 388 | (named_type 389 | (qualified_name 390 | (namespace_name_as_prefix) 391 | (name))) 392 | (name)) 393 | (description (text))) 394 | (tag 395 | (tag_name) 396 | (fqsen 397 | (named_type 398 | (qualified_name 399 | (namespace_name_as_prefix 400 | (namespace_name (name) (name))) 401 | (name))) 402 | (name)) 403 | (description (text))) 404 | (tag 405 | (tag_name) 406 | (fqsen 407 | (named_type (name)) 408 | (name)) 409 | (description (text))) 410 | (tag 411 | (tag_name) 412 | (fqsen 413 | (named_type 414 | (qualified_name 415 | (namespace_name_as_prefix 416 | (namespace_name (name) (name))) 417 | (name))) 418 | (name)) 419 | (description (text)))) 420 | 421 | ===================== 422 | @see w/ FQSEN for properties w/ description 423 | ===================== 424 | /** 425 | * @see $some_variable some description 426 | * @see \MyClass::$someProp some description 427 | * @see \Vendor\Package\ClassName::$someProp some description 428 | * @see MyClass::$someProp some description 429 | * @see Vendor\Package\ClassName::$someProp some description 430 | */ 431 | --- 432 | (document 433 | (tag 434 | (tag_name) 435 | (fqsen 436 | (variable_name (name))) 437 | (description (text))) 438 | (tag 439 | (tag_name) 440 | (fqsen 441 | (named_type 442 | (qualified_name 443 | (namespace_name_as_prefix) 444 | (name))) 445 | (variable_name (name))) 446 | (description (text))) 447 | (tag 448 | (tag_name) 449 | (fqsen 450 | (named_type 451 | (qualified_name 452 | (namespace_name_as_prefix 453 | (namespace_name (name) (name))) 454 | (name))) 455 | (variable_name (name))) 456 | (description (text))) 457 | (tag 458 | (tag_name) 459 | (fqsen 460 | (named_type (name)) 461 | (variable_name (name))) 462 | (description (text))) 463 | (tag 464 | (tag_name) 465 | (fqsen 466 | (named_type 467 | (qualified_name 468 | (namespace_name_as_prefix 469 | (namespace_name (name) (name))) 470 | (name))) 471 | (variable_name (name))) 472 | (description (text)))) 473 | 474 | ===================== 475 | @see w/ FQSEN for class constants w/ description 476 | ===================== 477 | /** 478 | * @see \MyClass::SOME_CONSTANT some description 479 | * @see \Vendor\Package\ClassName::SOME_CONSTANT some description 480 | * @see MyClass::SOME_CONSTANT some description 481 | * @see Vendor\Package\ClassName::SOME_CONSTANT some description 482 | */ 483 | --- 484 | (document 485 | (tag 486 | (tag_name) 487 | (fqsen 488 | (named_type 489 | (qualified_name 490 | (namespace_name_as_prefix) 491 | (name))) 492 | (name)) 493 | (description (text))) 494 | (tag 495 | (tag_name) 496 | (fqsen 497 | (named_type 498 | (qualified_name 499 | (namespace_name_as_prefix 500 | (namespace_name (name) (name))) 501 | (name))) 502 | (name)) 503 | (description (text))) 504 | (tag 505 | (tag_name) 506 | (fqsen 507 | (named_type (name)) 508 | (name)) 509 | (description (text))) 510 | (tag 511 | (tag_name) 512 | (fqsen 513 | (named_type 514 | (qualified_name 515 | (namespace_name_as_prefix 516 | (namespace_name (name) (name))) 517 | (name))) 518 | (name)) 519 | (description (text)))) 520 | 521 | ===================== 522 | @mixin 523 | ===================== 524 | /** 525 | * @mixin \MyClass 526 | * @mixin \Vendor\Package\ClassName 527 | * @mixin MyClass 528 | * @mixin Vendor\Package\ClassName 529 | */ 530 | --- 531 | (document 532 | (tag 533 | (tag_name) 534 | (named_type 535 | (qualified_name 536 | (namespace_name_as_prefix) 537 | (name)))) 538 | (tag 539 | (tag_name) 540 | (named_type 541 | (qualified_name 542 | (namespace_name_as_prefix 543 | (namespace_name (name) (name))) 544 | (name)))) 545 | (tag 546 | (tag_name) 547 | (named_type (name))) 548 | (tag 549 | (tag_name) 550 | (named_type 551 | (qualified_name 552 | (namespace_name_as_prefix 553 | (namespace_name (name) (name))) 554 | (name))))) 555 | 556 | -------------------------------------------------------------------------------- /test/corpus/special.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | @author 3 | ===================== 4 | /** 5 | * @author Foo Bar 6 | * @author F. Bar 7 | * @author F. Bar 8 | */ 9 | --- 10 | (document 11 | (tag (tag_name) (author_name)) 12 | (tag (tag_name) (author_name)) 13 | (tag (tag_name) (author_name) (email_address))) 14 | 15 | -------------------------------------------------------------------------------- /test/corpus/typed_tags.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | @global 3 | ===================== 4 | /** 5 | * @global int $foo 6 | * @global MyClass[]|MyNameSpace\MyClass[] $foo 7 | */ 8 | --- 9 | (document 10 | (tag 11 | (tag_name) 12 | (primitive_type) 13 | (variable_name (name))) 14 | (tag 15 | (tag_name) 16 | (union_type 17 | (array_type (named_type (name))) 18 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 19 | (variable_name (name)))) 20 | 21 | 22 | ===================== 23 | @method w/o description 24 | ===================== 25 | /** 26 | * @method int methodName(int $param) 27 | * @method MyClass[]|MyNameSpace\MyClass[] methodName(int $param) 28 | */ 29 | --- 30 | (document 31 | (tag 32 | (tag_name) 33 | (primitive_type) 34 | (name) 35 | (parameters 36 | (parameter 37 | (primitive_type) 38 | (variable_name (name))))) 39 | (tag 40 | (tag_name) 41 | (union_type 42 | (array_type (named_type (name))) 43 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 44 | (name) 45 | (parameters 46 | (parameter 47 | (primitive_type) 48 | (variable_name (name)))))) 49 | 50 | 51 | ===================== 52 | @method w/ description 53 | ===================== 54 | /** 55 | * @method int methodName(int $param) some description 56 | * @method MyClass[]|MyNameSpace\MyClass[] methodName(int $param) some description 57 | */ 58 | --- 59 | (document 60 | (tag 61 | (tag_name) 62 | (primitive_type) 63 | (name) 64 | (parameters 65 | (parameter 66 | (primitive_type) 67 | (variable_name (name)))) 68 | (description (text))) 69 | (tag 70 | (tag_name) 71 | (union_type 72 | (array_type (named_type (name))) 73 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 74 | (name) 75 | (parameters 76 | (parameter 77 | (primitive_type) 78 | (variable_name (name)))) 79 | (description (text)))) 80 | 81 | 82 | ===================== 83 | @method w/ and w/o return type (#36) 84 | ===================== 85 | /** 86 | * @method DOMNodeList getSelectorContents(string $selector) 87 | * @method getSelectorContents(string $selector) 88 | */ 89 | --- 90 | (document 91 | (tag 92 | (tag_name) 93 | (named_type (name)) 94 | (name) 95 | (parameters 96 | (parameter 97 | (primitive_type) 98 | (variable_name (name))))) 99 | (tag 100 | (tag_name) 101 | (name) 102 | (parameters 103 | (parameter 104 | (primitive_type) 105 | (variable_name (name)))))) 106 | 107 | 108 | ===================== 109 | @param w/ varname & w/o description 110 | ===================== 111 | /** 112 | * @param int $foo 113 | * @param MyClass[]|MyNameSpace\MyClass[] $foo 114 | */ 115 | --- 116 | (document 117 | (tag 118 | (tag_name) 119 | (primitive_type) 120 | (variable_name (name))) 121 | (tag 122 | (tag_name) 123 | (union_type 124 | (array_type (named_type (name))) 125 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 126 | (variable_name (name)))) 127 | 128 | ===================== 129 | @param w/ varname & w/ description 130 | ===================== 131 | /** 132 | * @param int $foo some description 133 | * @param MyClass[]|MyNameSpace\MyClass[] $foo some description 134 | */ 135 | --- 136 | (document 137 | (tag 138 | (tag_name) 139 | (primitive_type) 140 | (variable_name (name)) 141 | (description (text))) 142 | (tag 143 | (tag_name) 144 | (union_type 145 | (array_type (named_type (name))) 146 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 147 | (variable_name (name)) 148 | (description (text)))) 149 | 150 | 151 | 152 | ===================== 153 | @property w/ varname & w/o description 154 | ===================== 155 | /** 156 | * @property int $foo 157 | * @property MyClass[]|MyNameSpace\MyClass[] $foo 158 | */ 159 | --- 160 | (document 161 | (tag 162 | (tag_name) 163 | (primitive_type) 164 | (variable_name (name))) 165 | (tag 166 | (tag_name) 167 | (union_type 168 | (array_type (named_type (name))) 169 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 170 | (variable_name (name)))) 171 | 172 | ===================== 173 | @property w/ varname & w/ description 174 | ===================== 175 | /** 176 | * @property int $foo some description 177 | * @property MyClass[]|MyNameSpace\MyClass[] $foo some description 178 | */ 179 | --- 180 | (document 181 | (tag 182 | (tag_name) 183 | (primitive_type) 184 | (variable_name (name)) 185 | (description (text))) 186 | (tag 187 | (tag_name) 188 | (union_type 189 | (array_type (named_type (name))) 190 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 191 | (variable_name (name)) 192 | (description (text)))) 193 | 194 | 195 | 196 | ===================== 197 | @property-read w/ varname & w/o description 198 | ===================== 199 | /** 200 | * @property-read int $foo 201 | * @property-read MyClass[]|MyNameSpace\MyClass[] $foo 202 | */ 203 | --- 204 | (document 205 | (tag 206 | (tag_name) 207 | (primitive_type) 208 | (variable_name (name))) 209 | (tag 210 | (tag_name) 211 | (union_type 212 | (array_type (named_type (name))) 213 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 214 | (variable_name (name)))) 215 | 216 | ===================== 217 | @property-read w/ varname & w/ description 218 | ===================== 219 | /** 220 | * @property-read int $foo some description 221 | * @property-read MyClass[]|MyNameSpace\MyClass[] $foo some description 222 | */ 223 | --- 224 | (document 225 | (tag 226 | (tag_name) 227 | (primitive_type) 228 | (variable_name (name)) 229 | (description (text))) 230 | (tag 231 | (tag_name) 232 | (union_type 233 | (array_type (named_type (name))) 234 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 235 | (variable_name (name)) 236 | (description (text)))) 237 | 238 | 239 | 240 | ===================== 241 | @property-write w/ varname & w/o description 242 | ===================== 243 | /** 244 | * @property-write int $foo 245 | * @property-write MyClass[]|MyNameSpace\MyClass[] $foo 246 | */ 247 | --- 248 | (document 249 | (tag 250 | (tag_name) 251 | (primitive_type) 252 | (variable_name (name))) 253 | (tag 254 | (tag_name) 255 | (union_type 256 | (array_type (named_type (name))) 257 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 258 | (variable_name (name)))) 259 | 260 | ===================== 261 | @property-write w/ varname & w/ description 262 | ===================== 263 | /** 264 | * @property-write int $foo some description 265 | * @property-write MyClass[]|MyNameSpace\MyClass[] $foo some description 266 | */ 267 | --- 268 | (document 269 | (tag 270 | (tag_name) 271 | (primitive_type) 272 | (variable_name (name)) 273 | (description (text))) 274 | (tag 275 | (tag_name) 276 | (union_type 277 | (array_type (named_type (name))) 278 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 279 | (variable_name (name)) 280 | (description (text)))) 281 | 282 | 283 | 284 | ===================== 285 | @return w/o varname & description 286 | ===================== 287 | /** 288 | * @return int 289 | * @return MyClass[]|MyNameSpace\MyClass[] 290 | */ 291 | --- 292 | (document 293 | (tag 294 | (tag_name) 295 | (primitive_type)) 296 | (tag 297 | (tag_name) 298 | (union_type 299 | (array_type (named_type (name))) 300 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))))) 301 | 302 | ===================== 303 | @return w/o varname & w/ description 304 | ===================== 305 | /** 306 | * @return int some description 307 | * @return MyClass[]|MyNameSpace\MyClass[] some description 308 | */ 309 | --- 310 | (document 311 | (tag 312 | (tag_name) 313 | (primitive_type) 314 | (description (text))) 315 | (tag 316 | (tag_name) 317 | (union_type 318 | (array_type (named_type (name))) 319 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 320 | (description (text)))) 321 | 322 | 323 | 324 | ===================== 325 | @throws w/o description 326 | ===================== 327 | /** 328 | * @throws MyClass 329 | * @throws MyNameSpace\MyClass 330 | */ 331 | --- 332 | (document 333 | (tag 334 | (tag_name) 335 | (named_type (name))) 336 | (tag 337 | (tag_name) 338 | (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 339 | 340 | ===================== 341 | @throws w/ description 342 | ===================== 343 | /** 344 | * @throws MyClass some description 345 | * @throws MyNameSpace\MyClass some description 346 | */ 347 | --- 348 | (document 349 | (tag 350 | (tag_name) 351 | (named_type (name)) 352 | (description (text))) 353 | (tag 354 | (tag_name) 355 | (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))) 356 | (description (text)))) 357 | 358 | 359 | 360 | ===================== 361 | @var w/o varname & w/ description 362 | ===================== 363 | /** 364 | * @var int some description 365 | * @var MyClass[]|MyNameSpace\MyClass[] some description 366 | */ 367 | --- 368 | (document 369 | (tag 370 | (tag_name) 371 | (primitive_type) 372 | (description (text))) 373 | (tag 374 | (tag_name) 375 | (union_type 376 | (array_type (named_type (name))) 377 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 378 | (description (text)))) 379 | 380 | ===================== 381 | @var w/ varname & w/o description 382 | ===================== 383 | /** 384 | * @var int $foo 385 | * @var MyClass[]|MyNameSpace\MyClass[] $foo 386 | */ 387 | --- 388 | (document 389 | (tag 390 | (tag_name) 391 | (primitive_type) 392 | (variable_name (name))) 393 | (tag 394 | (tag_name) 395 | (union_type 396 | (array_type (named_type (name))) 397 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 398 | (variable_name (name)))) 399 | 400 | ===================== 401 | @var w/ varname & w/ description 402 | ===================== 403 | /** 404 | * @var int $foo some description 405 | * @var MyClass[]|MyNameSpace\MyClass[] $foo some description 406 | * @var (MyClass&MyNameSpace\MyClass)|null $foo some description 407 | */ 408 | --- 409 | (document 410 | (tag 411 | (tag_name) 412 | (primitive_type) 413 | (variable_name (name)) 414 | (description (text))) 415 | (tag 416 | (tag_name) 417 | (union_type 418 | (array_type (named_type (name))) 419 | (array_type (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))))) 420 | (variable_name (name)) 421 | (description (text))) 422 | (tag 423 | (tag_name) 424 | (disjunctive_normal_form_type 425 | (intersection_type 426 | (named_type (name)) 427 | (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name)))) 428 | (primitive_type)) 429 | (variable_name (name)) 430 | (description (text)))) 431 | -------------------------------------------------------------------------------- /test/corpus/types.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | Primitive types 3 | ===================== 4 | /** 5 | * @var array $foo 6 | * @var callable $foo 7 | * @var iterable $foo 8 | * @var bool $foo 9 | * @var float $foo 10 | * @var int $foo 11 | * @var string $foo 12 | * @var void $foo 13 | * @var mixed $foo 14 | * @var static $foo 15 | * @var false $foo 16 | * @var null $foo 17 | */ 18 | --- 19 | (document 20 | (tag 21 | (tag_name) 22 | (primitive_type) 23 | (variable_name (name))) 24 | (tag 25 | (tag_name) 26 | (named_type (name)) 27 | (variable_name (name))) 28 | (tag 29 | (tag_name) 30 | (primitive_type) 31 | (variable_name (name))) 32 | (tag 33 | (tag_name) 34 | (primitive_type) 35 | (variable_name (name))) 36 | (tag 37 | (tag_name) 38 | (primitive_type) 39 | (variable_name (name))) 40 | (tag 41 | (tag_name) 42 | (primitive_type) 43 | (variable_name (name))) 44 | (tag 45 | (tag_name) 46 | (primitive_type) 47 | (variable_name (name))) 48 | (tag 49 | (tag_name) 50 | (primitive_type) 51 | (variable_name (name))) 52 | (tag 53 | (tag_name) 54 | (primitive_type) 55 | (variable_name (name))) 56 | (tag 57 | (tag_name) 58 | (primitive_type) 59 | (variable_name (name))) 60 | (tag 61 | (tag_name) 62 | (primitive_type) 63 | (variable_name (name))) 64 | (tag 65 | (tag_name) 66 | (primitive_type) 67 | (variable_name (name)))) 68 | 69 | ===================== 70 | Namespaced types 71 | ===================== 72 | /** 73 | * @var MyClass $foo 74 | * @var \MyClass $foo 75 | * @var My\Namespace\MyClass $foo 76 | * @var \My\Namespace\MyClass $foo 77 | */ 78 | --- 79 | (document 80 | (tag 81 | (tag_name) 82 | (named_type (name)) 83 | (variable_name (name))) 84 | (tag 85 | (tag_name) 86 | (named_type 87 | (qualified_name 88 | (namespace_name_as_prefix) (name))) 89 | (variable_name (name))) 90 | (tag 91 | (tag_name) 92 | (named_type 93 | (qualified_name 94 | (namespace_name_as_prefix (namespace_name (name) (name))) 95 | (name))) 96 | (variable_name (name))) 97 | (tag 98 | (tag_name) 99 | (named_type 100 | (qualified_name 101 | (namespace_name_as_prefix (namespace_name (name) (name))) 102 | (name))) 103 | (variable_name (name)))) 104 | 105 | ===================== 106 | Array types 107 | ===================== 108 | /** 109 | * @var int[] $foo 110 | * @var MyClass[] $foo 111 | * @var \MyClass[] $foo 112 | * @var My\Namespace\MyClass[] $foo 113 | * @var \My\Namespace\MyClass[] $foo 114 | */ 115 | --- 116 | (document 117 | (tag 118 | (tag_name) 119 | (array_type (primitive_type)) 120 | (variable_name (name))) 121 | (tag 122 | (tag_name) 123 | (array_type (named_type (name))) 124 | (variable_name (name))) 125 | (tag 126 | (tag_name) 127 | (array_type 128 | (named_type (qualified_name (namespace_name_as_prefix) (name)))) 129 | (variable_name (name))) 130 | (tag 131 | (tag_name) 132 | (array_type 133 | (named_type 134 | (qualified_name 135 | (namespace_name_as_prefix 136 | (namespace_name (name) (name))) 137 | (name)))) 138 | (variable_name (name))) 139 | (tag 140 | (tag_name) 141 | (array_type 142 | (named_type 143 | (qualified_name 144 | (namespace_name_as_prefix 145 | (namespace_name (name) (name))) 146 | (name)))) 147 | (variable_name (name)))) 148 | 149 | ===================== 150 | List types 151 | ===================== 152 | /** 153 | * @var int|float|null $foo 154 | * @var MyClass|MyNameSpace\MyClass $foo 155 | * @var \MyNameSpace\MyClass|MyClass $foo 156 | */ 157 | --- 158 | (document 159 | (tag 160 | (tag_name) 161 | (union_type 162 | (primitive_type) 163 | (primitive_type) 164 | (primitive_type)) 165 | (variable_name (name))) 166 | (tag 167 | (tag_name) 168 | (union_type 169 | (named_type (name)) 170 | (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name)))) 171 | (variable_name (name))) 172 | (tag 173 | (tag_name) 174 | (union_type 175 | (named_type (qualified_name (namespace_name_as_prefix (namespace_name (name))) (name))) 176 | (named_type (name))) 177 | (variable_name (name)))) 178 | 179 | ===================== 180 | Combined list & array types 181 | ===================== 182 | /** 183 | * @var int[]|float[]|null $foo 184 | * @var MyClass[]|MyNameSpace\MyClass[] $foo 185 | * @var \MyNameSpace\MyClass[]|MyClass[] $foo 186 | */ 187 | --- 188 | (document 189 | (tag 190 | (tag_name) 191 | (union_type 192 | (array_type (primitive_type)) 193 | (array_type (primitive_type)) 194 | (primitive_type)) 195 | (variable_name (name))) 196 | (tag 197 | (tag_name) 198 | (union_type 199 | (array_type (named_type (name))) 200 | (array_type 201 | (named_type 202 | (qualified_name 203 | (namespace_name_as_prefix (namespace_name (name))) 204 | (name))))) 205 | (variable_name (name))) 206 | (tag 207 | (tag_name) 208 | (union_type 209 | (array_type 210 | (named_type 211 | (qualified_name 212 | (namespace_name_as_prefix (namespace_name (name))) 213 | (name)))) 214 | (array_type (named_type (name)))) 215 | (variable_name (name)))) 216 | -------------------------------------------------------------------------------- /test/corpus/versioning.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | @deprecated 3 | ===================== 4 | /** 5 | * @deprecated 6 | */ 7 | --- 8 | (document 9 | (tag (tag_name))) 10 | 11 | ===================== 12 | @deprecated w/ version 13 | ===================== 14 | /** 15 | * @deprecated 1.2.3 16 | * @deprecated 1.2.3-beta 17 | * @deprecated $Id$ 18 | * @deprecated git: $Id$ 19 | * @deprecated @package_version@ 20 | */ 21 | --- 22 | (document 23 | (tag (tag_name) (version)) 24 | (tag (tag_name) (version)) 25 | (tag (tag_name) (version)) 26 | (tag (tag_name) (version)) 27 | (tag (tag_name) (version))) 28 | 29 | ===================== 30 | @deprecated w/ description 31 | ===================== 32 | /** 33 | * @deprecated some description 34 | * @deprecated 35 | * description on next line 36 | * @deprecated $description starts with var 37 | * @deprecated @description starts with tag 38 | * @deprecated some description 39 | * continued on next line 40 | */ 41 | --- 42 | (document 43 | (tag (tag_name) (description (text))) 44 | (tag (tag_name) (description (text))) 45 | (tag (tag_name) (description (text))) 46 | (tag (tag_name) (description (text))) 47 | (tag (tag_name) (description (text) (text)))) 48 | 49 | ===================== 50 | @deprecated w/ version & description 51 | ===================== 52 | /** 53 | * @deprecated 1.2.3 some description 54 | * @deprecated 1.2.3-beta some description 55 | * @deprecated $Id$ some description 56 | * @deprecated git: $Id$ some description 57 | * @deprecated @package_version@ some description 58 | */ 59 | --- 60 | (document 61 | (tag (tag_name) (version) (description (text))) 62 | (tag (tag_name) (version) (description (text))) 63 | (tag (tag_name) (version) (description (text))) 64 | (tag (tag_name) (version) (description (text))) 65 | (tag (tag_name) (version) (description (text)))) 66 | 67 | ===================== 68 | @deprecated w/ version & description on next line 69 | ===================== 70 | /** 71 | * @deprecated 1.2.3 72 | * some description 73 | * @deprecated 1.2.3-beta 74 | * some description 75 | * @deprecated $Id$ 76 | * some description 77 | * @deprecated git: $Id$ 78 | * some description 79 | * @deprecated @package_version@ 80 | * some description 81 | */ 82 | --- 83 | (document 84 | (tag (tag_name) (version) (description (text))) 85 | (tag (tag_name) (version) (description (text))) 86 | (tag (tag_name) (version) (description (text))) 87 | (tag (tag_name) (version) (description (text))) 88 | (tag (tag_name) (version) (description (text)))) 89 | 90 | ===================== 91 | @deprecated w/ version & description w/ linebreak 92 | ===================== 93 | /** 94 | * @deprecated 1.2.3 some description 95 | * continued description 96 | * @deprecated 1.2.3-beta some description 97 | * continued description 98 | * @deprecated $Id$ some description 99 | * continued description 100 | * @deprecated git: $Id$ some description 101 | * continued description 102 | * @deprecated @package_version@ some description 103 | * continued description 104 | */ 105 | --- 106 | (document 107 | (tag (tag_name) (version) (description (text) (text))) 108 | (tag (tag_name) (version) (description (text) (text))) 109 | (tag (tag_name) (version) (description (text) (text))) 110 | (tag (tag_name) (version) (description (text) (text))) 111 | (tag (tag_name) (version) (description (text) (text)))) 112 | 113 | 114 | 115 | 116 | ===================== 117 | @version w/ version 118 | ===================== 119 | /** 120 | * @version 1.2.3 121 | * @version 1.2.3-beta 122 | * @version $Id$ 123 | * @version git: $Id$ 124 | * @version @package_version@ 125 | */ 126 | --- 127 | (document 128 | (tag (tag_name) (version)) 129 | (tag (tag_name) (version)) 130 | (tag (tag_name) (version)) 131 | (tag (tag_name) (version)) 132 | (tag (tag_name) (version))) 133 | 134 | ===================== 135 | @version w/ description 136 | ===================== 137 | /** 138 | * @version some description 139 | * @version 140 | * description on next line 141 | * @version $description starts with var 142 | * @version @description starts with tag 143 | * @version some description 144 | * continued on next line 145 | */ 146 | --- 147 | (document 148 | (tag (tag_name) (description (text))) 149 | (tag (tag_name) (description (text))) 150 | (tag (tag_name) (description (text))) 151 | (tag (tag_name) (description (text))) 152 | (tag (tag_name) (description (text) (text)))) 153 | 154 | ===================== 155 | @version w/ version & description 156 | ===================== 157 | /** 158 | * @version 1.2.3 some description 159 | * @version 1.2.3-beta some description 160 | * @version $Id$ some description 161 | * @version git: $Id$ some description 162 | * @version @package_version@ some description 163 | */ 164 | --- 165 | (document 166 | (tag (tag_name) (version) (description (text))) 167 | (tag (tag_name) (version) (description (text))) 168 | (tag (tag_name) (version) (description (text))) 169 | (tag (tag_name) (version) (description (text))) 170 | (tag (tag_name) (version) (description (text)))) 171 | 172 | ===================== 173 | @version w/ version & description on next line 174 | ===================== 175 | /** 176 | * @version 1.2.3 177 | * some description 178 | * @version 1.2.3-beta 179 | * some description 180 | * @version $Id$ 181 | * some description 182 | * @version git: $Id$ 183 | * some description 184 | * @version @package_version@ 185 | * some description 186 | */ 187 | --- 188 | (document 189 | (tag (tag_name) (version) (description (text))) 190 | (tag (tag_name) (version) (description (text))) 191 | (tag (tag_name) (version) (description (text))) 192 | (tag (tag_name) (version) (description (text))) 193 | (tag (tag_name) (version) (description (text)))) 194 | 195 | ===================== 196 | @version w/ version & description w/ linebreak 197 | ===================== 198 | /** 199 | * @version 1.2.3 some description 200 | * continued description 201 | * @version 1.2.3-beta some description 202 | * continued description 203 | * @version $Id$ some description 204 | * continued description 205 | * @version git: $Id$ some description 206 | * continued description 207 | * @version @package_version@ some description 208 | * continued description 209 | */ 210 | --- 211 | (document 212 | (tag (tag_name) (version) (description (text) (text))) 213 | (tag (tag_name) (version) (description (text) (text))) 214 | (tag (tag_name) (version) (description (text) (text))) 215 | (tag (tag_name) (version) (description (text) (text))) 216 | (tag (tag_name) (version) (description (text) (text)))) 217 | 218 | 219 | 220 | 221 | 222 | ===================== 223 | @version w/ version 224 | ===================== 225 | /** 226 | * @version 1.2.3 227 | * @version 1.2.3-beta 228 | * @version $Id$ 229 | * @version git: $Id$ 230 | * @version @package_version@ 231 | */ 232 | --- 233 | (document 234 | (tag (tag_name) (version)) 235 | (tag (tag_name) (version)) 236 | (tag (tag_name) (version)) 237 | (tag (tag_name) (version)) 238 | (tag (tag_name) (version))) 239 | 240 | ===================== 241 | @version w/ description 242 | ===================== 243 | /** 244 | * @version some description 245 | * @version 246 | * description on next line 247 | * @version $description starts with var 248 | * @version @description starts with tag 249 | * @version some description 250 | * continued on next line 251 | */ 252 | --- 253 | (document 254 | (tag (tag_name) (description (text))) 255 | (tag (tag_name) (description (text))) 256 | (tag (tag_name) (description (text))) 257 | (tag (tag_name) (description (text))) 258 | (tag (tag_name) (description (text) (text)))) 259 | 260 | ===================== 261 | @version w/ version & description 262 | ===================== 263 | /** 264 | * @version 1.2.3 some description 265 | * @version 1.2.3-beta some description 266 | * @version $Id$ some description 267 | * @version git: $Id$ some description 268 | * @version @package_version@ some description 269 | */ 270 | --- 271 | (document 272 | (tag (tag_name) (version) (description (text))) 273 | (tag (tag_name) (version) (description (text))) 274 | (tag (tag_name) (version) (description (text))) 275 | (tag (tag_name) (version) (description (text))) 276 | (tag (tag_name) (version) (description (text)))) 277 | 278 | ===================== 279 | @version w/ version & description on next line 280 | ===================== 281 | /** 282 | * @version 1.2.3 283 | * some description 284 | * @version 1.2.3-beta 285 | * some description 286 | * @version $Id$ 287 | * some description 288 | * @version git: $Id$ 289 | * some description 290 | * @version @package_version@ 291 | * some description 292 | */ 293 | --- 294 | (document 295 | (tag (tag_name) (version) (description (text))) 296 | (tag (tag_name) (version) (description (text))) 297 | (tag (tag_name) (version) (description (text))) 298 | (tag (tag_name) (version) (description (text))) 299 | (tag (tag_name) (version) (description (text)))) 300 | 301 | ===================== 302 | @version w/ version & description w/ linebreak 303 | ===================== 304 | /** 305 | * @version 1.2.3 some description 306 | * continued description 307 | * @version 1.2.3-beta some description 308 | * continued description 309 | * @version $Id$ some description 310 | * continued description 311 | * @version git: $Id$ some description 312 | * continued description 313 | * @version @package_version@ some description 314 | * continued description 315 | */ 316 | --- 317 | (document 318 | (tag (tag_name) (version) (description (text) (text))) 319 | (tag (tag_name) (version) (description (text) (text))) 320 | (tag (tag_name) (version) (description (text) (text))) 321 | (tag (tag_name) (version) (description (text) (text))) 322 | (tag (tag_name) (version) (description (text) (text)))) 323 | --------------------------------------------------------------------------------