Merge commit '1aafaff4d26dac5a36dd3495be33e1c20161d761'

pull/708/head
Wilfred Hughes 2024-04-28 23:30:09 +07:00
commit 27fb722ac7
54 changed files with 96256 additions and 88133 deletions

@ -12,7 +12,7 @@ Since difftastic is now conservative with parse errors
(DFT_PARSE_ERROR_LIMIT is 0 by default), this seems like a better
tradeoff.
Updated CSS, Go, Lua and Python parsers.
Updated C, CSS, Go, Lua and Python parsers.
### Diffing

@ -1,22 +0,0 @@
image: Visual Studio 2022
environment:
nodejs_version: "18"
platform:
- x64
install:
- ps: Install-Product node $env:nodejs_version
- node --version
- npm --version
- npm install
test_script:
- npm run test-windows
build: off
branches:
only:
- master

@ -0,0 +1,39 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{json,toml,yml,gyp}]
indent_style = space
indent_size = 2
[*.js]
indent_style = space
indent_size = 2
[*.rs]
indent_style = space
indent_size = 4
[*.{c,cc,h}]
indent_style = space
indent_size = 4
[*.{py,pyi}]
indent_style = space
indent_size = 4
[*.swift]
indent_style = space
indent_size = 4
[*.go]
indent_style = tab
indent_size = 8
[Makefile]
indent_style = tab
indent_size = 8

@ -1,20 +0,0 @@
module.exports = {
'env': {
'commonjs': true,
'es2021': true,
},
'extends': 'google',
'overrides': [
],
'parserOptions': {
'ecmaVersion': 'latest',
'sourceType': 'module',
},
'rules': {
'indent': ['error', 2, {'SwitchCase': 1}],
'max-len': [
'error',
{'code': 120, 'ignoreComments': true, 'ignoreUrls': true, 'ignoreStrings': true},
],
},
};

@ -1,6 +1,14 @@
/src/** linguist-vendored
/examples/* linguist-vendored
* text eol=lf
test/corpus/crlf.txt text eol=crlf
src/grammar.json -diff
src/node-types.json -diff
src/parser.c -diff
examples/* linguist-vendored
src/*.json linguist-generated
src/parser.c linguist-generated
src/tree_sitter/* linguist-generated
bindings/** linguist-generated
binding.gyp linguist-generated
setup.py linguist-generated
Makefile linguist-generated
Package.swift linguist-generated

@ -0,0 +1,59 @@
name: Bug Report
description: File a bug or issue
title: "bug: "
labels: [bug]
body:
- type: markdown
attributes:
value: |
**Before** reporting an issue, make sure to search [existing issues](https://github.com/tree-sitter/tree-sitter-c/issues). Usage questions such as ***"How do I...?"*** either belong in [Discussions](https://github.com/tree-sitter/tree-sitter/discussions) upstream or in our [Discord server](https://discord.gg/w7nTvsVJhm) and will be closed.
If your issue is related to a bug in your editor-experience because your editor *leverages* tree-sitter and this parser, then it is likely your issue does *NOT* belong here and belongs in the relevant editor's repository.
- type: checkboxes
attributes:
label: Did you check existing issues?
description: Make sure you've checked all of the below before submitting an issue
options:
- label: I have read all the [tree-sitter docs](https://tree-sitter.github.io/tree-sitter/using-parsers) if it relates to using the parser
required: false
- label: I have searched the existing issues of tree-sitter-c
required: true
- type: input
attributes:
label: "Tree-Sitter CLI Version, if relevant (output of `tree-sitter --version`)"
placeholder: "tree-sitter 0.20.8 (6bbb50bef8249e6460e7d69e42cc8146622fa4fd)"
validations:
required: false
- type: textarea
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is. Please include any related errors you see such as parsing errors or tree-sitter cli errors.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce/Bad Parse Tree
description: Steps to reproduce the behavior. If you have a bad parse tree, please include it here. You can get this by running `tree-sitter parse <path-to-file>` and copying the output.
placeholder: |
1.
2.
3.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior/Parse Tree
description: A concise description of what you expected to happen, or in the case of a bad parse tree, the expected parse tree.
validations:
required: true
- type: textarea
attributes:
label: Repro
description: Minimal code to reproduce this issue. Ideally this should be reproducible with the C library or the tree-sitter cli, do not suggest an editor or external tool.
value: |
// Example code that causes the issue
void foo() {
// Code that fails to parse, or causes an error
}
render: C
validations:
required: false

@ -0,0 +1,36 @@
name: Feature Request
description: Suggest a new feature
title: "feature: "
labels: [enhancement]
body:
- type: checkboxes
attributes:
label: Did you check the tree-sitter docs?
description: Make sure you read all the docs before submitting a feature request
options:
- label: I have read all the [tree-sitter docs](https://tree-sitter.github.io/tree-sitter/using-parsers) if it relates to using the parser
required: false
- type: textarea
validations:
required: true
attributes:
label: Is your feature request related to a problem? Please describe.
description: A clear and concise description of what the problem is. Ex. I think the grammar models this rule incorrectly and can be improved, or the C spec has officially added a new feature that should be added to the grammar.
- type: textarea
validations:
required: true
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
- type: textarea
validations:
required: true
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
- type: textarea
validations:
required: false
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here. If your feature request is related to a new C feature, please include a link to the relevant **official** C documentation.

@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
commit-message:
prefix: "ci"

@ -1,30 +1,44 @@
name: CI
on:
workflow_dispatch:
pull_request:
push:
branches: [master]
paths:
- grammar.js
- src/**
- test/**
- bindings/**
- binding.gyp
pull_request:
paths:
- grammar.js
- src/**
- test/**
- bindings/**
- binding.gyp
concurrency:
group: ${{github.workflow}}-${{github.ref}}
cancel-in-progress: true
jobs:
test:
runs-on: ${{ matrix.os }}
name: Test parser
runs-on: ${{matrix.os}}
strategy:
fail-fast: true
fail-fast: false
matrix:
os: [macos-latest, ubuntu-latest]
os: [ubuntu-latest, windows-latest, macos-14]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up tree-sitter
uses: tree-sitter/setup-action/cli@v1
- name: Run tests
uses: tree-sitter/parser-test-action@v2
with:
node-version: 18
- run: npm install
- run: npm test
test_windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
test-rust: ${{runner.os == 'Linux'}}
- name: Parse examples
uses: tree-sitter/parse-action@v4
with:
node-version: 18
- run: npm install
- run: npm run test-windows
files: examples/*

@ -2,18 +2,25 @@ name: Lint
on:
push:
branches:
- master
branches: [master]
paths:
- grammar.js
pull_request:
branches:
- "**"
paths:
- grammar.js
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
cache: npm
node-version: ${{vars.NODE_VERSION}}
- name: Install modules
run: npm install
run: npm ci --legacy-peer-deps
- name: Run ESLint
run: npm run lint

@ -0,0 +1,23 @@
name: Publish packages
on:
push:
tags: ["*"]
concurrency:
group: ${{github.workflow}}-${{github.ref}}
cancel-in-progress: true
jobs:
npm:
uses: tree-sitter/workflows/.github/workflows/package-npm.yml@main
secrets:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
crates:
uses: tree-sitter/workflows/.github/workflows/package-crates.yml@main
secrets:
CARGO_REGISTRY_TOKEN: ${{secrets.CARGO_REGISTRY_TOKEN}}
pypi:
uses: tree-sitter/workflows/.github/workflows/package-pypi.yml@main
secrets:
PYPI_API_TOKEN: ${{secrets.PYPI_API_TOKEN}}

@ -1,103 +0,0 @@
name: Release
on:
workflow_run:
workflows: ["CI"]
branches:
- master
types:
- completed
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get previous commit SHA
id: get_previous_commit
run: |
LATEST_TAG=$(git describe --tags --abbrev=0)
if [[ -z "$LATEST_TAG" ]]; then
echo "No tag found. Failing..."
exit 1
fi
echo "latest_tag=${LATEST_TAG#v}" >> "$GITHUB_ENV" # Remove 'v' prefix from the tag
- name: Check if version changed and is greater than the previous
id: version_check
run: |
# Compare the current version with the version from the previous commit
PREVIOUS_NPM_VERSION=${{ env.latest_tag }}
CURRENT_NPM_VERSION=$(jq -r '.version' package.json)
CURRENT_CARGO_VERSION=$(awk -F '"' '/^version/ {print $2}' Cargo.toml)
if [[ "$CURRENT_NPM_VERSION" != "$CURRENT_CARGO_VERSION" ]]; then # Cargo.toml and package.json versions must match
echo "Mismatch: NPM version ($CURRENT_NPM_VERSION) and Cargo.toml version ($CURRENT_CARGO_VERSION)"
echo "version_changed=false" >> "$GITHUB_ENV"
else
if [[ "$PREVIOUS_NPM_VERSION" == "$CURRENT_NPM_VERSION" ]]; then
echo "version_changed=" >> "$GITHUB_ENV"
else
IFS='.' read -ra PREVIOUS_VERSION_PARTS <<< "$PREVIOUS_NPM_VERSION"
IFS='.' read -ra CURRENT_VERSION_PARTS <<< "$CURRENT_NPM_VERSION"
VERSION_CHANGED=false
for i in "${!PREVIOUS_VERSION_PARTS[@]}"; do
if [[ ${CURRENT_VERSION_PARTS[i]} -gt ${PREVIOUS_VERSION_PARTS[i]} ]]; then
VERSION_CHANGED=true
break
elif [[ ${CURRENT_VERSION_PARTS[i]} -lt ${PREVIOUS_VERSION_PARTS[i]} ]]; then
break
fi
done
echo "version_changed=$VERSION_CHANGED" >> "$GITHUB_ENV"
echo "current_version=${CURRENT_NPM_VERSION}" >> "$GITHUB_ENV"
fi
fi
- name: Display result
run: |
echo "Version bump detected: ${{ env.version_changed }}"
- name: Fail if version is lower
if: env.version_changed == 'false'
run: exit 1
- name: Setup Node
if: env.version_changed == 'true'
uses: actions/setup-node@v3
with:
node-version: 18
registry-url: "https://registry.npmjs.org"
- name: Publish to NPM
if: env.version_changed == 'true'
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
run: npm publish
- name: Setup Rust
if: env.version_changed == 'true'
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Publish to Crates.io
if: env.version_changed == 'true'
uses: katyo/publish-crates@v2
with:
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
- name: Tag versions
if: env.version_changed == 'true'
run: |
git checkout master
git config user.name github-actions[bot]
git config user.email github-actions[bot]@users.noreply.github.com
git tag -d "v${{ env.current_version }}" || true
git push origin --delete "v${{ env.current_version }}" || true
git tag -a "v${{ env.current_version }}" -m "Version ${{ env.current_version }}"
git push origin "v${{ env.current_version }}"

@ -1,6 +1,32 @@
# Rust artifacts
Cargo.lock
node_modules
build
package-lock.json
/target/
.build/
target/
# Node artifacts
build/
prebuilds/
node_modules/
# Swift artifacts
.build/
# Python artifacts
dist/
*.egg-info
*.whl
# C artifacts
*.a
*.so
*.so.*
*.dylib
*.dll
*.pc
# Examples
/examples/*/
# Grammar volatiles
*.wasm
*.obj
*.o

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

@ -1,5 +0,0 @@
language: node_js
sudo: false
node_js: 10

