mirror of https://github.com/Wilfred/difftastic/
Merge dbfe5710db into cc064349ac
commit
75bd5f2e57
@ -0,0 +1 @@
|
||||
tree-sitter-gdscript/src/
|
||||
@ -0,0 +1,46 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
|
||||
[*.{json,toml,yml,gyp}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.js]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.scm]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{c,cc,h}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.rs]
|
||||
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
|
||||
|
||||
[parser.c]
|
||||
indent_size = 2
|
||||
|
||||
[{alloc,array,parser}.h]
|
||||
indent_size = 2
|
||||
@ -0,0 +1,37 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
# Generated source files
|
||||
src/*.json linguist-generated
|
||||
src/parser.c linguist-generated
|
||||
src/tree_sitter/* linguist-generated
|
||||
|
||||
# C bindings
|
||||
bindings/c/* linguist-generated
|
||||
CMakeLists.txt linguist-generated
|
||||
Makefile linguist-generated
|
||||
|
||||
# Rust bindings
|
||||
bindings/rust/* linguist-generated
|
||||
Cargo.toml linguist-generated
|
||||
Cargo.lock linguist-generated
|
||||
|
||||
# Node.js bindings
|
||||
bindings/node/* linguist-generated
|
||||
binding.gyp linguist-generated
|
||||
package.json linguist-generated
|
||||
package-lock.json linguist-generated
|
||||
|
||||
# Python bindings
|
||||
bindings/python/** linguist-generated
|
||||
setup.py linguist-generated
|
||||
pyproject.toml linguist-generated
|
||||
|
||||
# Go bindings
|
||||
bindings/go/* linguist-generated
|
||||
go.mod linguist-generated
|
||||
go.sum linguist-generated
|
||||
|
||||
# Swift bindings
|
||||
bindings/swift/** linguist-generated
|
||||
Package.swift linguist-generated
|
||||
Package.resolved linguist-generated
|
||||
@ -0,0 +1,73 @@
|
||||
# This workflow will
|
||||
# - test tree sitter grammar
|
||||
# - upload build native binaries as an artifact for each major platform
|
||||
# - download artifacts for each major platform and bundle them to be published
|
||||
# to npm
|
||||
# when a new version tag is pushed to the master branch.
|
||||
name: Test Build Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: [v*]
|
||||
|
||||
jobs:
|
||||
|
||||
build_native_binaries:
|
||||
strategy:
|
||||
matrix:
|
||||
# Use macos-14 for arm, however the artifact upload name conflicts with
|
||||
# macos-latest. There's probably a way to crossbuild for arm with
|
||||
# prebuildify.
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
# Why is npm only occassionally installing peer dependencies?
|
||||
# I cannot get consistent peer dependency installs with the same command runs.
|
||||
# Should I always explicitly run npm i tree-sitter? The general consensus is yes.
|
||||
# But then, why does it install peer deps sometimes?
|
||||
- run: |
|
||||
node --version
|
||||
npm --version
|
||||
- run: npm ci --include=peer --include=optional --include=dev
|
||||
- run: npm i tree-sitter
|
||||
- run: npm run versions
|
||||
- run: npm test
|
||||
- run: npm run prebuild
|
||||
# upload-artifact@v4 requires each artifact name to be unique.
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: prebuilds-${{ matrix.os }}
|
||||
path: prebuilds
|
||||
retention-days: 1
|
||||
|
||||
|
||||
publish_npm:
|
||||
needs: build_native_binaries
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
# https://docs.github.com/en/actions/use-cases-and-examples/publishing-packages/publishing-nodejs-packages#publishing-packages-to-the-npm-registry
|
||||
# https://github.com/actions/setup-node/issues/342
|
||||
# This is required to publish to npm.
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: |
|
||||
node --version
|
||||
npm --version
|
||||
- run: npm ci
|
||||
# Download all artifacts and merge into prebuilds dir.
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: prebuilds
|
||||
pattern: prebuilds-*
|
||||
merge-multiple: true
|
||||
- run: ls -R prebuilds
|
||||
- run: npm publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
@ -0,0 +1,22 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'grammar.js'
|
||||
- 'corpus/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
- run: |
|
||||
node --version
|
||||
npm --version
|
||||
- run: npm ci --include=dev --include=optional --include=peer
|
||||
- run: npm test
|
||||
@ -0,0 +1,41 @@
|
||||
# Rust artifacts
|
||||
target/
|
||||
|
||||
# Node artifacts
|
||||
build/
|
||||
prebuilds/
|
||||
node_modules/
|
||||
|
||||
# Swift artifacts
|
||||
.build/
|
||||
|
||||
# Go artifacts
|
||||
_obj/
|
||||
|
||||
# Python artifacts
|
||||
.venv/
|
||||
dist/
|
||||
*.egg-info
|
||||
*.whl
|
||||
|
||||
# C artifacts
|
||||
*.a
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
*.dll
|
||||
*.pc
|
||||
parser.exp
|
||||
parser.lib
|
||||
parser.obj
|
||||
scanner.obj
|
||||
|
||||
# Grammar volatiles
|
||||
*.wasm
|
||||
*.obj
|
||||
*.o
|
||||
|
||||
# Archives
|
||||
*.tar.gz
|
||||
*.tgz
|
||||
*.zip
|
||||
@ -0,0 +1,8 @@
|
||||
corpus
|
||||
examples
|
||||
build
|
||||
script
|
||||
parser.exp
|
||||
parser.lib
|
||||
parser.obj
|
||||
scanner.obj
|
||||
@ -0,0 +1,58 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(tree-sitter-gdscript
|
||||
VERSION "6.0.0"
|
||||
DESCRIPTION "Grammar for Godot's built-in scripting language."
|
||||
HOMEPAGE_URL "https://github.com/prestonknopp/tree-sitter-gdscript"
|
||||
LANGUAGES C)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
|
||||
option(TREE_SITTER_REUSE_ALLOCATOR "Reuse the library allocator" OFF)
|
||||
|
||||
set(TREE_SITTER_ABI_VERSION 14 CACHE STRING "Tree-sitter ABI version")
|
||||
if(NOT ${TREE_SITTER_ABI_VERSION} MATCHES "^[0-9]+$")
|
||||
unset(TREE_SITTER_ABI_VERSION CACHE)
|
||||
message(FATAL_ERROR "TREE_SITTER_ABI_VERSION must be an integer")
|
||||
endif()
|
||||
|
||||
find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI")
|
||||
|
||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c"
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json"
|
||||
COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json
|
||||
--abi=${TREE_SITTER_ABI_VERSION}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMENT "Generating parser.c")
|
||||
|
||||
add_library(tree-sitter-gdscript src/parser.c)
|
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c)
|
||||
target_sources(tree-sitter-gdscript PRIVATE src/scanner.c)
|
||||
endif()
|
||||
target_include_directories(tree-sitter-gdscript PRIVATE src)
|
||||
|
||||
target_compile_definitions(tree-sitter-gdscript PRIVATE
|
||||
$<$<BOOL:${TREE_SITTER_REUSE_ALLOCATOR}>:TREE_SITTER_REUSE_ALLOCATOR>
|
||||
$<$<CONFIG:Debug>:TREE_SITTER_DEBUG>)
|
||||
|
||||
set_target_properties(tree-sitter-gdscript
|
||||
PROPERTIES
|
||||
C_STANDARD 11
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}"
|
||||
DEFINE_SYMBOL "")
|
||||
|
||||
configure_file(bindings/c/tree-sitter-gdscript.pc.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-gdscript.pc" @ONLY)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(FILES bindings/c/tree-sitter-gdscript.h
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/tree_sitter")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-gdscript.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig")
|
||||
install(TARGETS tree-sitter-gdscript
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
|
||||
add_custom_target(ts-test "${TREE_SITTER_CLI}" test
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMENT "tree-sitter test")
|
||||
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "tree-sitter-gdscript"
|
||||
description = "Grammar for Godot's built-in scripting language."
|
||||
version = "6.0.0"
|
||||
authors = ["Preston Knopp <prestonknopp@gmail.com>"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
keywords = ["incremental", "parsing", "tree-sitter", "gdscript"]
|
||||
categories = ["parsing", "text-editors"]
|
||||
repository = "https://github.com/prestonknopp/tree-sitter-gdscript"
|
||||
edition = "2021"
|
||||
autoexamples = false
|
||||
|
||||
build = "bindings/rust/build.rs"
|
||||
include = ["bindings/rust/*", "grammar.js", "queries/*", "src/*", "tree-sitter.json"]
|
||||
|
||||
[lib]
|
||||
path = "bindings/rust/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
tree-sitter-language = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.1.22"
|
||||
|
||||
[dev-dependencies]
|
||||
tree-sitter = "0.24.6"
|
||||
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Max Brunsfeld
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@ -0,0 +1,94 @@
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Windows is not supported)
|
||||
endif
|
||||
|
||||
LANGUAGE_NAME := tree-sitter-gdscript
|
||||
HOMEPAGE_URL := https://github.com/prestonknopp/tree-sitter-gdscript
|
||||
VERSION := 6.0.0
|
||||
|
||||
# repository
|
||||
SRC_DIR := src
|
||||
|
||||
TS ?= tree-sitter
|
||||
|
||||
# install directory layout
|
||||
PREFIX ?= /usr/local
|
||||
INCLUDEDIR ?= $(PREFIX)/include
|
||||
LIBDIR ?= $(PREFIX)/lib
|
||||
PCLIBDIR ?= $(LIBDIR)/pkgconfig
|
||||
|
||||
# source/object files
|
||||
PARSER := $(SRC_DIR)/parser.c
|
||||
EXTRAS := $(filter-out $(PARSER),$(wildcard $(SRC_DIR)/*.c))
|
||||
OBJS := $(patsubst %.c,%.o,$(PARSER) $(EXTRAS))
|
||||
|
||||
# flags
|
||||
ARFLAGS ?= rcs
|
||||
override CFLAGS += -I$(SRC_DIR) -std=c11 -fPIC
|
||||
|
||||
# ABI versioning
|
||||
SONAME_MAJOR = $(shell sed -n 's/\#define LANGUAGE_VERSION //p' $(PARSER))
|
||||
SONAME_MINOR = $(word 1,$(subst ., ,$(VERSION)))
|
||||
|
||||
# OS-specific bits
|
||||
ifeq ($(shell uname),Darwin)
|
||||
SOEXT = dylib
|
||||
SOEXTVER_MAJOR = $(SONAME_MAJOR).$(SOEXT)
|
||||
SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).$(SOEXT)
|
||||
LINKSHARED = -dynamiclib -Wl,-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SOEXTVER),-rpath,@executable_path/../Frameworks
|
||||
else
|
||||
SOEXT = so
|
||||
SOEXTVER_MAJOR = $(SOEXT).$(SONAME_MAJOR)
|
||||
SOEXTVER = $(SOEXT).$(SONAME_MAJOR).$(SONAME_MINOR)
|
||||
LINKSHARED = -shared -Wl,-soname,lib$(LANGUAGE_NAME).$(SOEXTVER)
|
||||
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|@PROJECT_VERSION@|$(VERSION)|' \
|
||||
-e 's|@CMAKE_INSTALL_LIBDIR@|$(LIBDIR:$(PREFIX)/%=%)|' \
|
||||
-e 's|@CMAKE_INSTALL_INCLUDEDIR@|$(INCLUDEDIR:$(PREFIX)/%=%)|' \
|
||||
-e 's|@PROJECT_DESCRIPTION@|$(DESCRIPTION)|' \
|
||||
-e 's|@PROJECT_HOMEPAGE_URL@|$(HOMEPAGE_URL)|' \
|
||||
-e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@
|
||||
|
||||
$(PARSER): $(SRC_DIR)/grammar.json
|
||||
$(TS) generate $^
|
||||
|
||||
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
|
||||
|
||||
.PHONY: all install uninstall clean test
|
||||
@ -0,0 +1,37 @@
|
||||
// swift-tools-version:5.3
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "TreeSitterGDScript",
|
||||
products: [
|
||||
.library(name: "TreeSitterGDScript", targets: ["TreeSitterGDScript"]),
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/ChimeHQ/SwiftTreeSitter", from: "0.8.0"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "TreeSitterGDScript",
|
||||
dependencies: [],
|
||||
path: ".",
|
||||
sources: [
|
||||
"src/parser.c",
|
||||
"src/scanner.c",
|
||||
],
|
||||
resources: [
|
||||
.copy("queries")
|
||||
],
|
||||
publicHeadersPath: "bindings/swift",
|
||||
cSettings: [.headerSearchPath("src")]
|
||||
),
|
||||
.testTarget(
|
||||
name: "TreeSitterGDScriptTests",
|
||||
dependencies: [
|
||||
"SwiftTreeSitter",
|
||||
"TreeSitterGDScript",
|
||||
],
|
||||
path: "bindings/swift/TreeSitterGDScriptTests"
|
||||
)
|
||||
],
|
||||
cLanguageStandard: .c11
|
||||
)
|
||||
@ -0,0 +1,51 @@
|
||||
tree-sitter-gdscript
|
||||
====================
|
||||
|
||||
GDScript grammar for [tree-sitter][].
|
||||
|
||||
## Latest Godot Commit Syntactically Synced
|
||||
|
||||
Note: *Some commits may have been missed.*
|
||||
|
||||
```bash
|
||||
git log --oneline --no-merges modules/gdscript
|
||||
```
|
||||
|
||||
[6ae54fd787](https://github.com/godotengine/godot/commits/6ae54fd787)
|
||||
|
||||
## How To
|
||||
|
||||
- Test grammar
|
||||
1. `npm run genTest`
|
||||
- Test scanner
|
||||
1. Edit "src/scanner.c"
|
||||
1. `npm run test`, no need to generate.
|
||||
- Build prebuilds
|
||||
1. `npm run genTest`
|
||||
1. `npm run prebuild`
|
||||
- Build with node-gyp
|
||||
1. `npm run genTest`
|
||||
1. `npm install node-gyp`
|
||||
1. `node-gyp rebuild`
|
||||
- Edit
|
||||
1. Write tests in corpus to express behavior.
|
||||
1. Make grammar or scanner edits.
|
||||
1. See above for running tests.
|
||||
1. `npm run format`
|
||||
1. Commit changes.
|
||||
- If commit is an issue fix, prefix message with `fix(#<issue-number>):`
|
||||
- List the rules changed in commit message.
|
||||
- Note what rules need to be updated in [nvim-treesitter][] queries.
|
||||
1. Commit generated files with the latest non-wip commit.
|
||||
1. Push
|
||||
- Release
|
||||
1. Manually edit version in package files: CMakeLists.txt, Cargo.toml,
|
||||
Makefile, pyproject.toml, tree-sitter.json
|
||||
1. `npm version <major, minor, patch> -m "<> version bump"`
|
||||
1. `git push --follow-tags`
|
||||
|
||||
Note: `node-gyp-build` will check for binaries in both `build` and `prebuilds`
|
||||
directories.
|
||||
|
||||
[tree-sitter]: https://github.com/tree-sitter/tree-sitter
|
||||
[nvim-treesitter]: https://github.com/nvim-treesitter/nvim-treesitter
|
||||
@ -0,0 +1,30 @@
|
||||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "tree_sitter_gdscript_binding",
|
||||
"dependencies": [
|
||||
"<!(node -p \"require('node-addon-api').targets\"):node_addon_api_except",
|
||||
],
|
||||
"include_dirs": [
|
||||
"src",
|
||||
],
|
||||
"sources": [
|
||||
"bindings/node/binding.cc",
|
||||
"src/parser.c",
|
||||
"src/scanner.c",
|
||||
],
|
||||
"conditions": [
|
||||
["OS!='win'", {
|
||||
"cflags_c": [
|
||||
"-std=c11",
|
||||
],
|
||||
}, { # OS == "win"
|
||||
"cflags_c": [
|
||||
"/std:c11",
|
||||
"/utf-8",
|
||||
],
|
||||
}],
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
#ifndef TREE_SITTER_GDSCRIPT_H_
|
||||
#define TREE_SITTER_GDSCRIPT_H_
|
||||
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const TSLanguage *tree_sitter_gdscript(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_GDSCRIPT_H_
|
||||
@ -0,0 +1,10 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||
|
||||
Name: tree-sitter-gdscript
|
||||
Description: @PROJECT_DESCRIPTION@
|
||||
URL: @PROJECT_HOMEPAGE_URL@
|
||||
Version: @PROJECT_VERSION@
|
||||
Libs: -L${libdir} -ltree-sitter-gdscript
|
||||
Cflags: -I${includedir}
|
||||
@ -0,0 +1,15 @@
|
||||
package tree_sitter_gdscript
|
||||
|
||||
// #cgo CFLAGS: -std=c11 -fPIC
|
||||
// #include "../../src/parser.c"
|
||||
// #if __has_include("../../src/scanner.c")
|
||||
// #include "../../src/scanner.c"
|
||||
// #endif
|
||||
import "C"
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// Get the tree-sitter Language for this grammar.
|
||||
func Language() unsafe.Pointer {
|
||||
return unsafe.Pointer(C.tree_sitter_gdscript())
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package tree_sitter_gdscript_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
tree_sitter "github.com/tree-sitter/go-tree-sitter"
|
||||
tree_sitter_gdscript "github.com/prestonknopp/tree-sitter-gdscript/bindings/go"
|
||||
)
|
||||
|
||||
func TestCanLoadGrammar(t *testing.T) {
|
||||
language := tree_sitter.NewLanguage(tree_sitter_gdscript.Language())
|
||||
if language == nil {
|
||||
t.Errorf("Error loading GDScript grammar")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
# This module, i.e. the nim bindings, can be placed anywhere in your nim project
|
||||
# or kept in the bindings directory.
|
||||
#
|
||||
# However the following assumes that when compiling your project or main module that
|
||||
# "tree-sitter-gdscript/" is accessible from the current working directory.
|
||||
{.passC: "-Itree-sitter-gdscript/src".}
|
||||
{.compile: "tree-sitter-gdscript/src/parser.c".}
|
||||
{.compile: "tree-sitter-gdscript/src/scanner.c".}
|
||||
proc tree_sitter_gdscript*(): pointer {.importc.}
|
||||
@ -0,0 +1,20 @@
|
||||
#include <napi.h>
|
||||
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
|
||||
extern "C" TSLanguage *tree_sitter_gdscript();
|
||||
|
||||
// "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, "gdscript");
|
||||
auto language = Napi::External<TSLanguage>::New(env, tree_sitter_gdscript());
|
||||
language.TypeTag(&LANGUAGE_TYPE_TAG);
|
||||
exports["language"] = language;
|
||||
return exports;
|
||||
}
|
||||
|
||||
NODE_API_MODULE(tree_sitter_gdscript_binding, Init)
|
||||
@ -0,0 +1,9 @@
|
||||
const assert = require("node:assert");
|
||||
const { test } = require("node:test");
|
||||
|
||||
const Parser = require("tree-sitter");
|
||||
|
||||
test("can load grammar", () => {
|
||||
const parser = new Parser();
|
||||
assert.doesNotThrow(() => parser.setLanguage(require(".")));
|
||||
});
|
||||
@ -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;
|
||||
@ -0,0 +1,11 @@
|
||||
const root = require("path").join(__dirname, "..", "..");
|
||||
|
||||
module.exports =
|
||||
typeof process.versions.bun === "string"
|
||||
// Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time
|
||||
? require(`../../prebuilds/${process.platform}-${process.arch}/tree-sitter-gdscript.node`)
|
||||
: require("node-gyp-build")(root);
|
||||
|
||||
try {
|
||||
module.exports.nodeTypeInfo = require("../../src/node-types.json");
|
||||
} catch (_) {}
|
||||
@ -0,0 +1,11 @@
|
||||
from unittest import TestCase
|
||||
|
||||
import tree_sitter, tree_sitter_gdscript
|
||||
|
||||
|
||||
class TestLanguage(TestCase):
|
||||
def test_can_load_grammar(self):
|
||||
try:
|
||||
tree_sitter.Language(tree_sitter_gdscript.language())
|
||||
except Exception:
|
||||
self.fail("Error loading GDScript grammar")
|
||||
42
vendored_parsers/tree-sitter-gdscript/bindings/python/tree_sitter_gdscript/__init__.py
generated
vendored
42
vendored_parsers/tree-sitter-gdscript/bindings/python/tree_sitter_gdscript/__init__.py
generated
vendored
@ -0,0 +1,42 @@
|
||||
"""Grammar for Godot's built-in scripting language."""
|
||||
|
||||
from importlib.resources import files as _files
|
||||
|
||||
from ._binding import language
|
||||
|
||||
|
||||
def _get_query(name, file):
|
||||
query = _files(f"{__package__}.queries") / file
|
||||
globals()[name] = query.read_text()
|
||||
return globals()[name]
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
# NOTE: uncomment these to include any queries that this grammar contains:
|
||||
|
||||
# if name == "HIGHLIGHTS_QUERY":
|
||||
# return _get_query("HIGHLIGHTS_QUERY", "highlights.scm")
|
||||
# if name == "INJECTIONS_QUERY":
|
||||
# return _get_query("INJECTIONS_QUERY", "injections.scm")
|
||||
# if name == "LOCALS_QUERY":
|
||||
# return _get_query("LOCALS_QUERY", "locals.scm")
|
||||
# if name == "TAGS_QUERY":
|
||||
# return _get_query("TAGS_QUERY", "tags.scm")
|
||||
|
||||
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||
|
||||
|
||||
__all__ = [
|
||||
"language",
|
||||
# "HIGHLIGHTS_QUERY",
|
||||
# "INJECTIONS_QUERY",
|
||||
# "LOCALS_QUERY",
|
||||
# "TAGS_QUERY",
|
||||
]
|
||||
|
||||
|
||||
def __dir__():
|
||||
return sorted(__all__ + [
|
||||
"__all__", "__builtins__", "__cached__", "__doc__", "__file__",
|
||||
"__loader__", "__name__", "__package__", "__path__", "__spec__",
|
||||
])
|
||||
10
vendored_parsers/tree-sitter-gdscript/bindings/python/tree_sitter_gdscript/__init__.pyi
generated
vendored
10
vendored_parsers/tree-sitter-gdscript/bindings/python/tree_sitter_gdscript/__init__.pyi
generated
vendored
@ -0,0 +1,10 @@
|
||||
from typing import Final
|
||||
|
||||
# NOTE: uncomment these to include any queries that this grammar contains:
|
||||
|
||||
# HIGHLIGHTS_QUERY: Final[str]
|
||||
# INJECTIONS_QUERY: Final[str]
|
||||
# LOCALS_QUERY: Final[str]
|
||||
# TAGS_QUERY: Final[str]
|
||||
|
||||
def language() -> object: ...
|
||||
27
vendored_parsers/tree-sitter-gdscript/bindings/python/tree_sitter_gdscript/binding.c
generated
vendored
27
vendored_parsers/tree-sitter-gdscript/bindings/python/tree_sitter_gdscript/binding.c
generated
vendored
@ -0,0 +1,27 @@
|
||||
#include <Python.h>
|
||||
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
|
||||
TSLanguage *tree_sitter_gdscript(void);
|
||||
|
||||
static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) {
|
||||
return PyCapsule_New(tree_sitter_gdscript(), "tree_sitter.Language", NULL);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
0
vendored_parsers/tree-sitter-gdscript/bindings/python/tree_sitter_gdscript/py.typed
generated
vendored
0
vendored_parsers/tree-sitter-gdscript/bindings/python/tree_sitter_gdscript/py.typed
generated
vendored
@ -0,0 +1,19 @@
|
||||
fn main() {
|
||||
let src_dir = std::path::Path::new("src");
|
||||
|
||||
let mut c_config = cc::Build::new();
|
||||
c_config.std("c11").include(src_dir);
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
c_config.flag("-utf-8");
|
||||
|
||||
let parser_path = src_dir.join("parser.c");
|
||||
c_config.file(&parser_path);
|
||||
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
|
||||
|
||||
let scanner_path = src_dir.join("scanner.c");
|
||||
c_config.file(&scanner_path);
|
||||
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
|
||||
|
||||
c_config.compile("tree-sitter-gdscript");
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
//! This crate provides GDScript language support for the [tree-sitter][] parsing library.
|
||||
//!
|
||||
//! Typically, you will use the [LANGUAGE][] constant to add this language to a
|
||||
//! tree-sitter [Parser][], and then use the parser to parse some code:
|
||||
//!
|
||||
//! ```
|
||||
//! let code = r#"
|
||||
//! "#;
|
||||
//! let mut parser = tree_sitter::Parser::new();
|
||||
//! let language = tree_sitter_gdscript::LANGUAGE;
|
||||
//! parser
|
||||
//! .set_language(&language.into())
|
||||
//! .expect("Error loading GDScript parser");
|
||||
//! let tree = parser.parse(code, None).unwrap();
|
||||
//! assert!(!tree.root_node().has_error());
|
||||
//! ```
|
||||
//!
|
||||
//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
|
||||
//! [tree-sitter]: https://tree-sitter.github.io/
|
||||
|
||||
use tree_sitter_language::LanguageFn;
|
||||
|
||||
extern "C" {
|
||||
fn tree_sitter_gdscript() -> *const ();
|
||||
}
|
||||
|
||||
/// The tree-sitter [`LanguageFn`][LanguageFn] for this grammar.
|
||||
///
|
||||
/// [LanguageFn]: https://docs.rs/tree-sitter-language/*/tree_sitter_language/struct.LanguageFn.html
|
||||
pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_gdscript) };
|
||||
|
||||
/// 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");
|
||||
|
||||
// NOTE: uncomment these to include any queries that this grammar contains:
|
||||
|
||||
// pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm");
|
||||
// pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm");
|
||||
// pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm");
|
||||
// pub const TAGS_QUERY: &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.into())
|
||||
.expect("Error loading GDScript parser");
|
||||
}
|
||||
}
|
||||
16
vendored_parsers/tree-sitter-gdscript/bindings/swift/TreeSitterGDScript/gdscript.h
generated
vendored
16
vendored_parsers/tree-sitter-gdscript/bindings/swift/TreeSitterGDScript/gdscript.h
generated
vendored
@ -0,0 +1,16 @@
|
||||
#ifndef TREE_SITTER_GDSCRIPT_H_
|
||||
#define TREE_SITTER_GDSCRIPT_H_
|
||||
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const TSLanguage *tree_sitter_gdscript(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_GDSCRIPT_H_
|
||||
@ -0,0 +1,12 @@
|
||||
import XCTest
|
||||
import SwiftTreeSitter
|
||||
import TreeSitterGDScript
|
||||
|
||||
final class TreeSitterGDScriptTests: XCTestCase {
|
||||
func testCanLoadGrammar() throws {
|
||||
let parser = Parser()
|
||||
let language = Language(language: tree_sitter_gdscript())
|
||||
XCTAssertNoThrow(try parser.setLanguage(language),
|
||||
"Error loading GDScript grammar")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
(V(1, 2) + V(2, 3)).b().c().d = ('Hello' + 'World').b.c.d()
|
||||
@ -0,0 +1,16 @@
|
||||
extends Node
|
||||
|
||||
func _ready():
|
||||
var x := 2
|
||||
for i in range(x):
|
||||
prints(i)
|
||||
|
||||
while x > 0:
|
||||
print(x)
|
||||
|
||||
if x > 0:
|
||||
print("if test")
|
||||
elif x < 0:
|
||||
print("if test")
|
||||
else:
|
||||
print("if test")
|
||||
@ -0,0 +1,76 @@
|
||||
# Excerpted from:
|
||||
# https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_styleguide.html
|
||||
class_name StateMachine
|
||||
extends Node
|
||||
## Hierarchical State machine for the player.
|
||||
##
|
||||
## Initializes states and delegates engine callbacks ([method Node._physics_process],
|
||||
## [method Node._unhandled_input]) to the state.
|
||||
|
||||
signal state_changed(previous, new)
|
||||
|
||||
@export var initial_state: Node
|
||||
var is_active = true:
|
||||
set = set_is_active
|
||||
|
||||
@onready var _state = initial_state:
|
||||
set = set_state
|
||||
@onready var _state_name = _state.name
|
||||
|
||||
|
||||
func _init():
|
||||
add_to_group("state_machine")
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
print("this happens before the ready method!")
|
||||
|
||||
|
||||
func _ready():
|
||||
state_changed.connect(_on_state_changed)
|
||||
_state.enter()
|
||||
|
||||
|
||||
func _unhandled_input(event):
|
||||
_state.unhandled_input(event)
|
||||
|
||||
|
||||
func _physics_process(delta):
|
||||
_state.physics_process(delta)
|
||||
|
||||
|
||||
func transition_to(target_state_path, msg={}):
|
||||
if not has_node(target_state_path):
|
||||
return
|
||||
|
||||
var target_state = get_node(target_state_path)
|
||||
assert(target_state.is_composite == false)
|
||||
|
||||
_state.exit()
|
||||
self._state = target_state
|
||||
_state.enter(msg)
|
||||
Events.player_state_changed.emit(_state.name)
|
||||
|
||||
|
||||
func set_is_active(value):
|
||||
is_active = value
|
||||
set_physics_process(value)
|
||||
set_process_unhandled_input(value)
|
||||
set_block_signals(not value)
|
||||
|
||||
|
||||
func set_state(value):
|
||||
_state = value
|
||||
_state_name = _state.name
|
||||
|
||||
|
||||
func _on_state_changed(previous, new):
|
||||
print("state changed")
|
||||
state_changed.emit()
|
||||
|
||||
|
||||
class State:
|
||||
var foo = 0
|
||||
|
||||
func _init():
|
||||
print("Hello!")
|
||||
@ -0,0 +1,5 @@
|
||||
func hello():
|
||||
match 0:
|
||||
0 when false: print("does not run")
|
||||
## Invalid:
|
||||
# 1 when true, 2 when false: print("This does not parse")
|
||||
@ -0,0 +1,11 @@
|
||||
# Error: @export cannot be applied to static var
|
||||
# but annotations are still parsed.
|
||||
# @export static var hello: int
|
||||
|
||||
static var foo = 1
|
||||
|
||||
class Foo:
|
||||
static var bar
|
||||
|
||||
static var name := "Me"
|
||||
static var value: int
|
||||
@ -0,0 +1,3 @@
|
||||
func hello():
|
||||
for i: int in [1,2,3]:
|
||||
pass
|
||||
@ -0,0 +1,18 @@
|
||||
take(func name():
|
||||
print('hello')
|
||||
return 1
|
||||
pass
|
||||
1 + 1
|
||||
,
|
||||
""
|
||||
)
|
||||
|
||||
take(func name():
|
||||
1 + 1; pass
|
||||
, "")
|
||||
|
||||
take(func name():
|
||||
pass
|
||||
pass, "")
|
||||
|
||||
take(func name(): "")
|
||||
@ -0,0 +1,2 @@
|
||||
func _init(arg1, arg2).(arg1, arg2):
|
||||
pass
|
||||
@ -0,0 +1,62 @@
|
||||
# Verified with v4.0.beta17.official [c40020513]
|
||||
|
||||
# FIXME: tree-sitter-gdscript can't parse this yet.
|
||||
var p = func(): if true: pass else: pass
|
||||
# If stmts can be inline. (They do not eval to their last expr.)
|
||||
t(func(): if true: 'string' else: 100)
|
||||
|
||||
|
||||
|
||||
# GDScript v2 cannot parse this:
|
||||
#if true: print(1); print(2) else: print(3); print(4)
|
||||
|
||||
# But, can parse this:
|
||||
# prints:
|
||||
# 1
|
||||
# 2
|
||||
var p = func(): if true: print(1); print(2) else: print(3); print(4)
|
||||
|
||||
# prints:
|
||||
# outer 3
|
||||
#var c = func(): if true: if false: print('inner 1'); print('inner 2') else: print('outer 3') else: print(4)
|
||||
|
||||
# some whitespace handling between statement groups.
|
||||
# returns: 2
|
||||
var x = func hello(): var b = 2; return b;
|
||||
|
||||
if true: print('a') ; print('b');
|
||||
else: print('c'); var a: int = 0; a + 1; return a
|
||||
# prints:
|
||||
# a
|
||||
# b
|
||||
|
||||
# func bodies end at a comma. remaining args can follow.
|
||||
# no newline needed.
|
||||
take(func(): var a = 2; return x, 1)
|
||||
take(func():
|
||||
print("hello world")
|
||||
pass, "")
|
||||
|
||||
# func bodies also end at a paren.
|
||||
t(func():
|
||||
print('hello')
|
||||
1 + 1)
|
||||
|
||||
# These are valid.
|
||||
t(func():
|
||||
pass
|
||||
)
|
||||
|
||||
t(
|
||||
func(): pass,
|
||||
func():
|
||||
pass
|
||||
)
|
||||
|
||||
# types can be specified
|
||||
var d = func(hello: int, string: String) -> int:
|
||||
return string.length() + hello
|
||||
|
||||
t(func name(a: int, b: int) -> int: return a + b)
|
||||
t(func name(a: int, b: int) -> int:
|
||||
return a + b, "last argument")
|
||||
@ -0,0 +1,17 @@
|
||||
match x:
|
||||
1: pass
|
||||
_: pass
|
||||
TYPE_ARRAY: pass
|
||||
var new_var: pass
|
||||
|
||||
[]: pass
|
||||
[1, 3, "test", null]: pass
|
||||
[var start, _]: pass
|
||||
[42, ..]: pass
|
||||
|
||||
{}: pass
|
||||
{"name": "Dennis"}: pass
|
||||
{"name": "Dennis", "age": var age}: pass
|
||||
{"key": "godotisawesome", ..}: pass
|
||||
|
||||
1, 2, 3: pass
|
||||
@ -0,0 +1,7 @@
|
||||
var hello:
|
||||
set(v):
|
||||
print()
|
||||
pass
|
||||
get():
|
||||
print()
|
||||
pass
|
||||
@ -0,0 +1,60 @@
|
||||
extends SceneTree
|
||||
|
||||
# interesting, godot looks for a get_node() func when '$' is used on a non node?
|
||||
func get_node(a):
|
||||
return null
|
||||
|
||||
# func hello(one,):
|
||||
# print('hello')
|
||||
|
||||
class n extends Node:
|
||||
|
||||
# no: remote static func rfunc():
|
||||
# no: static remote func rfunc():
|
||||
static func rfunc():
|
||||
pass
|
||||
|
||||
# no: master export var world = 'world'
|
||||
remotesync var hello = 'world'
|
||||
export remote var butt = 'world'
|
||||
|
||||
|
||||
var x setget setter,getter
|
||||
var y setget setter
|
||||
var a setget ,getter
|
||||
|
||||
func setter(a):pass
|
||||
func getter():pass
|
||||
|
||||
func _initialize():
|
||||
var b: String = "hello"
|
||||
print(b)
|
||||
var butt = 'buttface'
|
||||
var next = 'next'
|
||||
var d = {
|
||||
'hello': 'world',
|
||||
world = 'hello',
|
||||
butt: 'buttt',
|
||||
butt + next: 'buttnext',
|
||||
}
|
||||
var d2 = {hello='hello',}
|
||||
print(1 % 5)
|
||||
print(d)
|
||||
|
||||
var n = $node
|
||||
n = $ node
|
||||
n = $'1/a'
|
||||
|
||||
# var x = n is get_node(a)
|
||||
|
||||
var res = 'Response'
|
||||
|
||||
match 'Response':
|
||||
res: print('response')
|
||||
# no:
|
||||
# match {'Response':'ok'}:
|
||||
# {res: 'ok'}: print('okay')
|
||||
|
||||
# no:
|
||||
# match {'Response':'ok'}:
|
||||
# {Response = 'ok'}: print('okay')
|
||||
@ -0,0 +1,5 @@
|
||||
module github.com/prestonknopp/tree-sitter-gdscript
|
||||
|
||||
go 1.22
|
||||
|
||||
require github.com/tree-sitter/go-tree-sitter v0.24.0
|
||||
@ -0,0 +1,930 @@
|
||||
const PREC = {
|
||||
typed_parameter: -1,
|
||||
conditional: -1,
|
||||
|
||||
parenthesized_expression: 1,
|
||||
or: 3,
|
||||
and: 4,
|
||||
in: 5,
|
||||
compare: 6,
|
||||
bitwise_or: 7,
|
||||
bitwise_and: 8,
|
||||
xor: 9,
|
||||
shift: 10,
|
||||
plus: 11,
|
||||
times: 12,
|
||||
power: 13,
|
||||
unary: 14,
|
||||
is: 15,
|
||||
as: 16,
|
||||
call: 17,
|
||||
attribute: 18,
|
||||
attribute_expression: 19,
|
||||
type: 20,
|
||||
};
|
||||
|
||||
module.exports = grammar({
|
||||
name: "gdscript",
|
||||
|
||||
word: ($) => $._identifier,
|
||||
|
||||
extras: ($) => [$.comment, /[\s\uFEFF\u2060\u200B]/, $.line_continuation],
|
||||
|
||||
externals: ($) => [
|
||||
$._newline,
|
||||
$._indent,
|
||||
$._dedent,
|
||||
$._string_start,
|
||||
$._string_content,
|
||||
$._string_end,
|
||||
$._string_name_start,
|
||||
$._node_path_start,
|
||||
|
||||
// Allow the external scanner to check for the validity of closing brackets
|
||||
// so that it can avoid returning dedent tokens between brackets.
|
||||
"]",
|
||||
")",
|
||||
"}",
|
||||
|
||||
// Allow the external scanner to check for valid comma and colon tokens when
|
||||
// scanning for a $._body_end token.
|
||||
",",
|
||||
// Allowing the scanner to check if colon is a valid token when
|
||||
// parsing body ends works for expected cases. One case is using a lambda as
|
||||
// a dictionary key e.g. `{func(): pass: 'value'}`.
|
||||
// However, it breaks nested if else chains.
|
||||
/* ":", */
|
||||
$._body_end,
|
||||
],
|
||||
|
||||
inline: ($) => [$._simple_statement, $._compound_statement],
|
||||
|
||||
supertypes: ($) => [
|
||||
$._compound_statement,
|
||||
$._pattern,
|
||||
$._expression,
|
||||
$._primary_expression,
|
||||
$._attribute_expression,
|
||||
$._parameters,
|
||||
],
|
||||
|
||||
rules: {
|
||||
source: ($) => repeat($._statement),
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Atoms -
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
_identifier: ($) => /[a-zA-Z_][a-zA-Z_0-9]*/,
|
||||
// any "symbol"
|
||||
identifier: ($) => $._identifier,
|
||||
// named symbol of a statement
|
||||
// such as a function name or class name
|
||||
name: ($) => $._identifier,
|
||||
// Code region syntax, parsed to offer code folding support (these are #region and #endregion marks)
|
||||
region_start: ($) =>
|
||||
seq(token(prec(100, "#region")), optional($.region_label)),
|
||||
region_end: ($) =>
|
||||
token(seq(prec(100, "#endregion"), optional(/[^\r\n]*/))),
|
||||
region_label: ($) => /[^\r\n]+/,
|
||||
comment: ($) => token(seq("#", /.*/)),
|
||||
true: ($) => "true",
|
||||
false: ($) => "false",
|
||||
null: ($) => "null",
|
||||
static_keyword: ($) => "static",
|
||||
remote_keyword: ($) =>
|
||||
choice(
|
||||
"remote",
|
||||
"master",
|
||||
"puppet",
|
||||
"remotesync",
|
||||
"mastersync",
|
||||
"puppetsync",
|
||||
),
|
||||
|
||||
escape_sequence: ($) =>
|
||||
token(
|
||||
seq(
|
||||
"\\",
|
||||
choice(
|
||||
/u[a-fA-F\d]{4}/,
|
||||
/U[a-fA-F\d]{6}/,
|
||||
/x[a-fA-F\d]{2}/,
|
||||
/o\d{3}/,
|
||||
/\r\n/,
|
||||
/[^uxo]/,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
string: ($) =>
|
||||
seq(
|
||||
alias($._string_start, '"'),
|
||||
repeat(choice($.escape_sequence, $._string_content)),
|
||||
alias($._string_end, '"'),
|
||||
),
|
||||
|
||||
float: ($) => {
|
||||
const digits = repeat1(/[0-9]+_?/);
|
||||
const exponent = seq(/[eE][\+-]?/, digits);
|
||||
|
||||
return token(
|
||||
choice(
|
||||
seq(digits, ".", optional(digits), optional(exponent)),
|
||||
seq(optional(digits), ".", digits, optional(exponent)),
|
||||
seq(digits, exponent),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
integer: ($) =>
|
||||
token(
|
||||
choice(
|
||||
seq(choice("0x", "0X"), repeat1(/_?[A-Fa-f0-9]+/)),
|
||||
seq(choice("0o", "0O"), repeat1(/_?[0-7]+/)),
|
||||
seq(choice("0b", "0B"), repeat1(/_?[0-1]+/)),
|
||||
repeat1(/[0-9]+_?/),
|
||||
),
|
||||
),
|
||||
|
||||
string_name: ($) =>
|
||||
seq(
|
||||
alias($._string_name_start, '&"'),
|
||||
repeat(choice($.escape_sequence, $._string_content)),
|
||||
alias($._string_end, '"'),
|
||||
),
|
||||
node_path: ($) =>
|
||||
seq(
|
||||
alias($._node_path_start, '^"'),
|
||||
repeat(choice($.escape_sequence, $._string_content)),
|
||||
alias($._string_end, '"'),
|
||||
),
|
||||
get_node: ($) =>
|
||||
prec.right(
|
||||
seq(
|
||||
choice(
|
||||
seq(
|
||||
"$",
|
||||
choice(
|
||||
alias($.string, "value"),
|
||||
seq(
|
||||
optional("/"),
|
||||
$._identifier,
|
||||
repeat(seq("/", $._identifier)),
|
||||
),
|
||||
),
|
||||
),
|
||||
seq(
|
||||
"%",
|
||||
choice(
|
||||
alias($.string, "value"),
|
||||
seq($._identifier, repeat(seq("/", $._identifier))),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Type -
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Higher precedence is required to avoid conflicts with the "in" keyword in
|
||||
// $.for_statement.
|
||||
type: ($) =>
|
||||
prec(PREC.type, choice($.attribute, $.identifier, $.subscript)),
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Statements -
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
_statement: ($) => choice($._simple_statements, $._compound_statement),
|
||||
|
||||
body: ($) =>
|
||||
choice(
|
||||
$._simple_statements,
|
||||
$._newline,
|
||||
$._body_end,
|
||||
seq(
|
||||
$._indent,
|
||||
repeat($._statement),
|
||||
choice($._body_end, $._dedent),
|
||||
),
|
||||
),
|
||||
|
||||
// Simple statements
|
||||
|
||||
_simple_statements: ($) =>
|
||||
seq(
|
||||
trailSep1($._simple_statement, repeat1(";")),
|
||||
choice($._newline, $._body_end),
|
||||
),
|
||||
|
||||
_simple_statement: ($) =>
|
||||
choice(
|
||||
$._annotations,
|
||||
$.signal_statement,
|
||||
$.class_name_statement,
|
||||
$.extends_statement,
|
||||
$.expression_statement,
|
||||
$.export_variable_statement,
|
||||
$.onready_variable_statement,
|
||||
$.variable_statement,
|
||||
$.const_statement,
|
||||
$.return_statement,
|
||||
$.pass_statement,
|
||||
$.break_statement,
|
||||
$.breakpoint_statement,
|
||||
$.continue_statement,
|
||||
$.region_start,
|
||||
$.region_end,
|
||||
),
|
||||
|
||||
expression_statement: ($) =>
|
||||
choice($._expression, $.assignment, $.augmented_assignment),
|
||||
|
||||
// -- Annotation
|
||||
|
||||
annotation: ($) =>
|
||||
prec.right(
|
||||
seq("@", $.identifier, optional(field("arguments", $.arguments))),
|
||||
),
|
||||
|
||||
// The syntax tree looks better when annotations are grouped in a container
|
||||
// node in contexts like variable_statement and function_definition.
|
||||
_annotations: ($) => repeat1($.annotation),
|
||||
annotations: ($) => $._annotations,
|
||||
|
||||
// -- Variables
|
||||
|
||||
inferred_type: ($) => choice(":=", seq(":", "=")),
|
||||
|
||||
_variable_assignment: ($) => seq("=", field("value", $._rhs_expression)),
|
||||
_variable_inferred_type_assignment: ($) =>
|
||||
seq(field("type", $.inferred_type), field("value", $._rhs_expression)),
|
||||
_variable_typed_assignment: ($) =>
|
||||
seq(":", field("type", $.type), "=", field("value", $._rhs_expression)),
|
||||
|
||||
_variable_typed_definition: ($) =>
|
||||
choice(seq(":", field("type", $.type)), $._variable_typed_assignment),
|
||||
|
||||
// -- SetGet
|
||||
|
||||
set_body: ($) => seq("set", $.parameters, ":", field("body", $.body)),
|
||||
get_body: ($) =>
|
||||
seq(
|
||||
"get",
|
||||
// Let's alias parameters as an un-named node since
|
||||
// get does not take any parameters.
|
||||
optional(alias($.parameters, "()")),
|
||||
":",
|
||||
field("body", $.body),
|
||||
),
|
||||
|
||||
_set_assign: ($) => seq("set", "=", field("set", $.setter)),
|
||||
_get_assign: ($) => seq("get", "=", field("get", $.getter)),
|
||||
|
||||
_setget_assign: ($) =>
|
||||
choice(
|
||||
seq($._set_assign, optional(seq(",", $._get_assign))),
|
||||
seq($._get_assign, optional(seq(",", $._set_assign))),
|
||||
),
|
||||
|
||||
_setget_body: ($) =>
|
||||
seq(
|
||||
":",
|
||||
choice(
|
||||
$._setget_assign,
|
||||
seq(
|
||||
$._indent,
|
||||
choice(
|
||||
seq(field("set", $.set_body), optional(field("get", $.get_body))),
|
||||
seq(field("get", $.get_body), optional(field("set", $.set_body))),
|
||||
$._setget_assign,
|
||||
),
|
||||
$._dedent,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
setter: ($) => $._identifier,
|
||||
getter: ($) => $._identifier,
|
||||
setget: ($) =>
|
||||
choice(
|
||||
$._setget_body,
|
||||
seq(
|
||||
"setget",
|
||||
choice($.setter, seq($.setter, ",", $.getter), seq(",", $.getter)),
|
||||
),
|
||||
),
|
||||
|
||||
_variable_statement: ($) =>
|
||||
seq(
|
||||
optional($.annotations),
|
||||
optional(field("static", $.static_keyword)),
|
||||
"var",
|
||||
field("name", $.name),
|
||||
optional(
|
||||
choice(
|
||||
$._variable_typed_definition,
|
||||
$._variable_inferred_type_assignment,
|
||||
$._variable_assignment,
|
||||
),
|
||||
),
|
||||
optional(field("setget", $.setget)),
|
||||
),
|
||||
|
||||
variable_statement: ($) =>
|
||||
seq(optional($.remote_keyword), $._variable_statement),
|
||||
|
||||
export_variable_statement: ($) =>
|
||||
seq(
|
||||
"export",
|
||||
optional(field("arguments", $.arguments)),
|
||||
optional(choice("onready", $.remote_keyword)),
|
||||
$._variable_statement,
|
||||
),
|
||||
|
||||
onready_variable_statement: ($) => seq("onready", $._variable_statement),
|
||||
|
||||
const_statement: ($) =>
|
||||
seq(
|
||||
"const",
|
||||
field("name", $.name),
|
||||
choice(
|
||||
$._variable_inferred_type_assignment,
|
||||
$._variable_typed_assignment,
|
||||
$._variable_assignment,
|
||||
),
|
||||
),
|
||||
|
||||
return_statement: ($) => seq("return", optional($._rhs_expression)),
|
||||
|
||||
pass_statement: ($) => prec.left("pass"),
|
||||
break_statement: ($) => prec.left("break"),
|
||||
breakpoint_statement: ($) => "breakpoint",
|
||||
continue_statement: ($) => prec.left("continue"),
|
||||
|
||||
signal_statement: ($) =>
|
||||
seq(
|
||||
"signal",
|
||||
field("name", $.name),
|
||||
optional(field("parameters", $.parameters)),
|
||||
),
|
||||
|
||||
class_name_statement: ($) =>
|
||||
seq(
|
||||
optional($.annotations),
|
||||
"class_name",
|
||||
field("name", $.name),
|
||||
optional(seq(",", field("icon_path", $.string))),
|
||||
field("extends", optional($.extends_statement)),
|
||||
),
|
||||
|
||||
extends_statement: ($) =>
|
||||
prec(PREC.type, seq("extends", choice($.string, $.type))),
|
||||
|
||||
_compound_statement: ($) =>
|
||||
choice(
|
||||
$.if_statement,
|
||||
$.for_statement,
|
||||
$.while_statement,
|
||||
$.function_definition,
|
||||
$.constructor_definition,
|
||||
$.class_definition,
|
||||
$.enum_definition,
|
||||
$.match_statement,
|
||||
),
|
||||
|
||||
if_statement: ($) =>
|
||||
seq(
|
||||
"if",
|
||||
field("condition", $._expression),
|
||||
":",
|
||||
field("body", $.body),
|
||||
repeat(field("alternative", $.elif_clause)),
|
||||
optional(field("alternative", $.else_clause)),
|
||||
),
|
||||
|
||||
elif_clause: ($) =>
|
||||
seq(
|
||||
"elif",
|
||||
field("condition", $._expression),
|
||||
":",
|
||||
field("body", $.body),
|
||||
),
|
||||
|
||||
else_clause: ($) => seq("else", ":", field("body", $.body)),
|
||||
|
||||
for_statement: ($) =>
|
||||
seq(
|
||||
"for",
|
||||
field("left", $.identifier),
|
||||
optional(seq(":", field("type", $.type))),
|
||||
"in",
|
||||
field("right", $._expression),
|
||||
":",
|
||||
field("body", $.body),
|
||||
),
|
||||
|
||||
while_statement: ($) =>
|
||||
seq(
|
||||
"while",
|
||||
field("condition", $._expression),
|
||||
":",
|
||||
field("body", $.body),
|
||||
),
|
||||
|
||||
class_definition: ($) =>
|
||||
seq(
|
||||
optional($.annotations),
|
||||
"class",
|
||||
field("name", $.name),
|
||||
optional(field("extends", $.extends_statement)),
|
||||
":",
|
||||
field("body", $.class_body),
|
||||
),
|
||||
|
||||
class_body: ($) =>
|
||||
choice(
|
||||
$._class_member,
|
||||
$._newline,
|
||||
$._body_end,
|
||||
seq(
|
||||
$._indent,
|
||||
repeat($._class_member),
|
||||
choice($._body_end, $._dedent),
|
||||
),
|
||||
),
|
||||
|
||||
// A class body can only directly contain class members. Then these class
|
||||
// members can contain statements in their bodies, but not directly in the
|
||||
// class.
|
||||
_class_member: ($) =>
|
||||
choice($._simple_class_members, $._compound_class_member),
|
||||
|
||||
_simple_class_members: ($) =>
|
||||
seq(
|
||||
trailSep1($._simple_class_member, repeat1(";")),
|
||||
choice($._newline, $._body_end),
|
||||
),
|
||||
|
||||
_simple_class_member: ($) =>
|
||||
choice(
|
||||
$.const_statement,
|
||||
$.extends_statement,
|
||||
$.pass_statement,
|
||||
$.signal_statement,
|
||||
$.variable_statement,
|
||||
),
|
||||
|
||||
_compound_class_member: ($) =>
|
||||
choice($.class_definition, $.enum_definition, $.function_definition),
|
||||
|
||||
// -- Enum
|
||||
enum_definition: ($) =>
|
||||
seq(
|
||||
"enum",
|
||||
optional(field("name", $.name)),
|
||||
field("body", $.enumerator_list),
|
||||
),
|
||||
|
||||
enumerator_list: ($) => seq("{", trailCommaSep1($.enumerator), "}"),
|
||||
|
||||
_enumerator_expression: ($) =>
|
||||
choice(
|
||||
$.integer,
|
||||
$.binary_operator,
|
||||
$.identifier,
|
||||
$.unary_operator,
|
||||
$.attribute,
|
||||
$.subscript,
|
||||
$.call,
|
||||
$.parenthesized_expression,
|
||||
),
|
||||
|
||||
enumerator: ($) =>
|
||||
seq(
|
||||
field("left", $.identifier),
|
||||
optional(seq("=", field("right", $._enumerator_expression))),
|
||||
),
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Match -
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
match_statement: ($) =>
|
||||
seq(
|
||||
"match",
|
||||
field("value", $._expression),
|
||||
":",
|
||||
field("body", $.match_body),
|
||||
),
|
||||
|
||||
match_body: ($) =>
|
||||
seq(
|
||||
$._indent,
|
||||
// Annotations are generally supported as statements throughout code but
|
||||
// as match blocks are expressions, we need to explicitly allow them
|
||||
// here. The pattern section body itself supports statements (thus annotations).
|
||||
repeat1(
|
||||
seq(
|
||||
optional(repeat(seq($.annotation, optional($._newline)))),
|
||||
$.pattern_section,
|
||||
),
|
||||
),
|
||||
$._dedent,
|
||||
),
|
||||
|
||||
// Sources:
|
||||
// - https://github.com/godotengine/godot-proposals/issues/4775
|
||||
// - https://github.com/godotengine/godot/pull/80085
|
||||
//
|
||||
// One guard per section. Meaning Comma separated patterns cannot each have
|
||||
// a guard.
|
||||
pattern_guard: ($) => seq("when", $._expression),
|
||||
|
||||
pattern_section: ($) =>
|
||||
seq(
|
||||
commaSep1($._pattern),
|
||||
optional($.pattern_guard),
|
||||
":",
|
||||
field("body", $.body),
|
||||
),
|
||||
|
||||
_pattern: ($) =>
|
||||
choice(
|
||||
$._primary_expression,
|
||||
$.conditional_expression,
|
||||
$.pattern_binding,
|
||||
),
|
||||
|
||||
// Rather than creating distinct pattern array, dictionary, and expression
|
||||
// rules, we insert $.pattern_binding and $.pattern_open_ending into the
|
||||
// $.array and $.dictionary rules. Although, they are only valid in the
|
||||
// context of a pattern, this keeps the grammar simpler and allows us to
|
||||
// have arbitrary expressions in patterns.
|
||||
//
|
||||
// Additionally, $.dictionary accepts comma separated list of keys mixed
|
||||
// with pairs. This is also only valid in patterns and keeps the grammar a
|
||||
// bit simpler.
|
||||
pattern_binding: ($) => seq("var", $.identifier),
|
||||
pattern_open_ending: ($) => "..",
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Expressions -
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
_expression: ($) => choice($._primary_expression, $.conditional_expression),
|
||||
|
||||
_primary_expression: ($) =>
|
||||
choice(
|
||||
$.binary_operator,
|
||||
$.identifier,
|
||||
$.string,
|
||||
$.integer,
|
||||
$.float,
|
||||
$.true,
|
||||
$.false,
|
||||
$.null,
|
||||
$.unary_operator,
|
||||
$.string_name,
|
||||
$.node_path,
|
||||
$.get_node,
|
||||
$.attribute,
|
||||
$.subscript,
|
||||
$.base_call,
|
||||
$.call,
|
||||
$.array,
|
||||
$.dictionary,
|
||||
$.parenthesized_expression,
|
||||
$.await_expression,
|
||||
),
|
||||
|
||||
_rhs_expression: ($) => choice($._expression, $.lambda),
|
||||
|
||||
// This makes an attribute's ast linear
|
||||
// When attribute is used inside $.attribute it becomes recursive spaghetti
|
||||
_attribute_expression: ($) =>
|
||||
prec(
|
||||
PREC.attribute_expression,
|
||||
choice(
|
||||
$.binary_operator,
|
||||
$.identifier,
|
||||
$.string,
|
||||
$.integer,
|
||||
$.float,
|
||||
$.true,
|
||||
$.false,
|
||||
$.null,
|
||||
$.unary_operator,
|
||||
$.node_path,
|
||||
$.get_node,
|
||||
$.subscript,
|
||||
$.base_call,
|
||||
$.call,
|
||||
$.array,
|
||||
$.dictionary,
|
||||
$.parenthesized_expression,
|
||||
),
|
||||
),
|
||||
|
||||
// -- Operators
|
||||
|
||||
binary_operator: ($) => {
|
||||
// Inspired by tree-sitter-c
|
||||
const operators = [
|
||||
[seq("not", "in"), PREC.in],
|
||||
["in", PREC.in],
|
||||
["and", PREC.and],
|
||||
["&&", PREC.and],
|
||||
["or", PREC.or],
|
||||
["||", PREC.or],
|
||||
["+", PREC.plus],
|
||||
["-", PREC.plus],
|
||||
["*", PREC.times],
|
||||
["/", PREC.times],
|
||||
["**", PREC.times],
|
||||
["%", PREC.times],
|
||||
["|", PREC.bitwise_or],
|
||||
["&", PREC.bitwise_and],
|
||||
["^", PREC.xor],
|
||||
["<<", PREC.shift],
|
||||
[">>", PREC.shift],
|
||||
["<", PREC.compare],
|
||||
["<=", PREC.compare],
|
||||
["==", PREC.compare],
|
||||
["!=", PREC.compare],
|
||||
[">=", PREC.compare],
|
||||
[">", PREC.compare],
|
||||
["as", PREC.as],
|
||||
[seq("is", "not"), PREC.is],
|
||||
["is", PREC.is],
|
||||
];
|
||||
|
||||
const choices = operators.map(([operator, precedence]) => {
|
||||
return prec.left(
|
||||
precedence,
|
||||
seq(
|
||||
field("left", $._primary_expression),
|
||||
field("op", operator),
|
||||
field("right", $._primary_expression),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
return choice(...choices);
|
||||
},
|
||||
|
||||
unary_operator: ($) =>
|
||||
choice(
|
||||
prec(PREC.unary, seq(choice("not", "!"), $._primary_expression)),
|
||||
prec(PREC.unary, seq("-", $._primary_expression)),
|
||||
prec(PREC.unary, seq("+", $._primary_expression)),
|
||||
prec(PREC.unary, seq("~", $._primary_expression)),
|
||||
),
|
||||
|
||||
// -- Accessors
|
||||
subscript_arguments: ($) =>
|
||||
seq("[", trailCommaSep1($._rhs_expression), "]"),
|
||||
subscript: ($) =>
|
||||
// The high precedence resolves ambiguity when parsing a definition
|
||||
// followed by code on the same line like class C: var x = my_array[0]
|
||||
prec(
|
||||
PREC.attribute,
|
||||
seq($._primary_expression, field("arguments", $.subscript_arguments)),
|
||||
),
|
||||
|
||||
attribute_call: ($) =>
|
||||
prec(PREC.attribute, seq($.identifier, field("arguments", $.arguments))),
|
||||
attribute_subscript: ($) =>
|
||||
prec(
|
||||
PREC.attribute,
|
||||
seq($.identifier, field("arguments", $.subscript_arguments)),
|
||||
),
|
||||
attribute: ($) =>
|
||||
prec(
|
||||
PREC.attribute,
|
||||
seq(
|
||||
$._attribute_expression,
|
||||
repeat1(
|
||||
seq(
|
||||
".",
|
||||
choice($.attribute_subscript, $.attribute_call, $.identifier),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
conditional_expression: ($) =>
|
||||
prec.right(
|
||||
PREC.conditional,
|
||||
seq(
|
||||
field("left", $._expression),
|
||||
"if",
|
||||
field("condition", $._expression),
|
||||
"else",
|
||||
field("right", $._expression),
|
||||
),
|
||||
),
|
||||
|
||||
parenthesized_expression: ($) =>
|
||||
prec(PREC.parenthesized_expression, seq("(", $._rhs_expression, ")")),
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Await -
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
await_expression: ($) => seq("await", $._expression),
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Assignment -
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
assignment: ($) =>
|
||||
seq(field("left", $._expression), "=", field("right", $._rhs_expression)),
|
||||
|
||||
augmented_assignment: ($) =>
|
||||
seq(
|
||||
field("left", $._expression),
|
||||
field(
|
||||
"op",
|
||||
choice(
|
||||
"+=",
|
||||
"-=",
|
||||
"*=",
|
||||
"/=",
|
||||
"**=",
|
||||
"%=",
|
||||
">>=",
|
||||
"<<=",
|
||||
"&=",
|
||||
"^=",
|
||||
"|=",
|
||||
),
|
||||
),
|
||||
field("right", $._rhs_expression),
|
||||
),
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Data Structs -
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
pair: ($) =>
|
||||
seq(
|
||||
choice(
|
||||
seq(field("left", $._rhs_expression), ":"), // Lambdas are allowed here.
|
||||
seq(field("left", $.identifier), "="),
|
||||
),
|
||||
field("value", choice($._rhs_expression, $.pattern_binding)),
|
||||
),
|
||||
|
||||
// See $.pattern_binding for more information.
|
||||
dictionary: ($) =>
|
||||
seq(
|
||||
"{",
|
||||
optional(
|
||||
trailCommaSep1(
|
||||
choice(
|
||||
$.pair,
|
||||
// This allows dictionaries in pattern sections to support "key"
|
||||
// only pattern matching:
|
||||
// match { "key_to_match": some_value }:
|
||||
// { "key_to_match" }: print("Matches here!")
|
||||
$._primary_expression,
|
||||
),
|
||||
),
|
||||
),
|
||||
optional($.pattern_open_ending),
|
||||
"}",
|
||||
),
|
||||
|
||||
array: ($) =>
|
||||
seq(
|
||||
"[",
|
||||
optional(trailCommaSep1(choice($._rhs_expression, $.pattern_binding))),
|
||||
optional($.pattern_open_ending),
|
||||
"]",
|
||||
),
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Function Definition -
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
typed_parameter: ($) =>
|
||||
prec(PREC.typed_parameter, seq($.identifier, ":", field("type", $.type))),
|
||||
|
||||
default_parameter: ($) =>
|
||||
seq($.identifier, "=", field("value", $._rhs_expression)),
|
||||
|
||||
typed_default_parameter: ($) =>
|
||||
prec(
|
||||
PREC.typed_parameter,
|
||||
choice(
|
||||
seq(
|
||||
$.identifier,
|
||||
":",
|
||||
field("type", $.type),
|
||||
"=",
|
||||
field("value", $._rhs_expression),
|
||||
),
|
||||
seq(
|
||||
$.identifier,
|
||||
field("type", $.inferred_type),
|
||||
field("value", $._rhs_expression),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
variadic_parameter: ($) =>
|
||||
seq(
|
||||
"...",
|
||||
$._parameters,
|
||||
),
|
||||
|
||||
_parameters: ($) =>
|
||||
choice(
|
||||
$.identifier,
|
||||
$.typed_parameter,
|
||||
$.default_parameter,
|
||||
$.typed_default_parameter,
|
||||
$.variadic_parameter,
|
||||
),
|
||||
|
||||
parameters: ($) => seq("(", optional(trailCommaSep1($._parameters)), ")"),
|
||||
|
||||
_return_type: ($) => seq("->", field("return_type", $.type)),
|
||||
|
||||
function_definition: ($) =>
|
||||
seq(
|
||||
optional($.annotations),
|
||||
optional(choice($.static_keyword, $.remote_keyword)),
|
||||
"func",
|
||||
optional(field("name", $.name)),
|
||||
field("parameters", $.parameters),
|
||||
optional($._return_type),
|
||||
// body is optional to support abstract function definitions. Without
|
||||
// body, there must be a newline or body_end. _return_type with generic
|
||||
// parameters without a newline or body_end will erroneously parse
|
||||
// any following lines.
|
||||
choice(seq(":", field("body", $.body)), $._newline, $._body_end),
|
||||
),
|
||||
|
||||
lambda: ($) =>
|
||||
seq(
|
||||
"func",
|
||||
optional(field("name", $.name)),
|
||||
field("parameters", $.parameters),
|
||||
optional($._return_type),
|
||||
":",
|
||||
field("body", $.body),
|
||||
),
|
||||
|
||||
constructor_definition: ($) =>
|
||||
seq(
|
||||
"func",
|
||||
"_init",
|
||||
field("parameters", $.parameters),
|
||||
optional(seq(".", field("arguments", $.arguments))),
|
||||
optional($._return_type),
|
||||
":",
|
||||
field("body", $.body),
|
||||
),
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Function Call -
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
arguments: ($) =>
|
||||
seq("(", optional(trailCommaSep1($._rhs_expression)), ")"),
|
||||
|
||||
base_call: ($) =>
|
||||
prec(PREC.call, seq(".", $.identifier, field("arguments", $.arguments))),
|
||||
|
||||
call: ($) =>
|
||||
prec(
|
||||
PREC.call,
|
||||
seq($._primary_expression, field("arguments", $.arguments)),
|
||||
),
|
||||
// This rule is for trailing backslashes to indicate line continuation. We
|
||||
// capture those as anonymous '\' tokens to be able to preserve them in code
|
||||
// formatters.
|
||||
line_continuation: ($) => token(seq("\\", /\r?\n/)),
|
||||
}, // end rules
|
||||
});
|
||||
|
||||
function sep1(rule, separator) {
|
||||
return seq(rule, repeat(seq(separator, rule)));
|
||||
}
|
||||
|
||||
function trailSep1(rule, sep) {
|
||||
return seq(sep1(rule, sep), optional(sep));
|
||||
}
|
||||
|
||||
function commaSep1(rule) {
|
||||
return sep1(rule, ",");
|
||||
}
|
||||
|
||||
function trailCommaSep1(rule) {
|
||||
return trailSep1(rule, ",");
|
||||
}
|
||||
@ -0,0 +1,399 @@
|
||||
{
|
||||
"name": "tree-sitter-gdscript",
|
||||
"version": "6.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "tree-sitter-gdscript",
|
||||
"version": "6.0.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-addon-api": "^8.3.1",
|
||||
"node-gyp-build": "^4.8.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prebuildify": "^6.0.1",
|
||||
"prettier": "^3.6.2",
|
||||
"tree-sitter-cli": "^0.24.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tree-sitter": "^0.21.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"tree-sitter": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.75.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.75.0.tgz",
|
||||
"integrity": "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz",
|
||||
"integrity": "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18 || ^20 || >= 21"
|
||||
}
|
||||
},
|
||||
"node_modules/node-gyp-build": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
|
||||
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"node-gyp-build": "bin.js",
|
||||
"node-gyp-build-optional": "optional.js",
|
||||
"node-gyp-build-test": "build-test.js"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz",
|
||||
"integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/prebuildify": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/prebuildify/-/prebuildify-6.0.1.tgz",
|
||||
"integrity": "sha512-8Y2oOOateom/s8dNBsGIcnm6AxPmLH4/nanQzL5lQMU+sC0CMhzARZHizwr36pUPLdvBnOkCNQzxg4djuFSgIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.5",
|
||||
"mkdirp-classic": "^0.5.3",
|
||||
"node-abi": "^3.3.0",
|
||||
"npm-run-path": "^3.1.0",
|
||||
"pump": "^3.0.0",
|
||||
"tar-fs": "^2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"prebuildify": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
||||
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
||||
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^2.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-sitter": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.21.1.tgz",
|
||||
"integrity": "sha512-7dxoA6kYvtgWw80265MyqJlkRl4yawIjO7S5MigytjELkX43fV2WsAXzsNfO7sBpPPCF5Gp0+XzHk0DwLCq3xQ==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"node-addon-api": "^8.0.0",
|
||||
"node-gyp-build": "^4.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-sitter-cli": {
|
||||
"version": "0.24.7",
|
||||
"resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.24.7.tgz",
|
||||
"integrity": "sha512-o4gnE82pVmMMhJbWwD6+I9yr4lXii5Ci5qEQ2pFpUbVy1YiD8cizTJaqdcznA0qEbo7l2OneI1GocChPrI4YGQ==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"tree-sitter": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "tree-sitter-gdscript",
|
||||
"version": "6.0.0",
|
||||
"description": "Grammar for Godot's built-in scripting language.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/prestonknopp/tree-sitter-gdscript.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "Preston Knopp",
|
||||
"main": "bindings/node",
|
||||
"keywords": [
|
||||
"incremental",
|
||||
"parsing",
|
||||
"tree-sitter",
|
||||
"gdscript",
|
||||
"godot"
|
||||
],
|
||||
"files": [
|
||||
"grammar.js",
|
||||
"tree-sitter.json",
|
||||
"binding.gyp",
|
||||
"prebuilds/**",
|
||||
"bindings/node/*",
|
||||
"queries/*",
|
||||
"src/**",
|
||||
"*.wasm"
|
||||
],
|
||||
"dependencies": {
|
||||
"node-addon-api": "^8.3.1",
|
||||
"node-gyp-build": "^4.8.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prebuildify": "^6.0.1",
|
||||
"prettier": "^3.6.2",
|
||||
"tree-sitter-cli": "^0.24.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tree-sitter": "^0.21.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"tree-sitter": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"install": "node-gyp-build",
|
||||
"prebuild": "prebuildify --strip -t electron@34.5.5 -t electron@35.3.0 -t electron@36.2.0 -t v20.19.1 -t v22.15.0 -t v23.11.0 -t v24.0.1",
|
||||
"prestart": "tree-sitter build --wasm",
|
||||
"start": "tree-sitter playground",
|
||||
"versions": "node --version && npm --version && tree-sitter --version",
|
||||
"test": "tree-sitter test && node --test bindings/node/*_test.js",
|
||||
"generate": "tree-sitter generate",
|
||||
"genTest": "tree-sitter generate && npm test",
|
||||
"parse": "tree-sitter parse",
|
||||
"ts": "tree-sitter",
|
||||
"format": "prettier -w grammar.js package.json"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=42", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "tree-sitter-gdscript"
|
||||
description = "Grammar for Godot's built-in scripting language."
|
||||
version = "6.0.0"
|
||||
keywords = ["incremental", "parsing", "tree-sitter", "gdscript"]
|
||||
classifiers = [
|
||||
"Intended Audience :: Developers",
|
||||
"Topic :: Software Development :: Compilers",
|
||||
"Topic :: Text Processing :: Linguistic",
|
||||
"Typing :: Typed",
|
||||
]
|
||||
authors = [{ name = "Preston Knopp", email = "prestonknopp@gmail.com" }]
|
||||
requires-python = ">=3.9"
|
||||
license.text = "MIT"
|
||||
readme = "README.md"
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/prestonknopp/tree-sitter-gdscript"
|
||||
|
||||
[project.optional-dependencies]
|
||||
core = ["tree-sitter~=0.22"]
|
||||
|
||||
[tool.cibuildwheel]
|
||||
build = "cp39-*"
|
||||
build-frontend = "build"
|
||||
@ -0,0 +1,62 @@
|
||||
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_gdscript", "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 = "cp39", "abi3"
|
||||
return python, abi, platform
|
||||
|
||||
|
||||
setup(
|
||||
packages=find_packages("bindings/python"),
|
||||
package_dir={"": "bindings/python"},
|
||||
package_data={
|
||||
"tree_sitter_gdscript": ["*.pyi", "py.typed"],
|
||||
"tree_sitter_gdscript.queries": ["*.scm"],
|
||||
},
|
||||
ext_package="tree_sitter_gdscript",
|
||||
ext_modules=[
|
||||
Extension(
|
||||
name="_binding",
|
||||
sources=[
|
||||
"bindings/python/tree_sitter_gdscript/binding.c",
|
||||
"src/parser.c",
|
||||
"src/scanner.c",
|
||||
],
|
||||
extra_compile_args=[
|
||||
"-std=c11",
|
||||
"-fvisibility=hidden",
|
||||
] if system() != "Windows" else [
|
||||
"/std:c11",
|
||||
"/utf-8",
|
||||
],
|
||||
define_macros=[
|
||||
("Py_LIMITED_API", "0x03090000"),
|
||||
("PY_SSIZE_T_CLEAN", None),
|
||||
("TREE_SITTER_HIDE_SYMBOLS", 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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,554 @@
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "tree_sitter/parser.h"
|
||||
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define VEC_RESIZE(vec, _cap) \
|
||||
void *tmp = realloc((vec)->data, (_cap) * sizeof((vec)->data[0])); \
|
||||
assert(tmp != NULL); \
|
||||
(vec)->data = tmp; \
|
||||
(vec)->cap = (_cap);
|
||||
|
||||
#define VEC_GROW(vec, _cap) \
|
||||
if ((vec)->cap < (_cap)) { \
|
||||
VEC_RESIZE((vec), (_cap)); \
|
||||
}
|
||||
|
||||
#define VEC_PUSH(vec, el) \
|
||||
if ((vec)->cap == (vec)->len) { \
|
||||
VEC_RESIZE((vec), MAX(16, (vec)->len * 2)); \
|
||||
} \
|
||||
(vec)->data[(vec)->len++] = (el);
|
||||
|
||||
#define VEC_POP(vec) (vec)->len--;
|
||||
|
||||
#define VEC_NEW \
|
||||
{ .len = 0, .cap = 0, .data = NULL }
|
||||
|
||||
#define VEC_BACK(vec) ((vec)->data[(vec)->len - 1])
|
||||
|
||||
#define VEC_FREE(vec) \
|
||||
{ \
|
||||
if ((vec)->data != NULL) \
|
||||
free((vec)->data); \
|
||||
}
|
||||
|
||||
#define VEC_CLEAR(vec) \
|
||||
{ (vec)->len = 0; }
|
||||
|
||||
enum TokenType {
|
||||
NEWLINE,
|
||||
INDENT,
|
||||
DEDENT,
|
||||
STRING_START,
|
||||
STRING_CONTENT,
|
||||
STRING_END,
|
||||
STRING_NAME_START,
|
||||
NODE_PATH_START,
|
||||
CLOSE_PAREN,
|
||||
CLOSE_BRACKET,
|
||||
CLOSE_BRACE,
|
||||
COMMA,
|
||||
/* COLON, // See grammar.js externals */
|
||||
BODY_END,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SingleQuote = 1 << 0,
|
||||
DoubleQuote = 1 << 1,
|
||||
Triple = 1 << 2,
|
||||
Raw = 1 << 3,
|
||||
Name = 1 << 4,
|
||||
NodePath = 1 << 5,
|
||||
} Flags;
|
||||
|
||||
typedef struct {
|
||||
char flags;
|
||||
} Delimiter;
|
||||
|
||||
static inline Delimiter new_delimiter() { return (Delimiter){0}; }
|
||||
|
||||
static inline bool is_triple(Delimiter *delimiter) {
|
||||
return delimiter->flags & Triple;
|
||||
}
|
||||
|
||||
static inline bool is_raw(Delimiter *delimiter) {
|
||||
return delimiter->flags & Raw;
|
||||
}
|
||||
|
||||
static inline bool is_name(Delimiter *delimiter) {
|
||||
return delimiter->flags & Name;
|
||||
}
|
||||
|
||||
static inline bool is_node_path(Delimiter *delimiter) {
|
||||
return delimiter->flags & NodePath;
|
||||
}
|
||||
|
||||
static inline int32_t end_character(Delimiter *delimiter) {
|
||||
if (delimiter->flags & SingleQuote) {
|
||||
return '\'';
|
||||
}
|
||||
if (delimiter->flags & DoubleQuote) {
|
||||
return '"';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void set_triple(Delimiter *delimiter) {
|
||||
delimiter->flags |= Triple;
|
||||
}
|
||||
|
||||
static inline void set_raw(Delimiter *delimiter) {
|
||||
delimiter->flags |= Raw;
|
||||
}
|
||||
|
||||
static inline void set_name(Delimiter *delimiter) {
|
||||
delimiter->flags |= Name;
|
||||
}
|
||||
|
||||
static inline void set_node_path(Delimiter *delimiter) {
|
||||
delimiter->flags |= NodePath;
|
||||
}
|
||||
|
||||
static inline void set_end_character(Delimiter *delimiter, int32_t character) {
|
||||
switch (character) {
|
||||
case '\'':
|
||||
delimiter->flags |= SingleQuote;
|
||||
break;
|
||||
case '"':
|
||||
delimiter->flags |= DoubleQuote;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *delimiter_string(Delimiter *delimiter) {
|
||||
if (delimiter->flags & SingleQuote) {
|
||||
return "\'";
|
||||
}
|
||||
if (delimiter->flags & DoubleQuote) {
|
||||
return "\"";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint32_t len;
|
||||
uint32_t cap;
|
||||
uint16_t *data;
|
||||
} indent_vec;
|
||||
|
||||
typedef struct {
|
||||
uint32_t len;
|
||||
uint32_t cap;
|
||||
Delimiter *data;
|
||||
} delimiter_vec;
|
||||
|
||||
typedef struct {
|
||||
indent_vec *indents;
|
||||
delimiter_vec *delimiters;
|
||||
} Scanner;
|
||||
|
||||
static inline void advance(TSLexer *lexer) { lexer->advance(lexer, false); }
|
||||
|
||||
static inline void skip(TSLexer *lexer) { lexer->advance(lexer, true); }
|
||||
|
||||
/**
|
||||
* Skip whitespace characters and update indentation tracking.
|
||||
*
|
||||
* @param lexer The lexer to advance
|
||||
* @param indent_length Pointer to current indentation length (modified in place)
|
||||
* @param found_end_of_line Pointer to end-of-line flag (set to true if newline encountered), can be NULL
|
||||
* @return true if a whitespace character was processed, false otherwise
|
||||
*
|
||||
* Handles:
|
||||
* - ' ' (space): increments indent_length
|
||||
* - '\t' (tab): adds 8 to indent_length
|
||||
* - '\n' (newline): resets indent_length to 0, sets found_end_of_line to true (if not NULL)
|
||||
* - '\r', '\f' (carriage return, form feed): resets indent_length to 0
|
||||
*/
|
||||
static inline bool skip_whitespace(TSLexer *lexer, uint32_t *indent_length, bool *found_end_of_line) {
|
||||
if (lexer->lookahead == '\n') {
|
||||
if (found_end_of_line) {
|
||||
*found_end_of_line = true;
|
||||
}
|
||||
|
||||
*indent_length = 0;
|
||||
skip(lexer);
|
||||
|
||||
return true;
|
||||
} else if (lexer->lookahead == ' ') {
|
||||
(*indent_length)++;
|
||||
skip(lexer);
|
||||
|
||||
return true;
|
||||
} else if (lexer->lookahead == '\r' || lexer->lookahead == '\f') {
|
||||
*indent_length = 0;
|
||||
skip(lexer);
|
||||
|
||||
return true;
|
||||
} else if (lexer->lookahead == '\t') {
|
||||
*indent_length += 8;
|
||||
skip(lexer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void handle_quote(TSLexer *lexer, Delimiter *delimiter, char quote) {
|
||||
set_end_character(delimiter, quote);
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
if (lexer->lookahead == quote) {
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == quote) {
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
set_triple(delimiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool tree_sitter_gdscript_external_scanner_scan(void *payload, TSLexer *lexer,
|
||||
const bool *valid_symbols) {
|
||||
Scanner *scanner = (Scanner *)payload;
|
||||
|
||||
bool error_recovery_mode =
|
||||
valid_symbols[STRING_CONTENT] && valid_symbols[INDENT];
|
||||
bool within_brackets = valid_symbols[CLOSE_BRACE] ||
|
||||
valid_symbols[CLOSE_PAREN] ||
|
||||
valid_symbols[CLOSE_BRACKET];
|
||||
|
||||
if (valid_symbols[STRING_CONTENT] && scanner->delimiters->len > 0 &&
|
||||
!error_recovery_mode) {
|
||||
Delimiter delimiter = VEC_BACK(scanner->delimiters);
|
||||
int32_t end_char = end_character(&delimiter);
|
||||
bool has_content = false;
|
||||
while (lexer->lookahead) {
|
||||
if (lexer->lookahead == '\\') {
|
||||
if (is_raw(&delimiter)) {
|
||||
// Step over the backslash.
|
||||
lexer->advance(lexer, false);
|
||||
// Step over any escaped quotes.
|
||||
if (lexer->lookahead == end_character(&delimiter) ||
|
||||
lexer->lookahead == '\\') {
|
||||
lexer->advance(lexer, false);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
lexer->mark_end(lexer);
|
||||
lexer->result_symbol = STRING_CONTENT;
|
||||
return has_content;
|
||||
}
|
||||
} else if (lexer->lookahead == end_char) {
|
||||
if (is_triple(&delimiter)) {
|
||||
lexer->mark_end(lexer);
|
||||
lexer->advance(lexer, false);
|
||||
if (lexer->lookahead == end_char) {
|
||||
lexer->advance(lexer, false);
|
||||
if (lexer->lookahead == end_char) {
|
||||
if (has_content) {
|
||||
lexer->result_symbol = STRING_CONTENT;
|
||||
} else {
|
||||
lexer->advance(lexer, false);
|
||||
lexer->mark_end(lexer);
|
||||
VEC_POP(scanner->delimiters);
|
||||
lexer->result_symbol = STRING_END;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
lexer->mark_end(lexer);
|
||||
lexer->result_symbol = STRING_CONTENT;
|
||||
return true;
|
||||
}
|
||||
lexer->mark_end(lexer);
|
||||
lexer->result_symbol = STRING_CONTENT;
|
||||
return true;
|
||||
}
|
||||
if (has_content) {
|
||||
lexer->result_symbol = STRING_CONTENT;
|
||||
} else {
|
||||
lexer->advance(lexer, false);
|
||||
VEC_POP(scanner->delimiters);
|
||||
lexer->result_symbol = STRING_END;
|
||||
}
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
advance(lexer);
|
||||
has_content = true;
|
||||
}
|
||||
}
|
||||
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
|
||||
|
||||
bool found_end_of_line = false;
|
||||
uint32_t indent_length = 0;
|
||||
|
||||
// Track the indentation level of the most recent line that contained actual content
|
||||
// (comments or code statements). This is used to prevent premature DEDENT emission
|
||||
// when empty lines appear between content at the same indentation level, and to
|
||||
// maintain proper scope association for comments that appear at the end of blocks.
|
||||
uint32_t last_non_empty_indent = 0;
|
||||
|
||||
for (;;) {
|
||||
if (skip_whitespace(lexer, &indent_length, &found_end_of_line)) {
|
||||
continue;
|
||||
} else if (lexer->lookahead == '#') {
|
||||
// The current scanner can scan past a line return into a comment.
|
||||
// In that case we want to stop processing here, since it means
|
||||
// we're looking potentially at a comment on the next line compared
|
||||
// to the starting point of this scan.
|
||||
if (!found_end_of_line) {
|
||||
break;
|
||||
}
|
||||
|
||||
last_non_empty_indent = indent_length;
|
||||
|
||||
// Consume the entire comment line
|
||||
while (lexer->lookahead && lexer->lookahead != '\n') {
|
||||
skip(lexer);
|
||||
}
|
||||
|
||||
if (lexer->lookahead == '\n') {
|
||||
skip(lexer);
|
||||
indent_length = 0;
|
||||
}
|
||||
} else if (lexer->lookahead == '\\') {
|
||||
skip(lexer);
|
||||
if (lexer->lookahead == '\r') {
|
||||
skip(lexer);
|
||||
}
|
||||
if (lexer->lookahead == '\n' || lexer->eof(lexer)) {
|
||||
skip(lexer);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (lexer->eof(lexer)) {
|
||||
// At EOF, use the last non-empty line's indentation if we haven't seen content
|
||||
// this prevents dedenting to 0 at EOF if the last line is empty
|
||||
if (last_non_empty_indent > 0) {
|
||||
indent_length = last_non_empty_indent;
|
||||
}
|
||||
|
||||
if (scanner->indents->len > 0) {
|
||||
uint16_t current_indent_length = VEC_BACK(scanner->indents);
|
||||
if (indent_length != current_indent_length) {
|
||||
indent_length = 0;
|
||||
}
|
||||
} else {
|
||||
indent_length = 0;
|
||||
}
|
||||
found_end_of_line = true;
|
||||
break;
|
||||
} else if (lexer->lookahead == '\n') {
|
||||
// Empty line, skip it and continue
|
||||
skip(lexer);
|
||||
indent_length = 0;
|
||||
} else {
|
||||
if (indent_length == 0 && last_non_empty_indent > 0) {
|
||||
// We're at content at level 0, but we had non-empty content at a higher level
|
||||
// Check if we should defer DEDENT
|
||||
if (scanner->indents->len > 0) {
|
||||
uint16_t current_indent_length = VEC_BACK(scanner->indents);
|
||||
if (last_non_empty_indent == current_indent_length ) {
|
||||
// We had comments at the current indent level, don't dedent immediately
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_end_of_line) {
|
||||
if (scanner->indents->len > 0) {
|
||||
uint16_t current_indent_length = VEC_BACK(scanner->indents);
|
||||
|
||||
if (valid_symbols[INDENT] &&
|
||||
indent_length > current_indent_length) {
|
||||
VEC_PUSH(scanner->indents, indent_length);
|
||||
lexer->result_symbol = INDENT;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (valid_symbols[DEDENT] && indent_length < current_indent_length) {
|
||||
VEC_POP(scanner->indents);
|
||||
lexer->result_symbol = DEDENT;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_symbols[NEWLINE] && !error_recovery_mode) {
|
||||
lexer->result_symbol = NEWLINE;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// This if statement can be placed before the above if statement that
|
||||
// handles newlines. However, it feels safer to give indentation and
|
||||
// newlines higher precedence.
|
||||
if (
|
||||
// Guard against BODY_END tokens overriding valid tokens.
|
||||
!valid_symbols[COMMA] &&
|
||||
/* !valid_symbols[COLON] && */
|
||||
!valid_symbols[CLOSE_PAREN] && !valid_symbols[CLOSE_BRACE] &&
|
||||
!valid_symbols[CLOSE_BRACKET] &&
|
||||
|
||||
// Body ends occur in error recovery mode since the grammar does not
|
||||
// (cannot?) specify that a body can end with the below characters
|
||||
// without consuming them itself.
|
||||
(error_recovery_mode || valid_symbols[BODY_END])) {
|
||||
if (lexer->lookahead == ',' || // separator
|
||||
lexer->lookahead == ')' || // args, params, paren expr
|
||||
lexer->lookahead == '}' || // dictionary (may not be needed)
|
||||
lexer->lookahead == ']' // array
|
||||
/* lexer->lookahead == ':' // key-value pairs (breaks if
|
||||
elses) */
|
||||
) {
|
||||
// BODY_END tokens can take the place of a dedent. Therefore, we
|
||||
// should pop the stack when DEDENT is valid.
|
||||
if (valid_symbols[DEDENT] && scanner->indents->len > 0) {
|
||||
VEC_POP(scanner->indents);
|
||||
}
|
||||
lexer->result_symbol = BODY_END;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_symbols[STRING_START] ||
|
||||
valid_symbols[STRING_NAME_START] ||
|
||||
valid_symbols[NODE_PATH_START]) {
|
||||
Delimiter delimiter = new_delimiter();
|
||||
|
||||
bool has_flags = true;
|
||||
|
||||
switch (lexer->lookahead) {
|
||||
case 'r': set_raw(&delimiter); break;
|
||||
case '&': set_name(&delimiter); break;
|
||||
case '^': set_node_path(&delimiter); break;
|
||||
|
||||
// For backward compatibility with 3.x versions
|
||||
case '@': set_node_path(&delimiter); break;
|
||||
default: has_flags = false; break;
|
||||
}
|
||||
|
||||
if (has_flags) advance(lexer);
|
||||
|
||||
if (lexer->lookahead == '\'' || lexer->lookahead == '"') {
|
||||
handle_quote(lexer, &delimiter, lexer->lookahead);
|
||||
}
|
||||
|
||||
if (end_character(&delimiter)) {
|
||||
VEC_PUSH(scanner->delimiters, delimiter);
|
||||
|
||||
if (is_node_path(&delimiter)) {
|
||||
lexer->result_symbol = NODE_PATH_START;
|
||||
} else if (is_name(&delimiter)) {
|
||||
lexer->result_symbol = STRING_NAME_START;
|
||||
} else {
|
||||
lexer->result_symbol = STRING_START;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (has_flags) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned tree_sitter_gdscript_external_scanner_serialize(void *payload,
|
||||
char *buffer) {
|
||||
Scanner *scanner = (Scanner *)payload;
|
||||
|
||||
size_t size = 0;
|
||||
|
||||
size_t delimiter_count = scanner->delimiters->len;
|
||||
if (delimiter_count > UINT8_MAX) {
|
||||
delimiter_count = UINT8_MAX;
|
||||
}
|
||||
buffer[size++] = (char)delimiter_count;
|
||||
|
||||
if (delimiter_count > 0) {
|
||||
memcpy(&buffer[size], scanner->delimiters->data, delimiter_count);
|
||||
}
|
||||
size += delimiter_count;
|
||||
|
||||
for (int iter = 1; (uint32_t)iter < scanner->indents->len &&
|
||||
size < TREE_SITTER_SERIALIZATION_BUFFER_SIZE;
|
||||
++iter) {
|
||||
buffer[size++] = (char)scanner->indents->data[iter];
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void tree_sitter_gdscript_external_scanner_deserialize(void *payload,
|
||||
const char *buffer,
|
||||
unsigned length) {
|
||||
Scanner *scanner = (Scanner *)payload;
|
||||
|
||||
VEC_CLEAR(scanner->delimiters);
|
||||
VEC_CLEAR(scanner->indents);
|
||||
VEC_PUSH(scanner->indents, 0);
|
||||
|
||||
if (length > 0) {
|
||||
size_t size = 0;
|
||||
|
||||
size_t delimiter_count = (uint8_t)buffer[size++];
|
||||
if (delimiter_count > 0) {
|
||||
VEC_GROW(scanner->delimiters, delimiter_count);
|
||||
scanner->delimiters->len = delimiter_count;
|
||||
memcpy(scanner->delimiters->data, &buffer[size], delimiter_count);
|
||||
size += delimiter_count;
|
||||
}
|
||||
|
||||
// Deserialize the indents
|
||||
for (; size < length; size++) {
|
||||
VEC_PUSH(scanner->indents, (unsigned char)buffer[size]);
|
||||
}
|
||||
|
||||
assert(size == length);
|
||||
}
|
||||
}
|
||||
|
||||
void *tree_sitter_gdscript_external_scanner_create() {
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
|
||||
_Static_assert(sizeof(Delimiter) == sizeof(char), "");
|
||||
#else
|
||||
assert(sizeof(Delimiter) == sizeof(char));
|
||||
#endif
|
||||
Scanner *scanner = calloc(1, sizeof(Scanner));
|
||||
if (!scanner) {
|
||||
// What is the tree-sitter idiomatic way to handle this?
|
||||
// fprintf(stderr, "Failed to allocate memory for scanner\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scanner->indents = calloc(1, sizeof(indent_vec));
|
||||
scanner->delimiters = calloc(1, sizeof(delimiter_vec));
|
||||
tree_sitter_gdscript_external_scanner_deserialize(scanner, NULL, 0);
|
||||
return scanner;
|
||||
}
|
||||
|
||||
void tree_sitter_gdscript_external_scanner_destroy(void *payload) {
|
||||
Scanner *scanner = (Scanner *)payload;
|
||||
VEC_FREE(scanner->indents);
|
||||
VEC_FREE(scanner->delimiters);
|
||||
free(scanner->indents);
|
||||
free(scanner->delimiters);
|
||||
free(scanner);
|
||||
}
|
||||
@ -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 size);
|
||||
extern void *(*ts_current_calloc)(size_t count, size_t size);
|
||||
extern void *(*ts_current_realloc)(void *ptr, size_t size);
|
||||
extern void (*ts_current_free)(void *ptr);
|
||||
|
||||
#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,291 @@
|
||||
#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(push)
|
||||
#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(pop)
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_ARRAY_H_
|
||||
@ -0,0 +1,266 @@
|
||||
#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
|
||||
|
||||
#ifndef TREE_SITTER_API_H_
|
||||
typedef uint16_t TSStateId;
|
||||
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 *);
|
||||
void (*log)(const TSLexer *, const char *, ...);
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
typedef struct {
|
||||
int32_t start;
|
||||
int32_t end;
|
||||
} TSCharacterRange;
|
||||
|
||||
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;
|
||||
const TSStateId *primary_state_ids;
|
||||
};
|
||||
|
||||
static inline bool set_contains(TSCharacterRange *ranges, uint32_t len, int32_t lookahead) {
|
||||
uint32_t index = 0;
|
||||
uint32_t size = len - index;
|
||||
while (size > 1) {
|
||||
uint32_t half_size = size / 2;
|
||||
uint32_t mid_index = index + half_size;
|
||||
TSCharacterRange *range = &ranges[mid_index];
|
||||
if (lookahead >= range->start && lookahead <= range->end) {
|
||||
return true;
|
||||
} else if (lookahead > range->end) {
|
||||
index = mid_index;
|
||||
}
|
||||
size -= half_size;
|
||||
}
|
||||
TSCharacterRange *range = &ranges[index];
|
||||
return (lookahead >= range->start && lookahead <= range->end);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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; \
|
||||
next_state: \
|
||||
lexer->advance(lexer, skip); \
|
||||
start: \
|
||||
skip = false; \
|
||||
lookahead = lexer->lookahead;
|
||||
|
||||
#define ADVANCE(state_value) \
|
||||
{ \
|
||||
state = state_value; \
|
||||
goto next_state; \
|
||||
}
|
||||
|
||||
#define ADVANCE_MAP(...) \
|
||||
{ \
|
||||
static const uint16_t map[] = { __VA_ARGS__ }; \
|
||||
for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \
|
||||
if (map[i] == lookahead) { \
|
||||
state = map[i + 1]; \
|
||||
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_name, children, precedence, prod_id) \
|
||||
{{ \
|
||||
.reduce = { \
|
||||
.type = TSParseActionTypeReduce, \
|
||||
.symbol = symbol_name, \
|
||||
.child_count = children, \
|
||||
.dynamic_precedence = precedence, \
|
||||
.production_id = prod_id \
|
||||
}, \
|
||||
}}
|
||||
|
||||
#define RECOVER() \
|
||||
{{ \
|
||||
.type = TSParseActionTypeRecover \
|
||||
}}
|
||||
|
||||
#define ACCEPT_INPUT() \
|
||||
{{ \
|
||||
.type = TSParseActionTypeAccept \
|
||||
}}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_PARSER_H_
|
||||
@ -0,0 +1,191 @@
|
||||
=====================================
|
||||
Abstract class_name statement
|
||||
=====================================
|
||||
|
||||
@abstract class_name BaseClass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_name_statement
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)))
|
||||
|
||||
=====================================
|
||||
Abstract class definition
|
||||
=====================================
|
||||
|
||||
@abstract class TestClass:
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(class_body
|
||||
(pass_statement))))
|
||||
|
||||
=====================================
|
||||
Abstract class with extends
|
||||
=====================================
|
||||
|
||||
@abstract class TestClass extends BaseClass:
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(extends_statement (type (identifier)))
|
||||
(class_body
|
||||
(pass_statement))))
|
||||
|
||||
=====================================
|
||||
Abstract function declaration
|
||||
=====================================
|
||||
|
||||
@abstract func test_func()
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(parameters)))
|
||||
|
||||
=====================================
|
||||
Abstract function with parameters
|
||||
=====================================
|
||||
|
||||
@abstract func abstract_with_params(param1: String, param2: int)
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(parameters
|
||||
(typed_parameter (identifier) (type (identifier)))
|
||||
(typed_parameter (identifier) (type (identifier))))))
|
||||
|
||||
=====================================
|
||||
Abstract function with return type
|
||||
=====================================
|
||||
|
||||
@abstract func abstract_with_return_type() -> String
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(parameters)
|
||||
(type (identifier))))
|
||||
|
||||
=====================================
|
||||
Abstract function with parameters and return type
|
||||
=====================================
|
||||
|
||||
@abstract func abstract_with_params_and_return(input: String) -> int
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(parameters
|
||||
(typed_parameter (identifier) (type (identifier))))
|
||||
(type (identifier))))
|
||||
|
||||
=====================================
|
||||
Mixed abstract and concrete methods in class
|
||||
=====================================
|
||||
|
||||
@abstract class TestClass:
|
||||
@abstract func test_func()
|
||||
|
||||
func concrete_method():
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(class_body
|
||||
(function_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(parameters))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement))))))
|
||||
|
||||
=====================================
|
||||
Standalone abstract and concrete functions
|
||||
=====================================
|
||||
|
||||
@abstract func simple_abstract()
|
||||
|
||||
@abstract func abstract_with_params(param1: String, param2: int)
|
||||
|
||||
@abstract func abstract_with_return_type() -> String
|
||||
|
||||
@abstract func abstract_with_params_and_return(input: String) -> int
|
||||
|
||||
func concrete_method():
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(parameters))
|
||||
(function_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(parameters
|
||||
(typed_parameter (identifier) (type (identifier)))
|
||||
(typed_parameter (identifier) (type (identifier)))))
|
||||
(function_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(parameters)
|
||||
(type (identifier)))
|
||||
(function_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(name)
|
||||
(parameters
|
||||
(typed_parameter (identifier) (type (identifier))))
|
||||
(type (identifier)))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement))))
|
||||
@ -0,0 +1,306 @@
|
||||
=====================================
|
||||
Inline Comments in Set and Get Blocks
|
||||
=====================================
|
||||
|
||||
var prop = 10: # var comment
|
||||
set(value): # set comment
|
||||
prop = value
|
||||
get: # get comment
|
||||
return prop
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement
|
||||
name: (name)
|
||||
value: (integer)
|
||||
setget: (setget
|
||||
(comment)
|
||||
set: (set_body
|
||||
(parameters
|
||||
(identifier))
|
||||
(comment)
|
||||
body: (body
|
||||
(expression_statement
|
||||
(assignment
|
||||
left: (identifier)
|
||||
right: (identifier)))))
|
||||
get: (get_body
|
||||
(comment)
|
||||
body: (body
|
||||
(return_statement
|
||||
(identifier)))))))
|
||||
|
||||
=====================================
|
||||
Inline Comments in Class and Function Definitions
|
||||
=====================================
|
||||
|
||||
class InnerClass: # class comment
|
||||
pass
|
||||
|
||||
func _init(): # constructor comment
|
||||
pass
|
||||
|
||||
func foo(): # func comment
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_definition
|
||||
(name)
|
||||
(comment)
|
||||
(class_body
|
||||
(pass_statement)))
|
||||
(constructor_definition
|
||||
(parameters)
|
||||
(comment)
|
||||
(body
|
||||
(pass_statement)))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(comment)
|
||||
(body
|
||||
(pass_statement))))
|
||||
|
||||
|
||||
=====================================
|
||||
Inline Comments in If/Elif/Else
|
||||
=====================================
|
||||
|
||||
func test():
|
||||
if true: # if comment
|
||||
pass
|
||||
elif false: # elif comment
|
||||
pass
|
||||
else: # else comment
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(if_statement
|
||||
(true)
|
||||
(comment)
|
||||
(body
|
||||
(pass_statement))
|
||||
(elif_clause
|
||||
(false)
|
||||
(comment)
|
||||
(body
|
||||
(pass_statement)))
|
||||
(else_clause
|
||||
(comment)
|
||||
(body
|
||||
(pass_statement)))))))
|
||||
|
||||
=====================================
|
||||
Inline Comments in Match Block
|
||||
=====================================
|
||||
|
||||
func test():
|
||||
match 0: # match comment
|
||||
1: # case comment
|
||||
pass
|
||||
_: # default comment
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(match_statement
|
||||
(integer)
|
||||
(comment)
|
||||
(match_body
|
||||
(pattern_section
|
||||
(integer)
|
||||
(comment)
|
||||
(body
|
||||
(pass_statement)))
|
||||
(pattern_section
|
||||
(identifier)
|
||||
(comment)
|
||||
(body
|
||||
(pass_statement))))))))
|
||||
|
||||
=====================================
|
||||
Inline Comments in For Loop
|
||||
=====================================
|
||||
|
||||
func test():
|
||||
for i in 10: # for comment
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(for_statement
|
||||
(identifier)
|
||||
(integer)
|
||||
(comment)
|
||||
(body
|
||||
(pass_statement))))))
|
||||
|
||||
=====================================
|
||||
Inline Comments in While Loop
|
||||
=====================================
|
||||
|
||||
func test():
|
||||
while false: # while comment
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(while_statement
|
||||
(false)
|
||||
(comment)
|
||||
(body
|
||||
(pass_statement))))))
|
||||
|
||||
=====================================
|
||||
Inline Comments in Lambda
|
||||
=====================================
|
||||
|
||||
func test():
|
||||
var lam = func(): # lambda comment
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(variable_statement
|
||||
(name)
|
||||
(lambda
|
||||
(parameters)
|
||||
(comment)
|
||||
(body
|
||||
(pass_statement)))))))
|
||||
|
||||
=====================================
|
||||
Inline Trailing Comments
|
||||
=====================================
|
||||
|
||||
func test():
|
||||
return # function trailing comment at end
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(return_statement)
|
||||
(comment))))
|
||||
|
||||
=====================================
|
||||
Inline Trailing Comments After Class Definition
|
||||
=====================================
|
||||
|
||||
class MyClass:
|
||||
pass # class trailing comment
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_definition
|
||||
(name)
|
||||
(class_body
|
||||
(pass_statement)
|
||||
(comment))))
|
||||
|
||||
=====================================
|
||||
Inline Comments After Control Flow
|
||||
=====================================
|
||||
|
||||
func test():
|
||||
for x in y:
|
||||
continue
|
||||
|
||||
# Comment
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(for_statement
|
||||
(identifier)
|
||||
(identifier)
|
||||
(body
|
||||
(continue_statement)))
|
||||
(comment)
|
||||
(pass_statement))))
|
||||
|
||||
=====================================
|
||||
Trailing Comments After Final Statement
|
||||
=====================================
|
||||
|
||||
func test():
|
||||
pass
|
||||
# comment after final statement
|
||||
|
||||
func test2():
|
||||
pass
|
||||
# another comment after final statement
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(comment)))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(comment))))
|
||||
|
||||
=====================================
|
||||
Comments: dedented comment in function body
|
||||
=====================================
|
||||
|
||||
func test():
|
||||
# properly indented comment
|
||||
# improperly indented comment
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(comment)
|
||||
(comment)
|
||||
(pass_statement))))
|
||||
@ -0,0 +1,20 @@
|
||||
============================================
|
||||
Annotations and keywords
|
||||
============================================
|
||||
|
||||
@outside
|
||||
@inside static func hello():
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(annotation (identifier))
|
||||
(function_definition
|
||||
(annotations
|
||||
(annotation (identifier)))
|
||||
(static_keyword)
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement))))
|
||||
@ -0,0 +1,169 @@
|
||||
============================================
|
||||
Functions: Variadic parameters
|
||||
============================================
|
||||
|
||||
func sum(first_number: float, ...numbers: Array) -> float:
|
||||
return 0.0
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type
|
||||
(identifier)))
|
||||
(variadic_parameter
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type
|
||||
(identifier)))))
|
||||
(type
|
||||
(identifier))
|
||||
(body
|
||||
(return_statement
|
||||
(float)))))
|
||||
|
||||
============================================
|
||||
Functions: Generic types in parameters and return types
|
||||
============================================
|
||||
|
||||
func process_data(items: Array[String], mapping: Dictionary[int, String]) -> Dictionary[String, int]:
|
||||
pass
|
||||
|
||||
func get_nodes() -> Array[Node]:
|
||||
return []
|
||||
|
||||
func store_values(data: Dictionary[String, float]):
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type
|
||||
(subscript
|
||||
(identifier)
|
||||
(subscript_arguments
|
||||
(identifier)))))
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type
|
||||
(subscript
|
||||
(identifier)
|
||||
(subscript_arguments
|
||||
(identifier)
|
||||
(identifier))))))
|
||||
(type
|
||||
(subscript
|
||||
(identifier)
|
||||
(subscript_arguments
|
||||
(identifier)
|
||||
(identifier))))
|
||||
(body
|
||||
(pass_statement)))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(type
|
||||
(subscript
|
||||
(identifier)
|
||||
(subscript_arguments
|
||||
(identifier))))
|
||||
(body
|
||||
(return_statement
|
||||
(array))))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type
|
||||
(subscript
|
||||
(identifier)
|
||||
(subscript_arguments
|
||||
(identifier)
|
||||
(identifier))))))
|
||||
(body
|
||||
(pass_statement))))
|
||||
|
||||
============================================
|
||||
Functions: Type inference in function parameters
|
||||
============================================
|
||||
|
||||
func set_avatar_at(at := AvatarAt.LEFT) -> void:
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
name: (name)
|
||||
parameters: (parameters
|
||||
(typed_default_parameter
|
||||
(identifier)
|
||||
type: (inferred_type)
|
||||
value: (attribute
|
||||
(identifier)
|
||||
(identifier))))
|
||||
return_type: (type
|
||||
(identifier))
|
||||
body: (body
|
||||
(pass_statement))))
|
||||
|
||||
============================================
|
||||
Functions: Type inference in multiple function parameters
|
||||
============================================
|
||||
|
||||
func test(x := 10, y := "hello"):
|
||||
pass
|
||||
|
||||
---
|
||||
(source
|
||||
(function_definition
|
||||
name: (name)
|
||||
parameters: (parameters
|
||||
(typed_default_parameter
|
||||
(identifier)
|
||||
type: (inferred_type)
|
||||
value: (integer))
|
||||
(typed_default_parameter
|
||||
(identifier)
|
||||
type: (inferred_type)
|
||||
value: (string)))
|
||||
body: (body
|
||||
(pass_statement))))
|
||||
|
||||
============================================
|
||||
Callables: Calling a callable named tool
|
||||
============================================
|
||||
|
||||
var tool = Callable()
|
||||
|
||||
func test():
|
||||
tool.call()
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement
|
||||
name: (name)
|
||||
value: (call
|
||||
(identifier)
|
||||
arguments: (arguments)))
|
||||
(function_definition
|
||||
name: (name)
|
||||
parameters: (parameters)
|
||||
body: (body
|
||||
(expression_statement
|
||||
(attribute
|
||||
(identifier)
|
||||
(attribute_call
|
||||
(identifier)
|
||||
arguments: (arguments)))))))
|
||||
@ -0,0 +1,104 @@
|
||||
============================================
|
||||
Inner Class: Test basic class with function
|
||||
============================================
|
||||
|
||||
class Name:
|
||||
func hello(): pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_definition (name)
|
||||
(class_body
|
||||
(function_definition (name) (parameters)
|
||||
(body (pass_statement))))))
|
||||
|
||||
============================================
|
||||
Inner Class: Test class with extends on one line and function
|
||||
============================================
|
||||
|
||||
class Name extends Type:
|
||||
func hello(): pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_definition (name) (extends_statement (type (identifier)))
|
||||
(class_body
|
||||
(function_definition (name) (parameters)
|
||||
(body (pass_statement))))))
|
||||
|
||||
============================================
|
||||
Inner Class: Test class with extends only
|
||||
============================================
|
||||
|
||||
class Name:
|
||||
extends Type
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_definition (name)
|
||||
(class_body
|
||||
(extends_statement (type (identifier))))))
|
||||
|
||||
============================================
|
||||
Inner Class: Inner class with function definition on the same line
|
||||
============================================
|
||||
|
||||
class C: func test(x):
|
||||
print(x)
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_definition
|
||||
name: (name)
|
||||
body: (class_body
|
||||
(function_definition
|
||||
name: (name)
|
||||
parameters: (parameters
|
||||
(identifier))
|
||||
body: (body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
arguments: (arguments
|
||||
(identifier)))))))))
|
||||
|
||||
============================================
|
||||
Inner Class: Inner class with variable declaration on the same line
|
||||
============================================
|
||||
|
||||
class MyClass: var x = 10
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_definition
|
||||
name: (name)
|
||||
body: (class_body
|
||||
(variable_statement
|
||||
name: (name)
|
||||
value: (integer)))))
|
||||
|
||||
============================================
|
||||
Inner Class: Inner class with static function definition on the same line
|
||||
============================================
|
||||
|
||||
class Helper: static func utility():
|
||||
return true
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_definition
|
||||
name: (name)
|
||||
body: (class_body
|
||||
(function_definition
|
||||
(static_keyword)
|
||||
name: (name)
|
||||
parameters: (parameters)
|
||||
body: (body
|
||||
(return_statement
|
||||
(true)))))))
|
||||
@ -0,0 +1,361 @@
|
||||
============================================
|
||||
#67 Parsing error when there are two or more consecutive semicolons
|
||||
============================================
|
||||
|
||||
test() ; ; print()
|
||||
class T:
|
||||
var hello: T = "";; ;const c = 1;;;;;signal world
|
||||
func hello():
|
||||
pass;;pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments)))
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments)))
|
||||
(class_definition
|
||||
(name)
|
||||
(class_body
|
||||
(variable_statement
|
||||
(name)
|
||||
(type
|
||||
(identifier))
|
||||
(string))
|
||||
(const_statement
|
||||
(name)
|
||||
(integer))
|
||||
(signal_statement
|
||||
(name))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement))))))
|
||||
|
||||
============================================
|
||||
#57 Parser can't handle certain multiline raw strings
|
||||
============================================
|
||||
|
||||
r"hello"
|
||||
|
||||
r"hello
|
||||
"
|
||||
|
||||
"
|
||||
asdfasdfasf
|
||||
"
|
||||
|
||||
print(r"hello
|
||||
")
|
||||
|
||||
var a = "
|
||||
asdfasdfasf
|
||||
"
|
||||
|
||||
---
|
||||
(source
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement (string))
|
||||
(expression_statement
|
||||
(call (identifier) (arguments (string))))
|
||||
(variable_statement (name) (string)))
|
||||
|
||||
|
||||
============================================
|
||||
#56 Error when matching a dictionary without specifying values
|
||||
============================================
|
||||
|
||||
match x:
|
||||
{ "key", 1, 0xFF, "key": 100 }: pass
|
||||
|
||||
---
|
||||
(source
|
||||
(match_statement
|
||||
(identifier)
|
||||
(match_body
|
||||
(pattern_section
|
||||
(dictionary
|
||||
(string)
|
||||
(integer)
|
||||
(integer)
|
||||
(pair
|
||||
(string)
|
||||
(integer)))
|
||||
(body
|
||||
(pass_statement))))))
|
||||
|
||||
============================================
|
||||
#61 Extends with a class name less than three characters causes a parse error
|
||||
============================================
|
||||
|
||||
class_name UI extends Control
|
||||
class_name Hello extends World
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(class_name_statement
|
||||
(name)
|
||||
(extends_statement (type (identifier))))
|
||||
(class_name_statement
|
||||
(name)
|
||||
(extends_statement (type (identifier)))))
|
||||
|
||||
============================================
|
||||
#21 Parse condition with comparison_operator and binary_operator wrong
|
||||
============================================
|
||||
|
||||
1 == 2 or 3 == 4
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(binary_operator
|
||||
(binary_operator
|
||||
(integer)
|
||||
(integer))
|
||||
(binary_operator
|
||||
(integer)
|
||||
(integer)))))
|
||||
|
||||
============================================
|
||||
Variable right after lambda
|
||||
============================================
|
||||
|
||||
func _on_pressed_button() -> void:
|
||||
var root = func() -> Node:
|
||||
var node: Node
|
||||
var node_type: String = lib.editor.root.get_class()
|
||||
|
||||
match node_type:
|
||||
"Node3D":
|
||||
node = Node3D.new()
|
||||
"Node2D":
|
||||
node = Node2D.new()
|
||||
|
||||
return node
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(type (identifier))
|
||||
(body
|
||||
(variable_statement
|
||||
(name)
|
||||
(lambda
|
||||
(parameters)
|
||||
(type (identifier))
|
||||
(body
|
||||
(variable_statement
|
||||
(name)
|
||||
(type (identifier)))
|
||||
(variable_statement
|
||||
(name)
|
||||
(type (identifier))
|
||||
(attribute
|
||||
(identifier)
|
||||
(identifier)
|
||||
(identifier)
|
||||
(attribute_call
|
||||
(identifier)
|
||||
(arguments))))
|
||||
(match_statement
|
||||
(identifier)
|
||||
(match_body
|
||||
(pattern_section
|
||||
(string)
|
||||
(body
|
||||
(expression_statement
|
||||
(assignment
|
||||
(identifier)
|
||||
(attribute
|
||||
(identifier)
|
||||
(attribute_call
|
||||
(identifier)
|
||||
(arguments)))))))
|
||||
(pattern_section
|
||||
(string)
|
||||
(body
|
||||
(expression_statement
|
||||
(assignment
|
||||
(identifier)
|
||||
(attribute
|
||||
(identifier)
|
||||
(attribute_call
|
||||
(identifier)
|
||||
(arguments)))))))))
|
||||
(return_statement
|
||||
(identifier))))))))
|
||||
|
||||
============================================
|
||||
Highlight incorrect when just setting get
|
||||
============================================
|
||||
|
||||
var selection:
|
||||
get:
|
||||
return interface.get_selection()
|
||||
|
||||
var children:
|
||||
get:
|
||||
return selected[0].get_children()
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement
|
||||
(name)
|
||||
(setget
|
||||
(get_body
|
||||
(body
|
||||
(return_statement
|
||||
(attribute
|
||||
(identifier)
|
||||
(attribute_call
|
||||
(identifier)
|
||||
(arguments))))))))
|
||||
(variable_statement
|
||||
(name)
|
||||
(setget
|
||||
(get_body
|
||||
(body
|
||||
(return_statement
|
||||
(attribute
|
||||
(subscript
|
||||
(identifier)
|
||||
(subscript_arguments
|
||||
(integer)))
|
||||
(attribute_call
|
||||
(identifier)
|
||||
(arguments)))))))))
|
||||
|
||||
============================================
|
||||
Export Var Stmt can be onready
|
||||
============================================
|
||||
|
||||
export(NodePath) onready var path = get_node(path)
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(export_variable_statement
|
||||
(arguments
|
||||
(identifier))
|
||||
(name)
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(identifier)))))
|
||||
|
||||
============================================
|
||||
Literals bugs with [get_node]
|
||||
============================================
|
||||
|
||||
$"../inspectorHeader/inspectorHeaderHBoxContainer/CurrentBlock"
|
||||
$"../../CommandsSettings"
|
||||
$'../../Node'
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(get_node))
|
||||
(expression_statement
|
||||
(get_node))
|
||||
(expression_statement
|
||||
(get_node)))
|
||||
|
||||
============================================
|
||||
Fails to parse basic blocks
|
||||
============================================
|
||||
|
||||
extends Node
|
||||
|
||||
func _ready():
|
||||
var x := 2
|
||||
for i in range(x):
|
||||
prints(i)
|
||||
|
||||
while x > 0:
|
||||
print(x)
|
||||
|
||||
if x > 0:
|
||||
print("if test")
|
||||
elif x < 0:
|
||||
print("if test")
|
||||
else:
|
||||
print("if test")
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(extends_statement
|
||||
(type (identifier)))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(variable_statement
|
||||
(name)
|
||||
(inferred_type)
|
||||
(integer))
|
||||
(for_statement
|
||||
(identifier)
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(identifier)))
|
||||
(body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(identifier))))))
|
||||
(while_statement
|
||||
(binary_operator
|
||||
(identifier)
|
||||
(integer))
|
||||
(body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(identifier))))))
|
||||
(if_statement
|
||||
(binary_operator
|
||||
(identifier)
|
||||
(integer))
|
||||
(body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(string)))))
|
||||
(elif_clause
|
||||
(binary_operator
|
||||
(identifier)
|
||||
(integer))
|
||||
(body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(string))))))
|
||||
(else_clause
|
||||
(body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(string))))))))))
|
||||
@ -0,0 +1,36 @@
|
||||
============================================
|
||||
#73273 Lambda assign after if
|
||||
============================================
|
||||
|
||||
if true: v = func(): test()
|
||||
if true: v = func(): test()
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(if_statement
|
||||
(true)
|
||||
(body
|
||||
(expression_statement
|
||||
(assignment
|
||||
(identifier)
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments)))))))))
|
||||
(if_statement
|
||||
(true)
|
||||
(body
|
||||
(expression_statement
|
||||
(assignment
|
||||
(identifier)
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments))))))))))
|
||||
@ -0,0 +1,64 @@
|
||||
============================================
|
||||
Setget parse failure
|
||||
============================================
|
||||
|
||||
var is_active = true:
|
||||
set = set_is_active
|
||||
|
||||
@onready var _state = initial_state:
|
||||
set = set_state
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement
|
||||
name: (name)
|
||||
value: (true)
|
||||
setget: (setget
|
||||
set: (setter)))
|
||||
(variable_statement
|
||||
(annotations
|
||||
(annotation
|
||||
(identifier)))
|
||||
name: (name)
|
||||
value: (identifier)
|
||||
setget: (setget
|
||||
set: (setter))))
|
||||
|
||||
============================================
|
||||
#35 Parsing: The valid syntax : set = ... : get = ... is not supported
|
||||
============================================
|
||||
|
||||
var is_active := false: set = set_is_active
|
||||
var test = -1: get = get_test
|
||||
|
||||
var x = true: get = g, set = s
|
||||
var y = false: set = s, get = g
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement
|
||||
name: (name)
|
||||
type: (inferred_type)
|
||||
value: (false)
|
||||
setget: (setget
|
||||
set: (setter)))
|
||||
(variable_statement
|
||||
name: (name)
|
||||
value: (unary_operator (integer))
|
||||
setget: (setget
|
||||
get: (getter)))
|
||||
(variable_statement
|
||||
name: (name)
|
||||
value: (true)
|
||||
setget: (setget
|
||||
get: (getter)
|
||||
set: (setter)))
|
||||
(variable_statement
|
||||
name: (name)
|
||||
value: (false)
|
||||
setget: (setget
|
||||
set: (setter)
|
||||
get: (getter)))
|
||||
)
|
||||
@ -0,0 +1,464 @@
|
||||
=====================================
|
||||
Lambdas Assignment
|
||||
=====================================
|
||||
|
||||
var x = func hello():
|
||||
pass
|
||||
|
||||
var x = func():
|
||||
pass
|
||||
|
||||
var x = func hello(): pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement
|
||||
(name)
|
||||
(lambda
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement))))
|
||||
(variable_statement
|
||||
(name)
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement))))
|
||||
(variable_statement
|
||||
(name)
|
||||
(lambda
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)))))
|
||||
|
||||
=====================================
|
||||
Lambdas in Dictionary
|
||||
=====================================
|
||||
|
||||
{key = func(): pass; pass, key = 1}
|
||||
{key = 1, 'key': func():
|
||||
pass
|
||||
pass}
|
||||
{key = 1, 'key': func():
|
||||
pass
|
||||
pass, 'key': 1}
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(dictionary
|
||||
(pair (identifier)
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement))))
|
||||
(pair (identifier) (integer))))
|
||||
(expression_statement
|
||||
(dictionary
|
||||
(pair (identifier) (integer))
|
||||
(pair (string)
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement))))))
|
||||
(expression_statement
|
||||
(dictionary
|
||||
(pair
|
||||
(identifier)
|
||||
(integer))
|
||||
(pair
|
||||
(string)
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement))))
|
||||
(pair
|
||||
(string)
|
||||
(integer)))))
|
||||
|
||||
; =====================================
|
||||
; Lambdas as Dictionary Keys
|
||||
; =====================================
|
||||
|
||||
; {func():
|
||||
; pass
|
||||
; pass: 'value'}
|
||||
|
||||
; ---
|
||||
|
||||
; (source
|
||||
; (expression_statement
|
||||
; (dictionary
|
||||
; (pair
|
||||
; (lambda
|
||||
; (parameters)
|
||||
; (body
|
||||
; (pass_statement)
|
||||
; (pass_statement)))
|
||||
; (string)))))
|
||||
|
||||
=====================================
|
||||
Lambdas in Array
|
||||
=====================================
|
||||
|
||||
[func x(): pass; pass]
|
||||
[func x(): pass; pass,]
|
||||
[func x():
|
||||
pass
|
||||
pass]
|
||||
[func x():
|
||||
pass
|
||||
pass,]
|
||||
[
|
||||
func():
|
||||
pass
|
||||
pass,
|
||||
func():
|
||||
pass
|
||||
pass,
|
||||
]
|
||||
|
||||
func x():
|
||||
if true:
|
||||
var a = [func(): pass ; pass,]
|
||||
var a = [func():
|
||||
pass
|
||||
pass,]
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(array
|
||||
(lambda
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement)))))
|
||||
(expression_statement
|
||||
(array
|
||||
(lambda
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement)))))
|
||||
(expression_statement
|
||||
(array
|
||||
(lambda
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement)))))
|
||||
(expression_statement
|
||||
(array
|
||||
(lambda
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement)))))
|
||||
(expression_statement
|
||||
(array
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement)))
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement)))))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(if_statement
|
||||
(true)
|
||||
(body
|
||||
(variable_statement
|
||||
(name)
|
||||
(array
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement)))))
|
||||
(variable_statement
|
||||
(name)
|
||||
(array
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement))))))))))
|
||||
|
||||
=====================================
|
||||
Lambdas Nested
|
||||
=====================================
|
||||
|
||||
var x = func(): (func hello(): pass) ; pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement
|
||||
(name)
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(expression_statement
|
||||
(parenthesized_expression
|
||||
(lambda
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)))))
|
||||
(pass_statement)))))
|
||||
|
||||
=====================================
|
||||
Lambdas as Params
|
||||
=====================================
|
||||
|
||||
func hello(p = func(p: int) -> int: pass; pass, x: int):
|
||||
pass
|
||||
|
||||
func hello(p = func(p: int) -> int:
|
||||
pass
|
||||
pass, x: int):
|
||||
pass
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters
|
||||
(default_parameter
|
||||
(identifier)
|
||||
(lambda
|
||||
(parameters
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type (identifier))))
|
||||
(type (identifier))
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement))))
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type (identifier))))
|
||||
(body
|
||||
(pass_statement)))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters
|
||||
(default_parameter
|
||||
(identifier)
|
||||
(lambda
|
||||
(parameters
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type (identifier))))
|
||||
(type (identifier))
|
||||
(body
|
||||
(pass_statement)
|
||||
(pass_statement))))
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type (identifier))))
|
||||
(body
|
||||
(pass_statement))))
|
||||
|
||||
=====================================
|
||||
Lambdas as Args
|
||||
=====================================
|
||||
|
||||
hello(func(): pass)
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)))))))
|
||||
|
||||
|
||||
=====================================
|
||||
Lambdas in Statements
|
||||
=====================================
|
||||
|
||||
func x(p: int = 1) -> int:
|
||||
if p == 1:
|
||||
var v = func(p: int) -> int:
|
||||
var result = v + p
|
||||
return result
|
||||
return x(p)
|
||||
else:
|
||||
return (func(v: int) -> int:
|
||||
var result = v + p
|
||||
return result)(p)
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters
|
||||
(typed_default_parameter
|
||||
(identifier)
|
||||
(type (identifier))
|
||||
(integer)))
|
||||
(type (identifier))
|
||||
(body
|
||||
(if_statement
|
||||
(binary_operator
|
||||
(identifier)
|
||||
(integer))
|
||||
(body
|
||||
(variable_statement
|
||||
(name)
|
||||
(lambda
|
||||
(parameters
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type (identifier))))
|
||||
(type (identifier))
|
||||
(body
|
||||
(variable_statement
|
||||
(name)
|
||||
(binary_operator
|
||||
(identifier)
|
||||
(identifier)))
|
||||
(return_statement
|
||||
(identifier)))))
|
||||
(return_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(identifier)))))
|
||||
(else_clause
|
||||
(body
|
||||
(return_statement
|
||||
(call
|
||||
(parenthesized_expression
|
||||
(lambda
|
||||
(parameters
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type (identifier))))
|
||||
(type (identifier))
|
||||
(body
|
||||
(variable_statement
|
||||
(name)
|
||||
(binary_operator
|
||||
(identifier)
|
||||
(identifier)))
|
||||
(return_statement
|
||||
(identifier)))))
|
||||
(arguments
|
||||
(identifier))))))))))
|
||||
|
||||
=====================================
|
||||
Lambdas Return Stmt
|
||||
=====================================
|
||||
|
||||
var x = func():
|
||||
pass
|
||||
return func x(t: T) -> T:
|
||||
pass
|
||||
return t
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement
|
||||
(name)
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(pass_statement)
|
||||
(return_statement
|
||||
(lambda
|
||||
(name)
|
||||
(parameters
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type (identifier))))
|
||||
(type (identifier))
|
||||
(body
|
||||
(pass_statement)
|
||||
(return_statement
|
||||
(identifier)))))))))
|
||||
|
||||
=====================================
|
||||
Lambdas Nested Ifs
|
||||
=====================================
|
||||
|
||||
func x():
|
||||
x(func():
|
||||
if true:
|
||||
y(func():
|
||||
if true:
|
||||
pass
|
||||
else:
|
||||
var x = 1 + 1 ,
|
||||
"END y")
|
||||
else:
|
||||
pass, "END x")
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(if_statement
|
||||
(true)
|
||||
(body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(lambda
|
||||
(parameters)
|
||||
(body
|
||||
(if_statement
|
||||
(true)
|
||||
(body
|
||||
(pass_statement))
|
||||
(else_clause
|
||||
(body
|
||||
(variable_statement
|
||||
(name)
|
||||
(binary_operator
|
||||
(integer)
|
||||
(integer))))))))
|
||||
(string)))))
|
||||
(else_clause
|
||||
(body
|
||||
(pass_statement))))))
|
||||
(string)))))))
|
||||
|
||||
@ -0,0 +1,148 @@
|
||||
===
|
||||
Syntax sugar line continuations
|
||||
===
|
||||
|
||||
$get/node/\
|
||||
my/node
|
||||
|
||||
%hello/ \
|
||||
world
|
||||
|
||||
&"hello \
|
||||
world"
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(get_node
|
||||
(line_continuation)))
|
||||
(expression_statement
|
||||
(get_node
|
||||
(line_continuation)))
|
||||
(expression_statement
|
||||
(string_name
|
||||
(escape_sequence))))
|
||||
|
||||
===
|
||||
Invalid syntax sugar line continuations
|
||||
===
|
||||
|
||||
# This is invalid GDScript but I'm making the parser accept it for the sake of simplicity with line continuations
|
||||
$get\
|
||||
/node
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(comment)
|
||||
(expression_statement
|
||||
(get_node
|
||||
(line_continuation))))
|
||||
|
||||
===
|
||||
Line continuation in binary expressions
|
||||
===
|
||||
|
||||
func _handles(resource):
|
||||
return resource is NoiseTexture2D \
|
||||
or resource is GradientTexture1D
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
name: (name)
|
||||
parameters: (parameters
|
||||
(identifier))
|
||||
body: (body
|
||||
(return_statement
|
||||
(binary_operator
|
||||
left: (binary_operator
|
||||
left: (identifier)
|
||||
right: (identifier))
|
||||
(line_continuation)
|
||||
right: (binary_operator
|
||||
left: (identifier)
|
||||
right: (identifier)))))))
|
||||
|
||||
===
|
||||
Line continuation in function calls
|
||||
===
|
||||
|
||||
func _process(delta):
|
||||
move_and_slide(velocity * \
|
||||
delta)
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
name: (name)
|
||||
parameters: (parameters
|
||||
(identifier))
|
||||
body: (body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
arguments: (arguments
|
||||
(binary_operator
|
||||
left: (identifier)
|
||||
(line_continuation)
|
||||
right: (identifier))))))))
|
||||
|
||||
===
|
||||
Line continuation in array literals
|
||||
===
|
||||
|
||||
func test():
|
||||
var array = [
|
||||
1, \
|
||||
2, \
|
||||
3
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
name: (name)
|
||||
parameters: (parameters)
|
||||
body: (body
|
||||
(variable_statement
|
||||
name: (name)
|
||||
value: (array
|
||||
(integer)
|
||||
(line_continuation)
|
||||
(integer)
|
||||
(line_continuation)
|
||||
(integer))))))
|
||||
|
||||
===
|
||||
Line continuation in dictionary
|
||||
===
|
||||
|
||||
func test():
|
||||
var dict = {
|
||||
"key": \
|
||||
"value",
|
||||
"key2": \
|
||||
"value2"
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
name: (name)
|
||||
parameters: (parameters)
|
||||
body: (body
|
||||
(variable_statement
|
||||
name: (name)
|
||||
value: (dictionary
|
||||
(pair
|
||||
left: (string)
|
||||
value: (string))
|
||||
(pair
|
||||
left: (string)
|
||||
value: (string)))))))
|
||||
@ -0,0 +1,269 @@
|
||||
=====================================
|
||||
Single
|
||||
=====================================
|
||||
|
||||
match x:
|
||||
1: pass
|
||||
_: pass
|
||||
TYPE_ARRAY:
|
||||
pass
|
||||
var new_var:
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(match_statement (identifier) (match_body
|
||||
(pattern_section (integer) (body (pass_statement)))
|
||||
(pattern_section (identifier) (body (pass_statement)))
|
||||
(pattern_section (identifier) (body (pass_statement)))
|
||||
(pattern_section (pattern_binding (identifier)) (body (pass_statement)))
|
||||
)))
|
||||
|
||||
=====================================
|
||||
Multiple
|
||||
=====================================
|
||||
|
||||
match x:
|
||||
_:
|
||||
pass
|
||||
1, 2, 3: pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(match_statement (identifier) (match_body
|
||||
(pattern_section (identifier) (body (pass_statement)))
|
||||
(pattern_section (integer) (integer) (integer)
|
||||
(body (pass_statement)))
|
||||
)))
|
||||
|
||||
=====================================
|
||||
Arrays
|
||||
=====================================
|
||||
|
||||
match x:
|
||||
[]: pass
|
||||
[1, 3, "test", null]:
|
||||
pass
|
||||
[var start, _]: pass
|
||||
[42, ..]:
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(match_statement (identifier) (match_body
|
||||
(pattern_section (array) (body (pass_statement)))
|
||||
(pattern_section
|
||||
(array (integer) (integer) (string) (null))
|
||||
(body (pass_statement)))
|
||||
(pattern_section
|
||||
(array (pattern_binding (identifier)) (identifier))
|
||||
(body (pass_statement)))
|
||||
(pattern_section
|
||||
(array (integer) (pattern_open_ending))
|
||||
(body (pass_statement)))
|
||||
)))
|
||||
|
||||
=====================================
|
||||
Dicts
|
||||
=====================================
|
||||
|
||||
match x:
|
||||
{}: pass
|
||||
{"name": "Dennis"}: pass
|
||||
{"name": "Dennis", "age": var age}: pass
|
||||
{"key": "godotisawesome", ..}: pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(match_statement (identifier) (match_body
|
||||
(pattern_section (dictionary) (body (pass_statement)))
|
||||
(pattern_section
|
||||
(dictionary (pair (string) (string)))
|
||||
(body (pass_statement)))
|
||||
(pattern_section
|
||||
(dictionary
|
||||
(pair (string) (string))
|
||||
(pair (string) (pattern_binding (identifier))))
|
||||
(body (pass_statement)))
|
||||
(pattern_section
|
||||
(dictionary
|
||||
(pair (string) (string))
|
||||
(pattern_open_ending))
|
||||
(body (pass_statement)))
|
||||
)))
|
||||
|
||||
=====================================
|
||||
Expressions
|
||||
=====================================
|
||||
|
||||
match x:
|
||||
Hello.World: pass
|
||||
Hello.World(): pass
|
||||
function(): pass
|
||||
Color().a: pass
|
||||
[var hello, _, ..]: pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(match_statement (identifier) (match_body
|
||||
(pattern_section
|
||||
(attribute (identifier) (identifier))
|
||||
(body (pass_statement)))
|
||||
(pattern_section
|
||||
(attribute (identifier) (attribute_call (identifier) (arguments)))
|
||||
(body (pass_statement)))
|
||||
(pattern_section
|
||||
(call (identifier) (arguments))
|
||||
(body (pass_statement)))
|
||||
(pattern_section
|
||||
(attribute
|
||||
(call (identifier) (arguments))
|
||||
(identifier))
|
||||
(body (pass_statement)))
|
||||
(pattern_section
|
||||
(array
|
||||
(pattern_binding (identifier))
|
||||
(identifier)
|
||||
(pattern_open_ending))
|
||||
(body (pass_statement))))))
|
||||
|
||||
============================================
|
||||
Match: conditional expression, annotation, and call
|
||||
============================================
|
||||
|
||||
match get_value():
|
||||
result if run_check() else fallback:
|
||||
@warning_ignore("test")
|
||||
handle_value()
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(match_statement
|
||||
value: (call
|
||||
(identifier)
|
||||
arguments: (arguments))
|
||||
body: (match_body
|
||||
(pattern_section
|
||||
(conditional_expression
|
||||
left: (identifier)
|
||||
condition: (call
|
||||
(identifier)
|
||||
arguments: (arguments))
|
||||
right: (identifier))
|
||||
body: (body
|
||||
(annotation
|
||||
(identifier)
|
||||
arguments: (arguments
|
||||
(string)))
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
arguments: (arguments))))))))
|
||||
|
||||
============================================
|
||||
Match: Simple conditional expression
|
||||
============================================
|
||||
|
||||
match 0:
|
||||
0 if true else 2:
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(match_statement
|
||||
value: (integer)
|
||||
body: (match_body
|
||||
(pattern_section
|
||||
(conditional_expression
|
||||
left: (integer)
|
||||
condition: (true)
|
||||
right: (integer))
|
||||
body: (body
|
||||
(pass_statement))))))
|
||||
|
||||
============================================
|
||||
Match: Nested conditional expressions with identifiers
|
||||
============================================
|
||||
|
||||
match value:
|
||||
x if condition else y:
|
||||
print("matched")
|
||||
a if b else c if d else e:
|
||||
print("complex ternary")
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(match_statement
|
||||
value: (identifier)
|
||||
body: (match_body
|
||||
(pattern_section
|
||||
(conditional_expression
|
||||
left: (identifier)
|
||||
condition: (identifier)
|
||||
right: (identifier))
|
||||
body: (body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
arguments: (arguments
|
||||
(string))))))
|
||||
(pattern_section
|
||||
(conditional_expression
|
||||
left: (identifier)
|
||||
condition: (identifier)
|
||||
right: (conditional_expression
|
||||
left: (identifier)
|
||||
condition: (identifier)
|
||||
right: (identifier)))
|
||||
body: (body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
arguments: (arguments
|
||||
(string)))))))))
|
||||
|
||||
============================================
|
||||
Match: Annotations within match statements
|
||||
============================================
|
||||
|
||||
match 1:
|
||||
_:
|
||||
print(0)
|
||||
@warning_ignore("unreachable_pattern")
|
||||
1:
|
||||
print(1)
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(match_statement
|
||||
value: (integer)
|
||||
body: (match_body
|
||||
(pattern_section
|
||||
(identifier)
|
||||
body: (body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
arguments: (arguments
|
||||
(integer))))))
|
||||
(annotation
|
||||
(identifier)
|
||||
arguments: (arguments
|
||||
(string)))
|
||||
(pattern_section
|
||||
(integer)
|
||||
body: (body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
arguments: (arguments
|
||||
(integer)))))))))
|
||||
@ -0,0 +1,133 @@
|
||||
=====================================
|
||||
Region: Empty region
|
||||
=====================================
|
||||
|
||||
#region empty
|
||||
#endregion
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(region_start
|
||||
(region_label))
|
||||
(region_end))
|
||||
|
||||
=====================================
|
||||
Region: Basic anonymous region with code
|
||||
=====================================
|
||||
|
||||
#region
|
||||
func _ready() -> void:
|
||||
pass
|
||||
#endregion
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(region_start)
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters)
|
||||
(type (identifier))
|
||||
(body (pass_statement)))
|
||||
(region_end))
|
||||
|
||||
=====================================
|
||||
Region: Named region with more code
|
||||
=====================================
|
||||
|
||||
#region process
|
||||
func _process(delta: float) -> void:
|
||||
position += velocity * delta
|
||||
#endregion
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(region_start
|
||||
(region_label))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type (identifier))))
|
||||
(type (identifier))
|
||||
(body
|
||||
(expression_statement
|
||||
(augmented_assignment
|
||||
(identifier)
|
||||
(binary_operator
|
||||
(identifier)
|
||||
(identifier))))))
|
||||
(region_end))
|
||||
|
||||
=====================================
|
||||
Region: Region with leading indentation
|
||||
=====================================
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
#region movement
|
||||
pass
|
||||
#endregion
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters
|
||||
(typed_parameter
|
||||
(identifier)
|
||||
(type (identifier))))
|
||||
(type (identifier))
|
||||
(body
|
||||
(region_start
|
||||
(region_label))
|
||||
(pass_statement)
|
||||
(region_end))))
|
||||
|
||||
=====================================
|
||||
Region: Two sibling regions
|
||||
=====================================
|
||||
|
||||
#region variables
|
||||
var health: int = 100
|
||||
var speed: float = 5.0
|
||||
#endregion
|
||||
|
||||
#region functions
|
||||
func take_damage(amount) -> void:
|
||||
health -= amount
|
||||
#endregion
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(region_start
|
||||
(region_label))
|
||||
(variable_statement
|
||||
(name)
|
||||
(type
|
||||
(identifier))
|
||||
(integer))
|
||||
(variable_statement
|
||||
(name)
|
||||
(type
|
||||
(identifier))
|
||||
(float))
|
||||
(region_end)
|
||||
(region_start
|
||||
(region_label))
|
||||
(function_definition
|
||||
(name)
|
||||
(parameters
|
||||
(identifier))
|
||||
(type
|
||||
(identifier))
|
||||
(body
|
||||
(expression_statement
|
||||
(augmented_assignment
|
||||
(identifier)
|
||||
(identifier)))))
|
||||
(region_end))
|
||||
@ -0,0 +1,50 @@
|
||||
=====================================
|
||||
Sample - GDScript 1
|
||||
=====================================
|
||||
|
||||
extends Node2D
|
||||
class_name CustomNode, "icon_path"
|
||||
|
||||
class Data extends Resource:
|
||||
var source: DataSource
|
||||
|
||||
func process_source() -> ProcessedSource:
|
||||
if source.is_processable():
|
||||
var processed = ProcessedSource.new(source)
|
||||
return processed
|
||||
return null
|
||||
|
||||
func _ready():
|
||||
for i in range(100):
|
||||
var child = Node.new()
|
||||
child.name = str("Name-", i)
|
||||
add_child(child)
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(extends_statement (type (identifier)))
|
||||
(class_name_statement (name) (string))
|
||||
(class_definition (name) (extends_statement (type (identifier)))
|
||||
(class_body
|
||||
(variable_statement (name) (type (identifier)))
|
||||
(function_definition (name) (parameters) (type (identifier))
|
||||
(body
|
||||
(if_statement (attribute (identifier) (attribute_call (identifier) (arguments)))
|
||||
(body
|
||||
(variable_statement (name)
|
||||
(attribute (identifier) (attribute_call (identifier) (arguments (identifier)))))
|
||||
(return_statement (identifier))))
|
||||
(return_statement (null))))))
|
||||
(function_definition (name) (parameters)
|
||||
(body
|
||||
(for_statement (identifier) (call (identifier) (arguments (integer)))
|
||||
(body
|
||||
(variable_statement (name)
|
||||
(attribute (identifier) (attribute_call (identifier) (arguments))))
|
||||
(expression_statement
|
||||
(assignment
|
||||
(attribute (identifier) (identifier))
|
||||
(call (identifier) (arguments (string) (identifier)))))
|
||||
(expression_statement
|
||||
(call (identifier) (arguments (identifier)))))))))
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,179 @@
|
||||
============================================
|
||||
Typed Arrays (#18)
|
||||
============================================
|
||||
|
||||
var a1: Array[IClass.IIClass]
|
||||
var a3: Array[int]
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement
|
||||
(name)
|
||||
(type
|
||||
(subscript
|
||||
(identifier)
|
||||
(subscript_arguments
|
||||
(attribute
|
||||
(identifier)
|
||||
(identifier))))))
|
||||
(variable_statement
|
||||
(name)
|
||||
(type
|
||||
(subscript
|
||||
(identifier)
|
||||
(subscript_arguments
|
||||
(identifier))))))
|
||||
|
||||
============================================
|
||||
Static Variable Statements
|
||||
============================================
|
||||
|
||||
static var name
|
||||
static var name := "Me"
|
||||
static var name: int
|
||||
|
||||
# There may be valid annotations for static vars.
|
||||
@some_annotation static var name
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement (static_keyword) (name))
|
||||
(variable_statement (static_keyword) (name) (inferred_type) (string))
|
||||
(variable_statement (static_keyword) (name) (type (identifier)))
|
||||
(comment)
|
||||
(variable_statement
|
||||
(annotations (annotation (identifier)))
|
||||
(static_keyword)
|
||||
(name)))
|
||||
|
||||
|
||||
============================================
|
||||
Static Typed For Loop
|
||||
============================================
|
||||
|
||||
for i: int in [1, 2]:
|
||||
pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(for_statement
|
||||
(identifier)
|
||||
(type (identifier))
|
||||
(array
|
||||
(integer)
|
||||
(integer))
|
||||
(body
|
||||
(pass_statement))))
|
||||
|
||||
============================================
|
||||
SetGet Getter with Empty Parenthesis
|
||||
============================================
|
||||
|
||||
var x:
|
||||
get(): pass
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement
|
||||
(name)
|
||||
(setget
|
||||
(get_body
|
||||
(body
|
||||
(pass_statement))))))
|
||||
|
||||
============================================
|
||||
Pattern Guards for Match Statement
|
||||
============================================
|
||||
|
||||
var a = 0
|
||||
match a:
|
||||
0 when false: print("does not run")
|
||||
0 when true: print("but this does")
|
||||
|
||||
var when = 1
|
||||
match when:
|
||||
when when when:
|
||||
when
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(variable_statement (name) (integer))
|
||||
(match_statement
|
||||
(identifier)
|
||||
(match_body
|
||||
(pattern_section
|
||||
(integer)
|
||||
(pattern_guard
|
||||
(false))
|
||||
(body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(string))))))
|
||||
(pattern_section
|
||||
(integer)
|
||||
(pattern_guard
|
||||
(true))
|
||||
(body
|
||||
(expression_statement
|
||||
(call
|
||||
(identifier)
|
||||
(arguments
|
||||
(string))))))))
|
||||
(variable_statement (name) (integer))
|
||||
(match_statement
|
||||
(identifier)
|
||||
(match_body
|
||||
(pattern_section
|
||||
(identifier)
|
||||
(pattern_guard
|
||||
(identifier))
|
||||
(body
|
||||
(expression_statement (identifier)))))))
|
||||
|
||||
============================================
|
||||
Is Not Test
|
||||
============================================
|
||||
|
||||
x is T
|
||||
x is not T
|
||||
x is (not T)
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement (binary_operator (identifier) (identifier)))
|
||||
(expression_statement (binary_operator (identifier) (identifier)))
|
||||
(expression_statement (binary_operator (identifier) (parenthesized_expression (unary_operator (identifier))))))
|
||||
|
||||
============================================
|
||||
In And Not In Test
|
||||
============================================
|
||||
|
||||
x in y
|
||||
x not in y
|
||||
not (x in y)
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(binary_operator
|
||||
(identifier)
|
||||
(identifier)))
|
||||
(expression_statement
|
||||
(binary_operator
|
||||
(identifier)
|
||||
(identifier)))
|
||||
(expression_statement
|
||||
(unary_operator
|
||||
(parenthesized_expression
|
||||
(binary_operator
|
||||
(identifier)
|
||||
(identifier))))))
|
||||
@ -0,0 +1,671 @@
|
||||
===============================================================
|
||||
Double-quoted regular string
|
||||
===============================================================
|
||||
|
||||
"I used to be an adventurer like you."
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Double-quoted regular string containing escape sequence
|
||||
===============================================================
|
||||
|
||||
"Then i \took an arrow in \the knee."
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string
|
||||
(escape_sequence)
|
||||
(escape_sequence))))
|
||||
|
||||
===============================================================
|
||||
Double-quoted raw string
|
||||
===============================================================
|
||||
|
||||
r"Wake up Mr. Freeman."
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Double-quoted raw string containing escape sequence
|
||||
===============================================================
|
||||
|
||||
r"Wake up and smell \the ashes."
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Single-quoted regular string
|
||||
===============================================================
|
||||
|
||||
'Would you kindly?'
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Single-quoted regular string containing escape sequence
|
||||
===============================================================
|
||||
|
||||
'Wind\'s howling.'
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string (escape_sequence))))
|
||||
|
||||
===============================================================
|
||||
Single-quoted raw string
|
||||
===============================================================
|
||||
|
||||
r'Patrolling the Mojave almost makes you wish for a nuclear winter.'
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Single-quoted raw string containing escape sequence
|
||||
===============================================================
|
||||
|
||||
r'Praise \the sun.'
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Triple double-quoted regular string
|
||||
===============================================================
|
||||
|
||||
"""Snake?
|
||||
Snake?!
|
||||
SNAAAAKE!"""
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Triple double-quoted regular string containing escape sequence
|
||||
===============================================================
|
||||
|
||||
"""It's \too dangerous \to go alone!
|
||||
Take this."""
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string
|
||||
(escape_sequence)
|
||||
(escape_sequence))))
|
||||
|
||||
===============================================================
|
||||
Triple double-quoted raw string
|
||||
===============================================================
|
||||
|
||||
r"""Requiescat
|
||||
in
|
||||
pace."""
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Triple double-quoted raw string containing escape sequence
|
||||
===============================================================
|
||||
|
||||
r"""Rip and \tear,
|
||||
until it's done"""
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Triple single-quoted regular string
|
||||
===============================================================
|
||||
|
||||
'''You must construct
|
||||
additional pylons!'''
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Triple single-quoted regular string containing escape sequence
|
||||
===============================================================
|
||||
|
||||
'''We\'re more ghost
|
||||
\than people.'''
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string
|
||||
(escape_sequence)
|
||||
(escape_sequence))))
|
||||
|
||||
===============================================================
|
||||
Triple single-quoted raw string
|
||||
===============================================================
|
||||
|
||||
r'''Heroes
|
||||
never
|
||||
die!'''
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Triple single-quoted raw string containing escape sequence
|
||||
===============================================================
|
||||
|
||||
r'''For
|
||||
\the
|
||||
a\\iance!'''
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string)))
|
||||
|
||||
===============================================================
|
||||
Double-quoted string_name
|
||||
===============================================================
|
||||
|
||||
&"Hadouken!"
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string_name)))
|
||||
|
||||
===============================================================
|
||||
Double-quoted string_name containing escape sequence
|
||||
===============================================================
|
||||
|
||||
&"No cost \too great."
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string_name (escape_sequence))))
|
||||
|
||||
===============================================================
|
||||
Single-quoted string_name
|
||||
===============================================================
|
||||
|
||||
&'Why do we fight?'
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string_name)))
|
||||
|
||||
===============================================================
|
||||
Single-quoted string_name containing escape sequence
|
||||
===============================================================
|
||||
|
||||
&'Cut off \their limbs!'
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string_name (escape_sequence))))
|
||||
|
||||
===============================================================
|
||||
Triple double-quoted string_name
|
||||
===============================================================
|
||||
|
||||
&"""It's a
|
||||
mad world, kid."""
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string_name)))
|
||||
|
||||
===============================================================
|
||||
Triple double-quoted string_name containing escape sequence
|
||||
===============================================================
|
||||
|
||||
&"""And it's only
|
||||
ge\t\ting madder."""
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string_name
|
||||
(escape_sequence)
|
||||
(escape_sequence))))
|
||||
|
||||
===============================================================
|
||||
Triple single-quoted string_name
|
||||
===============================================================
|
||||
|
||||
&'''I am
|
||||
fragile'''
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string_name)))
|
||||
|
||||
===============================================================
|
||||
Triple single-quoted string_name containing escape sequence
|
||||
===============================================================
|
||||
|
||||
&'''but not
|
||||
\that fragile.'''
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(string_name (escape_sequence))))
|
||||
|
||||
===============================================================
|
||||
Double-quoted node_path
|
||||
===============================================================
|
||||
|
||||
^"./../Sandwich/makes/me:strong"
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(node_path)))
|
||||
|
||||
===============================================================
|
||||
Double-quoted node_path containing escape sequence
|
||||
===============================================================
|
||||
|
||||
^"../../Ain't/no/rest/for/\the:wicked!"
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(node_path (escape_sequence))))
|
||||
|
||||
===============================================================
|
||||
Single-quoted node_path
|
||||
===============================================================
|
||||
|
||||
^'Did/i/ever/tell/you/definition:of:insanity?'
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(node_path)))
|
||||
|
||||
===============================================================
|
||||
Single-quoted node_path containing escape sequence
|
||||
===============================================================
|
||||
|
||||
^'You\'ve/met/with/a/terrible/fate:haven\'t:you?'
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(node_path
|
||||
(escape_sequence)
|
||||
(escape_sequence))))
|
||||
|
||||
===============================================================
|
||||
Triple double-quoted node_path
|
||||
===============================================================
|
||||
|
||||
^"""We/stand/upon/the
|
||||
/precipice:of:change"""
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(node_path)))
|
||||
|
||||
===============================================================
|
||||
Triple double-quoted node_path containing escape sequence
|
||||
===============================================================
|
||||
|
||||
^"""The/pas\t/is/a/puzzle
|
||||
/like/a/broken:mirror"""
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(node_path (escape_sequence))))
|
||||
|
||||
===============================================================
|
||||
Triple single-quoted node_path
|
||||
===============================================================
|
||||
|
||||
^'''As/you/piece/it/together
|
||||
/you:cut/yourself'''
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(node_path)))
|
||||
|
||||
==============================================================
|
||||
Triple single-quoted node_path containing escape sequence
|
||||
==============================================================
|
||||
|
||||
^'''Do/a/barrel
|
||||
:ro\\'''
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(node_path (escape_sequence))))
|
||||
|
||||
==============================================================
|
||||
Unquoted get_node
|
||||
==============================================================
|
||||
|
||||
$_We/all/start/with/innocence
|
||||
%But/the/world/leads/us/to/guilt_
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(get_node))
|
||||
(expression_statement
|
||||
(get_node)))
|
||||
|
||||
==============================================================
|
||||
Double-quoted get_node
|
||||
==============================================================
|
||||
|
||||
$"0Your/health/is:low"
|
||||
%"0Do/you/any/potions/or:food?"
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(get_node))
|
||||
(expression_statement
|
||||
(get_node)))
|
||||
|
||||
==============================================================
|
||||
Double-quoted get_node containing escape sequence
|
||||
==============================================================
|
||||
|
||||
$"\the/power:is:yours"
|
||||
%"\return/to\the/mission:"
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(get_node (escape_sequence)))
|
||||
(expression_statement
|
||||
(get_node
|
||||
(escape_sequence)
|
||||
(escape_sequence))))
|
||||
|
||||
==============================================================
|
||||
Single-quoted get_node
|
||||
==============================================================
|
||||
|
||||
$'../They/call/me:zero'
|
||||
%'Because/i/am:nothing'
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(get_node))
|
||||
(expression_statement
|
||||
(get_node)))
|
||||
|
||||
==============================================================
|
||||
Single-quoted get_node containing escape sequence
|
||||
==============================================================
|
||||
|
||||
$'People/don\'t/forget'
|
||||
%'Nothing/gets:\forgiven'
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(get_node (escape_sequence)))
|
||||
(expression_statement
|
||||
(get_node (escape_sequence))))
|
||||
|
||||
==============================================================
|
||||
Triple double-quoted get_node
|
||||
==============================================================
|
||||
|
||||
$"""../A hunter
|
||||
/is:hunter"""
|
||||
%"""./Even/in
|
||||
/a:dream"""
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(get_node))
|
||||
(expression_statement
|
||||
(get_node)))
|
||||
|
||||
==============================================================
|
||||
Triple double-quoted get_node containing escape sequence
|
||||
==============================================================
|
||||
|
||||
$"""This/was
|
||||
/a:\triumph"""
|
||||
%"""I'm/making/a/no\te/here
|
||||
/huge:success"""
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(get_node (escape_sequence)))
|
||||
(expression_statement
|
||||
(get_node (escape_sequence))))
|
||||
|
||||
|
||||
==============================================================
|
||||
Triple single-quoted get_node
|
||||
==============================================================
|
||||
|
||||
$'''Honor/
|
||||
died'''
|
||||
%'''on/the
|
||||
/beach'''
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(get_node))
|
||||
(expression_statement
|
||||
(get_node)))
|
||||
|
||||
==============================================================
|
||||
Triple single-quoted get_node containing escape sequence
|
||||
==============================================================
|
||||
|
||||
$'''Stop/right:
|
||||
\there'''
|
||||
%'''Crimina\\:
|
||||
scum'''
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(get_node (escape_sequence)))
|
||||
(expression_statement
|
||||
(get_node (escape_sequence))))
|
||||
|
||||
==============================================================
|
||||
Extras and errors
|
||||
==============================================================
|
||||
|
||||
# Somehow, these are perfectly valid.
|
||||
# Maybe a bug?
|
||||
# Probably because they look like literals but they aren't.
|
||||
$ _Fus/ro / dah
|
||||
% You/are/finally/ \
|
||||
awake
|
||||
|
||||
# These are not valid.
|
||||
# It's because, there must be at least and at most one "/" symbol between the identifiers
|
||||
$Let me/guess
|
||||
%Someone//stole/your/sweetrool
|
||||
|
||||
# Btw, $ nodepath supports "/" symbol at the begining
|
||||
$/i/m/not/even/angry
|
||||
|
||||
# But % uniquenode does not.
|
||||
# (This might be a bug)
|
||||
%/open/your/eyes
|
||||
|
||||
# These are valid too.
|
||||
$ "Why/did/i \
|
||||
/move:here?"
|
||||
% "I/guess/it:was:\the \
|
||||
:weather"
|
||||
$ 'Ah/s***'
|
||||
% '../here/we/go: \
|
||||
again'
|
||||
$ """Here/come/the\test/results:"""
|
||||
% \
|
||||
"""You \
|
||||
are/a/horrible:person"""
|
||||
$ '''Punc/a\tree'''
|
||||
% '''\to/gather:wood'''
|
||||
|
||||
# But these are not valid.
|
||||
# They should be a token.
|
||||
|
||||
var v = & ""
|
||||
var v = & ''
|
||||
var v = & """"""
|
||||
var v = & ''''''
|
||||
var v = r ""
|
||||
var v = r ''
|
||||
var v = r """"""
|
||||
var v = r ''''''
|
||||
var v = ^ ""
|
||||
var v = ^ ''
|
||||
var v = ^ """"""
|
||||
var v = ^ ''''''
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(comment)
|
||||
(comment)
|
||||
(comment)
|
||||
(expression_statement
|
||||
(get_node))
|
||||
(expression_statement
|
||||
(get_node
|
||||
(line_continuation)))
|
||||
(comment)
|
||||
(comment)
|
||||
(expression_statement
|
||||
(get_node (ERROR)))
|
||||
(expression_statement
|
||||
(get_node (ERROR)))
|
||||
(comment)
|
||||
(expression_statement
|
||||
(get_node))
|
||||
(comment)
|
||||
(comment)
|
||||
(expression_statement
|
||||
(get_node (ERROR)))
|
||||
(comment)
|
||||
(expression_statement
|
||||
(get_node (escape_sequence)))
|
||||
(expression_statement
|
||||
(get_node
|
||||
(escape_sequence)
|
||||
(escape_sequence)))
|
||||
(expression_statement
|
||||
(get_node))
|
||||
(expression_statement
|
||||
(get_node (escape_sequence)))
|
||||
(expression_statement
|
||||
(get_node (escape_sequence)))
|
||||
(expression_statement
|
||||
(get_node (escape_sequence)))
|
||||
(expression_statement
|
||||
(get_node (escape_sequence)))
|
||||
(expression_statement
|
||||
(get_node (escape_sequence)))
|
||||
(comment)
|
||||
(comment)
|
||||
(variable_statement (name) (ERROR) (string))
|
||||
(variable_statement (name) (ERROR) (string))
|
||||
(variable_statement (name) (ERROR) (string))
|
||||
(variable_statement (name) (ERROR) (string))
|
||||
(variable_statement (name) (ERROR (identifier)) (string))
|
||||
(variable_statement (name) (ERROR (identifier)) (string))
|
||||
(variable_statement (name) (ERROR (identifier)) (string))
|
||||
(variable_statement (name) (ERROR (identifier)) (string))
|
||||
(variable_statement (name) (ERROR) (string))
|
||||
(variable_statement (name) (ERROR) (string))
|
||||
(variable_statement (name) (ERROR) (string))
|
||||
(variable_statement (name) (ERROR) (string)))
|
||||
@ -0,0 +1,25 @@
|
||||
============================================
|
||||
Subscripts
|
||||
============================================
|
||||
|
||||
T[1, 2]
|
||||
T.T[1, 2, 3]
|
||||
|
||||
---
|
||||
|
||||
(source
|
||||
(expression_statement
|
||||
(subscript
|
||||
(identifier)
|
||||
(subscript_arguments
|
||||
(integer)
|
||||
(integer))))
|
||||
(expression_statement
|
||||
(attribute
|
||||
(identifier)
|
||||
(attribute_subscript
|
||||
(identifier)
|
||||
(subscript_arguments
|
||||
(integer)
|
||||
(integer)
|
||||
(integer))))))
|
||||
@ -0,0 +1,35 @@
|
||||
{
|
||||
"grammars": [
|
||||
{
|
||||
"name": "gdscript",
|
||||
"camelcase": "GDScript",
|
||||
"scope": "source.gdscript",
|
||||
"file-types": [
|
||||
".gd"
|
||||
],
|
||||
"injection-regex": "^gdscript$"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"version": "6.0.0",
|
||||
"license": "MIT",
|
||||
"description": "Grammar for Godot's built-in scripting language.",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Preston Knopp",
|
||||
"email": "prestonknopp@gmail.com"
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"repository": "https://github.com/PrestonKnopp/tree-sitter-gdscript"
|
||||
}
|
||||
},
|
||||
"bindings": {
|
||||
"c": true,
|
||||
"go": true,
|
||||
"node": true,
|
||||
"python": true,
|
||||
"rust": true,
|
||||
"swift": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
tree-sitter-godot-resource/src/
|
||||
@ -0,0 +1,46 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
|
||||
[*.{json,toml,yml,gyp}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.js]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.scm]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{c,cc,h}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.rs]
|
||||
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
|
||||
|
||||
[parser.c]
|
||||
indent_size = 2
|
||||
|
||||
[{alloc,array,parser}.h]
|
||||
indent_size = 2
|
||||
@ -0,0 +1,37 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
# Generated source files
|
||||
src/*.json linguist-generated
|
||||
src/parser.c linguist-generated
|
||||
src/tree_sitter/* linguist-generated
|
||||
|
||||
# C bindings
|
||||
bindings/c/* linguist-generated
|
||||
CMakeLists.txt linguist-generated
|
||||
Makefile linguist-generated
|
||||
|
||||
# Rust bindings
|
||||
bindings/rust/* linguist-generated
|
||||
Cargo.toml linguist-generated
|
||||
Cargo.lock linguist-generated
|
||||
|
||||
# Node.js bindings
|
||||
bindings/node/* linguist-generated
|
||||
binding.gyp linguist-generated
|
||||
package.json linguist-generated
|
||||
package-lock.json linguist-generated
|
||||
|
||||
# Python bindings
|
||||
bindings/python/** linguist-generated
|
||||
setup.py linguist-generated
|
||||
pyproject.toml linguist-generated
|
||||
|
||||
# Go bindings
|
||||
bindings/go/* linguist-generated
|
||||
go.mod linguist-generated
|
||||
go.sum linguist-generated
|
||||
|
||||
# Swift bindings
|
||||
bindings/swift/** linguist-generated
|
||||
Package.swift linguist-generated
|
||||
Package.resolved linguist-generated
|
||||
@ -0,0 +1,73 @@
|
||||
# This workflow will
|
||||
# - test tree sitter grammar
|
||||
# - upload build native binaries as an artifact for each major platform
|
||||
# - download artifacts for each major platform and bundle them to be published
|
||||
# to npm
|
||||
# when a new version tag is pushed to the master branch.
|
||||
name: Test Build Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: [v*]
|
||||
|
||||
jobs:
|
||||
|
||||
build_native_binaries:
|
||||
strategy:
|
||||
matrix:
|
||||
# Use macos-14 for arm, however the artifact upload name conflicts with
|
||||
# macos-latest. There's probably a way to crossbuild for arm with
|
||||
# prebuildify.
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
# Why is npm only occassionally installing peer dependencies?
|
||||
# I cannot get consistent peer dependency installs with the same command runs.
|
||||
# Should I always explicitly run npm i tree-sitter? The general consensus is yes.
|
||||
# But then, why does it install peer deps sometimes?
|
||||
- run: |
|
||||
node --version
|
||||
npm --version
|
||||
- run: npm ci --include=peer --include=optional --include=dev
|
||||
- run: npm i tree-sitter
|
||||
- run: npm run versions
|
||||
- run: npm test
|
||||
- run: npm run prebuild
|
||||
# upload-artifact@v4 requires each artifact name to be unique.
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: prebuilds-${{ matrix.os }}
|
||||
path: prebuilds
|
||||
retention-days: 1
|
||||
|
||||
|
||||
publish_npm:
|
||||
needs: build_native_binaries
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
# https://docs.github.com/en/actions/use-cases-and-examples/publishing-packages/publishing-nodejs-packages#publishing-packages-to-the-npm-registry
|
||||
# https://github.com/actions/setup-node/issues/342
|
||||
# This is required to publish to npm.
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: |
|
||||
node --version
|
||||
npm --version
|
||||
- run: npm ci
|
||||
# Download all artifacts and merge into prebuilds dir.
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: prebuilds
|
||||
pattern: prebuilds-*
|
||||
merge-multiple: true
|
||||
- run: ls -R prebuilds
|
||||
- run: npm publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
@ -0,0 +1,22 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'grammar.js'
|
||||
- 'corpus/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
- run: |
|
||||
node --version
|
||||
npm --version
|
||||
- run: npm ci --include=dev --include=optional --include=peer
|
||||
- run: npm test
|
||||
@ -0,0 +1,41 @@
|
||||
# Rust artifacts
|
||||
target/
|
||||
|
||||
# Node artifacts
|
||||
build/
|
||||
prebuilds/
|
||||
node_modules/
|
||||
|
||||
# Swift artifacts
|
||||
.build/
|
||||
|
||||
# Go artifacts
|
||||
_obj/
|
||||
|
||||
# Python artifacts
|
||||
.venv/
|
||||
dist/
|
||||
*.egg-info
|
||||
*.whl
|
||||
|
||||
# C artifacts
|
||||
*.a
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
*.dll
|
||||
*.pc
|
||||
parser.exp
|
||||
parser.lib
|
||||
parser.obj
|
||||
scanner.obj
|
||||
|
||||
# Grammar volatiles
|
||||
*.wasm
|
||||
*.obj
|
||||
*.o
|
||||
|
||||
# Archives
|
||||
*.tar.gz
|
||||
*.tgz
|
||||
*.zip
|
||||
@ -0,0 +1,8 @@
|
||||
corpus
|
||||
examples
|
||||
build
|
||||
script
|
||||
parser.exp
|
||||
parser.lib
|
||||
parser.obj
|
||||
scanner.obj
|
||||
@ -0,0 +1,58 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(tree-sitter-godot-resource
|
||||
VERSION "0.7.0"
|
||||
DESCRIPTION "Grammar for the Godot game engine's resource format."
|
||||
HOMEPAGE_URL "https://github.com/prestonknopp/tree-sitter-godot-resource"
|
||||
LANGUAGES C)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
|
||||
option(TREE_SITTER_REUSE_ALLOCATOR "Reuse the library allocator" OFF)
|
||||
|
||||
set(TREE_SITTER_ABI_VERSION 14 CACHE STRING "Tree-sitter ABI version")
|
||||
if(NOT ${TREE_SITTER_ABI_VERSION} MATCHES "^[0-9]+$")
|
||||
unset(TREE_SITTER_ABI_VERSION CACHE)
|
||||
message(FATAL_ERROR "TREE_SITTER_ABI_VERSION must be an integer")
|
||||
endif()
|
||||
|
||||
find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI")
|
||||
|
||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c"
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json"
|
||||
COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json
|
||||
--abi=${TREE_SITTER_ABI_VERSION}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMENT "Generating parser.c")
|
||||
|
||||
add_library(tree-sitter-godot-resource src/parser.c)
|
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c)
|
||||
target_sources(tree-sitter-godot-resource PRIVATE src/scanner.c)
|
||||
endif()
|
||||
target_include_directories(tree-sitter-godot-resource PRIVATE src)
|
||||
|
||||
target_compile_definitions(tree-sitter-godot-resource PRIVATE
|
||||
$<$<BOOL:${TREE_SITTER_REUSE_ALLOCATOR}>:TREE_SITTER_REUSE_ALLOCATOR>
|
||||
$<$<CONFIG:Debug>:TREE_SITTER_DEBUG>)
|
||||
|
||||
set_target_properties(tree-sitter-godot-resource
|
||||
PROPERTIES
|
||||
C_STANDARD 11
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}"
|
||||
DEFINE_SYMBOL "")
|
||||
|
||||
configure_file(bindings/c/tree-sitter-godot-resource.pc.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-godot-resource.pc" @ONLY)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(FILES bindings/c/tree-sitter-godot-resource.h
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/tree_sitter")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-godot-resource.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig")
|
||||
install(TARGETS tree-sitter-godot-resource
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
|
||||
add_custom_target(ts-test "${TREE_SITTER_CLI}" test
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMENT "tree-sitter test")
|
||||
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "tree-sitter-godot-resource"
|
||||
description = "Grammar for the Godot game engine's resource format."
|
||||
version = "0.7.0"
|
||||
authors = ["Preston Knopp"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
keywords = ["incremental", "parsing", "tree-sitter", "godot-resource"]
|
||||
categories = ["parsing", "text-editors"]
|
||||
repository = "https://github.com/prestonknopp/tree-sitter-godot-resource"
|
||||
edition = "2021"
|
||||
autoexamples = false
|
||||
|
||||
build = "bindings/rust/build.rs"
|
||||
include = ["bindings/rust/*", "grammar.js", "queries/*", "src/*", "tree-sitter.json"]
|
||||
|
||||
[lib]
|
||||
path = "bindings/rust/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
tree-sitter-language = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.1.22"
|
||||
|
||||
[dev-dependencies]
|
||||
tree-sitter = "0.24.6"
|
||||
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Preston Knopp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@ -0,0 +1,94 @@
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error Windows is not supported)
|
||||
endif
|
||||
|
||||
LANGUAGE_NAME := tree-sitter-godot-resource
|
||||
HOMEPAGE_URL := https://github.com/prestonknopp/tree-sitter-godot-resource
|
||||
VERSION := 0.7.0
|
||||
|
||||
# repository
|
||||
SRC_DIR := src
|
||||
|
||||
TS ?= tree-sitter
|
||||
|
||||
# install directory layout
|
||||
PREFIX ?= /usr/local
|
||||
INCLUDEDIR ?= $(PREFIX)/include
|
||||
LIBDIR ?= $(PREFIX)/lib
|
||||
PCLIBDIR ?= $(LIBDIR)/pkgconfig
|
||||
|
||||
# source/object files
|
||||
PARSER := $(SRC_DIR)/parser.c
|
||||
EXTRAS := $(filter-out $(PARSER),$(wildcard $(SRC_DIR)/*.c))
|
||||
OBJS := $(patsubst %.c,%.o,$(PARSER) $(EXTRAS))
|
||||
|
||||
# flags
|
||||
ARFLAGS ?= rcs
|
||||
override CFLAGS += -I$(SRC_DIR) -std=c11 -fPIC
|
||||
|
||||
# ABI versioning
|
||||
SONAME_MAJOR = $(shell sed -n 's/\#define LANGUAGE_VERSION //p' $(PARSER))
|
||||
SONAME_MINOR = $(word 1,$(subst ., ,$(VERSION)))
|
||||
|
||||
# OS-specific bits
|
||||
ifeq ($(shell uname),Darwin)
|
||||
SOEXT = dylib
|
||||
SOEXTVER_MAJOR = $(SONAME_MAJOR).$(SOEXT)
|
||||
SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).$(SOEXT)
|
||||
LINKSHARED = -dynamiclib -Wl,-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SOEXTVER),-rpath,@executable_path/../Frameworks
|
||||
else
|
||||
SOEXT = so
|
||||
SOEXTVER_MAJOR = $(SOEXT).$(SONAME_MAJOR)
|
||||
SOEXTVER = $(SOEXT).$(SONAME_MAJOR).$(SONAME_MINOR)
|
||||
LINKSHARED = -shared -Wl,-soname,lib$(LANGUAGE_NAME).$(SOEXTVER)
|
||||
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|@PROJECT_VERSION@|$(VERSION)|' \
|
||||
-e 's|@CMAKE_INSTALL_LIBDIR@|$(LIBDIR:$(PREFIX)/%=%)|' \
|
||||
-e 's|@CMAKE_INSTALL_INCLUDEDIR@|$(INCLUDEDIR:$(PREFIX)/%=%)|' \
|
||||
-e 's|@PROJECT_DESCRIPTION@|$(DESCRIPTION)|' \
|
||||
-e 's|@PROJECT_HOMEPAGE_URL@|$(HOMEPAGE_URL)|' \
|
||||
-e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@
|
||||
|
||||
$(PARSER): $(SRC_DIR)/grammar.json
|
||||
$(TS) generate $^
|
||||
|
||||
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
|
||||
|
||||
.PHONY: all install uninstall clean test
|
||||
@ -0,0 +1,37 @@
|
||||
// swift-tools-version:5.3
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "TreeSitterGodotResource",
|
||||
products: [
|
||||
.library(name: "TreeSitterGodotResource", targets: ["TreeSitterGodotResource"]),
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/ChimeHQ/SwiftTreeSitter", from: "0.8.0"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "TreeSitterGodotResource",
|
||||
dependencies: [],
|
||||
path: ".",
|
||||
sources: [
|
||||
"src/parser.c",
|
||||
"src/scanner.c",
|
||||
],
|
||||
resources: [
|
||||
.copy("queries")
|
||||
],
|
||||
publicHeadersPath: "bindings/swift",
|
||||
cSettings: [.headerSearchPath("src")]
|
||||
),
|
||||
.testTarget(
|
||||
name: "TreeSitterGodotResourceTests",
|
||||
dependencies: [
|
||||
"SwiftTreeSitter",
|
||||
"TreeSitterGodotResource",
|
||||
],
|
||||
path: "bindings/swift/TreeSitterGodotResourceTests"
|
||||
)
|
||||
],
|
||||
cLanguageStandard: .c11
|
||||
)
|
||||
@ -0,0 +1,5 @@
|
||||
# tree-sitter-godot-resource
|
||||
|
||||
Godot resource grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter).
|
||||
|
||||
Parses tscn and tres files.
|
||||
@ -0,0 +1,31 @@
|
||||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "tree_sitter_godot_resource_binding",
|
||||
"dependencies": [
|
||||
"<!(node -p \"require('node-addon-api').targets\"):node_addon_api_except",
|
||||
],
|
||||
"include_dirs": [
|
||||
"src",
|
||||
],
|
||||
"sources": [
|
||||
"bindings/node/binding.cc",
|
||||
"src/parser.c",
|
||||
# NOTE: if your language has an external scanner, add it here.
|
||||
"src/scanner.c",
|
||||
],
|
||||
"conditions": [
|
||||
["OS!='win'", {
|
||||
"cflags_c": [
|
||||
"-std=c11",
|
||||
],
|
||||
}, { # OS == "win"
|
||||
"cflags_c": [
|
||||
"/std:c11",
|
||||
"/utf-8",
|
||||
],
|
||||
}],
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
16
vendored_parsers/tree-sitter-godot-resource/bindings/c/tree-sitter-godot-resource.h
generated
vendored
16
vendored_parsers/tree-sitter-godot-resource/bindings/c/tree-sitter-godot-resource.h
generated
vendored
@ -0,0 +1,16 @@
|
||||
#ifndef TREE_SITTER_GODOT_RESOURCE_H_
|
||||
#define TREE_SITTER_GODOT_RESOURCE_H_
|
||||
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const TSLanguage *tree_sitter_godot_resource(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_GODOT_RESOURCE_H_
|
||||
10
vendored_parsers/tree-sitter-godot-resource/bindings/c/tree-sitter-godot-resource.pc.in
generated
vendored
10
vendored_parsers/tree-sitter-godot-resource/bindings/c/tree-sitter-godot-resource.pc.in
generated
vendored
@ -0,0 +1,10 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||
|
||||
Name: tree-sitter-godot-resource
|
||||
Description: @PROJECT_DESCRIPTION@
|
||||
URL: @PROJECT_HOMEPAGE_URL@
|
||||
Version: @PROJECT_VERSION@
|
||||
Libs: -L${libdir} -ltree-sitter-godot-resource
|
||||
Cflags: -I${includedir}
|
||||
@ -0,0 +1,14 @@
|
||||
package tree_sitter_godot_resource
|
||||
|
||||
// #cgo CFLAGS: -std=c11 -fPIC
|
||||
// #include "../../src/parser.c"
|
||||
// // NOTE: if your language has an external scanner, add it here.
|
||||
// #include "../../src/scanner.c"
|
||||
import "C"
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// Get the tree-sitter Language for this grammar.
|
||||
func Language() unsafe.Pointer {
|
||||
return unsafe.Pointer(C.tree_sitter_godot_resource())
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package tree_sitter_godot_resource_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
tree_sitter "github.com/tree-sitter/go-tree-sitter"
|
||||
tree_sitter_godot_resource "github.com/prestonknopp/tree-sitter-godot-resource/bindings/go"
|
||||
)
|
||||
|
||||
func TestCanLoadGrammar(t *testing.T) {
|
||||
language := tree_sitter.NewLanguage(tree_sitter_godot_resource.Language())
|
||||
if language == nil {
|
||||
t.Errorf("Error loading GodotResource grammar")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
# This module, i.e. the nim bindings, can be placed anywhere in your nim project
|
||||
# or kept in the bindings directory.
|
||||
#
|
||||
# However the following assumes that when compiling your project or main module that
|
||||
# "tree-sitter-godot-resource/" is accessible from the current working directory.
|
||||
{.passC: "-Itree-sitter-godot-resource/src".}
|
||||
{.compile: "tree-sitter-godot-resource/src/parser.c".}
|
||||
{.compile: "tree-sitter-godot-resource/src/scanner.c".}
|
||||
proc tree_sitter_godot_resource*(): pointer {.importc.}
|
||||
@ -0,0 +1,20 @@
|
||||
#include <napi.h>
|
||||
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
|
||||
extern "C" TSLanguage *tree_sitter_godot_resource();
|
||||
|
||||
// "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, "godot_resource");
|
||||
auto language = Napi::External<TSLanguage>::New(env, tree_sitter_godot_resource());
|
||||
language.TypeTag(&LANGUAGE_TYPE_TAG);
|
||||
exports["language"] = language;
|
||||
return exports;
|
||||
}
|
||||
|
||||
NODE_API_MODULE(tree_sitter_godot_resource_binding, Init)
|
||||
@ -0,0 +1,9 @@
|
||||
const assert = require("node:assert");
|
||||
const { test } = require("node:test");
|
||||
|
||||
const Parser = require("tree-sitter");
|
||||
|
||||
test("can load grammar", () => {
|
||||
const parser = new Parser();
|
||||
assert.doesNotThrow(() => parser.setLanguage(require(".")));
|
||||
});
|
||||
@ -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;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue