Remove Hack parser

Waiting on upstream to merge my changes first.
html_output
Wilfred Hughes 2022-02-07 21:43:37 +07:00
parent 85f2d7aa4b
commit 7291900b56
372 changed files with 0 additions and 322654 deletions

@ -65,7 +65,6 @@ Difftastic supports the following languages:
* Elixir
* Emacs Lisp
* Go
* Hack
* Haskell
* Java
* JavaScript (and JSX)

@ -104,11 +104,6 @@ fn main() {
src_dir: "vendor/tree-sitter-go-src",
extra_files: vec![],
},
TreeSitterParser {
name: "tree-sitter-hack",
src_dir: "vendor/tree-sitter-hack-src",
extra_files: vec!["scanner.cc"],
},
TreeSitterParser {
name: "tree-sitter-haskell",
src_dir: "vendor/tree-sitter-haskell-src",

@ -14,7 +14,6 @@ Difftastic uses the following tree-sitter parsers:
| Elixir | [elixir-lang/tree-sitter-elixir](https://github.com/elixir-lang/tree-sitter-elixir) |
| Emacs Lisp | [wilfred/tree-sitter-elisp](https://github.com/Wilfred/tree-sitter-elisp) |
| Go | [tree-sitter/tree-sitter-go](https://github.com/tree-sitter/tree-sitter-go) |
| Hack | [slackhq/tree-sitter-hack](https://github.com/slackhq/tree-sitter-hack) |
| Haskell | [tree-sitter/tree-sitter-haskell](https://github.com/tree-sitter/tree-sitter-haskell) |
| Java | [tree-sitter/tree-sitter-java](https://github.com/tree-sitter/tree-sitter-java) |
| JavaScript, JSX | [tree-sitter/tree-sitter-javascript](https://github.com/tree-sitter/tree-sitter-javascript) |

@ -28,7 +28,6 @@ pub enum Language {
Elixir,
EmacsLisp,
Go,
Hack,
Haskell,
Java,
JavaScript,
@ -77,7 +76,6 @@ fn from_shebang(src: &str) -> Option<Language> {
"lisp" | "sbc" | "ccl" | "clisp" | "ecl" => return Some(CommonLisp),
"elixir" => return Some(Elixir),
"runghc" | "runhaskell" | "runhugs" => return Some(Haskell),
"hhvm" => return Some(Hack),
"chakra" | "d8" | "gjs" | "js" | "node" | "nodejs" | "qjs" | "rhino" | "v8"
| "v8-shell" => return Some(JavaScript),
"ocaml" | "ocamlrun" | "ocamlscript" => return Some(OCaml),
@ -88,11 +86,6 @@ fn from_shebang(src: &str) -> Option<Language> {
}
}
}
// Hack can use <?hh in files with a .php extension.
if first_line.starts_with("<?hh") {
return Some(Hack);
}
}
None
@ -137,7 +130,6 @@ fn from_extension(extension: &OsStr) -> Option<Language> {
"el" => Some(EmacsLisp),
"ex" | "exs" => Some(Elixir),
"go" => Some(Go),
"hack" | "hck" => Some(Hack),
"hs" => Some(Haskell),
"java" => Some(Java),
"cjs" | "js" | "mjs" => Some(JavaScript),

@ -53,7 +53,6 @@ extern "C" {
fn tree_sitter_elisp() -> ts::Language;
fn tree_sitter_elixir() -> ts::Language;
fn tree_sitter_go() -> ts::Language;
fn tree_sitter_hack() -> ts::Language;
fn tree_sitter_haskell() -> ts::Language;
fn tree_sitter_java() -> ts::Language;
fn tree_sitter_javascript() -> ts::Language;
@ -240,20 +239,6 @@ pub fn from_language(language: guess::Language) -> TreeSitterConfig {
.unwrap(),
}
}
Hack => {
// TODO: upstream
// TODO: upstream doesn't support the `readonly` keyword yet.
let query = "(comment) @comment\n\n(string) @string\n(heredoc) @string\n(prefixed_string) @string\n\n[\n \"class\"\n \"interface\"\n \"trait\"\n \"public\"\n \"protected\"\n \"private\"\n \"static\"\n \"async\"\n \"function\"\n \"return\"\n \"if\"\n \"else\"\n \"elseif\"\n \"while\"\n \"for\"\n \"foreach\"\n \"break\"\n \"continue\"\n \"type\"\n \"new\"\n \"throw\"\n] @keyword\n\n(type_specifier) @type\n";
let language = unsafe { tree_sitter_hack() };
TreeSitterConfig {
name: "Hack",
language,
atom_nodes: (vec!["prefixed_stirng", "heredoc"]).into_iter().collect(),
delimiter_tokens: (vec![("[", "]"), ("(", ")"), ("{", "}")]),
highlight_query: ts::Query::new(language, query).unwrap(),
}
}
Haskell => {
let language = unsafe { tree_sitter_haskell() };
TreeSitterConfig {

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

@ -1,6 +0,0 @@
BasedOnStyle: Google
ColumnLimit: 100
AlignAfterOpenBracket: AlwaysBreak
BinPackParameters: false
BinPackArguments: false

@ -1,14 +0,0 @@
/examples/* linguist-vendored
# Explicitly list files in src so scanner.cc and scanner.c are not included.
/src/tree_sitter/* linguist-vendored
/src/binding.cc linguist-vendored
/src/grammar.json linguist-vendored
/src/node-types.json linguist-vendored
/src/parser.c linguist-vendored
/src/tree_sitter/* binary
/src/binding.cc binary
/src/grammar.json binary
/src/node-types.json binary
/src/parser.c binary

@ -1,11 +0,0 @@
# Code of Conduct
## Introduction
Diversity and inclusion make our community strong. We encourage participation from the most varied and diverse backgrounds possible and want to be very clear about where we stand.
Our goal is to maintain a safe, helpful and friendly community for everyone, regardless of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other defining characteristic.
This code and related procedures also apply to unacceptable behavior occurring outside the scope of community activities, in all community venues (online and in-person) as well as in all one-on-one communications, and anywhere such behavior has the potential to adversely affect the safety and well-being of community members.
For more information on our code of conduct, please visit [https://slackhq.github.io/code-of-conduct](https://slackhq.github.io/code-of-conduct)

@ -1,60 +0,0 @@
# Contributors Guide
Interested in contributing? Awesome! Before you do though, please read our
[Code of Conduct](https://slackhq.github.io/code-of-conduct). We take it very seriously, and expect that you will as
well.
There are many ways you can contribute! :heart:
### Bug Reports and Fixes :bug:
- If you find a bug, please search for it in the [Issues](https://github.com/slackhq/tree-sitter-hack/issues), and if it isn't already tracked,
[create a new issue](https://github.com/slackhq/tree-sitter-hack/issues/new). Fill out the "Bug Report" section of the issue template. Even if an Issue is closed, feel free to comment and add details, it will still
be reviewed.
- Issues that have already been identified as a bug (note: able to reproduce) will be labelled `bug`.
- If you'd like to submit a fix for a bug, [send a Pull Request](#creating_a_pull_request) and mention the Issue number.
- Include tests that isolate the bug and verifies that it was fixed.
### New Features :bulb:
- If you'd like to add new functionality to this project, describe the problem you want to solve in a [new Issue](https://github.com/slackhq/tree-sitter-hack/issues/new).
- Issues that have been identified as a feature request will be labelled `enhancement`.
- If you'd like to implement the new feature, please wait for feedback from the project
maintainers before spending too much time writing the code. In some cases, `enhancement`s may
not align well with the project objectives at the time.
### Tests :mag:, Documentation :books:, Miscellaneous :sparkles:
- If you'd like to improve the tests, you want to make the documentation clearer, you have an
alternative implementation of something that may have advantages over the way its currently
done, or you have any other change, we would be happy to hear about it!
- If its a trivial change, go ahead and [send a Pull Request](#creating_a_pull_request) with the changes you have in mind.
- If not, [open an Issue](https://github.com/slackhq/tree-sitter-hack/issues/new) to discuss the idea first.
If you're new to our project and looking for some way to make your first contribution, look for
Issues labelled `good first contribution`.
## Requirements
For your contribution to be accepted:
- [x] You must have signed the [Contributor License Agreement (CLA)](https://cla-assistant.io/slackhq/tree-sitter-hack).
- [x] The test suite must be complete and pass.
- [x] The changes must be approved by code review.
- [x] Commits should be atomic and messages must be descriptive. Related issues should be mentioned by Issue number.
If the contribution doesn't meet the above criteria, you may fail our automated checks or a maintainer will discuss it with you. You can continue to improve a Pull Request by adding commits to the branch from which the PR was created.
[Interested in knowing more about about pull requests at Slack?](https://slack.engineering/on-empathy-pull-requests-979e4257d158#.awxtvmb2z)
## Creating a Pull Request
1. :fork_and_knife: Fork the repository on GitHub.
2. :runner: Clone/fetch your fork to your local development machine. It's a good idea to run the tests just
to make sure everything is in order.
3. :herb: Create a new branch and check it out.
4. :crystal_ball: Make your changes and commit them locally. Magic happens here!
5. :arrow_heading_up: Push your new branch to your fork. (e.g. `git push username fix-issue-16`).
6. :inbox_tray: Open a Pull Request on github.com from your new branch on your fork to `main` in this
repository.
## Maintainers
There are more details about processes and workflow in the [Maintainer's Guide](./maintainers_guide.md).

@ -1,36 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: ''
---
### Describe the bug
A clear and concise description of what the bug is.
### Requirements (place an `x` in each of the `[ ]`)**
* [ ] I've read and understood the [Contributing guidelines](../CONTRIBUTING.md) and have done my best effort to follow them.
* [ ] I've read and agree to the [Code of Conduct](https://slackhq.github.io/code-of-conduct).
* [ ] I've searched for any related issues and avoided creating a duplicate issue.
### To Reproduce
Steps to reproduce the behavior:
### Expected behavior
A clear and concise description of what you expected to happen.
#### Screenshots
If applicable, add screenshots to help explain your problem.
#### Reproducible in:
{project_name} version:
{platform_name} version:
OS version(s):
#### Additional context
Add any other context about the problem here.

@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Code of Conduct
url: https://slackhq.github.io/code-of-conduct
about: Code of Conduct

@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE]"
labels: enhancement
assignees: ''
---
### Description
Describe your request here.
### Requirements (place an `x` in each of the `[ ]`)
* [ ] I've read and understood the [Contributing guidelines](../CONTRIBUTING.md) and have done my best effort to follow them.
* [ ] I've read and agree to the [Code of Conduct](https://slackhq.github.io/code-of-conduct).
* [ ] I've searched for any related issues and avoided creating a duplicate issue.

@ -1,8 +0,0 @@
### Summary
Describe the goal of this PR. Mention any related Issue numbers.
### Requirements (place an `x` in each `[ ]`)
* [ ] I've read and understood the [Contributing Guidelines](https://github.com/slackhq/tree-sitter-hack/blob/main/.github/CONTRIBUTING.md) and have done my best effort to follow them.
* [ ] I've read and agree to the [Code of Conduct](https://slackhq.github.io/code-of-conduct).

@ -1,69 +0,0 @@
# Maintainers Guide
This document describes tools, tasks and workflow that one needs to be familiar with in order to effectively maintain
this project. If you use this package within your own software as is but don't plan on modifying it, this guide is
**not** for you.
## Tools (optional)
> Are there any build tools, dependencies, or other programs someone maintaining this project
> needs to be familiar with?
## Tasks
### Testing
> How do you run the tests?
### Generating Documentation (optional)
> If the documentation is generated from source, how does someone run the generation?
> Are the docs published on a website (GitHub Pages)?
### Releasing
> A description of the process to make a release for this project. Do not share any secrets here.
## Workflow
### Versioning and Tags
> Does this project use semver? What does the numbering system look like? Are releases tagged in git?
### Branches
> Describe any specific branching workflow. For example:
> `main` is where active development occurs.
> Long running branches named feature branches are occasionally created for collaboration on a feature that has a large scope (because everyone cannot push commits to another person's open Pull Request)
> At some point in the future after a major version increment, there may be maintenance branches
> for older major versions.
### Issue Management
Labels are used to run issues through an organized workflow. Here are the basic definitions:
* `bug`: A confirmed bug report. A bug is considered confirmed when reproduction steps have been
documented and the issue has been reproduced.
* `enhancement`: A feature request for something this package might not already do.
* `docs`: An issue that is purely about documentation work.
* `tests`: An issue that is purely about testing work.
* `needs feedback`: An issue that may have claimed to be a bug but was not reproducible, or was otherwise missing some information.
* `discussion`: An issue that is purely meant to hold a discussion. Typically the maintainers are looking for feedback in this issues.
* `question`: An issue that is like a support request because the user's usage was not correct.
* `semver:major|minor|patch`: Metadata about how resolving this issue would affect the version number.
* `security`: An issue that has special consideration for security reasons.
* `good first contribution`: An issue that has a well-defined relatively-small scope, with clear expectations. It helps when the testing approach is also known.
* `duplicate`: An issue that is functionally the same as another issue. Apply this only if you've linked the other issue by number.
> You may want to add more labels for subsystems of your project, depending on how complex it is.
**Triage** is the process of taking new issues that aren't yet "seen" and marking them with a basic
level of information with labels. An issue should have **one** of the following labels applied:
`bug`, `enhancement`, `question`, `needs feedback`, `docs`, `tests`, or `discussion`.
Issues are closed when a resolution has been reached. If for any reason a closed issue seems
relevant once again, reopening is great and better than creating a duplicate issue.
## Everything else
When in doubt, find the other maintainers and ask.

@ -1,28 +0,0 @@
name: Build/test
on:
pull_request:
branches:
- "**"
push:
branches:
- "main"
jobs:
test_ubuntu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 14
- run: npm install
- run: npm test
test_macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 14
- run: brew install gnu-sed
- run: npm install
- run: npm test

@ -1,5 +0,0 @@
#!/bin/bash
if [ -n "$(git status --porcelain)" ]; then
exit 1
fi

@ -1,24 +0,0 @@
name: validate
on:
pull_request:
branches:
- "**"
push:
branches:
- "main"
jobs:
check-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 14
- run: npm install
- run: npm run build
- name: Generate corpus
run: "${GITHUB_WORKSPACE}/bin/generate-corpus"
shell: bash
- name: Check for changes
run: "${GITHUB_WORKSPACE}/.github/workflows/validate.sh"
shell: bash

@ -1,12 +0,0 @@
node_modules/
build/
*.log
.DS_Store
.vscode/settings.json
examples
package-lock.json
tmp
Cargo.lock
/target/
test/cases/**/*.json

@ -1,11 +0,0 @@
test
build
bin
examples
tmp
.vscode
.prettierignore
.prettierrc
.rubocop.yml
.clang-format

@ -1,2 +0,0 @@
package-lock=false
engine-strict=true

@ -1,2 +0,0 @@
src/
package.json

@ -1,27 +0,0 @@
{
"arrowParens": "avoid",
"tabWidth": 2,
"useTabs": false,
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"overrides": [
{
"files": ["*.json", ".prettierrc"],
"options": {
"parser": "json5",
"quoteProps": "preserve",
"singleQuote": false,
"trailingComma": "all",
},
},
{
"files": [".vscode/tasks.json"],
"options": {
"parser": "json",
"quoteProps": "preserve",
"singleQuote": false,
},
},
],
}

@ -1,2 +0,0 @@
Style/PerlBackrefs:
Enabled: false

@ -1,153 +0,0 @@
{
"version": "2.0.0",
"presentation": {
"showReuseMessage": false,
"clear": true,
"focus": false,
"reveal": "silent"
},
"tasks": [
{
"label": "ts-parse",
"type": "shell",
"command": "F=${file}; bin/generate-parser && { npx tree-sitter parse $F>\"${F%.*}.exp\"; code -r \"${F%.*}.exp\"; }",
"detail": "npx tree-sitter generate && tree-sitter parse ${file}",
"problemMatcher": []
},
{
"label": "ts-query",
"type": "shell",
"command": "F=${file}; parsed=$(bin/ts-query $F) && echo \"$parsed\">\"${F%.*}.exp\" && code -r \"${F%.*}.exp\"",
"detail": "bin/ts-query ${file} (implictly runs `npx tree-sitter generate`)",
"problemMatcher": []
},
{
"label": "hh-json",
"type": "shell",
"command": "F=${file}; bin/hh-json $F>\"${F%.*}.json\"; code -r \"${F%.*}.json\"",
"detail": "bin/hh-json ${file}",
"problemMatcher": []
},
{
"label": "hh-errors",
"type": "shell",
"command": "bin/hh-errors ${file}",
"detail": "bin/hh-errors ${file}",
"problemMatcher": {
"fileLocation": "absolute",
"pattern": [
{
"regexp": "^([^\\s].*)$",
"file": 1
},
{
"regexp": "^\\((\\d+),(\\d+)\\)-\\((\\d+),(\\d+)\\) (.*)$",
"loop": true,
"line": 1,
"column": 2,
"endLine": 3,
"endColumn": 4,
"message": 5
}
]
}
},
{
"label": "ts-errors",
"type": "shell",
"command": "bin/ts-errors ${file}",
"detail": "bin/ts-errors ${file}",
"problemMatcher": {
"fileLocation": "absolute",
"pattern": [
{
"regexp": "^([^\\s].*)$",
"file": 1
},
{
"regexp": "^\\((\\d+),(\\d+)\\)-\\((\\d+),(\\d+)\\) (.*)$",
"loop": true,
"line": 1,
"column": 2,
"endLine": 3,
"endColumn": 4,
"message": 5
}
]
}
},
{
"type": "npm",
"script": "test",
"group": "test",
"label": "npm: test",
"detail": "bin/test-corpus && bin/test-examples",
"problemMatcher": {
"fileLocation": "relative",
"pattern": [
{
"regexp": "^([^\\s].*)$",
"file": 1
},
{
"regexp": "^\\((\\d+),(\\d+)\\)-\\((\\d+),(\\d+)\\) (.*)$",
"loop": true,
"line": 1,
"column": 2,
"endLine": 3,
"endColumn": 4,
"message": 5
}
]
}
},
{
"type": "npm",
"script": "test-corpus",
"label": "npm: test-corpus",
"detail": "bin/test-corpus",
"problemMatcher": {
"fileLocation": "relative",
"pattern": [
{
"regexp": "^([^\\s].*)$",
"file": 1
},
{
"regexp": "^\\((\\d+),(\\d+)\\)-\\((\\d+),(\\d+)\\) (.*)$",
"loop": true,
"line": 1,
"column": 2,
"endLine": 3,
"endColumn": 4,
"message": 5
}
]
}
},
{
"type": "npm",
"script": "test-examples",
"label": "npm: test-examples",
"detail": "bin/test-examples",
"problemMatcher": {
"fileLocation": "relative",
"pattern": [
{
"regexp": "^([^\\s].*)$",
"file": 1
},
{
"regexp": "^\\((\\d+),(\\d+)\\)-\\((\\d+),(\\d+)\\) (.*)$",
"loop": true,
"line": 1,
"column": 2,
"endLine": 3,
"endColumn": 4,
"message": 5
}
]
}
}
]
}

@ -1,26 +0,0 @@
[package]
name = "tree-sitter-hack"
description = "hack grammar for the tree-sitter parsing library"
version = "0.0.4"
keywords = ["incremental", "parsing", "hack"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/slackhq/tree-sitter-hack"
edition = "2018"
license = "MIT"
build = "bindings/rust/build.rs"
include = [
"bindings/rust/*",
"grammar.js",
"queries/*",
"src/*",
]
[lib]
path = "bindings/rust/lib.rs"
[dependencies]
tree-sitter = "0.19.3"
[build-dependencies]
cc = "1.0"

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

@ -1,91 +0,0 @@
# tree-sitter-hack
![build](https://github.com/slackhq/tree-sitter-hack/actions/workflows/ci.yml/badge.svg)
At Slack proactively securing our systems is a top priority. One way we achieve this is by automating the detection of vulnerabilities with static code analysis scanning. Although an abundance of tools exist for scanning the majority of programming languages, our codebase is overwhelmingly written in [Hack](https://hacklang.org/) - a language not widely used outside of Slack. Rather than building our own tool from scratch, we are extending the functionality of an open source static analysis tool, [Semgrep](https://github.com/returntocorp/semgrep), to be compatible with Hack. But how do we teach Semgrep the Hack programming language?
Like all human languages, programming languages have a structure to them known as grammar. Grammar rules are used to create a parser which converts source code into a concrete syntax tree (CST) which is a structural representation of the code. [Tree-Sitter](https://github.com/tree-sitter/tree-sitter) is a fast and robust library that can generate a CST from our Hack grammar rules. This CST has many use cases such as robust syntax highlighting, code folding, linting, etc. Most importantly, Semgrep uses this CST to understand Hack on a semantic level. This semantic understanding in conjunction with Semgrep rules can detect vulnerabilities in source code. This process is demonstrated by the following diagram.
![tree-sitter-hack use in Semgrep](diagram.png)
In summary, we use tree-sitter-hack to teach Semgrep the Hack programming language.
## Installation
```
$ git clone https://github.com/slackhq/tree-sitter-hack
$ cd tree-sitter-hack
$ npm install
```
## Usage
```
$ echo 'function main(): void { print "wyd, world\\n"; }' > script.hack
$ npx tree-sitter generate
$ npx tree-sitter parse script.hack
(script [0, 0] - [3, 0]
(function_declaration [0, 0] - [2, 1]
name: (identifier [0, 9] - [0, 13])
(parameters [0, 13] - [0, 15])
return_type: (primitive_type [0, 17] - [0, 21])
body: (compound_statement [0, 22] - [2, 1]
(expression_statement [1, 2] - [1, 23]
(print_expression [1, 2] - [1, 22]
(string [1, 8] - [1, 22]))))))
```
## Testing
```
$ npx tree-sitter generate
$ bin/test-corpus
```
## Scripts
**`bin/generate-parser`**
Wrapper around `tree-sitter generate` that skips parser generation if `grammar.js` hasn't changed since last run.
**`bin/generate-corpus`**
Unlike most other Tree-sitter projects, we breakout test cases into separate files (see [`test/cases`](test/cases)). This is done so editors have an easier time syntax highlighting test cases. But also I find individual files easier to navigate than the `corpus.txt` files used by Tree-sitter.
We use `bin/generate-corpus` to generate the `test/corpus/case1.txt` from individual `test/cases` files so we can still use `tree-sitter test`.
**`bin/test-corpus`**
Run `bin/generate-corpus` and `bin/generate-parser` before running `tree-sitter test`.
**`bin/test-dir`**
Run `bin/ts-errors` on all files with `.hack` or `.php` extension in the given directory recursively.
```
$ ./bin/test-dir hhvm/hphp/hack/test
examples/hhvm/hphp/hack/test/error_formatting_highlighted/zero_width_syntax_err.php
(3,11)-(3,18) extends
examples/hhvm/hphp/hack/test/autocomplete/not_shape_key_string.php
(3,1)-(6,1) function foo(): string {\n return "AUTO332\n}\n
(4,10)-(6,1) "AUTO332\n}\n
...
```
## Note
npm doesn't allow packages with the word "hack" in their registry which is why the repo
name does not match the package name.
> Unfortunately, the word "hack" triggers our spam detection and can't be used in package names. We recommend choosing other keywords that highlight your package's functionality.
## References
There's no published official Hacklang language spec so we have to make do.
- [HHVM Blog](https://hhvm.com/blog/) - Good source of language [deprecations](https://hhvm.com/blog/2019/10/01/deprecating-references.html) and [changes](https://hhvm.com/blog/2020/07/06/hhvm-4.65.html#breaking-changes).
- [Hack Documentation](https://docs.hhvm.com/hack/) - Source at [hhvm/user-documentation](https://github.com/hhvm/user-documentation).
- [Hack Parser Source](https://github.com/facebook/hhvm/tree/4da98da2f5ddc0989d3d150dddc1b06ee4087440/hphp/hack/src/parser)
- [tree-sitter-javascript](https://github.com/tree-sitter/tree-sitter-javascript) and [tree-sitter-php](https://github.com/tree-sitter/tree-sitter-php) - Used to guide writing [`grammar.js`](grammar.js)
- Deprecated [Hack Language Specification](https://github.com/facebookarchive/hack-langspec)
- [PHP Language Specification](https://github.com/php/php-langspec) -
Does not apply 100% to Hacklang, but still a good reference.
- Bug icon in diagram made by Freepik

@ -1,22 +0,0 @@
FROM hhvm/hhvm:4.68-latest
ENV NODE_VERSION 14.7.0
ENV NVM_DIR /usr/local/nvm
WORKDIR /tree-sitter-hack
RUN \
apt-get update -y && \
apt-get install -y build-essential ruby fd-find
RUN \
mkdir -p ${NVM_DIR} && \
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash && \
. ${NVM_DIR}/nvm.sh && \
nvm install ${NODE_VERSION} && \
ln -s $(which node) /usr/local/bin && \
ln -s $(which npm) /usr/local/bin && \
ln -s $(which npx) /usr/local/bin && \
printf "unsafe-perm = true\n" >.npmrc
RUN mkdir -p /mnt/tree-sitter-hack

@ -1,23 +0,0 @@
#!/bin/bash
set -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
IMAGE_NAME="tree-sitter-hack"
CONTAINER_NAME="tree-sitter-hack"
docker build --rm $DIR -t $IMAGE_NAME
if docker ps -a --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
docker stop $CONTAINER_NAME >/dev/null
docker rm $CONTAINER_NAME >/dev/null
fi
docker run -td \
--name $CONTAINER_NAME \
-v $(realpath .):/mnt/tree-sitter-hack:rw \
$IMAGE_NAME
docker exec -it $CONTAINER_NAME sh -c 'ln -s /mnt/tree-sitter-hack/* /tree-sitter-hack'
docker exec -it $CONTAINER_NAME sh -c 'rm -rf build node_modules package-lock.json'
docker exec -it $CONTAINER_NAME sh -c 'npm install'

@ -1,32 +0,0 @@
#!/bin/bash
set -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
IMAGE_NAME="tree-sitter-hack"
CONTAINER_NAME="tree-sitter-hack"
case "$1" in
"")
args="/bin/bash"
;;
install)
args="npm $@"
;;
build | reset | test*)
args="npm run $@"
;;
node-gyp*)
args="npx $@"
;;
*)
args="$@"
;;
esac
bash -c "docker exec -it $CONTAINER_NAME $args"

@ -1,25 +0,0 @@
#!/bin/bash
set -e
# Taken from https://git.io/JJOXZ
function fetch() {
path="examples/$1"
url=$2
sha=$3
if [ ! -d "$path" ]; then
git clone --depth 1 --branch "$sha" "https://github.com/$url" "$path"
fi
pushd "$path" >/dev/null
git fetch --depth 1 origin "$sha" && git reset --hard "$sha"
popd >/dev/null
}
mkdir -p examples
fetch "hack-sql-fake" "slackhq/hack-sql-fake" "v4.0.5"
fetch "hack-json-schema" "slackhq/hack-json-schema" "v4.27.1"
fetch "hhvm" "facebook/hhvm" "HHVM-4.67.0"

@ -1,56 +0,0 @@
#!/bin/bash
set -e
source bin/require_sed
# This script creates corpus *.txt files expected by `tree-sitter test` in the format
# expected [0] based on *.php and *.exp files in test/cases.
#
# [0] https://tree-sitter.github.io/tree-sitter/creating-parsers#:~:text=Return%20statements
for cases_path in test/cases/*; do
corpus_name=$(basename $cases_path)
corpus_path="test/corpus/$corpus_name.txt"
echo "Generating $corpus_path"
cases="$(ls -d $cases_path/* | grep -E '^[^.]*\.exp$' | $sed -Ee 's/.exp$//' | sort -bu)"
printf "" >$corpus_path
first=1
for case in $cases; do
exp="$case.exp"
if [[ -f "$case.php" ]]; then
code="$case.php"
elif [[ -f "$case.hack" ]]; then
code="$case.hack"
elif [[ -f "$case.hhi" ]]; then
code="$case.hhi"
else
printf "Source file not found for $exp\n"
exit 1
fi
# Use the test case file name as the description
description=$(printf "$(basename $case)" | $sed -e 's/^\(.\)/\u\1/g' -e 's/-/ /g')
if [[ $first -eq 0 ]]; then
printf "\n" >>$corpus_path
else
first=0
fi
printf "==========================\n" >>$corpus_path
printf "$description\n" >>$corpus_path
printf "==========================\n\n" >>$corpus_path
cat $code >>$corpus_path
printf "\n---\n\n" >>$corpus_path
cat $exp >>$corpus_path
done
done

@ -1,31 +0,0 @@
#!/bin/bash
set -e
while [ $# -gt 0 ]; do
case "$1" in
--force)
FORCE=1
shift
;;
*)
break
;;
esac
done
mkdir -p tmp
CACHED_SHA=$(cat 'tmp/grammar.js.sha' 2>/dev/null || true)
GRAMMAR_SHA=$(sha256sum 'grammar.js' | cut -d' ' -f1)
# Exit if grammar.js hasn't changed since last time we generated parser.
if [ "$FORCE" != 1 ] && [ "$CACHED_SHA" = "$GRAMMAR_SHA" ]; then
exit
fi
printf "Generating parser...\n"
npx tree-sitter generate
printf "$GRAMMAR_SHA" >'tmp/grammar.js.sha'

@ -1,30 +0,0 @@
#!/bin/bash
set -e
# Print files with hh_parse errors and filter out the rest.
hh_parse --show-file-name --full-fidelity-errors-all $@ |
grep -v 'A \.php file must begin with' |
grep -v 'Nested ternary expressions inside ternary expressions are ambiguous' |
# Only print file paths that have errors
ruby -e "$(
cat <<-RUBY
path = nil
ARGF.each_line do |line|
# Consume lines until we have something that does *not* look like a file path.
next path = line if line =~ /(^.*\.(php|hack))\s/
unless path.nil?
# Print the file path before we print any errors.
puts path
# Only print the file path once.
path = nil
end
puts line
end
RUBY
)"

@ -1,102 +0,0 @@
#!/bin/bash
set -e
# Parse Hack source and filter noisy node objects.
hh_parse --full-fidelity-text-json $@ |
jq '.parse_tree' |
# Remove low-value elements and simplify name tokens.
jq "$(
cat <<-JQ
# Return true if an element is low value.
def trivia:
(. == [] or . == {}) or
type == "object" and
(
.kind == "markup_section" or
.kind == "whitespace" or
.kind == "end_of_file" or
.kind == "end_of_line" or
.kind == "missing" or
(
.kind == "token" and
# Note: parenthesis matter here.
(.token.kind | IN(";", ":", ",", "[", "]", "{", "}", "(", ")", "<<", ">>"))
)
);
# Transform/replace some objects with a simplified version.
def transform:
# {
# "kind": "token",
# "token": {
# "kind": "final",
# "text": "final"
# }
# }
if type == "object" and
.kind == "token" and
.token.kind == .token.text
then .token.text
# {
# "kind": "token",
# "token": {
# "kind": "XHP_class_name",
# "text": ":head"
# }
# }
elif type == "object" and
.kind == "token" and
has("token") and
(.token | keys) == ["kind", "text"]
then {(.token.kind): .token.text}
# {
# "kind": "list_item",
# "list_item": {
# "kind": "...",
# }
# }
elif type == "object" and .kind == "list_item" and has("list_item")
then .list_item
# "...": {
# "kind": "list",
# "elements": [
# {}
# ]
# }
elif type == "object" and .kind == "list" and has("elements")
then .elements
else .
end;
walk(
if type == "object" then
# Remove keys with low-value values.
with_entries(select(.value | trivia | not)) | map_values(transform)
elif type == "array" then
# Remove low-value array elements.
map(select(trivia | not)) | map(transform)
else .
end
)
JQ
)"

@ -1,14 +0,0 @@
#!/bin/bash
[ -n "$fd" ] && exit 0
if [[ "$(uname)" == Darwin* ]]; then
fd="$(command -v fd || echo "")"
else
fd="$(command -v fdfind || echo "")"
fi
if [ -z "$fd" ]; then
echo "fd is required for this script to work."
exit 1
fi

@ -1,6 +0,0 @@
#!/bin/bash
if ! ruby --version | grep -qE "^ruby (2\.[7-]|[3-]\.)"; then
echo "Ruby 2.7 or later is required for this script to work."
exit 1
fi

@ -1,10 +0,0 @@
#!/bin/bash
[ -n "$sed" ] && exit 0
sed="$(command -v gsed || command -v sed)"
if ! $sed --version 2>/dev/null | grep -q "GNU sed"; then
echo "GNU sed is required for this script to work."
exit 1
fi

@ -1,16 +0,0 @@
#!/bin/bash
set -e
source bin/require_fd
bin/generate-parser
bin/generate-corpus
printf "\033[1mRunning Tree-sitter corpus tests...\033[0m\n"
npx tree-sitter test
printf "\n"
printf "\033[1mGetting Hacklang corpus errors...\033[0m\n"
bin/hh-errors "$($fd '\.(hack|php)$' test/cases)"

@ -1,11 +0,0 @@
#!/bin/bash
set -e
source bin/require_fd
# Note: By default, fd ignores hidden directories,
# hidden files, and .gitignore patterns
# To change this behavior, use --hidden and/or --no-ignore with fd calls
{ fd . -e php "$@" | xargs -r egrep -l "^<\?hh" & fd . -e hack "$@"; } | xargs -r -n 256 bin/ts-errors

@ -1,81 +0,0 @@
#!/bin/bash
set -e
source bin/require_fd
while [[ $# -gt 0 ]]; do
case $1 in
--filter)
filter=$2
shift
shift
;;
--count)
count=1
shift
;;
--name-only)
name_only=1
shift
;;
*)
break
;;
esac
done
function filter-hack() {
grep -E --color=never '.*\.(hack|php)$' | sort -u
}
function find-hack() {
$fd '\.(hack|php)$' "$@" | sort -u
}
function print-results() {
if [[ "$count" -eq 1 ]]; then
failures="$(cat /dev/stdin | filter-hack | wc -l | tr -d ' ')"
# Very important
if [[ "$filures" -eq 1 ]]; then
echo "$failures failure"
else
echo "$failures failures"
fi
elif [[ "$name_only" -eq 1 ]]; then
filter-hack
else
cat /dev/stdin
fi
}
hhvm_failures="examples/hhvm-failures.txt"
hhvm_tests="examples/hhvm/hphp/hack/test"
# The HHVM repo has tests that verify intentional errors. We aren't doing that (yet).
# Filter out intentionally failing Hack files.
if ! test -f "$hhvm_failures"; then
printf "\033[1mGetting known HHVM failures...\033[0m\n"
find-hack $hhvm_tests |
xargs -n 256 bin/hh-errors 2>/dev/null |
filter-hack >$hhvm_failures
echo "$(wc -l <$hhvm_failures | tr -d ' ') known HHVM failures"
fi
printf "\033[1mGetting Tree-sitter examples errors...\033[0m\n"
find-hack $(ls -d examples/*/ | grep -v 'examples/hhvm') |
xargs -r bin/ts-errors |
print-results
comm -13 <(sort $hhvm_failures) <(find-hack $hhvm_tests | grep -E "$filter") |
# Looks interesting, but I think too experimental to support yet?
grep -v 'examples/hhvm/hphp/hack/test/pocket_universes' |
grep -v 'examples/hhvm/hphp/hack/test/typecheck/goto' |
xargs -r -n 256 bin/ts-errors |
print-results

@ -1,75 +0,0 @@
#!/bin/bash
set -e
source bin/require_ruby
# Find errors in `tree-sitter parse` output and print them in a format easily consumable
# by VSCode. The Hacklang parser already has an error format easily consumable by VSCode
# so we match that format.
#
# $ bin/ts-error $@
# examples/hack-sql-fake/src/QueryContext.php
# (5,1)-(5,8) ERROR
# (10,3)-(10,6) MISING
# examples/hack-sql-fake/src/SQLCommandProcessor.php
# (2,3)-(2,4) ERROR
#
bin/generate-parser
# Filter down to files with errors.
npx tree-sitter parse --quiet $@ |
cut -f1 |
# Get full errors for failing files.
xargs -r npx tree-sitter parse |
# Format errors and print file paths first followed by errors.
ruby -e "
errors = []
ARGF.each_line do |line|
# (ERROR [101, 0] - [101, 14]
# file.hack 0 ms (MISSING \";\" [229, 19] - [229, 19])
next if line !~ /\((ERROR|MISSING)( .*)? \[(\d+), (\d+)\] - \[(\d+), (\d+)\]/
errors << [
\$1, # type
\$2, # message
\$3.to_i, # line
\$4.to_i, # column
\$5.to_i, # endLine
\$6.to_i, # endColumn
]
# Tree-sitter includes the file path at the end of the parser output.
next if line !~ /(^.*\.(php|hack))\s/
puts \$1
source = File.read(\$1).split(\"\n\") << [''] # In case of trailing newline.
errors.uniq.each do |type, message, line, column, endLine, endColumn|
# Use source code as the error message for now.
if message.nil?
if line == endLine
message = source[line][column..endColumn]
else
message = [
source[line][column..],
*source[line + 1...endLine],
source[endLine][..endColumn]
].join('\n')[0..90]
end
else
message = \"#{type} #{message&.strip}\".strip
end
# Increment numbers to match VSCode's 1-indexing. Use Hack error format.
puts \"(#{line + 1},#{column + 1})-(#{endLine + 1},#{endColumn + 1}) #{message}\"
end
errors = []
end
"

@ -1,27 +0,0 @@
#!/bin/bash
set -e
source bin/require_sed
# Make Tree-sitter output look like a query.
#
# $ npx tree-sitter parse $@
# (script [0, 0] - [1, 0]
# (while_statement [0, 0] - [0, 12]
# condition: (parenthesized_expression [0, 6] - [0, 9]
# (integer [0, 7] - [0, 8]))
# body: (expression_statement [0, 10] - [0, 12]
# (integer [0, 10] - [0, 11]))))
#
# $ bin/ts-query $@
# (script
# (while_statement
# condition: (parenthesized_expression
# (integer))
# body: (expression_statement
# (integer))))
bin/generate-parser 1>/dev/null
npx tree-sitter parse $@ | $sed -e 's/ \[.*\]//'

@ -1,26 +0,0 @@
{
"targets": [
{
"target_name": "tree_sitter_hack_binding",
"include_dirs": [
"<!(node -e \"require('nan')\")",
"src"
],
"sources": [
"src/parser.c",
"bindings/node/binding.cc",
"src/scanner.cc"
],
"cflags_c": [
"-std=c99",
"-Wno-trigraphs"
],
"xcode_settings": {
# Augmented assignment coalesce ??= looks like a C trigraph. Ignore trigraphs.
"OTHER_CFLAGS": [
"-Wno-trigraphs"
]
}
}
]
}

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

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

@ -1,25 +0,0 @@
fn main() {
let src_dir = std::path::Path::new("src");
let mut c_config = cc::Build::new();
c_config.include(&src_dir);
c_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable")
.flag_if_supported("-Wno-trigraphs");
let parser_path = src_dir.join("parser.c");
c_config.file(&parser_path);
c_config.compile("parser");
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
let mut cpp_config = cc::Build::new();
cpp_config.cpp(true);
cpp_config.include(&src_dir);
cpp_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable");
let scanner_path = src_dir.join("scanner.cc");
cpp_config.file(&scanner_path);
cpp_config.compile("scanner");
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
}

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

File diff suppressed because it is too large Load Diff

@ -1,38 +0,0 @@
{
"name": "tree-sitter-hacklang",
"version": "0.0.4",
"description": "Hack grammar for tree-sitter",
"main": "bindings/node",
"keywords": [
"parser",
"lexer",
"hacklang",
"hhvm"
],
"author": "Antonio de Jesus Ochoa Solano",
"license": "MIT",
"homepage": "https://github.com/slackhq/tree-sitter-hack#readme",
"bugs": {
"url": "https://github.com/slackhq/tree-sitter-hack/issues"
},
"engines": {
"node": ">=14.7.0"
},
"dependencies": {
"nan": "^2.14.1"
},
"devDependencies": {
"tree-sitter-cli": "^0.19.5"
},
"scripts": {
"build": "bin/generate-parser --force && node-gyp build",
"test": "bin/generate-corpus && tree-sitter test",
"test-corpus": "bin/test-corpus",
"test-examples": "bin/test-examples",
"reset": "rm -rf build node_modules package-lock.json tmp/grammar.js.sha && npm install && npm run build"
},
"repository": {
"type": "git",
"url": "git+https://github.com/slackhq/tree-sitter-hack.git"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,370 +0,0 @@
#include <tree_sitter/parser.h>
#include <cwctype>
#include <string>
/**
* Debugging helper macros. Example output:
*
* > HEREDOC_START
* scan_start() <-
* next E
* next O
* next F
* del EOF
* set HEREDOC_START
* stop \n
* next \n
* scan_delimiter() <-
* scan_delimiter() -> false
* scan_start() -> true
*
* > HEREDOC_START_NEWLINE HEREDOC_BODY HEREDOC_END_NEWLINE HEREDOC_END
* scan_body() <-
* next \n
* stop $
* scan_delimiter() <-
* scan_delimiter() -> false
* set HEREDOC_START_NEWLINE
* scan_body() -> true
*/
#define debug 0
#define print(...) \
if (debug) printf(__VA_ARGS__)
#define peek() lexer->lookahead
#define next() \
{ \
print("next %s\n", str(peek()).c_str()); \
lexer->advance(lexer, false); \
}
#define skip() \
{ \
print("skip %s\n", str(peek()).c_str()); \
lexer->advance(lexer, true); \
}
#define stop() \
{ \
print("stop %s\n", str(peek()).c_str()); \
lexer->mark_end(lexer); \
}
#define set(symbol) \
{ \
print("set %s\n", TokenTypes[symbol]); \
lexer->result_symbol = symbol; \
}
#define ret(function, result) \
print("%s() -> %s\n", function, result ? "true" : "false"); \
return result;
namespace {
using std::string;
enum TokenType {
HEREDOC_START,
HEREDOC_START_NEWLINE,
HEREDOC_BODY,
HEREDOC_END_NEWLINE,
HEREDOC_END,
};
const char *TokenTypes[] = {
"HEREDOC_START", //
"HEREDOC_START_NEWLINE", //
"HEREDOC_BODY", //
"HEREDOC_END_NEWLINE", //
"HEREDOC_END", //
};
static string str(int32_t chr) {
switch (chr) {
case '\n':
return "\\n";
case '\r':
return "\\r";
case '\t':
return "\\t";
case ' ':
return "\\s";
case '\0':
return "\\0";
default:
if (iswspace(chr)) {
return "\\s";
}
string str;
str += chr;
return str;
}
}
struct Scanner {
unsigned serialize(char *buffer) {
if (delimiter.length() + 2 >= TREE_SITTER_SERIALIZATION_BUFFER_SIZE) return 0;
buffer[0] = is_nowdoc;
buffer[1] = did_start;
buffer[2] = did_end;
delimiter.copy(&buffer[3], delimiter.length());
return delimiter.length() + 3;
}
void deserialize(const char *buffer, unsigned length) {
if (length == 0) {
is_nowdoc = false;
did_start = false;
did_end = false;
delimiter.clear();
} else {
is_nowdoc = buffer[0];
did_start = buffer[1];
did_end = buffer[2];
delimiter.assign(&buffer[3], &buffer[length]);
}
}
/**
* Note: if we return false for a scan, variable value changes are overwritten with the values of
* the last successful scan. https://tree-sitter.github.io/tree-sitter/creating-parsers#serialize
*/
bool scan(TSLexer *lexer, const bool *expected) {
print("\n> ");
if (expected[HEREDOC_START]) print("%s ", TokenTypes[HEREDOC_START]);
if (expected[HEREDOC_START_NEWLINE]) print("%s ", TokenTypes[HEREDOC_START_NEWLINE]);
if (expected[HEREDOC_BODY]) print("%s ", TokenTypes[HEREDOC_BODY]);
if (expected[HEREDOC_END_NEWLINE]) print("%s ", TokenTypes[HEREDOC_END_NEWLINE]);
if (expected[HEREDOC_END]) print("%s ", TokenTypes[HEREDOC_END]);
print("\n");
if (expected[HEREDOC_BODY] || expected[HEREDOC_END]) {
return scan_body(lexer);
}
if (expected[HEREDOC_START]) {
return scan_start(lexer);
}
return false;
}
bool scan_start(TSLexer *lexer) {
print("scan_start() <-\n");
while (iswspace(peek())) skip();
is_nowdoc = peek() == '\'';
delimiter.clear();
int32_t quote = 0;
if (is_nowdoc || peek() == '"') {
quote = peek();
next();
}
if (iswalpha(peek()) || peek() == '_') {
delimiter += peek();
next();
while (iswalnum(peek()) || peek() == '_') {
delimiter += peek();
next();
}
}
print("del %s\n", delimiter.c_str());
if (peek() == quote) {
next();
} else if (quote != 0) {
// Opening quote exists, but we found no matching closing quote.
ret("scan_start", false);
}
// A valid delimiter must end with a newline with no whitespace in between.
if (peek() != '\n' || delimiter.empty()) {
return false;
}
set(HEREDOC_START);
stop();
next();
if (scan_delimiter(lexer)) {
if (peek() == ';') next();
if (peek() == '\n') {
// <<<EOF\n
// EOF; ^^ able to detect did_end
did_end = true;
}
}
ret("scan_start", true);
}
bool scan_delimiter(TSLexer *lexer) {
print("scan_delimiter() <-\n");
for (unsigned long index = 0; index < delimiter.length(); index++) {
if (delimiter[index] == peek()) {
next();
} else {
ret("scan_delimiter", false);
}
}
ret("scan_delimiter", true);
}
bool scan_body(TSLexer *lexer) {
print("scan_body() <-\n");
bool did_advance = false;
for (;;) {
if (peek() == '\0') {
return false;
}
if (peek() == '\\') {
next();
next();
did_advance = true;
continue;
}
if ((peek() == '{' || peek() == '$') && !is_nowdoc) {
stop();
if (peek() == '{') next();
if (peek() == '$') {
next();
if (is_identifier_start_char(peek())) {
set(HEREDOC_BODY);
ret("scan_body", did_advance);
}
}
did_advance = true;
continue;
}
if (did_end || peek() == '\n') {
if (did_advance) {
// <<<EOF
// x \n
// EOF; ^^ able to detect did_end
stop();
next();
} else if (peek() == '\n') {
if (did_end) {
// Detected did_end in a previous HEREDOC_BODY or HEREDOC_START scan. Can skip newline.
//
// <<<EOF\n
// EOF; ^^ detected did_end during HEREDOC_START scan
///
// <<<EOF
// x \n
// EOF; ^^ detected did_end during HEREDOC_BODY scan
skip();
} else {
// Did not detect did_end in a previous scan. Newline could be HEREDOC_START_NEWLINE,
// HEREDOC_BODY, HEREDOC_END_NEWLINE.
//
// <<<EOF\n
// x ^^ HEREDOC_START_NEWLINE
// EOF;
//
// <<<EOF
// $variable\n
// x ^^ HEREDOC_BODY
// EOF;
//
// <<<EOF
// $variable\n
// EOF; ^^ HEREDOC_END_NEWLINE
next();
stop();
}
}
if (scan_delimiter(lexer)) {
if (!did_advance && did_end) stop();
if (peek() == ';') next();
if (peek() == '\n') {
if (did_advance) {
set(HEREDOC_BODY);
did_start = true;
did_end = true;
} else if (did_end) {
set(HEREDOC_END);
delimiter.clear();
is_nowdoc = false;
did_start = false;
did_end = false;
} else {
set(HEREDOC_END_NEWLINE);
did_start = true;
did_end = true;
}
ret("scan_body", true);
}
} else if (!did_start && !did_advance) {
did_start = true;
set(HEREDOC_START_NEWLINE);
ret("scan_body", true);
}
did_advance = true;
continue;
}
next();
did_advance = true;
}
}
// This function returns true if c is a valid starting character of a name/identifier
bool is_identifier_start_char(int32_t c) {
return (c == '_') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || (128 <= c && c <= 255);
}
string delimiter;
bool is_nowdoc;
bool did_start;
bool did_end;
};
} // namespace
extern "C" {
void *tree_sitter_hack_external_scanner_create() { return new Scanner(); }
bool tree_sitter_hack_external_scanner_scan(void *payload, TSLexer *lexer, const bool *expected) {
Scanner *scanner = static_cast<Scanner *>(payload);
return scanner->scan(lexer, expected);
}
unsigned tree_sitter_hack_external_scanner_serialize(void *payload, char *state) {
Scanner *scanner = static_cast<Scanner *>(payload);
return scanner->serialize(state);
}
void tree_sitter_hack_external_scanner_deserialize(
void *payload, const char *state, unsigned length) {
Scanner *scanner = static_cast<Scanner *>(payload);
scanner->deserialize(state, length);
}
void tree_sitter_hack_external_scanner_destroy(void *payload) {
Scanner *scanner = static_cast<Scanner *>(payload);
delete scanner;
}
}

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

@ -1,25 +0,0 @@
(script
(function_declaration
(async_modifier)
name: (identifier)
(parameters)
return_type: (type_specifier)
body: (compound_statement))
(function_declaration
(async_modifier)
name: (identifier)
(type_parameters
(type_parameter
name: (identifier)
constraint_type: (type_specifier)))
(parameters)
body: (compound_statement))
(expression_statement
(lambda_expression
(async_modifier)
(parameters
(parameter
name: (variable)))
body: (binary_expression
left: (variable)
right: (integer)))))

@ -1,5 +0,0 @@
async function func0(): void {}
async function func1<T1 as int>() {}
async ($x) ==> $x + 1;

@ -1,15 +0,0 @@
(script
(function_declaration
name: (identifier)
(parameters
(parameter
(attribute_modifier
(qualified_identifier
(identifier)))
type: (type_specifier)
name: (variable)))
(attribute_modifier
(qualified_identifier
(identifier)))
return_type: (type_specifier)
body: (compound_statement)))

@ -1 +0,0 @@
function func(<<__Soft>> int $int): <<__Soft>> int {}

@ -1,22 +0,0 @@
(script
(class_declaration
name: (identifier)
(type_parameters
(type_parameter
(attribute_modifier
(qualified_identifier
(identifier)))
(reify_modifier)
name: (identifier)))
body: (member_declarations))
(function_declaration
name: (identifier)
(type_parameters
(type_parameter
(attribute_modifier
(qualified_identifier
(identifier)))
name: (identifier)))
(parameters)
return_type: (type_specifier)
body: (compound_statement)))

@ -1,3 +0,0 @@
class C<<<Reify>> reify T> {}
function func<<<Reify>> T>(): void {}

@ -1,53 +0,0 @@
(script
(alias_declaration
(attribute_modifier
(qualified_identifier
(identifier)))
(identifier)
(shape_type_specifier
(nullable_modifier)
(field_specifier
(optional_modifier)
(string)
(type_specifier))))
(alias_declaration
(attribute_modifier
(qualified_identifier
(identifier))
(arguments
(argument
(integer)))
(qualified_identifier
(identifier))
(arguments
(argument
(integer))
(argument
(integer))))
(identifier)
(function_type_specifier
(type_specifier
(qualified_identifier
(identifier)))
return_type: (type_specifier)))
(alias_declaration
(attribute_modifier
(qualified_identifier
(identifier))
(arguments
(argument
(integer)))
(qualified_identifier
(identifier))
(qualified_identifier
(identifier))
(arguments
(argument
(integer))
(argument
(integer))
(argument
(integer))))
(identifier)
as: (type_specifier)
(type_specifier)))

@ -1,10 +0,0 @@
<<A1>>
newtype T1 = ?shape(
?'int' => int
);
<<A3(1), A2(2,3,)>>
type T2 = (function(T1): string);
<<A4(1), A5, A6(1,3,4)>>
newtype T3 as int = int;

@ -1,41 +0,0 @@
(script
(class_declaration
(attribute_modifier
(qualified_identifier
(identifier))
(qualified_identifier
(identifier))
(arguments
(argument
(integer))
(argument
(integer))))
name: (identifier)
body: (member_declarations
(method_declaration
(attribute_modifier
(qualified_identifier
(identifier))
(qualified_identifier
(identifier))
(arguments
(argument
(integer))
(argument
(integer))))
name: (identifier)
(parameters)
body: (compound_statement))))
(function_declaration
(attribute_modifier
(qualified_identifier
(identifier))
(arguments
(argument
(qualified_identifier
(identifier))))
(qualified_identifier
(identifier)))
name: (identifier)
(parameters)
body: (compound_statement)))

@ -1,9 +0,0 @@
<<Attribute, Attribute(1, 2),>>
class C {
<<Attribute, Attribute(1, 2,)>>
function method() {}
}
<<Attribute(C,), Attribute>>
function func() {
}

@ -1,79 +0,0 @@
(script
(class_declaration
(abstract_modifier)
name: (identifier)
body: (member_declarations
(const_declaration
(abstract_modifier)
type: (type_specifier
(qualified_identifier
(identifier)
(identifier)))
(const_declarator
name: (identifier)))
(const_declaration
type: (type_specifier
(qualified_identifier
(identifier)
(identifier)))
(const_declarator
name: (identifier)
value: (scoped_identifier
(qualified_identifier
(identifier)
(identifier))
(identifier))))
(const_declaration
(const_declarator
name: (identifier)
value: (scoped_identifier
(qualified_identifier
(identifier)
(identifier))
(identifier))))
(const_declaration
type: (type_specifier)
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
type: (type_specifier)
(const_declarator
name: (identifier)
value: (integer))
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer))
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(abstract_modifier)
type: (type_specifier)
(const_declarator
name: (identifier)))
(const_declaration
(abstract_modifier)
type: (type_specifier)
(const_declarator
name: (identifier))
(const_declarator
name: (identifier)))
(const_declaration
(abstract_modifier)
(const_declarator
name: (identifier)))
(const_declaration
(abstract_modifier)
(const_declarator
name: (identifier))
(const_declarator
name: (identifier))))))

@ -1,15 +0,0 @@
abstract class C {
abstract const A\B C01;
const A\B C02 = A\B::C0;
const C03 = A\B::C0;
const int C1 = 1;
const int C2 = 1, C3 = 1;
const C4 = 1;
const C5 = 1, C6 = 1;
abstract const int C7;
abstract const int C8, C9;
abstract const CA;
abstract const CB, CC;
}

@ -1,21 +0,0 @@
(script
(class_declaration
name: (identifier)
body: (member_declarations
(method_declaration
(visibility_modifier)
name: (identifier)
(parameters
(parameter
(attribute_modifier
(qualified_identifier
(identifier)))
(visibility_modifier)
type: (type_specifier)
name: (variable)
default_value: (integer))
(parameter
type: (type_specifier)
(variadic_modifier)
name: (variable)))
body: (compound_statement)))))

@ -1,3 +0,0 @@
class C {
public function __construct(<<__Soft>> private int $prop = 1, string ...$name) {}
}

@ -1,62 +0,0 @@
(script
(class_declaration
(abstract_modifier)
(final_modifier)
name: (identifier)
(type_parameters
(type_parameter
name: (identifier)
constraint_type: (type_specifier
(qualified_identifier
(identifier))))
(type_parameter
name: (identifier)
constraint_type: (type_specifier
(qualified_identifier
(identifier))
(type_arguments
(type_specifier
(qualified_identifier
(identifier)))
(type_specifier
(qualified_identifier
(identifier)))))))
(extends_clause
(type_specifier
(qualified_identifier
(identifier))))
(implements_clause
(type_specifier
(qualified_identifier
(identifier)
(identifier))
(type_arguments
(type_specifier
(qualified_identifier
(identifier)))
(type_specifier
(qualified_identifier
(identifier)))))
(type_specifier
(qualified_identifier
(identifier)
(identifier))))
body: (member_declarations
(method_declaration
name: (identifier)
(type_parameters
(type_parameter
name: (identifier)
constraint_type: (type_specifier
(qualified_identifier
(identifier))))
(type_parameter
name: (identifier)
constraint_type: (type_specifier
(qualified_identifier
(identifier)))))
(parameters)
return_type: (type_specifier
(qualified_identifier
(identifier)))
body: (compound_statement)))))

@ -1,3 +0,0 @@
abstract final class F<Ta as A, Tb super B<A, C>> extends B implements A\B<A, C>, C\D {
function method<Ta as A, Tb super B>(): Tc {}
}

@ -1,50 +0,0 @@
(script
(class_declaration
name: (identifier)
(type_parameters
(type_parameter
name: (identifier)))
(extends_clause
(type_specifier
(qualified_identifier
(identifier))
(type_arguments
(type_specifier
(qualified_identifier
(identifier))))))
(implements_clause
(type_specifier
(qualified_identifier
(identifier))
(type_arguments
(type_specifier
(qualified_identifier
(identifier))))))
(where_clause
(where_constraint
constraint_left_type: (type_specifier
(qualified_identifier
(identifier)))
constraint_right_type: (type_specifier
(qualified_identifier
(identifier)))))
body: (member_declarations
(method_declaration
(visibility_modifier)
name: (identifier)
(parameters
(parameter
type: (type_specifier
(qualified_identifier
(identifier)))
name: (variable)))
(where_clause
(where_constraint
constraint_left_type: (type_specifier
(nullable_modifier)
(qualified_identifier
(identifier)))
constraint_right_type: (type_specifier
(type_arguments
(type_specifier)))))
body: (compound_statement)))))

@ -1,3 +0,0 @@
class C <T1> extends B<T2> implements A<T3> where T2 = T3 {
private function __construct(T1 $param) where ?T1 super vec<int>, {}
}

@ -1,74 +0,0 @@
(script
(class_declaration
(attribute_modifier
(qualified_identifier
(identifier))
(arguments
(argument
(scoped_identifier
(qualified_identifier
(identifier))
(identifier))))
(qualified_identifier
(identifier))
(arguments
(argument
(integer))))
name: (identifier)
(type_parameters
(type_parameter
name: (identifier)
constraint_type: (type_specifier
(qualified_identifier
(identifier))))
(type_parameter
name: (identifier)
constraint_type: (type_specifier
(qualified_identifier
(identifier))
(type_arguments
(type_specifier
(qualified_identifier
(identifier)))
(type_specifier
(qualified_identifier
(identifier)))))))
(extends_clause
(type_specifier
(qualified_identifier
(identifier))))
(implements_clause
(type_specifier
(qualified_identifier
(identifier)
(identifier))
(type_arguments
(type_specifier
(qualified_identifier
(identifier)))
(type_specifier
(qualified_identifier
(identifier)))))
(type_specifier
(qualified_identifier
(identifier)
(identifier))))
body: (member_declarations
(method_declaration
name: (identifier)
(type_parameters
(type_parameter
name: (identifier)
constraint_type: (type_specifier
(qualified_identifier
(identifier))))
(type_parameter
name: (identifier)
constraint_type: (type_specifier
(qualified_identifier
(identifier)))))
(parameters)
return_type: (type_specifier
(qualified_identifier
(identifier)))
body: (compound_statement)))))

@ -1,4 +0,0 @@
<<Attribute(R::class), Attribute(1,),>>
class F<Ta as A, Tb super B<A, C>> extends B implements A\B<A, C>, C\D {
function method<Ta as A, Tb super B>(): Tc {}
}

@ -1,92 +0,0 @@
(script
(comment)
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(comment)
(const_declaration
type: (type_specifier)
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer))))

@ -1,29 +0,0 @@
// Kinda wish this wasn't allowed. Seems like asking for trouble.
const type = 1;
const newtype = 1;
// 🤦
const int int = 1;
const bool = 1;
const float = 1;
const int = 1;
const string = 1;
const arraykey = 1;
const void = 1;
const nonnull = 1;
const null = 1;
const mixed = 1;
const dynamic = 1;
const noreturn = 1;
const array = 1;
const varray = 1;
const darray = 1;
const vec = 1;
const dict = 1;
const keyset = 1;
const tuple = 1;
const shape = 1;

@ -1,25 +0,0 @@
(script
(const_declaration
type: (type_specifier)
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
type: (type_specifier)
(const_declarator
name: (identifier)
value: (integer))
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer)))
(const_declaration
(const_declarator
name: (identifier)
value: (integer))
(const_declarator
name: (identifier)
value: (integer))))

@ -1,4 +0,0 @@
const int C1 = 1;
const int C2 = 1, C3 = 1;
const C4 = 1;
const C5 = 1, C6 = 1;

@ -1,25 +0,0 @@
(script
(namespace_declaration
body: (compound_statement
(function_declaration
(attribute_modifier
(qualified_identifier
(identifier))
(qualified_identifier
(identifier)))
name: (identifier)
(parameters
(parameter
name: (variable)))
return_type: (type_specifier))
(function_declaration
(attribute_modifier
(qualified_identifier
(identifier))
(qualified_identifier
(identifier)))
name: (identifier)
(parameters
(parameter
name: (variable)))
return_type: (type_specifier)))))

@ -1,6 +0,0 @@
namespace {
<<__PHPStdLib, __Pure>>
function is_bool($var): bool;
<<__PHPStdLib, __Pure>>
function is_int($var): bool;
}

@ -1,11 +0,0 @@
(script
(enum_declaration
name: (identifier)
type: (type_specifier)
as: (type_specifier)
(enumerator
(identifier)
(integer))
(enumerator
(identifier)
(integer))))

@ -1,4 +0,0 @@
enum Enum: int as int {
F1 = 1;
F2 = 8;
}

@ -1,27 +0,0 @@
(script
(enum_declaration
name: (identifier)
type: (type_specifier))
(enum_declaration
(attribute_modifier
(qualified_identifier
(identifier)))
name: (identifier)
type: (type_specifier)
(enumerator
(identifier)
(integer))
(enumerator
(identifier)
(integer))
(enumerator
(identifier)
(scoped_identifier
(qualified_identifier
(identifier))
(identifier)))
(enumerator
(identifier)
(binary_expression
left: (string)
right: (string)))))

@ -1,9 +0,0 @@
enum Enum: int {}
<<Beenum>>
enum Enum : int {
F1 = 1;
F2 = 8;
F3 = C::CONST;
F4 = 'a'.'b';
}

@ -1,16 +0,0 @@
(script
(function_declaration
name: (identifier)
(parameters
(parameter
(attribute_modifier
(qualified_identifier
(identifier)))
(inout_modifier)
type: (type_specifier)
name: (variable))
(parameter
(inout_modifier)
type: (type_specifier)
name: (variable)))
body: (compound_statement)))

@ -1 +0,0 @@
function func(<<__Soft>> inout int $arg1, inout int $arg2) {}

@ -1,12 +0,0 @@
(script
(function_declaration
name: (identifier)
(parameters
(parameter
(attribute_modifier
(qualified_identifier
(identifier)))
type: (type_specifier)
(variadic_modifier)
name: (variable)))
body: (compound_statement)))

@ -1 +0,0 @@
function func(<<__Soft>> int ...$arg1) {}

@ -1,15 +0,0 @@
(script
(function_declaration
name: (identifier)
(type_parameters
(type_parameter
name: (identifier))
(type_parameter
name: (identifier)
constraint_type: (type_specifier))
(type_parameter
name: (identifier)
constraint_type: (type_specifier)))
(parameters)
return_type: (type_specifier)
body: (compound_statement)))

@ -1 +0,0 @@
function func<Ta, Tb as int, Td super int>(): void {}

@ -1,21 +0,0 @@
(script
(alias_declaration
(identifier)
(function_type_specifier
(type_specifier)
(type_specifier
(nullable_modifier))
return_type: (type_specifier)))
(function_declaration
name: (identifier)
(parameters
(parameter
type: (function_type_specifier
(inout_modifier)
(type_specifier)
return_type: (type_specifier))
name: (variable)))
return_type: (function_type_specifier
(type_specifier)
return_type: (type_specifier))
body: (compound_statement)))

@ -1,3 +0,0 @@
type func = (function(int, ?string,): string);
function func((function(inout int): string) $func): (function(int): string) {}

@ -1,57 +0,0 @@
(script
(function_declaration
name: (identifier)
(type_parameters
(type_parameter
name: (identifier)))
(parameters)
(where_clause
(where_constraint
constraint_left_type: (type_specifier
(qualified_identifier
(identifier)))
constraint_right_type: (type_specifier)))
body: (compound_statement))
(function_declaration
name: (identifier)
(type_parameters
(type_parameter
name: (identifier)))
(parameters)
(where_clause
(where_constraint
constraint_left_type: (type_specifier
(nullable_modifier)
(type_arguments
(type_specifier
(qualified_identifier
(identifier)))))
constraint_right_type: (type_specifier))
(where_constraint
constraint_left_type: (type_specifier
(qualified_identifier
(identifier)))
constraint_right_type: (type_specifier)))
body: (compound_statement))
(comment)
(function_declaration
name: (identifier)
(type_parameters
(type_parameter
name: (identifier)))
(parameters)
(where_clause
(where_constraint
constraint_left_type: (type_specifier
(nullable_modifier)
(type_arguments
(type_specifier
(qualified_identifier
(identifier)))))
constraint_right_type: (type_specifier))
(where_constraint
constraint_left_type: (type_specifier
(qualified_identifier
(identifier)))
constraint_right_type: (type_specifier)))
body: (compound_statement)))

@ -1,6 +0,0 @@
function func1<T>() where T = int, {}
function func2<T>() where ?vec<T> = int, T super int {}
# Optional comma. Why tho?
function func3<T>() where ?vec<T> = int T super int {}

@ -1,35 +0,0 @@
(script
(function_declaration
name: (identifier)
(type_parameters
(type_parameter
name: (identifier)))
(parameters)
return_type: (type_specifier
(qualified_identifier
(identifier)))
(where_clause
(where_constraint
constraint_left_type: (type_specifier
(qualified_identifier
(identifier)))
constraint_right_type: (type_specifier)))
body: (compound_statement))
(function_declaration
name: (identifier)
(type_parameters
(type_parameter
name: (identifier)))
(parameters)
return_type: (type_specifier
(qualified_identifier
(identifier)))
(where_clause
(where_constraint
constraint_left_type: (type_specifier
(type_arguments
(type_specifier
(qualified_identifier
(identifier)))))
constraint_right_type: (type_specifier)))
body: (compound_statement)))

@ -1,3 +0,0 @@
function func1<T>(): T where T as int {}
function func2<T>(): T where vec<T> = int {}

@ -1,43 +0,0 @@
(script
(function_declaration
name: (identifier)
(parameters)
return_type: (type_specifier)
body: (compound_statement))
(function_declaration
name: (identifier)
(parameters
(variadic_modifier))
body: (compound_statement))
(function_declaration
name: (identifier)
(parameters
(parameter
name: (variable)))
body: (compound_statement))
(function_declaration
name: (identifier)
(parameters
(parameter
type: (type_specifier)
name: (variable)))
body: (compound_statement))
(function_declaration
name: (identifier)
(parameters
(parameter
type: (type_specifier)
name: (variable)))
return_type: (type_specifier)
body: (compound_statement))
(function_declaration
name: (identifier)
(parameters
(parameter
type: (type_specifier)
name: (variable))
(parameter
type: (type_specifier)
name: (variable)))
return_type: (type_specifier)
body: (compound_statement)))

Some files were not shown because too many files have changed in this diff Show More