@ -1,14 +1,16 @@
[package]
name = "tree-sitter-c"
description = "C grammar for the tree-sitter parsing library"
version = "0.20.4"
authors = ["Max Brunsfeld <maxbrunsfeld@gmail.com>"]
description = "C grammar for tree-sitter"
version = "0.21.1"
authors = [
"Max Brunsfeld <maxbrunsfeld@gmail.com>",
"Amaan Qureshi <amaanq12@gmail.com>",
]
license = "MIT"
readme = "bindings/rust/README.md"
keywords = ["incremental", "parsing", "c"]
keywords = ["incremental", "parsing", "tree-sitter", "c"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/tree-sitter/tree-sitter-c"
edition = "2018"
edition = "2021"
autoexamples = false
build = "bindings/rust/build.rs"
@ -18,7 +20,7 @@ include = ["bindings/rust/*", "grammar.js", "queries/*", "src/*"]
path = "bindings/rust/lib.rs"
[dependencies]
tree-sitter = "0.20.10"
tree-sitter = ">=0.21.0"
[build-dependencies]
cc = "1.0"
cc = "1.0.90"

@ -0,0 +1,111 @@
VERSION := 0.21.1
LANGUAGE_NAME := tree-sitter-c
# repository
SRC_DIR := src
PARSER_REPO_URL := $(shell git -C $(SRC_DIR) remote get-url origin 2>/dev/null)
ifeq ($(PARSER_URL),)
PARSER_URL := $(subst .git,,$(PARSER_REPO_URL))
ifeq ($(shell echo $(PARSER_URL) | grep '^[a-z][-+.0-9a-z]*://'),)
PARSER_URL := $(subst :,/,$(PARSER_URL))
PARSER_URL := $(subst git@,https://,$(PARSER_URL))
endif
endif
TS ?= tree-sitter
# ABI versioning
SONAME_MAJOR := $(word 1,$(subst ., ,$(VERSION)))
SONAME_MINOR := $(word 2,$(subst ., ,$(VERSION)))
# install directory layout
PREFIX ?= /usr/local
INCLUDEDIR ?= $(PREFIX)/include
LIBDIR ?= $(PREFIX)/lib
PCLIBDIR ?= $(LIBDIR)/pkgconfig
# object files
OBJS := $(patsubst %.c,%.o,$(wildcard $(SRC_DIR)/*.c))
# flags
ARFLAGS := rcs
override CFLAGS += -I$(SRC_DIR) -std=c11 -fPIC
# OS-specific bits
ifeq ($(OS),Windows_NT)
$(error "Windows is not supported")
else ifeq ($(shell uname),Darwin)
SOEXT = dylib
SOEXTVER_MAJOR = $(SONAME_MAJOR).dylib
SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).dylib
LINKSHARED := $(LINKSHARED)-dynamiclib -Wl,
ifneq ($(ADDITIONAL_LIBS),)
LINKSHARED := $(LINKSHARED)$(ADDITIONAL_LIBS),
endif
LINKSHARED := $(LINKSHARED)-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SONAME_MAJOR).dylib,-rpath,@executable_path/../Frameworks
else
SOEXT = so
SOEXTVER_MAJOR = so.$(SONAME_MAJOR)
SOEXTVER = so.$(SONAME_MAJOR).$(SONAME_MINOR)
LINKSHARED := $(LINKSHARED)-shared -Wl,
ifneq ($(ADDITIONAL_LIBS),)
LINKSHARED := $(LINKSHARED)$(ADDITIONAL_LIBS)
endif
LINKSHARED := $(LINKSHARED)-soname,lib$(LANGUAGE_NAME).so.$(SONAME_MAJOR)
endif
ifneq ($(filter $(shell uname),FreeBSD NetBSD DragonFly),)
PCLIBDIR := $(PREFIX)/libdata/pkgconfig
endif
all: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc
lib$(LANGUAGE_NAME).a: $(OBJS)
$(AR) $(ARFLAGS) $@ $^
lib$(LANGUAGE_NAME).$(SOEXT): $(OBJS)
$(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@
ifneq ($(STRIP),)
$(STRIP) $@
endif
$(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in
sed -e 's|@URL@|$(PARSER_URL)|' \
-e 's|@VERSION@|$(VERSION)|' \
-e 's|@LIBDIR@|$(LIBDIR)|' \
-e 's|@INCLUDEDIR@|$(INCLUDEDIR)|' \
-e 's|@REQUIRES@|$(REQUIRES)|' \
-e 's|@ADDITIONAL_LIBS@|$(ADDITIONAL_LIBS)|' \
-e 's|=$(PREFIX)|=$${prefix}|' \
-e 's|@PREFIX@|$(PREFIX)|' $< > $@
$(SRC_DIR)/parser.c: grammar.js
$(TS) generate --no-bindings
install: all
install -d '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)'
install -m644 bindings/c/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h
install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc
install -m644 lib$(LANGUAGE_NAME).a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a
install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER)
ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR)
ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT)
uninstall:
$(RM) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a \
'$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) \
'$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) \
'$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) \
'$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h \
'$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc
clean:
$(RM) $(OBJS) $(LANGUAGE_NAME).pc lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT)
test:
$(TS) test
$(TS) parse examples/* --quiet --time
.PHONY: all install uninstall clean test

@ -3,7 +3,6 @@ import PackageDescription
let package = Package(
name: "TreeSitterC",
platforms: [.macOS(.v10_13), .iOS(.v11)],
products: [
.library(name: "TreeSitterC", targets: ["TreeSitterC"]),
],
@ -12,17 +11,27 @@ let package = Package(
.target(name: "TreeSitterC",
path: ".",
exclude: [
"binding.gyp",
"bindings",
"Cargo.toml",
"examples",
"grammar.js",
"LICENSE",
"Makefile",
"binding.gyp",
"bindings/c",
"bindings/go",
"bindings/node",
"bindings/python",
"bindings/rust",
"prebuilds",
"grammar.js",
"package.json",
"README.md",
"src/grammar.json",
"src/node-types.json",
"package-lock.json",
"pyproject.toml",
"setup.py",
"test",
"examples",
".editorconfig",
".github",
".gitignore",
".gitattributes",
".gitmodules",
],
sources: [
"src/parser.c",
@ -32,5 +41,6 @@ let package = Package(
],
publicHeadersPath: "bindings/swift",
cSettings: [.headerSearchPath("src")])
]
],
cLanguageStandard: .c11
)

@ -1,7 +1,18 @@
# tree-sitter-c
[![Build Status](https://travis-ci.org/tree-sitter/tree-sitter-c.svg?branch=master)](https://travis-ci.org/tree-sitter/tree-sitter-c)
[![Build status](https://ci.appveyor.com/api/projects/status/7u0sy6ajmxro4wfh/branch/master?svg=true)](https://ci.appveyor.com/project/maxbrunsfeld/tree-sitter-c/branch/master)
[![CI][ci]](https://github.com/tree-sitter/tree-sitter-c/actions/workflows/ci.yml)
[![discord][discord]](https://discord.gg/w7nTvsVJhm)
[![matrix][matrix]](https://matrix.to/#/#tree-sitter-chat:matrix.org)
[![crates][crates]](https://crates.io/crates/tree-sitter-c)
[![npm][npm]](https://www.npmjs.com/package/tree-sitter-c)
[![pypi][pypi]](https://pypi.org/project/tree-sitter-c)
C grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter).
Adapted from [this C99 grammar](http://slps.github.io/zoo/c/iso-9899-tc3.html).
[ci]: https://img.shields.io/github/actions/workflow/status/tree-sitter/tree-sitter-c/ci.yml?logo=github&label=CI
[discord]: https://img.shields.io/discord/1063097320771698699?logo=discord&label=discord
[matrix]: https://img.shields.io/matrix/tree-sitter-chat%3Amatrix.org?logo=matrix&label=matrix
[npm]: https://img.shields.io/npm/v/tree-sitter-c?logo=npm
[crates]: https://img.shields.io/crates/v/tree-sitter-c?logo=rust
[pypi]: https://img.shields.io/pypi/v/tree-sitter-c?logo=pypi&logoColor=ffd242

@ -2,17 +2,19 @@
"targets": [
{
"target_name": "tree_sitter_c_binding",
"dependencies": [
"<!(node -p \"require('node-addon-api').targets\"):node_addon_api_except",
],
"include_dirs": [
"<!(node -e \"require('nan')\")",
"src"
"src",
],
"sources": [
"bindings/node/binding.cc",
"src/parser.c",
"bindings/node/binding.cc"
],
"cflags_c": [
"-std=c99",
]
"-std=c11",
],
}
]
}

@ -0,0 +1,16 @@
#ifndef TREE_SITTER_C_H_
#define TREE_SITTER_C_H_
typedef struct TSLanguage TSLanguage;
#ifdef __cplusplus
extern "C" {
#endif
const TSLanguage *tree_sitter_c(void);
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_C_H_

@ -0,0 +1,11 @@
prefix=@PREFIX@
libdir=@LIBDIR@
includedir=@INCLUDEDIR@
Name: tree-sitter-c
Description: C grammar for tree-sitter
URL: @URL@
Version: @VERSION@
Requires: @REQUIRES@
Libs: -L${libdir} @ADDITIONAL_LIBS@ -ltree-sitter-c
Cflags: -I${includedir}

@ -0,0 +1,12 @@
package tree_sitter_c
// #cgo CFLAGS: -std=c11 -fPIC
// #include "../../src/parser.c"
import "C"
import "unsafe"
// Get the tree-sitter Language for this grammar.
func Language() unsafe.Pointer {
return unsafe.Pointer(C.tree_sitter_c())
}

@ -0,0 +1,15 @@
package tree_sitter_c_test
import (
"testing"
tree_sitter "github.com/smacker/go-tree-sitter"
"github.com/tree-sitter/tree-sitter-c"
)
func TestCanLoadGrammar(t *testing.T) {
language := tree_sitter.NewLanguage(tree_sitter_c.Language())
if language == nil {
t.Errorf("Error loading C grammar")
}
}

@ -0,0 +1,5 @@
module github.com/tree-sitter/tree-sitter-c
go 1.22
require github.com/smacker/go-tree-sitter v0.0.0-20230720070738-0d0a9f78d8f8

@ -1,30 +1,20 @@
#include "nan.h"
#include "tree_sitter/parser.h"
#include <node.h>
#include <napi.h>
using namespace v8;
typedef struct TSLanguage TSLanguage;
extern "C" TSLanguage *tree_sitter_c();
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_c());
Nan::Set(instance, Nan::New("name").ToLocalChecked(),
Nan::New("c").ToLocalChecked());
Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance);
// "tree-sitter", "language" hashed with BLAKE2
const napi_type_tag LANGUAGE_TYPE_TAG = {
0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16
};
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports["name"] = Napi::String::New(env, "c");
auto language = Napi::External<TSLanguage>::New(env, tree_sitter_c());
language.TypeTag(&LANGUAGE_TYPE_TAG);
exports["language"] = language;
return exports;
}
NODE_MODULE(tree_sitter_c_binding, Init)
} // namespace
NODE_API_MODULE(tree_sitter_c_binding, Init)

@ -0,0 +1,28 @@
type BaseNode = {
type: string;
named: boolean;
};
type ChildNode = {
multiple: boolean;
required: boolean;
types: BaseNode[];
};
type NodeInfo =
| (BaseNode & {
subtypes: BaseNode[];
})
| (BaseNode & {
fields: { [name: string]: ChildNode };
children: ChildNode[];
});
type Language = {
name: string;
language: unknown;
nodeTypeInfo: NodeInfo[];
};
declare const language: Language;
export = language;

@ -1,19 +1,7 @@
try {
module.exports = require('../../build/Release/tree_sitter_c_binding');
} catch (error1) {
if (error1.code !== 'MODULE_NOT_FOUND') {
throw error1;
}
try {
module.exports = require('../../build/Debug/tree_sitter_c_binding');
} catch (error2) {
if (error2.code !== 'MODULE_NOT_FOUND') {
throw error2;
}
throw error1;
}
}
const root = require("path").join(__dirname, "..", "..");
module.exports = require("node-gyp-build")(root);
try {
module.exports.nodeTypeInfo = require('../../src/node-types.json');
module.exports.nodeTypeInfo = require("../../src/node-types.json");
} catch (_) {}

@ -0,0 +1,5 @@
"C grammar for tree-sitter"
from ._binding import language
__all__ = ["language"]

@ -0,0 +1 @@
def language() -> int: ...

@ -0,0 +1,27 @@
#include <Python.h>
typedef struct TSLanguage TSLanguage;
TSLanguage *tree_sitter_c(void);
static PyObject* _binding_language(PyObject *self, PyObject *args) {
return PyLong_FromVoidPtr(tree_sitter_c());
}
static PyMethodDef methods[] = {
{"language", _binding_language, METH_NOARGS,
"Get the tree-sitter language for this grammar."},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "_binding",
.m_doc = NULL,
.m_size = -1,
.m_methods = methods
};
PyMODINIT_FUNC PyInit__binding(void) {
return PyModule_Create(&module);
}

@ -1,37 +0,0 @@
# tree-sitter-c
This crate provides a C grammar for the [tree-sitter][] parsing library. To
use this crate, add it to the `[dependencies]` section of your `Cargo.toml`
file. (Note that you will probably also need to depend on the
[`tree-sitter`][tree-sitter crate] crate to use the parsed result in any useful
way.)
``` toml
[dependencies]
tree-sitter = "0.17"
tree-sitter-c = "0.16"
```
Typically, you will use the [language][language func] function to add this
grammar to a tree-sitter [Parser][], and then use the parser to parse some code:
``` rust
let code = r#"
int double(int x) {
return x * 2;
}
"#;
let mut parser = Parser::new();
parser.set_language(tree_sitter_c::language()).expect("Error loading C grammar");
let parsed = parser.parse(code, None);
```
If you have any questions, please reach out to us in the [tree-sitter
discussions] page.
[Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
[language func]: https://docs.rs/tree-sitter-c/*/tree_sitter_c/fn.language.html
[Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
[tree-sitter]: https://tree-sitter.github.io/
[tree-sitter crate]: https://crates.io/crates/tree-sitter
[tree-sitter discussions]: https://github.com/tree-sitter/tree-sitter/discussions

@ -1,17 +1,12 @@
use std::path::Path;
extern crate cc;
fn main() {
let src_dir = Path::new("src");
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");
c_config.std("c11").include(src_dir);
let parser_path = src_dir.join("parser.c");
c_config.file(&parser_path);
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
c_config.compile("parser");
c_config.compile("tree-sitter-c");
}

@ -1,28 +1,20 @@
// -*- coding: utf-8 -*-
// ------------------------------------------------------------------------------------------------
// Copyright © 2021, tree-sitter-c authors.
// See the LICENSE file in this repo for license details.
// ------------------------------------------------------------------------------------------------
//! This crate provides a C grammar for the [tree-sitter][] parsing library.
//! This crate provides C language support for the [tree-sitter][] parsing library.
//!
//! Typically, you will use the [language][language func] function to add this grammar to a
//! 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:
//!
//! ```
//! use tree_sitter::Parser;
//!
//! let code = r#"
//! int double(int x) {
//! return x * 2;
//! }
//! int double(int x) {
//! return x * 2;
//! }
//! "#;
//! let mut parser = Parser::new();
//! parser.set_language(tree_sitter_c::language()).expect("Error loading C grammar");
//! let parsed = parser.parse(code, None);
//! # let parsed = parsed.unwrap();
//! # let root = parsed.root_node();
//! # assert!(!root.has_error());
//! parser.set_language(&tree_sitter_c::language()).expect("Error loading C grammar");
//! let tree = parser.parse(code, None).unwrap();
//! assert!(!tree.root_node().has_error());
//! ```
//!
//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
@ -36,31 +28,31 @@ extern "C" {
fn tree_sitter_c() -> Language;
}
/// Returns the tree-sitter [Language][] for this grammar.
/// 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_c() }
}
/// The source of the C tree-sitter grammar description.
pub const GRAMMAR: &str = include_str!("../../grammar.js");
/// The syntax highlighting query for this language.
pub const HIGHLIGHT_QUERY: &str = include_str!("../../queries/highlights.scm");
/// 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: &str = include_str!("../../src/node-types.json");
/// The syntax highlighting query for this language.
pub const HIGHLIGHT_QUERY: &str = include_str!("../../queries/highlights.scm");
/// The symbol tagging query for this language.
pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm");
#[cfg(test)]
mod tests {
#[test]
fn can_load_grammar() {
fn test_can_load_grammar() {
let mut parser = tree_sitter::Parser::new();
parser
.set_language(super::language())
.set_language(&super::language())
.expect("Error loading C grammar");
}
}

@ -7,10 +7,10 @@ typedef struct TSLanguage TSLanguage;
extern "C" {
#endif
extern TSLanguage *tree_sitter_c();
const TSLanguage *tree_sitter_c(void);
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_C_H_
#endif // TREE_SITTER_C_H_

@ -1,12 +1,10 @@
/**
* @file C grammar for tree-sitter
* @author Max Brunsfeld
* @author Max Brunsfeld <maxbrunsfeld@gmail.com>
* @author Amaan Qureshi <amaanq12@gmail.com>
* @license MIT
*/
/* eslint-disable arrow-parens */
/* eslint-disable camelcase */
/* eslint-disable-next-line spaced-comment */
/// <reference types="tree-sitter-cli/dsl" />
// @ts-check
@ -22,12 +20,12 @@ const PREC = {
BITWISE_AND: 5,
EQUAL: 6,
RELATIONAL: 7,
SIZEOF: 8,
OFFSETOF: 9,
SHIFT: 10,
ADD: 11,
MULTIPLY: 12,
CAST: 13,
OFFSETOF: 8,
SHIFT: 9,
ADD: 10,
MULTIPLY: 11,
CAST: 12,
SIZEOF: 13,
UNARY: 14,
CALL: 15,
FIELD: 16,
@ -57,16 +55,17 @@ module.exports = grammar({
conflicts: $ => [
[$._type_specifier, $._declarator],
[$._type_specifier, $._declarator, $.macro_type_specifier],
[$._type_specifier, $._expression],
[$._type_specifier, $._expression, $.macro_type_specifier],
[$._type_specifier, $._expression_not_binary],
[$._type_specifier, $._expression_not_binary, $.macro_type_specifier],
[$._type_specifier, $.macro_type_specifier],
[$.sized_type_specifier],
[$._type_specifier, $.sized_type_specifier],
[$.sized_type_specifier],
[$.attributed_statement],
[$._declaration_modifiers, $.attributed_statement],
[$.enum_specifier],
[$._type_specifier, $._old_style_parameter_list],
[$.parameter_list, $._old_style_parameter_list],
[$.function_declarator, $._function_declaration_declarator],
],
word: $ => $.identifier,
@ -77,6 +76,7 @@ module.exports = grammar({
// Top level items are block items with the exception of the expression statement
_top_level_item: $ => choice(
$.function_definition,
alias($._old_style_function_definition, $.function_definition),
$.linkage_specification,
$.declaration,
$._top_level_statement,
@ -93,6 +93,7 @@ module.exports = grammar({
_block_item: $ => choice(
$.function_definition,
alias($._old_style_function_definition, $.function_definition),
$.linkage_specification,
$.declaration,
$._statement,
@ -147,8 +148,10 @@ module.exports = grammar({
...preprocIf('', $ => $._block_item),
...preprocIf('_in_field_declaration_list', $ => $._field_declaration_list_item),
...preprocIf('_in_enumerator_list', $ => seq($.enumerator, ',')),
...preprocIf('_in_enumerator_list_no_comma', $ => $.enumerator, -1),
preproc_arg: _ => token(prec(-1, /\S([^/\n]|\\\r?\n)*/)),
preproc_arg: _ => token(prec(-1, /\S([^/\n]|\/[^*]|\\\r?\n)*/)),
preproc_directive: _ => /#[ \t]*[a-zA-Z0-9]\w*/,
_preproc_expression: $ => choice(
@ -226,27 +229,42 @@ module.exports = grammar({
function_definition: $ => seq(
optional($.ms_call_modifier),
$._declaration_specifiers,
optional($.ms_call_modifier),
field('declarator', $._declarator),
field('body', $.compound_statement),
),
_old_style_function_definition: $ => seq(
optional($.ms_call_modifier),
$._declaration_specifiers,
field('declarator', alias($._old_style_function_declarator, $.function_declarator)),
repeat($.declaration),
field('body', $.compound_statement),
),
declaration: $ => seq(
$._declaration_specifiers,
commaSep1(field('declarator', choice(
$._declarator,
seq(
optional($.ms_call_modifier),
$._declaration_declarator,
optional($.gnu_asm_expression),
),
$.init_declarator,
))),
';',
),
type_definition: $ => seq(
optional('__extension__'),
'typedef',
repeat($.type_qualifier),
field('type', $._type_specifier),
repeat($.type_qualifier),
commaSep1(field('declarator', $._type_declarator)),
$._type_definition_type,
$._type_definition_declarators,
repeat($.attribute_specifier),
';',
),
_type_definition_type: $ => seq(repeat($.type_qualifier), field('type', $._type_specifier), repeat($.type_qualifier)),
_type_definition_declarators: $ => commaSep1(field('declarator', $._type_declarator)),
_declaration_modifiers: $ => choice(
$.storage_class_specifier,
@ -342,6 +360,15 @@ module.exports = grammar({
$.identifier,
),
_declaration_declarator: $ => choice(
$.attributed_declarator,
$.pointer_declarator,
alias($._function_declaration_declarator, $.function_declarator),
$.array_declarator,
$.parenthesized_declarator,
$.identifier,
),
_field_declarator: $ => choice(
alias($.attributed_field_declarator, $.attributed_declarator),
alias($.pointer_field_declarator, $.pointer_declarator),
@ -371,21 +398,25 @@ module.exports = grammar({
parenthesized_declarator: $ => prec.dynamic(PREC.PAREN_DECLARATOR, seq(
'(',
optional($.ms_call_modifier),
$._declarator,
')',
)),
parenthesized_field_declarator: $ => prec.dynamic(PREC.PAREN_DECLARATOR, seq(
'(',
optional($.ms_call_modifier),
$._field_declarator,
')',
)),
parenthesized_type_declarator: $ => prec.dynamic(PREC.PAREN_DECLARATOR, seq(
'(',
optional($.ms_call_modifier),
$._type_declarator,
')',
)),
abstract_parenthesized_declarator: $ => prec(1, seq(
'(',
optional($.ms_call_modifier),
$._abstract_declarator,
')',
)),
@ -426,16 +457,32 @@ module.exports = grammar({
field('declarator', $._type_declarator),
))),
abstract_pointer_declarator: $ => prec.dynamic(1, prec.right(seq('*',
repeat($.ms_pointer_modifier),
repeat($.type_qualifier),
field('declarator', optional($._abstract_declarator)),
))),
function_declarator: $ => prec(1,
function_declarator: $ => prec.right(1,
seq(
field('declarator', $._declarator),
field('parameters', $.parameter_list),
optional($.gnu_asm_expression),
repeat(choice(
$.attribute_specifier,
$.identifier,
alias($.preproc_call_expression, $.call_expression),
)),
),
),
_function_declaration_declarator: $ => prec.right(1,
seq(
field('declarator', $._declarator),
field('parameters', $.parameter_list),
optional($.gnu_asm_expression),
repeat($.attribute_specifier),
)),
function_field_declarator: $ => prec(1, seq(
field('declarator', $._field_declarator),
field('parameters', $.parameter_list),
@ -449,6 +496,11 @@ module.exports = grammar({
field('parameters', $.parameter_list),
)),
_old_style_function_declarator: $ => seq(
field('declarator', $._declarator),
field('parameters', alias($._old_style_parameter_list, $.parameter_list)),
),
array_declarator: $ => prec(1, seq(
field('declarator', $._declarator),
'[',
@ -496,7 +548,11 @@ module.exports = grammar({
'auto',
'register',
'inline',
'__inline',
'__inline__',
'__forceinline',
'thread_local',
'__thread',
),
type_qualifier: _ => choice(
@ -505,6 +561,7 @@ module.exports = grammar({
'volatile',
'restrict',
'__restrict__',
'__extension__',
'_Atomic',
'_Noreturn',
'noreturn',
@ -520,17 +577,43 @@ module.exports = grammar({
$._type_identifier,
),
sized_type_specifier: $ => seq(
repeat1(choice(
'signed',
'unsigned',
'long',
'short',
)),
field('type', optional(choice(
prec.dynamic(-1, $._type_identifier),
$.primitive_type,
))),
sized_type_specifier: $ => choice(
seq(
repeat(choice(
'signed',
'unsigned',
'long',
'short',
)),
field('type', optional(choice(
prec.dynamic(-1, $._type_identifier),
$.primitive_type,
))),
repeat1(choice(
'signed',
'unsigned',
'long',
'short',
)),
),
seq(
repeat1(choice(
'signed',
'unsigned',
'long',
'short',
)),
field('type', optional(choice(
prec.dynamic(-1, $._type_identifier),
$.primitive_type,
))),
repeat(choice(
'signed',
'unsigned',
'long',
'short',
)),
),
),
primitive_type: _ => token(choice(
@ -568,8 +651,20 @@ module.exports = grammar({
enumerator_list: $ => seq(
'{',
commaSep($.enumerator),
optional(','),
repeat(choice(
seq($.enumerator, ','),
alias($.preproc_if_in_enumerator_list, $.preproc_if),
alias($.preproc_ifdef_in_enumerator_list, $.preproc_ifdef),
seq($.preproc_call, ','),
)),
optional(seq(
choice(
$.enumerator,
alias($.preproc_if_in_enumerator_list_no_comma, $.preproc_if),
alias($.preproc_ifdef_in_enumerator_list_no_comma, $.preproc_ifdef),
$.preproc_call,
),
)),
'}',
),
@ -617,13 +712,14 @@ module.exports = grammar({
field_declaration: $ => seq(
$._declaration_specifiers,
commaSep(seq(
field('declarator', $._field_declarator),
optional($.bitfield_clause),
)),
optional($._field_declaration_declarator),
optional($.attribute_specifier),
';',
),
_field_declaration_declarator: $ => commaSep1(seq(
field('declarator', $._field_declarator),
optional($.bitfield_clause),
)),
bitfield_clause: $ => seq(':', $._expression),
@ -641,6 +737,11 @@ module.exports = grammar({
commaSep(choice($.parameter_declaration, $.variadic_parameter)),
')',
),
_old_style_parameter_list: $ => seq(
'(',
commaSep(choice($.identifier, $.variadic_parameter)),
')',
),
parameter_declaration: $ => seq(
$._declaration_specifiers,
@ -676,6 +777,8 @@ module.exports = grammar({
$.break_statement,
$.continue_statement,
$.goto_statement,
$.seh_try_statement,
$.seh_leave_statement,
),
_top_level_statement: $ => choice(
@ -760,14 +863,18 @@ module.exports = grammar({
for_statement: $ => seq(
'for',
'(',
$._for_statement_body,
')',
field('body', $._statement),
),
_for_statement_body: $ => seq(
choice(
field('initializer', $.declaration),
seq(field('initializer', optional(choice($._expression, $.comma_expression))), ';'),
),
field('condition', optional(choice($._expression, $.comma_expression))), ';',
field('condition', optional(choice($._expression, $.comma_expression))),
';',
field('update', optional(choice($._expression, $.comma_expression))),
')',
field('body', $._statement),
),
return_statement: $ => seq(
@ -790,6 +897,27 @@ module.exports = grammar({
';',
),
seh_try_statement: $ => seq(
'__try',
field('body', $.compound_statement),
choice($.seh_except_clause, $.seh_finally_clause),
),
seh_except_clause: $ => seq(
'__except',
field('filter', $.parenthesized_expression),
field('body', $.compound_statement),
),
seh_finally_clause: $ => seq(
'__finally',
field('body', $.compound_statement),
),
seh_leave_statement: _ => seq(
'__leave', ';',
),
// Expressions
_expression: $ => choice(
@ -805,6 +933,7 @@ module.exports = grammar({
$.cast_expression,
$.pointer_expression,
$.sizeof_expression,
$.alignof_expression,
$.offsetof_expression,
$.generic_expression,
$.subscript_expression,
@ -813,16 +942,20 @@ module.exports = grammar({
$.compound_literal_expression,
$.identifier,
$.number_literal,
$.string_literal,
$._string,
$.true,
$.false,
$.null,
$.concatenated_string,
$.char_literal,
$.parenthesized_expression,
$.gnu_asm_expression,
),
_string: $ => prec.left(choice(
$.string_literal,
$.concatenated_string,
)),
comma_expression: $ => seq(
field('left', $._expression),
',',
@ -832,7 +965,7 @@ module.exports = grammar({
conditional_expression: $ => prec.right(PREC.CONDITIONAL, seq(
field('condition', $._expression),
'?',
optional(field('consequence', $._expression)),
optional(field('consequence', choice($._expression, $.comma_expression))),
':',
field('alternative', $._expression),
)),
@ -937,6 +1070,11 @@ module.exports = grammar({
),
)),
alignof_expression: $ => prec(PREC.SIZEOF, seq(
choice('__alignof__', '__alignof', '_alignof', 'alignof', '_Alignof'),
seq('(', field('type', $.type_descriptor), ')'),
)),
offsetof_expression: $ => prec(PREC.OFFSETOF, seq(
'offsetof',
seq('(', field('type', $.type_descriptor), ',', field('member', $._field_identifier), ')'),
@ -967,7 +1105,7 @@ module.exports = grammar({
choice('asm', '__asm__'),
repeat($.gnu_asm_qualifier),
'(',
field('assembly_code', choice($.string_literal, $.concatenated_string)),
field('assembly_code', $._string),
optional(seq(
field('output_operands', $.gnu_asm_output_operand_list),
optional(seq(
@ -1023,7 +1161,7 @@ module.exports = grammar({
gnu_asm_clobber_list: $ => seq(
':',
commaSep(field('register', $.string_literal)),
commaSep(field('register', $._string)),
),
gnu_asm_goto_list: $ => seq(
@ -1032,7 +1170,7 @@ module.exports = grammar({
),
// The compound_statement is added to parse macros taking statements as arguments, e.g. MYFORLOOP(1, 10, i, { foo(i); bar(i); })
argument_list: $ => seq('(', commaSep(choice($._expression, $.compound_statement)), ')'),
argument_list: $ => seq('(', commaSep(choice(seq(optional('__extension__'), $._expression), $.compound_statement)), ')'),
field_expression: $ => seq(
prec(PREC.FIELD, seq(
@ -1066,14 +1204,27 @@ module.exports = grammar({
'}',
),
initializer_pair: $ => seq(
field('designator', repeat1(choice($.subscript_designator, $.field_designator))),
'=',
field('value', choice($._expression, $.initializer_list)),
initializer_pair: $ => choice(
seq(
field('designator', repeat1(choice(
$.subscript_designator,
$.field_designator,
$.subscript_range_designator,
))),
'=',
field('value', choice($._expression, $.initializer_list)),
),
seq(
field('designator', $._field_identifier),
':',
field('value', choice($._expression, $.initializer_list)),
),
),
subscript_designator: $ => seq('[', $._expression, ']'),
subscript_range_designator: $ => seq('[', field('start', $._expression), '...', field('end', $._expression), ']'),
field_designator: $ => seq('.', $._field_identifier),
number_literal: _ => {
@ -1084,13 +1235,13 @@ module.exports = grammar({
const decimalDigits = seq(repeat1(decimal), repeat(seq(separator, repeat1(decimal))));
return token(seq(
optional(/[-\+]/),
optional(choice('0x', '0b')),
optional(choice(/0[xX]/, /0[bB]/)),
choice(
seq(
choice(
decimalDigits,
seq('0b', decimalDigits),
seq('0x', hexDigits),
seq(/0[bB]/, decimalDigits),
seq(/0[xX]/, hexDigits),
),
optional(seq('.', optional(hexDigits))),
),
@ -1103,23 +1254,29 @@ module.exports = grammar({
hexDigits,
)),
)),
repeat(choice('u', 'l', 'U', 'L', 'f', 'F')),
/[uUlLwWfFbBdD]*/,
));
},
char_literal: $ => seq(
choice('L\'', 'u\'', 'U\'', 'u8\'', '\''),
choice(
repeat1(choice(
$.escape_sequence,
alias(token.immediate(/[^\n']/), $.character),
),
)),
'\'',
),
concatenated_string: $ => seq(
$.string_literal,
repeat1(choice($.string_literal, $.identifier)), // Identifier is added to parse macros that are strings, like PRIu64
),
// Must concatenate at least 2 nodes, one of which must be a string_literal.
// Identifier is added to parse macros that are strings, like PRIu64.
concatenated_string: $ => prec.right(seq(
choice(
seq($.identifier, $.string_literal),
seq($.string_literal, $.string_literal),
seq($.string_literal, $.identifier),
),
repeat(choice($.string_literal, $.identifier)),
)),
string_literal: $ => seq(
choice('L"', 'u"', 'U"', 'u8"', '"'),
@ -1152,7 +1309,8 @@ module.exports = grammar({
null: _ => choice('NULL', 'nullptr'),
identifier: _ =>
/(\p{XID_Start}|_|\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8})(\p{XID_Continue}|\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8})*/,
// eslint-disable-next-line max-len
/(\p{XID_Start}|\$|_|\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8})(\p{XID_Continue}|\$|\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8})*/,
_type_identifier: $ => alias(
$.identifier,
@ -1203,9 +1361,11 @@ module.exports.PREC = PREC;
*
* @param {RuleBuilder<string>} content
*
* @param {number} precedence
*
* @return {RuleBuilders<string, string>}
*/
function preprocIf(suffix, content) {
function preprocIf(suffix, content, precedence = 0) {
/**
*
* @param {GrammarSymbols<string>} $
@ -1213,50 +1373,51 @@ function preprocIf(suffix, content) {
* @return {ChoiceRule}
*
*/
function elseBlock($) {
function alternativeBlock($) {
return choice(
suffix ? alias($['preproc_else' + suffix], $.preproc_else) : $.preproc_else,
suffix ? alias($['preproc_elif' + suffix], $.preproc_elif) : $.preproc_elif,
suffix ? alias($['preproc_elifdef' + suffix], $.preproc_elifdef) : $.preproc_elifdef,
);
}
return {
['preproc_if' + suffix]: $ => seq(
['preproc_if' + suffix]: $ => prec(precedence, seq(
preprocessor('if'),
field('condition', $._preproc_expression),
'\n',
repeat(content($)),
field('alternative', optional(elseBlock($))),
field('alternative', optional(alternativeBlock($))),
preprocessor('endif'),
),
)),
['preproc_ifdef' + suffix]: $ => seq(
['preproc_ifdef' + suffix]: $ => prec(precedence, seq(
choice(preprocessor('ifdef'), preprocessor('ifndef')),
field('name', $.identifier),
repeat(content($)),
field('alternative', optional(choice(elseBlock($), $.preproc_elifdef))),
field('alternative', optional(alternativeBlock($))),
preprocessor('endif'),
),
)),
['preproc_else' + suffix]: $ => seq(
['preproc_else' + suffix]: $ => prec(precedence, seq(
preprocessor('else'),
repeat(content($)),
),
)),
['preproc_elif' + suffix]: $ => seq(
['preproc_elif' + suffix]: $ => prec(precedence, seq(
preprocessor('elif'),
field('condition', $._preproc_expression),
'\n',
repeat(content($)),
field('alternative', optional(elseBlock($))),
),
field('alternative', optional(alternativeBlock($))),
)),
['preproc_elifdef' + suffix]: $ => seq(
['preproc_elifdef' + suffix]: $ => prec(precedence, seq(
choice(preprocessor('elifdef'), preprocessor('elifndef')),
field('name', $.identifier),
repeat(content($)),
field('alternative', optional(elseBlock($))),
),
field('alternative', optional(alternativeBlock($))),
)),
};
}

File diff suppressed because it is too large Load Diff

@ -1,31 +1,55 @@
{
"name": "tree-sitter-c",
"version": "0.20.4",
"description": "C grammar for node-tree-sitter",
"version": "0.21.1",
"description": "C grammar for tree-sitter",
"repository": "github:tree-sitter/tree-sitter-c",
"license": "MIT",
"author": "Max Brunsfeld <maxbrunsfeld@gmail.com>",
"contributors": [
"Amaan Qureshi <amaanq12@gmail.com>"
],
"main": "bindings/node",
"types": "bindings/node",
"keywords": [
"parser",
"lexer"
"incremental",
"parsing",
"tree-sitter",
"c"
],
"files": [
"grammar.js",
"binding.gyp",
"prebuilds/**",
"bindings/node/*",
"queries/*",
"src/**"
],
"repository": {
"type": "git",
"url": "https://github.com/tree-sitter/tree-sitter-c.git"
},
"author": "Max Brunsfeld",
"license": "MIT",
"dependencies": {
"nan": "^2.14.0"
"node-addon-api": "^8.0.0",
"node-gyp-build": "^4.8.0"
},
"peerDependencies": {
"tree-sitter": "^0.21.0"
},
"peerDependenciesMeta": {
"tree_sitter": {
"optional": true
}
},
"devDependencies": {
"eslint": "^8.41.0",
"eslint": "^8.57.0",
"eslint-config-google": "^0.14.0",
"tree-sitter-cli": "^0.20.0"
"tree-sitter-cli": "^0.22.2",
"prebuildify": "^6.0.0"
},
"scripts": {
"build": "tree-sitter generate && node-gyp build",
"install": "node-gyp-build",
"prebuildify": "prebuildify --napi --strip",
"build": "tree-sitter generate --no-bindings",
"build-wasm": "tree-sitter build --wasm",
"lint": "eslint grammar.js",
"test": "tree-sitter test && tree-sitter parse examples/* --quiet --time",
"test-windows": "tree-sitter test"
"parse": "tree-sitter parse",
"test": "tree-sitter test"
},
"tree-sitter": [
{
@ -35,9 +59,50 @@
"h"
],
"injection-regex": "^(c|h)$",
"highlights": [
"queries/highlights.scm"
"highlights": "queries/highlights.scm",
"tags": "queries/tags.scm"
}
],
"eslintConfig": {
"env": {
"commonjs": true,
"es2021": true
},
"extends": "google",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
"arrow-parens": "off",
"camel-case": "off",
"indent": [
"error",
2,
{
"SwitchCase": 1
}
],
"max-len": [
"error",
{
"code": 160,
"ignoreComments": true,
"ignoreUrls": true,
"ignoreStrings": true
}
],
"spaced-comment": [
"warn",
"always",
{
"line": {
"markers": [
"/"
]
}
}
]
}
]
}
}

@ -0,0 +1,33 @@
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "tree-sitter-c"
description = "C grammar for tree-sitter"
version = "0.21.1"
keywords = ["incremental", "parsing", "tree-sitter", "c"]
classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Topic :: Software Development :: Compilers",
"Topic :: Text Processing :: Linguistic",
"Typing :: Typed",
]
authors = [
{ name = "Max Brunsfeld", email = "maxbrunsfeld@gmail.com" },
{ name = "Amaan Qureshi", email = "amaanq12@gmail.com" },
]
requires-python = ">=3.8"
license.text = "MIT"
readme = "README.md"
[project.urls]
Homepage = "https://github.com/tree-sitter/tree-sitter-c"
[project.optional-dependencies]
core = ["tree-sitter~=0.21"]
[tool.cibuildwheel]
build = "cp38-*"
build-frontend = "build"

@ -1,3 +1,8 @@
(identifier) @variable
((identifier) @constant
(#match? @constant "^[A-Z][A-Z\\d_]*$"))
"break" @keyword
"case" @keyword
"const" @keyword
@ -57,6 +62,12 @@
(number_literal) @number
(char_literal) @number
(field_identifier) @property
(statement_identifier) @label
(type_identifier) @type
(primitive_type) @type
(sized_type_specifier) @type
(call_expression
function: (identifier) @function)
(call_expression
@ -67,15 +78,4 @@
(preproc_function_def
name: (identifier) @function.special)
(field_identifier) @property
(statement_identifier) @label
(type_identifier) @type
(primitive_type) @type
(sized_type_specifier) @type
((identifier) @constant
(#match? @constant "^[A-Z][A-Z\\d_]*$"))
(identifier) @variable
(comment) @comment

@ -0,0 +1,9 @@
(struct_specifier name: (type_identifier) @name body:(_)) @definition.class
(declaration type: (union_specifier name: (type_identifier) @name)) @definition.class
(function_declarator declarator: (identifier) @name) @definition.function
(type_definition declarator: (type_identifier) @name) @definition.type
(enum_specifier name: (type_identifier) @name) @definition.type

@ -0,0 +1,56 @@
from os.path import isdir, join
from platform import system
from setuptools import Extension, find_packages, setup
from setuptools.command.build import build
from wheel.bdist_wheel import bdist_wheel
class Build(build):
def run(self):
if isdir("queries"):
dest = join(self.build_lib, "tree_sitter_c", "queries")
self.copy_tree("queries", dest)
super().run()
class BdistWheel(bdist_wheel):
def get_tag(self):
python, abi, platform = super().get_tag()
if python.startswith("cp"):
python, abi = "cp38", "abi3"
return python, abi, platform
setup(
packages=find_packages("bindings/python"),
package_dir={"": "bindings/python"},
package_data={
"tree_sitter_c": ["*.pyi", "py.typed"],
"tree_sitter_c.queries": ["*.scm"],
},
ext_package="tree_sitter_c",
ext_modules=[
Extension(
name="_binding",
sources=[
"bindings/python/tree_sitter_c/binding.c",
"src/parser.c",
],
extra_compile_args=(
["-std=c11"] if system() != 'Windows' else []
),
define_macros=[
("Py_LIMITED_API", "0x03080000"),
("PY_SSIZE_T_CLEAN", None)
],
include_dirs=["src"],
py_limited_api=True,
)
],
cmdclass={
"build": Build,
"bdist_wheel": BdistWheel
},
zip_safe=False
)

File diff suppressed because it is too large Load Diff

@ -55,6 +55,10 @@
"type": "_expression",
"named": true,
"subtypes": [
{
"type": "alignof_expression",
"named": true
},
{
"type": "assignment_expression",
"named": true
@ -235,6 +239,14 @@
"type": "return_statement",
"named": true
},
{
"type": "seh_leave_statement",
"named": true
},
{
"type": "seh_try_statement",
"named": true
},
{
"type": "switch_statement",
"named": true
@ -384,12 +396,16 @@
"named": true,
"fields": {},
"children": {
"multiple": false,
"multiple": true,
"required": true,
"types": [
{
"type": "_abstract_declarator",
"named": true
},
{
"type": "ms_call_modifier",
"named": true
}
]
}
@ -413,6 +429,10 @@
"multiple": true,
"required": false,
"types": [
{
"type": "ms_pointer_modifier",
"named": true
},
{
"type": "type_qualifier",
"named": true
@ -420,6 +440,22 @@
]
}
},
{
"type": "alignof_expression",
"named": true,
"fields": {
"type": {
"multiple": false,
"required": true,
"types": [
{
"type": "type_descriptor",
"named": true
}
]
}
}
},
{
"type": "argument_list",
"named": true,
@ -924,6 +960,14 @@
"type": "return_statement",
"named": true
},
{
"type": "seh_leave_statement",
"named": true
},
{
"type": "seh_try_statement",
"named": true
},
{
"type": "switch_statement",
"named": true
@ -970,7 +1014,7 @@
"named": true,
"fields": {},
"children": {
"multiple": false,
"multiple": true,
"required": true,
"types": [
{
@ -1149,6 +1193,10 @@
{
"type": "_expression",
"named": true
},
{
"type": "comma_expression",
"named": true
}
]
}
@ -1168,12 +1216,40 @@
"required": true,
"types": [
{
"type": "_declarator",
"type": "array_declarator",
"named": true
},
{
"type": "attributed_declarator",
"named": true
},
{
"type": "function_declarator",
"named": true
},
{
"type": "gnu_asm_expression",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "init_declarator",
"named": true
},
{
"type": "ms_call_modifier",
"named": true
},
{
"type": "parenthesized_declarator",
"named": true
},
{
"type": "pointer_declarator",
"named": true
}
]
},
@ -1398,6 +1474,18 @@
{
"type": "enumerator",
"named": true
},
{
"type": "preproc_call",
"named": true
},
{
"type": "preproc_if",
"named": true
},
{
"type": "preproc_ifdef",
"named": true
}
]
}
@ -1669,6 +1757,18 @@
{
"type": "attribute_specifier",
"named": true
},
{
"type": "call_expression",
"named": true
},
{
"type": "gnu_asm_expression",
"named": true
},
{
"type": "identifier",
"named": true
}
]
}
@ -1720,6 +1820,10 @@
"type": "attribute_specifier",
"named": true
},
{
"type": "declaration",
"named": true
},
{
"type": "ms_call_modifier",
"named": true
@ -1766,6 +1870,10 @@
"multiple": true,
"required": false,
"types": [
{
"type": "concatenated_string",
"named": true
},
{
"type": "string_literal",
"named": true
@ -2086,9 +2194,17 @@
"type": "field_designator",
"named": true
},
{
"type": "field_identifier",
"named": true
},
{
"type": "subscript_designator",
"named": true
},
{
"type": "subscript_range_designator",
"named": true
}
]
},
@ -2356,6 +2472,10 @@
"multiple": true,
"required": false,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "parameter_declaration",
"named": true
@ -2372,7 +2492,7 @@
"named": true,
"fields": {},
"children": {
"multiple": false,
"multiple": true,
"required": true,
"types": [
{
@ -2386,6 +2506,10 @@
{
"type": "_type_declarator",
"named": true
},
{
"type": "ms_call_modifier",
"named": true
}
]
}
@ -2564,6 +2688,10 @@
"type": "preproc_elif",
"named": true
},
{
"type": "preproc_elifdef",
"named": true
},
{
"type": "preproc_else",
"named": true
@ -2625,6 +2753,10 @@
"type": "declaration",
"named": true
},
{
"type": "enumerator",
"named": true
},
{
"type": "field_declaration",
"named": true
@ -2680,6 +2812,10 @@
"type": "preproc_elif",
"named": true
},
{
"type": "preproc_elifdef",
"named": true
},
{
"type": "preproc_else",
"named": true
@ -2713,6 +2849,14 @@
"type": "declaration",
"named": true
},
{
"type": "enumerator",
"named": true
},
{
"type": "field_declaration",
"named": true
},
{
"type": "function_definition",
"named": true
@ -2772,6 +2916,10 @@
"type": "declaration",
"named": true
},
{
"type": "enumerator",
"named": true
},
{
"type": "field_declaration",
"named": true
@ -2863,6 +3011,10 @@
"type": "preproc_elif",
"named": true
},
{
"type": "preproc_elifdef",
"named": true
},
{
"type": "preproc_else",
"named": true
@ -2924,6 +3076,10 @@
"type": "declaration",
"named": true
},
{
"type": "enumerator",
"named": true
},
{
"type": "field_declaration",
"named": true
@ -3016,6 +3172,10 @@
"type": "declaration",
"named": true
},
{
"type": "enumerator",
"named": true
},
{
"type": "field_declaration",
"named": true
@ -3121,6 +3281,83 @@
]
}
},
{
"type": "seh_except_clause",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "compound_statement",
"named": true
}
]
},
"filter": {
"multiple": false,
"required": true,
"types": [
{
"type": "parenthesized_expression",
"named": true
}
]
}
}
},
{
"type": "seh_finally_clause",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "compound_statement",
"named": true
}
]
}
}
},
{
"type": "seh_leave_statement",
"named": true,
"fields": {}
},
{
"type": "seh_try_statement",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "compound_statement",
"named": true
}
]
}
},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "seh_except_clause",
"named": true
},
{
"type": "seh_finally_clause",
"named": true
}
]
}
},
{
"type": "sized_type_specifier",
"named": true,
@ -3272,6 +3509,32 @@
}
}
},
{
"type": "subscript_range_designator",
"named": true,
"fields": {
"end": {
"multiple": false,
"required": true,
"types": [
{
"type": "_expression",
"named": true
}
]
},
"start": {
"multiple": false,
"required": true,
"types": [
{
"type": "_expression",
"named": true
}
]
}
}
},
{
"type": "switch_statement",
"named": true,
@ -3438,6 +3701,10 @@
"multiple": true,
"required": false,
"types": [
{
"type": "attribute_specifier",
"named": true
},
{
"type": "type_qualifier",
"named": true
@ -3873,6 +4140,10 @@
"type": "^=",
"named": false
},
{
"type": "_Alignof",
"named": false
},
{
"type": "_Atomic",
"named": false
@ -3885,6 +4156,14 @@
"type": "_Noreturn",
"named": false
},
{
"type": "__alignof",
"named": false
},
{
"type": "__alignof__",
"named": false
},
{
"type": "__asm__",
"named": false
@ -3909,10 +4188,38 @@
"type": "__declspec",
"named": false
},
{
"type": "__except",
"named": false
},
{
"type": "__extension__",
"named": false
},
{
"type": "__fastcall",
"named": false
},
{
"type": "__finally",
"named": false
},
{
"type": "__forceinline",
"named": false
},
{
"type": "__inline",
"named": false
},
{
"type": "__inline__",
"named": false
},
{
"type": "__leave",
"named": false
},
{
"type": "__restrict__",
"named": false
@ -3925,6 +4232,14 @@
"type": "__thiscall",
"named": false
},
{
"type": "__thread",
"named": false
},
{
"type": "__try",
"named": false
},
{
"type": "__unaligned",
"named": false
@ -3933,10 +4248,18 @@
"type": "__vectorcall",
"named": false
},
{
"type": "_alignof",
"named": false
},
{
"type": "_unaligned",
"named": false
},
{
"type": "alignof",
"named": false
},
{
"type": "asm",
"named": false

File diff suppressed because it is too large Load Diff

@ -0,0 +1,54 @@
#ifndef TREE_SITTER_ALLOC_H_
#define TREE_SITTER_ALLOC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
// Allow clients to override allocation functions
#ifdef TREE_SITTER_REUSE_ALLOCATOR
extern void *(*ts_current_malloc)(size_t);
extern void *(*ts_current_calloc)(size_t, size_t);
extern void *(*ts_current_realloc)(void *, size_t);
extern void (*ts_current_free)(void *);
#ifndef ts_malloc
#define ts_malloc ts_current_malloc
#endif
#ifndef ts_calloc
#define ts_calloc ts_current_calloc
#endif
#ifndef ts_realloc
#define ts_realloc ts_current_realloc
#endif
#ifndef ts_free
#define ts_free ts_current_free
#endif
#else
#ifndef ts_malloc
#define ts_malloc malloc
#endif
#ifndef ts_calloc
#define ts_calloc calloc
#endif
#ifndef ts_realloc
#define ts_realloc realloc
#endif
#ifndef ts_free
#define ts_free free
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_ALLOC_H_

@ -0,0 +1,290 @@
#ifndef TREE_SITTER_ARRAY_H_
#define TREE_SITTER_ARRAY_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "./alloc.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
#pragma warning(disable : 4101)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
#define Array(T) \
struct { \
T *contents; \
uint32_t size; \
uint32_t capacity; \
}
/// Initialize an array.
#define array_init(self) \
((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL)
/// Create an empty array.
#define array_new() \
{ NULL, 0, 0 }
/// Get a pointer to the element at a given `index` in the array.
#define array_get(self, _index) \
(assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index])
/// Get a pointer to the first element in the array.
#define array_front(self) array_get(self, 0)
/// Get a pointer to the last element in the array.
#define array_back(self) array_get(self, (self)->size - 1)
/// Clear the array, setting its size to zero. Note that this does not free any
/// memory allocated for the array's contents.
#define array_clear(self) ((self)->size = 0)
/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is
/// less than the array's current capacity, this function has no effect.
#define array_reserve(self, new_capacity) \
_array__reserve((Array *)(self), array_elem_size(self), new_capacity)
/// Free any memory allocated for this array. Note that this does not free any
/// memory allocated for the array's contents.
#define array_delete(self) _array__delete((Array *)(self))
/// Push a new `element` onto the end of the array.
#define array_push(self, element) \
(_array__grow((Array *)(self), 1, array_elem_size(self)), \
(self)->contents[(self)->size++] = (element))
/// Increase the array's size by `count` elements.
/// New elements are zero-initialized.
#define array_grow_by(self, count) \
do { \
if ((count) == 0) break; \
_array__grow((Array *)(self), count, array_elem_size(self)); \
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
(self)->size += (count); \
} while (0)
/// Append all elements from one array to the end of another.
#define array_push_all(self, other) \
array_extend((self), (other)->size, (other)->contents)
/// Append `count` elements to the end of the array, reading their values from the
/// `contents` pointer.
#define array_extend(self, count, contents) \
_array__splice( \
(Array *)(self), array_elem_size(self), (self)->size, \
0, count, contents \
)
/// Remove `old_count` elements from the array starting at the given `index`. At
/// the same index, insert `new_count` new elements, reading their values from the
/// `new_contents` pointer.
#define array_splice(self, _index, old_count, new_count, new_contents) \
_array__splice( \
(Array *)(self), array_elem_size(self), _index, \
old_count, new_count, new_contents \
)
/// Insert one `element` into the array at the given `index`.
#define array_insert(self, _index, element) \
_array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element))
/// Remove one element from the array at the given `index`.
#define array_erase(self, _index) \
_array__erase((Array *)(self), array_elem_size(self), _index)
/// Pop the last element off the array, returning the element by value.
#define array_pop(self) ((self)->contents[--(self)->size])
/// Assign the contents of one array to another, reallocating if necessary.
#define array_assign(self, other) \
_array__assign((Array *)(self), (const Array *)(other), array_elem_size(self))
/// Swap one array with another
#define array_swap(self, other) \
_array__swap((Array *)(self), (Array *)(other))
/// Get the size of the array contents
#define array_elem_size(self) (sizeof *(self)->contents)
/// Search a sorted array for a given `needle` value, using the given `compare`
/// callback to determine the order.
///
/// If an existing element is found to be equal to `needle`, then the `index`
/// out-parameter is set to the existing value's index, and the `exists`
/// out-parameter is set to true. Otherwise, `index` is set to an index where
/// `needle` should be inserted in order to preserve the sorting, and `exists`
/// is set to false.
#define array_search_sorted_with(self, compare, needle, _index, _exists) \
_array__search_sorted(self, 0, compare, , needle, _index, _exists)
/// Search a sorted array for a given `needle` value, using integer comparisons
/// of a given struct field (specified with a leading dot) to determine the order.
///
/// See also `array_search_sorted_with`.
#define array_search_sorted_by(self, field, needle, _index, _exists) \
_array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists)
/// Insert a given `value` into a sorted array, using the given `compare`
/// callback to determine the order.
#define array_insert_sorted_with(self, compare, value) \
do { \
unsigned _index, _exists; \
array_search_sorted_with(self, compare, &(value), &_index, &_exists); \
if (!_exists) array_insert(self, _index, value); \
} while (0)
/// Insert a given `value` into a sorted array, using integer comparisons of
/// a given struct field (specified with a leading dot) to determine the order.
///
/// See also `array_search_sorted_by`.
#define array_insert_sorted_by(self, field, value) \
do { \
unsigned _index, _exists; \
array_search_sorted_by(self, field, (value) field, &_index, &_exists); \
if (!_exists) array_insert(self, _index, value); \
} while (0)
// Private
typedef Array(void) Array;
/// This is not what you're looking for, see `array_delete`.
static inline void _array__delete(Array *self) {
if (self->contents) {
ts_free(self->contents);
self->contents = NULL;
self->size = 0;
self->capacity = 0;
}
}
/// This is not what you're looking for, see `array_erase`.
static inline void _array__erase(Array *self, size_t element_size,
uint32_t index) {
assert(index < self->size);
char *contents = (char *)self->contents;
memmove(contents + index * element_size, contents + (index + 1) * element_size,
(self->size - index - 1) * element_size);
self->size--;
}
/// This is not what you're looking for, see `array_reserve`.
static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) {
if (new_capacity > self->capacity) {
if (self->contents) {
self->contents = ts_realloc(self->contents, new_capacity * element_size);
} else {
self->contents = ts_malloc(new_capacity * element_size);
}
self->capacity = new_capacity;
}
}
/// This is not what you're looking for, see `array_assign`.
static inline void _array__assign(Array *self, const Array *other, size_t element_size) {
_array__reserve(self, element_size, other->size);
self->size = other->size;
memcpy(self->contents, other->contents, self->size * element_size);
}
/// This is not what you're looking for, see `array_swap`.
static inline void _array__swap(Array *self, Array *other) {
Array swap = *other;
*other = *self;
*self = swap;
}
/// This is not what you're looking for, see `array_push` or `array_grow_by`.
static inline void _array__grow(Array *self, uint32_t count, size_t element_size) {
uint32_t new_size = self->size + count;
if (new_size > self->capacity) {
uint32_t new_capacity = self->capacity * 2;
if (new_capacity < 8) new_capacity = 8;
if (new_capacity < new_size) new_capacity = new_size;
_array__reserve(self, element_size, new_capacity);
}
}
/// This is not what you're looking for, see `array_splice`.
static inline void _array__splice(Array *self, size_t element_size,
uint32_t index, uint32_t old_count,
uint32_t new_count, const void *elements) {
uint32_t new_size = self->size + new_count - old_count;
uint32_t old_end = index + old_count;
uint32_t new_end = index + new_count;
assert(old_end <= self->size);
_array__reserve(self, element_size, new_size);
char *contents = (char *)self->contents;
if (self->size > old_end) {
memmove(
contents + new_end * element_size,
contents + old_end * element_size,
(self->size - old_end) * element_size
);
}
if (new_count > 0) {
if (elements) {
memcpy(
(contents + index * element_size),
elements,
new_count * element_size
);
} else {
memset(
(contents + index * element_size),
0,
new_count * element_size
);
}
}
self->size += new_count - old_count;
}
/// A binary search routine, based on Rust's `std::slice::binary_search_by`.
/// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`.
#define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \
do { \
*(_index) = start; \
*(_exists) = false; \
uint32_t size = (self)->size - *(_index); \
if (size == 0) break; \
int comparison; \
while (size > 1) { \
uint32_t half_size = size / 2; \
uint32_t mid_index = *(_index) + half_size; \
comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \
if (comparison <= 0) *(_index) = mid_index; \
size -= half_size; \
} \
comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \
if (comparison == 0) *(_exists) = true; \
else if (comparison < 0) *(_index) += 1; \
} while (0)
/// Helper macro for the `_sorted_by` routines below. This takes the left (existing)
/// parameter by reference in order to work with the generic sorting function above.
#define _compare_int(a, b) ((int)*(a) - (int)(b))
#ifdef _MSC_VER
#pragma warning(default : 4101)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_ARRAY_H_

@ -13,9 +13,8 @@ extern "C" {
#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 TSStateId;
typedef uint16_t TSSymbol;
typedef uint16_t TSFieldId;
typedef struct TSLanguage TSLanguage;
@ -130,9 +129,16 @@ struct TSLanguage {
* Lexer Macros
*/
#ifdef _MSC_VER
#define UNUSED __pragma(warning(suppress : 4101))
#else
#define UNUSED __attribute__((unused))
#endif
#define START_LEXER() \
bool result = false; \
bool skip = false; \
UNUSED \
bool eof = false; \
int32_t lookahead; \
goto start; \
@ -166,7 +172,7 @@ struct TSLanguage {
* Parse Table Macros
*/
#define SMALL_STATE(id) id - LARGE_STATE_COUNT
#define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT)
#define STATE(id) id
@ -176,7 +182,7 @@ struct TSLanguage {
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value \
.state = (state_value) \
} \
}}
@ -184,7 +190,7 @@ struct TSLanguage {
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value, \
.state = (state_value), \
.repetition = true \
} \
}}

@ -84,7 +84,17 @@ enum e3 {
};
enum e4: int {
val1,
#ifdef A
val1 = 'hey',
#else
val1 = 'ho',
#endif
#if HEY
val2 = 'hey',
#else
val2 = 'ho',
#endif
};
--------------------------------------------------------------------------------
@ -111,8 +121,34 @@ enum e4: int {
name: (type_identifier)
underlying_type: (primitive_type)
body: (enumerator_list
(enumerator
name: (identifier)))))
(preproc_ifdef
name: (identifier)
(enumerator
name: (identifier)
value: (char_literal
(character)
(character)
(character)))
alternative: (preproc_else
(enumerator
name: (identifier)
value: (char_literal
(character)
(character)))))
(preproc_if
condition: (identifier)
(enumerator
name: (identifier)
value: (char_literal
(character)
(character)
(character)))
alternative: (preproc_else
(enumerator
name: (identifier)
value: (char_literal
(character)
(character))))))))
================================================================================
Struct declarations containing preprocessor directives
@ -151,6 +187,8 @@ long int b, c = 5, d;
float d, e;
unsigned f;
short g, h;
int unsigned short i;
unsigned int long j;
--------------------------------------------------------------------------------
@ -177,6 +215,14 @@ short g, h;
(declaration
type: (sized_type_specifier)
declarator: (identifier)
declarator: (identifier))
(declaration
type: (sized_type_specifier
type: (primitive_type))
declarator: (identifier))
(declaration
type: (sized_type_specifier
type: (primitive_type))
declarator: (identifier)))
================================================================================
@ -188,6 +234,7 @@ extern int b, c;
auto int d;
register int e;
static int f;
register uint64_t rd_ asm("x" "10");
--------------------------------------------------------------------------------
@ -211,7 +258,17 @@ static int f;
(declaration
(storage_class_specifier)
(primitive_type)
(identifier)))
(identifier))
(declaration
(storage_class_specifier)
(primitive_type)
(identifier)
(gnu_asm_expression
(concatenated_string
(string_literal
(string_content))
(string_literal
(string_content))))))
================================================================================
Composite-typed variable declarations
@ -313,6 +370,16 @@ typedef unsigned short ushort;
typedef unsigned unsigned short;
typedef signed signed short;
typedef signed signed unsigned;
typedef unsigned long int long ull;
typedef int register_t __attribute__((__mode__(__word__)));
__extension__ typedef long int greg_t;
__extension__ typedef struct {
long long int quot;
long long int rem;
} lldiv_t;
--------------------------------------------------------------------------------
@ -418,7 +485,36 @@ typedef signed signed unsigned;
declarator: (primitive_type))
(type_definition
type: (sized_type_specifier)
declarator: (primitive_type)))
declarator: (primitive_type))
(type_definition
type: (sized_type_specifier
type: (primitive_type))
declarator: (type_identifier))
(type_definition
type: (primitive_type)
declarator: (type_identifier)
(attribute_specifier
(argument_list
(call_expression
function: (identifier)
arguments: (argument_list
(identifier))))))
(type_definition
type: (sized_type_specifier
type: (primitive_type))
declarator: (type_identifier))
(type_definition
type: (struct_specifier
body: (field_declaration_list
(field_declaration
type: (sized_type_specifier
type: (primitive_type))
declarator: (field_identifier))
(field_declaration
type: (sized_type_specifier
type: (primitive_type))
declarator: (field_identifier))))
declarator: (type_identifier)))
================================================================================
Function declarations
@ -467,6 +563,13 @@ void * do_stuff(int arg1) {
return 5;
}
// K&R style
int foo(bar, baz, qux)
int bar, baz;
char *qux;
{
}
--------------------------------------------------------------------------------
(translation_unit
@ -481,7 +584,25 @@ void * do_stuff(int arg1) {
declarator: (identifier)))))
body: (compound_statement
(return_statement
(number_literal)))))
(number_literal))))
(comment)
(function_definition
type: (primitive_type)
declarator: (function_declarator
declarator: (identifier)
parameters: (parameter_list
(identifier)
(identifier)
(identifier)))
(declaration
type: (primitive_type)
declarator: (identifier)
declarator: (identifier))
(declaration
type: (primitive_type)
declarator: (pointer_declarator
declarator: (identifier)))
body: (compound_statement)))
================================================================================
Function specifiers after types
@ -508,6 +629,38 @@ int static inline do_stuff(int arg1) {
(return_statement
(number_literal)))))
================================================================================
Function definitions with macro attributes
================================================================================
void * do_stuff(int arg1)
SOME_ATTR
SOME_ATTR(1)
{
return 5;
}
--------------------------------------------------------------------------------
(translation_unit
(function_definition
type: (primitive_type)
declarator: (pointer_declarator
declarator: (function_declarator
declarator: (identifier)
parameters: (parameter_list
(parameter_declaration
type: (primitive_type)
declarator: (identifier)))
(identifier)
(call_expression
function: (identifier)
arguments: (argument_list
(number_literal)))))
body: (compound_statement
(return_statement
(number_literal)))))
================================================================================
Linkage specifications
================================================================================
@ -566,7 +719,10 @@ const _Atomic unsigned long int x = 5;
restrict int y = 6;
volatile int z = 7;
constexpr int a = 8;
__thread int c = 9;
noreturn void b() {}
__extension__ extern int ffsll (long long int __ll)
__attribute__ ((__nothrow__ )) __attribute__ ((__const__));
--------------------------------------------------------------------------------
@ -597,13 +753,36 @@ noreturn void b() {}
(init_declarator
(identifier)
(number_literal)))
(declaration
(storage_class_specifier)
(primitive_type)
(init_declarator
(identifier)
(number_literal)))
(function_definition
(type_qualifier)
(primitive_type)
(function_declarator
(identifier)
(parameter_list))
(compound_statement)))
(compound_statement))
(declaration
(type_qualifier)
(storage_class_specifier)
(primitive_type)
(function_declarator
(identifier)
(parameter_list
(parameter_declaration
(sized_type_specifier
(primitive_type))
(identifier)))
(attribute_specifier
(argument_list
(identifier)))
(attribute_specifier
(argument_list
(identifier))))))
================================================================================
Local array declarations
@ -643,6 +822,14 @@ void die(const char *format, ...) __attribute__((noreturn))
__attribute__((format(printf,1,2)));
extern __attribute__((visibility("default"), weak)) int print_status();
extern int strerror_r(int __errnum, char *__buf,
int __buflen) __asm__(""
"__xpg_strerror_r")
__attribute__((__nothrow__)) __attribute__((__nonnull__(2)));
extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict,
__gnuc_va_list);
int f([[a::b(c), d]] int x) {}
[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]]
@ -741,6 +928,55 @@ struct __attribute__((__packed__)) foo_t {
(function_declarator
(identifier)
(parameter_list)))
(declaration
(storage_class_specifier)
(primitive_type)
(function_declarator
(identifier)
(parameter_list
(parameter_declaration
(primitive_type)
(identifier))
(parameter_declaration
(primitive_type)
(pointer_declarator
(identifier)))
(parameter_declaration
(primitive_type)
(identifier)))
(gnu_asm_expression
(concatenated_string
(string_literal)
(string_literal
(string_content))))
(attribute_specifier
(argument_list
(identifier)))
(attribute_specifier
(argument_list
(call_expression
(identifier)
(argument_list
(number_literal)))))))
(declaration
(storage_class_specifier)
(primitive_type)
(function_declarator
(identifier)
(parameter_list
(parameter_declaration
(type_identifier)
(abstract_pointer_declarator
(ms_pointer_modifier
(ms_restrict_modifier))))
(parameter_declaration
(type_qualifier)
(primitive_type)
(abstract_pointer_declarator
(ms_pointer_modifier
(ms_restrict_modifier))))
(parameter_declaration
(type_identifier)))))
(function_definition
(primitive_type)
(function_declarator
@ -903,3 +1139,49 @@ struct __attribute__((__packed__)) foo_t {
(field_declaration
(primitive_type)
(field_identifier)))))
================================================================================
More Assembly
================================================================================
int main() {
int var;
__asm__(
"nop;"
: [var] "=r"(var)
:
: "eax", "ra" "x"
);
}
--------------------------------------------------------------------------------
(translation_unit
(function_definition
(primitive_type)
(function_declarator
(identifier)
(parameter_list))
(compound_statement
(declaration
(primitive_type)
(identifier))
(expression_statement
(gnu_asm_expression
(string_literal
(string_content))
(gnu_asm_output_operand_list
(gnu_asm_output_operand
(identifier)
(string_literal
(string_content))
(identifier)))
(gnu_asm_input_operand_list)
(gnu_asm_clobber_list
(string_literal
(string_content))
(concatenated_string
(string_literal
(string_content))
(string_literal
(string_content)))))))))

@ -16,6 +16,8 @@ double a = {
123.456e-67,
.1E4f,
0x10.1p0,
0X1, 0B1,
2.0dd, 5wb,
};
--------------------------------------------------------------------------------
@ -38,6 +40,10 @@ double a = {
(number_literal)
(number_literal)
(number_literal)
(number_literal)
(number_literal)
(number_literal)
(number_literal)
(number_literal)))))
================================================================================
@ -47,6 +53,7 @@ Identifiers
int main() {
_abc;
d_EG123;
$f;
}
--------------------------------------------------------------------------------
@ -58,6 +65,8 @@ int main() {
(identifier)
(parameter_list))
(compound_statement
(expression_statement
(identifier))
(expression_statement
(identifier))
(expression_statement
@ -130,6 +139,7 @@ Function calls
int main() {
printf("hi! %d\n", x);
__assert_fail("some_error_message", 115, __extension__ __func__);
}
--------------------------------------------------------------------------------
@ -148,6 +158,14 @@ int main() {
(string_literal
(string_content)
(escape_sequence))
(identifier))))
(expression_statement
(call_expression
(identifier)
(argument_list
(string_literal
(string_content))
(number_literal)
(identifier)))))))
================================================================================
@ -258,6 +276,7 @@ String literals
int main() {
"a";
"b" "c" "d";
e "f" g;
"\"hi\"";
L"bonjour";
u"guten morgen";
@ -285,6 +304,12 @@ int main() {
(string_content))
(string_literal
(string_content))))
(expression_statement
(concatenated_string
(identifier)
(string_literal
(string_content))
(identifier)))
(expression_statement
(string_literal
(escape_sequence)
@ -649,6 +674,10 @@ int main() {
sizeof(x.a);
sizeof(const char **);
sizeof(char * ());
sizeof(1) + 1;
sizeof((1) + 1);
sizeof(int) + 1;
sizeof(struct foo) + sizeof(struct bar) + 1;
}
--------------------------------------------------------------------------------
@ -684,7 +713,81 @@ int main() {
(primitive_type)
(abstract_pointer_declarator
(abstract_function_declarator
(parameter_list)))))))))
(parameter_list))))))
(expression_statement
(binary_expression
(sizeof_expression
(parenthesized_expression
(number_literal)))
(number_literal)))
(expression_statement
(sizeof_expression
(parenthesized_expression
(binary_expression
(parenthesized_expression
(number_literal))
(number_literal)))))
(expression_statement
(binary_expression
(sizeof_expression
(type_descriptor
(primitive_type)))
(number_literal)))
(expression_statement
(binary_expression
(binary_expression
(sizeof_expression
(type_descriptor
(struct_specifier
(type_identifier))))
(sizeof_expression
(type_descriptor
(struct_specifier
(type_identifier)))))
(number_literal))))))
================================================================================
Alignof expressions
================================================================================
typedef struct {
long long __clang_max_align_nonce1
__attribute__((__aligned__(__alignof__(long long))));
long double __clang_max_align_nonce2
__attribute__((__aligned__(__alignof__(long double))));
} max_align_t;
--------------------------------------------------------------------------------
(translation_unit
(type_definition
(struct_specifier
(field_declaration_list
(field_declaration
(sized_type_specifier)
(field_identifier)
(attribute_specifier
(argument_list
(call_expression
(identifier)
(argument_list
(alignof_expression
(type_descriptor
(sized_type_specifier))))))))
(field_declaration
(sized_type_specifier
(primitive_type))
(field_identifier)
(attribute_specifier
(argument_list
(call_expression
(identifier)
(argument_list
(alignof_expression
(type_descriptor
(sized_type_specifier
(primitive_type)))))))))))
(primitive_type)))
================================================================================
Offsetof expressions
@ -693,6 +796,7 @@ Offsetof expressions
int main() {
offsetof( struct x, a );
offsetof( x, a );
offsetof( x, a ) + 1;
}
--------------------------------------------------------------------------------
@ -714,7 +818,14 @@ int main() {
(offsetof_expression
(type_descriptor
(type_identifier))
(field_identifier))))))
(field_identifier)))
(expression_statement
(binary_expression
(offsetof_expression
(type_descriptor
(type_identifier))
(field_identifier))
(number_literal))))))
================================================================================
Compound literals
@ -723,7 +834,9 @@ Compound literals
int main() {
x = (SomeType) {
.f1.f2[f3] = 5,
.f4 = {}
.f4 = {},
.f5[1 ... 10] = -1,
f6: 6,
};
y = (struct SomeStruct) {
7,
@ -759,7 +872,17 @@ int main() {
(initializer_pair
(field_designator
(field_identifier))
(initializer_list))))))
(initializer_list))
(initializer_pair
(field_designator
(field_identifier))
(subscript_range_designator
(number_literal)
(number_literal))
(number_literal))
(initializer_pair
(field_identifier)
(number_literal))))))
(expression_statement
(assignment_expression
(identifier)
@ -1191,3 +1314,115 @@ void fn (int *__restrict__ rptr) {
(pointer_expression
(identifier))
(number_literal))))))
================================================================================
Ternary
================================================================================
void f() {
0 ? 1 : 2;
a = 0 ? 1 : 2;
a = val ? b = 3, 1 : 0;
}
--------------------------------------------------------------------------------
(translation_unit
(function_definition
(primitive_type)
(function_declarator
(identifier)
(parameter_list))
(compound_statement
(expression_statement
(conditional_expression
(number_literal)
(number_literal)
(number_literal)))
(expression_statement
(assignment_expression
(identifier)
(conditional_expression
(number_literal)
(number_literal)
(number_literal))))
(expression_statement
(assignment_expression
(identifier)
(conditional_expression
(identifier)
(comma_expression
(assignment_expression
(identifier)
(number_literal))
(number_literal))
(number_literal)))))))
================================================================================
Concatenated strings
================================================================================
foo("hello" PRI " world");
foo("hello" PRI);
foo("hello" " world");
foo("hello" " world " PRI);
foo(PRI "hello" PRI);
foo(PRI "hello");
--------------------------------------------------------------------------------
(translation_unit
(expression_statement
(call_expression
function: (identifier)
arguments: (argument_list
(concatenated_string
(string_literal
(string_content))
(identifier)
(string_literal
(string_content))))))
(expression_statement
(call_expression
function: (identifier)
arguments: (argument_list
(concatenated_string
(string_literal
(string_content))
(identifier)))))
(expression_statement
(call_expression
function: (identifier)
arguments: (argument_list
(concatenated_string
(string_literal
(string_content))
(string_literal
(string_content))))))
(expression_statement
(call_expression
function: (identifier)
arguments: (argument_list
(concatenated_string
(string_literal
(string_content))
(string_literal
(string_content))
(identifier)))))
(expression_statement
(call_expression
function: (identifier)
arguments: (argument_list
(concatenated_string
(identifier)
(string_literal
(string_content))
(identifier)))))
(expression_statement
(call_expression
function: (identifier)
arguments: (argument_list
(concatenated_string
(identifier)
(string_literal
(string_content)))))))

@ -166,6 +166,16 @@ __fastcall void mymethod(){
return;
}
void __stdcall f() { }
void (__stdcall g)() { }
void __stdcall h();
void (__stdcall j());
typedef void(__stdcall *fp)();
---
(translation_unit
@ -184,4 +194,105 @@ __fastcall void mymethod(){
declarator: (identifier)
parameters: (parameter_list))
body: (compound_statement
(return_statement))))
(return_statement)))
(function_definition
type: (primitive_type)
(ms_call_modifier)
declarator: (function_declarator
declarator: (identifier)
parameters: (parameter_list))
body: (compound_statement))
(function_definition
type: (primitive_type)
declarator: (function_declarator
declarator: (parenthesized_declarator
(ms_call_modifier)
(identifier))
parameters: (parameter_list))
body: (compound_statement))
(declaration
type: (primitive_type)
declarator: (ms_call_modifier)
declarator: (function_declarator
declarator: (identifier)
parameters: (parameter_list)))
(declaration
type: (primitive_type)
declarator: (parenthesized_declarator
(ms_call_modifier)
(function_declarator
declarator: (identifier)
parameters: (parameter_list))))
(type_definition
type: (primitive_type)
declarator: (function_declarator
declarator: (parenthesized_declarator
(ms_call_modifier)
(pointer_declarator
declarator: (type_identifier)))
parameters: (parameter_list))))
================================
SEH exception handling
================================
int main() {
int arg;
__try {
__try {
arg = 1;
__leave;
} __except (-1) {
arg = 2;
}
__leave;
arg = 3;
} __finally {
printf("arg: %d\n", arg);
}
}
---
(translation_unit
(function_definition
(primitive_type)
(function_declarator
(identifier)
(parameter_list))
(compound_statement
(declaration
(primitive_type)
(identifier))
(seh_try_statement
(compound_statement
(seh_try_statement
(compound_statement
(expression_statement
(assignment_expression
(identifier)
(number_literal)))
(seh_leave_statement))
(seh_except_clause
(parenthesized_expression
(number_literal))
(compound_statement
(expression_statement
(assignment_expression
(identifier)
(number_literal))))))
(seh_leave_statement)
(expression_statement
(assignment_expression
(identifier)
(number_literal))))
(seh_finally_clause
(compound_statement
(expression_statement
(call_expression
(identifier)
(argument_list
(string_literal
(string_content)
(escape_sequence))
(identifier))))))))))

@ -42,6 +42,10 @@ Object-like macro definitions
+ y
#define SEVEN 7/* seven has an
* annoying comment */
#define EIGHT(x) do { \
x = x + 1; \
x = x / 2; \
} while (x > 0);
--------------------------------------------------------------------------------
@ -72,7 +76,12 @@ Object-like macro definitions
(preproc_def
name: (identifier)
value: (preproc_arg)
(comment)))
(comment))
(preproc_function_def
name: (identifier)
parameters: (preproc_params
(identifier))
value: (preproc_arg)))
================================================================================
Function-like macro definitions
@ -216,6 +225,54 @@ int b;
(primitive_type)
(identifier))))))
================================================================================
Mixing #elif and #elifdef
================================================================================
#ifndef DEFINE1
int i;
#elif defined(DEFINE2)
int j;
#endif
#if defined DEFINE3
int a;
#elifdef DEFINE4
int b;
#else
int c;
#endif
--------------------------------------------------------------------------------
(translation_unit
(preproc_ifdef
name: (identifier)
(declaration
type: (primitive_type)
declarator: (identifier))
alternative: (preproc_elif
condition: (preproc_defined
(identifier))
(declaration
type: (primitive_type)
declarator: (identifier))))
(preproc_if
condition: (preproc_defined
(identifier))
(declaration
type: (primitive_type)
declarator: (identifier))
alternative: (preproc_elifdef
name: (identifier)
(declaration
type: (primitive_type)
declarator: (identifier))
alternative: (preproc_else
(declaration
type: (primitive_type)
declarator: (identifier))))))
================================================================================
General if blocks
================================================================================