tree-sitter-bsl 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +188 -3
- package/binding.gyp +6 -4
- package/bindings/node/binding.cc +16 -2
- package/bindings/node/binding_test.js +16 -2
- package/bindings/node/index.d.ts +1 -0
- package/bindings/node/index.js +2 -1
- package/{grammar.js → grammars/bsl/grammar.js} +153 -43
- package/grammars/bsl/queries/highlights.scm +93 -0
- package/grammars/bsl/queries/injections.scm +8 -0
- package/{src → grammars/bsl/src}/grammar.json +1335 -775
- package/{src → grammars/bsl/src}/node-types.json +512 -10
- package/grammars/bsl/src/parser.c +32756 -0
- package/{src → grammars/bsl/src}/tree_sitter/array.h +71 -110
- package/grammars/sdbl/grammar.js +734 -0
- package/grammars/sdbl/queries/highlights.scm +131 -0
- package/grammars/sdbl/src/grammar.json +4697 -0
- package/grammars/sdbl/src/node-types.json +2635 -0
- package/grammars/sdbl/src/parser.c +77171 -0
- package/grammars/sdbl/src/tree_sitter/alloc.h +54 -0
- package/grammars/sdbl/src/tree_sitter/array.h +291 -0
- package/grammars/sdbl/src/tree_sitter/parser.h +286 -0
- package/package.json +32 -10
- package/prebuilds/darwin-arm64/tree-sitter-bsl.node +0 -0
- package/prebuilds/darwin-x64/tree-sitter-bsl.node +0 -0
- package/prebuilds/linux-arm64/tree-sitter-bsl.node +0 -0
- package/prebuilds/linux-x64/tree-sitter-bsl.node +0 -0
- package/prebuilds/win32-arm64/tree-sitter-bsl.node +0 -0
- package/prebuilds/win32-x64/tree-sitter-bsl.node +0 -0
- package/tree-sitter.json +14 -1
- package/src/parser.c +0 -28213
- package/tree-sitter-bsl.wasm +0 -0
- /package/{src → grammars/bsl/src}/tree_sitter/alloc.h +0 -0
- /package/{src → grammars/bsl/src}/tree_sitter/parser.h +0 -0
package/README.md
CHANGED
|
@@ -2,17 +2,202 @@
|
|
|
2
2
|
|
|
3
3
|
[![CI][ci]](https://github.com/alkoleft/tree-sitter-bsl/actions/workflows/ci.yml)
|
|
4
4
|
[![npm][npm]](https://www.npmjs.com/package/tree-sitter-bsl)
|
|
5
|
+
[![crates.io][crates]](https://crates.io/crates/tree-sitter-bsl)
|
|
6
|
+
[![PyPI][pypi]](https://pypi.org/project/tree-sitter-bsl/)
|
|
5
7
|
|
|
6
|
-
Грамматика 1C
|
|
8
|
+
Грамматика 1C BSL в формате [tree-sitter](https://github.com/tree-sitter/tree-sitter).
|
|
9
|
+
Пакет также содержит отдельную грамматику `sdbl` для языка запросов 1C.
|
|
7
10
|
|
|
8
11
|
[Попробовать](https://alkoleft.github.io/tree-sitter-bsl/)
|
|
9
12
|
|
|
10
13
|

|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
## Что входит
|
|
16
|
+
|
|
17
|
+
- `bsl`: грамматика исходных файлов BSL (`.bsl`, `.osl`).
|
|
18
|
+
- `sdbl`: грамматика самостоятельных текстов запросов 1C (`.sdbl`).
|
|
19
|
+
- Query-файлы tree-sitter для подсветки BSL/SDBL и внедрения статических
|
|
20
|
+
строковых литералов BSL, начинающихся с `ВЫБРАТЬ`, `SELECT`, `УНИЧТОЖИТЬ`
|
|
21
|
+
или `DROP`, как `sdbl`.
|
|
22
|
+
- Локальное dev-расширение Zed в [`editors/zed-bsl`](editors/zed-bsl) для
|
|
23
|
+
проверки подсветки BSL, самостоятельного SDBL и внедренного SDBL.
|
|
24
|
+
|
|
25
|
+
BSL и SDBL остаются разными контрактами парсера. Грамматика BSL не встраивает
|
|
26
|
+
SDBL в AST строковых литералов; разбор встроенных запросов выполняется через
|
|
27
|
+
tree-sitter injections и композицию на стороне редактора.
|
|
28
|
+
|
|
29
|
+
## Локальная разработка
|
|
30
|
+
|
|
31
|
+
Локальный tree-sitter playground запускается отдельно для каждой грамматики:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm start
|
|
35
|
+
npm run start:bsl
|
|
36
|
+
npm run start:sdbl
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`npm start` является псевдонимом для BSL playground. `npm run start:sdbl`
|
|
40
|
+
запускает playground самостоятельной грамматики SDBL. При необходимости можно
|
|
41
|
+
собрать оба WASM-парсера:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
npm run build:wasm
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Быстрая проверка дерева разбора:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
npm run parse:bsl -- examples/playground/basic.bsl
|
|
51
|
+
npm run parse:sdbl -- examples/playground/select.sdbl
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Небольшие примеры для playground лежат в
|
|
55
|
+
[`examples/playground`](examples/playground):
|
|
56
|
+
|
|
57
|
+
- [`basic.bsl`](examples/playground/basic.bsl) для синтаксиса исходных файлов
|
|
58
|
+
BSL;
|
|
59
|
+
- [`select.sdbl`](examples/playground/select.sdbl) и
|
|
60
|
+
[`query-package.sdbl`](examples/playground/query-package.sdbl) для синтаксиса
|
|
61
|
+
самостоятельных SDBL-запросов.
|
|
62
|
+
|
|
63
|
+
SDBL-примеры разбираются самостоятельной грамматикой SDBL. BSL-строки с
|
|
64
|
+
текстом запроса остаются узлами строк BSL; разбор встроенного запроса относится
|
|
65
|
+
к отдельному контракту injection/composition.
|
|
66
|
+
|
|
67
|
+
Основные команды проверки:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
npm run test:corpus
|
|
71
|
+
npm test
|
|
72
|
+
npm run test:all
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`npm run test:corpus` использует локальный для пакета `tree-sitter-cli` и
|
|
76
|
+
проверяет оба набора corpus-тестов. Для системного `tree-sitter` CLI, который
|
|
77
|
+
поддерживает `-p`, эквивалентные команды:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
tree-sitter test -p grammars/bsl
|
|
81
|
+
tree-sitter test -p grammars/sdbl
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Использование
|
|
85
|
+
|
|
86
|
+
### Rust
|
|
87
|
+
|
|
88
|
+
Добавьте зависимость в [`Cargo.toml`](Cargo.toml):
|
|
89
|
+
|
|
90
|
+
```toml
|
|
91
|
+
[dependencies]
|
|
92
|
+
tree-sitter = "0.25"
|
|
93
|
+
tree-sitter-bsl = "0.1"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```rust
|
|
97
|
+
use tree_sitter::Parser;
|
|
98
|
+
|
|
99
|
+
fn main() {
|
|
100
|
+
let mut parser = Parser::new();
|
|
101
|
+
parser
|
|
102
|
+
.set_language(&tree_sitter_bsl::LANGUAGE.into())
|
|
103
|
+
.expect("Error loading BSL grammar");
|
|
104
|
+
|
|
105
|
+
let source = r#"
|
|
106
|
+
Процедура Привет()
|
|
107
|
+
Сообщить("Привет, мир!");
|
|
108
|
+
КонецПроцедуры
|
|
109
|
+
"#;
|
|
110
|
+
|
|
111
|
+
let tree = parser.parse(source, None).unwrap();
|
|
112
|
+
println!("{}", tree.root_node().to_sexp());
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Node.js
|
|
117
|
+
|
|
118
|
+
Установите пакет:
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
npm install tree-sitter-bsl tree-sitter
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
const Parser = require("tree-sitter");
|
|
126
|
+
const BSL = require("tree-sitter-bsl");
|
|
127
|
+
|
|
128
|
+
const parser = new Parser();
|
|
129
|
+
parser.setLanguage(BSL);
|
|
130
|
+
|
|
131
|
+
const sourceCode = `
|
|
132
|
+
Процедура Привет()
|
|
133
|
+
Сообщить("Привет, мир!");
|
|
134
|
+
КонецПроцедуры
|
|
135
|
+
`;
|
|
136
|
+
|
|
137
|
+
const tree = parser.parse(sourceCode);
|
|
138
|
+
console.log(tree.rootNode.toString());
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Python
|
|
142
|
+
|
|
143
|
+
Установите пакет:
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
pip install tree-sitter-bsl tree-sitter
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
import tree_sitter_bsl as tsbsl
|
|
151
|
+
from tree_sitter import Language, Parser
|
|
152
|
+
|
|
153
|
+
BSL_LANGUAGE = Language(tsbsl.language())
|
|
154
|
+
parser = Parser(BSL_LANGUAGE)
|
|
155
|
+
|
|
156
|
+
source = """
|
|
157
|
+
Процедура Привет()
|
|
158
|
+
Сообщить("Привет, мир!");
|
|
159
|
+
КонецПроцедуры
|
|
160
|
+
""".encode()
|
|
161
|
+
|
|
162
|
+
tree = parser.parse(source)
|
|
163
|
+
print(tree.root_node.sexp())
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Грамматика запросов SDBL
|
|
167
|
+
|
|
168
|
+
Пакет также экспортирует самостоятельную грамматику языка запросов SDBL:
|
|
169
|
+
|
|
170
|
+
- Node.js: `require("tree-sitter-bsl").sdbl`;
|
|
171
|
+
- Rust: `tree_sitter_bsl::SDBL_LANGUAGE`;
|
|
172
|
+
- Python: `tree_sitter_bsl.SDBLLanguage()` или низкоуровневая капсула
|
|
173
|
+
`tree_sitter_bsl.sdbl_language()`;
|
|
174
|
+
- Go: `tree_sitter_bsl.SDBLLanguage()`;
|
|
175
|
+
- C: `tree_sitter_sdbl()` из `tree-sitter-bsl.h` и той же библиотеки.
|
|
176
|
+
|
|
177
|
+
Существующие точки входа BSL остаются языком пакета по умолчанию.
|
|
178
|
+
|
|
179
|
+
Пакет включает query-файлы tree-sitter для интеграций с редакторами:
|
|
180
|
+
|
|
181
|
+
- `grammars/bsl/queries/highlights.scm` для подсветки BSL;
|
|
182
|
+
- `grammars/bsl/queries/injections.scm` для внедрения статических строковых
|
|
183
|
+
литералов BSL, начинающихся с ключевых слов SDBL-выражений, как `sdbl`;
|
|
184
|
+
- `grammars/sdbl/queries/highlights.scm` для подсветки самостоятельного SDBL и
|
|
185
|
+
текста запросов, внедренного из BSL.
|
|
186
|
+
|
|
187
|
+
Для Zed используется локальное dev extension:
|
|
188
|
+
[`editors/zed-bsl`](editors/zed-bsl). Оно регистрирует BSL, SDBL и
|
|
189
|
+
специальную для Zed грамматику-носитель `sdbl_embedded`, чтобы исходный текст
|
|
190
|
+
внедренной BSL-строки подсвечивался без изменения контракта самостоятельной
|
|
191
|
+
грамматики `.sdbl`.
|
|
192
|
+
|
|
193
|
+
## Ссылки
|
|
13
194
|
|
|
14
195
|
- Грамматика основана на правилах [BSL Parser](https://github.com/1c-syntax/bsl-parser)
|
|
196
|
+
- Архитектурные решения: [`docs/decisions`](docs/decisions)
|
|
197
|
+
- Активный список parser-задач: [`spec/IMPLEMENTATION_TODO.md`](spec/IMPLEMENTATION_TODO.md)
|
|
198
|
+
- Контракт грамматики SDBL: [`spec/sdbl-query-language.md`](spec/sdbl-query-language.md)
|
|
15
199
|
|
|
16
200
|
[ci]: https://img.shields.io/github/actions/workflow/status/alkoleft/tree-sitter-bsl/ci.yml?logo=github&label=CI
|
|
17
201
|
[npm]: https://img.shields.io/npm/v/tree-sitter-bsl?logo=npm
|
|
18
|
-
[
|
|
202
|
+
[crates]: https://img.shields.io/crates/v/tree-sitter-bsl?logo=rust
|
|
203
|
+
[pypi]: https://img.shields.io/pypi/v/tree-sitter-bsl?logo=python
|
package/binding.gyp
CHANGED
|
@@ -6,18 +6,20 @@
|
|
|
6
6
|
"<!(node -p \"require('node-addon-api').targets\"):node_addon_api_except",
|
|
7
7
|
],
|
|
8
8
|
"include_dirs": [
|
|
9
|
-
"src",
|
|
9
|
+
"grammars/bsl/src",
|
|
10
|
+
"grammars/sdbl/src",
|
|
10
11
|
],
|
|
11
12
|
"sources": [
|
|
12
13
|
"bindings/node/binding.cc",
|
|
13
|
-
"src/parser.c",
|
|
14
|
+
"grammars/bsl/src/parser.c",
|
|
15
|
+
"grammars/sdbl/src/parser.c",
|
|
14
16
|
],
|
|
15
17
|
"variables": {
|
|
16
|
-
"has_scanner": "<!(node -p \"fs.existsSync('src/scanner.c')\")"
|
|
18
|
+
"has_scanner": "<!(node -p \"fs.existsSync('grammars/bsl/src/scanner.c')\")"
|
|
17
19
|
},
|
|
18
20
|
"conditions": [
|
|
19
21
|
["has_scanner=='true'", {
|
|
20
|
-
"sources+": ["src/scanner.c"],
|
|
22
|
+
"sources+": ["grammars/bsl/src/scanner.c"],
|
|
21
23
|
}],
|
|
22
24
|
["OS!='win'", {
|
|
23
25
|
"cflags_c": [
|
package/bindings/node/binding.cc
CHANGED
|
@@ -3,16 +3,30 @@
|
|
|
3
3
|
typedef struct TSLanguage TSLanguage;
|
|
4
4
|
|
|
5
5
|
extern "C" TSLanguage *tree_sitter_bsl();
|
|
6
|
+
extern "C" TSLanguage *tree_sitter_sdbl();
|
|
6
7
|
|
|
7
8
|
// "tree-sitter", "language" hashed with BLAKE2
|
|
8
9
|
const napi_type_tag LANGUAGE_TYPE_TAG = {
|
|
9
10
|
0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
Napi::
|
|
13
|
-
auto language = Napi::External<TSLanguage>::New(env,
|
|
13
|
+
Napi::External<TSLanguage> CreateLanguage(Napi::Env env, TSLanguage *language_fn()) {
|
|
14
|
+
auto language = Napi::External<TSLanguage>::New(env, language_fn());
|
|
14
15
|
language.TypeTag(&LANGUAGE_TYPE_TAG);
|
|
16
|
+
return language;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
Napi::Object CreateLanguageObject(Napi::Env env, TSLanguage *language_fn()) {
|
|
20
|
+
auto language = CreateLanguage(env, language_fn);
|
|
21
|
+
auto object = Napi::Object::New(env);
|
|
22
|
+
object["language"] = language;
|
|
23
|
+
return object;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
|
27
|
+
auto language = CreateLanguage(env, tree_sitter_bsl);
|
|
15
28
|
exports["language"] = language;
|
|
29
|
+
exports["sdbl"] = CreateLanguageObject(env, tree_sitter_sdbl);
|
|
16
30
|
return exports;
|
|
17
31
|
}
|
|
18
32
|
|
|
@@ -3,7 +3,21 @@ const { test } = require("node:test");
|
|
|
3
3
|
|
|
4
4
|
const Parser = require("tree-sitter");
|
|
5
5
|
|
|
6
|
-
test("can load grammar", () => {
|
|
6
|
+
test("can load BSL grammar", () => {
|
|
7
7
|
const parser = new Parser();
|
|
8
|
-
|
|
8
|
+
const BSL = require(".");
|
|
9
|
+
assert.doesNotThrow(() => parser.setLanguage(BSL));
|
|
10
|
+
|
|
11
|
+
const tree = parser.parse("Процедура Проверка()\nКонецПроцедуры");
|
|
12
|
+
assert.equal(tree.rootNode.hasError, false);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("can load SDBL grammar", () => {
|
|
16
|
+
const parser = new Parser();
|
|
17
|
+
const { sdbl } = require(".");
|
|
18
|
+
assert.ok(sdbl);
|
|
19
|
+
assert.doesNotThrow(() => parser.setLanguage(sdbl));
|
|
20
|
+
|
|
21
|
+
const tree = parser.parse("ВЫБРАТЬ\n *");
|
|
22
|
+
assert.equal(tree.rootNode.hasError, false);
|
|
9
23
|
});
|
package/bindings/node/index.d.ts
CHANGED
package/bindings/node/index.js
CHANGED
|
@@ -7,5 +7,6 @@ module.exports =
|
|
|
7
7
|
: require("node-gyp-build")(root);
|
|
8
8
|
|
|
9
9
|
try {
|
|
10
|
-
module.exports.nodeTypeInfo = require("../../src/node-types.json");
|
|
10
|
+
module.exports.nodeTypeInfo = require("../../grammars/bsl/src/node-types.json");
|
|
11
|
+
module.exports.sdbl.nodeTypeInfo = require("../../grammars/sdbl/src/node-types.json");
|
|
11
12
|
} catch (_) {}
|
|
@@ -110,19 +110,43 @@ function reservedKeywords($) {
|
|
|
110
110
|
return Object.keys(buildKeywords()).map((k) => $[k]);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Формирует список ключевых слов, допустимых как имена членов после доступа
|
|
115
|
+
*
|
|
116
|
+
* @param {*} $ grammar object
|
|
117
|
+
*/
|
|
118
|
+
function memberNameKeywords($) {
|
|
119
|
+
return [
|
|
120
|
+
...CORE_KEYWORDS.map(([, eng]) => $[`${eng.toUpperCase()}_KEYWORD`]),
|
|
121
|
+
$.NULL_KEYWORD,
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
|
|
113
125
|
const Preprocessor = {
|
|
114
126
|
preprocessor: ($) => {
|
|
115
|
-
const region =
|
|
116
|
-
|
|
127
|
+
const region = seq(
|
|
128
|
+
$.PREPROC_REGION_KEYWORD,
|
|
129
|
+
field('name', $.identifier),
|
|
130
|
+
repeat($._definition),
|
|
117
131
|
$.PREPROC_ENDREGION_KEYWORD,
|
|
118
|
-
|
|
132
|
+
);
|
|
119
133
|
|
|
120
|
-
const preproc_if =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
$.
|
|
134
|
+
const preproc_if = seq(
|
|
135
|
+
$.PREPROC_IF_KEYWORD,
|
|
136
|
+
$.expression,
|
|
137
|
+
$.THEN_KEYWORD,
|
|
138
|
+
repeat($._definition),
|
|
139
|
+
repeat(
|
|
140
|
+
seq(
|
|
141
|
+
$.PREPROC_ELSIF_KEYWORD,
|
|
142
|
+
$.expression,
|
|
143
|
+
$.THEN_KEYWORD,
|
|
144
|
+
repeat($._definition),
|
|
145
|
+
),
|
|
146
|
+
),
|
|
147
|
+
optional(seq($.PREPROC_ELSE_KEYWORD, repeat($._definition))),
|
|
124
148
|
$.PREPROC_ENDIF_KEYWORD,
|
|
125
|
-
|
|
149
|
+
);
|
|
126
150
|
|
|
127
151
|
const preproc_change = [
|
|
128
152
|
'Вставка',
|
|
@@ -169,8 +193,8 @@ const Preprocessor = {
|
|
|
169
193
|
alias(token(caseInsensitive('&' + annotation)), $.annotation),
|
|
170
194
|
);
|
|
171
195
|
return choice(
|
|
172
|
-
|
|
173
|
-
|
|
196
|
+
region,
|
|
197
|
+
preproc_if,
|
|
174
198
|
...preproc_change,
|
|
175
199
|
...annotations,
|
|
176
200
|
...compilation_directives,
|
|
@@ -187,7 +211,9 @@ module.exports = grammar({
|
|
|
187
211
|
|
|
188
212
|
inline: ($) => [],
|
|
189
213
|
|
|
190
|
-
conflicts: ($) => [
|
|
214
|
+
conflicts: ($) => [
|
|
215
|
+
[$._plain_variable_spec, $._exported_variable_spec],
|
|
216
|
+
],
|
|
191
217
|
|
|
192
218
|
word: ($) => $.identifier,
|
|
193
219
|
|
|
@@ -228,15 +254,41 @@ module.exports = grammar({
|
|
|
228
254
|
),
|
|
229
255
|
|
|
230
256
|
var_definition: ($) =>
|
|
231
|
-
prec(
|
|
257
|
+
prec.right(
|
|
232
258
|
1,
|
|
233
259
|
seq(
|
|
234
260
|
$.VAR_KEYWORD,
|
|
235
|
-
|
|
261
|
+
$._var_definition_variables,
|
|
236
262
|
optional(field('export', $.EXPORT_KEYWORD)),
|
|
237
263
|
optional(';'),
|
|
238
264
|
),
|
|
239
265
|
),
|
|
266
|
+
_var_definition_variables: ($) =>
|
|
267
|
+
seq(
|
|
268
|
+
repeat(
|
|
269
|
+
choice(
|
|
270
|
+
seq(
|
|
271
|
+
field('variable', alias($._exported_variable_spec, $.variable_spec)),
|
|
272
|
+
',',
|
|
273
|
+
),
|
|
274
|
+
seq(
|
|
275
|
+
field('variable', alias($._plain_variable_spec, $.variable_spec)),
|
|
276
|
+
',',
|
|
277
|
+
),
|
|
278
|
+
),
|
|
279
|
+
),
|
|
280
|
+
field('variable', alias($._plain_variable_spec, $.variable_spec)),
|
|
281
|
+
),
|
|
282
|
+
_plain_variable_spec: ($) =>
|
|
283
|
+
prec(2, seq(field('name', $.identifier))),
|
|
284
|
+
_exported_variable_spec: ($) =>
|
|
285
|
+
prec(
|
|
286
|
+
2,
|
|
287
|
+
seq(
|
|
288
|
+
field('name', $.identifier),
|
|
289
|
+
field('export', $.EXPORT_KEYWORD),
|
|
290
|
+
),
|
|
291
|
+
),
|
|
240
292
|
parameters: ($) => seq('(', commaSep(field('parameter', $.parameter)), ')'),
|
|
241
293
|
|
|
242
294
|
parameter: ($) =>
|
|
@@ -249,6 +301,7 @@ module.exports = grammar({
|
|
|
249
301
|
// Statements
|
|
250
302
|
_statement: ($) =>
|
|
251
303
|
choice(
|
|
304
|
+
$._empty_statement,
|
|
252
305
|
$.execute_statement,
|
|
253
306
|
$.call_statement,
|
|
254
307
|
$.assignment_statement,
|
|
@@ -270,42 +323,52 @@ module.exports = grammar({
|
|
|
270
323
|
$.await_statement,
|
|
271
324
|
),
|
|
272
325
|
|
|
326
|
+
_empty_statement: ($) => prec(-1, ';'),
|
|
327
|
+
|
|
273
328
|
call_statement: ($) =>
|
|
274
|
-
seq(choice($.method_call, $.call_expression), optional(';')),
|
|
329
|
+
prec.right(seq(choice($.method_call, $.call_expression), optional(';'))),
|
|
275
330
|
|
|
276
331
|
assignment_statement: ($) =>
|
|
277
|
-
seq(
|
|
332
|
+
prec.right(seq(
|
|
278
333
|
field('left', $._assignment_member),
|
|
279
334
|
'=',
|
|
280
335
|
field('right', $.expression),
|
|
281
336
|
optional(';'),
|
|
282
|
-
),
|
|
337
|
+
)),
|
|
283
338
|
|
|
284
339
|
return_statement: ($) =>
|
|
285
340
|
prec.right(seq($.RETURN_KEYWORD, field('result', optional($.expression)), optional(';'))),
|
|
286
341
|
|
|
287
342
|
try_statement: ($) =>
|
|
288
|
-
seq(
|
|
343
|
+
prec.right(seq(
|
|
289
344
|
$.TRY_KEYWORD,
|
|
290
345
|
repeat($._statement),
|
|
291
346
|
$.EXCEPT_KEYWORD,
|
|
292
|
-
repeat($.
|
|
347
|
+
repeat($._exception_statement),
|
|
293
348
|
$.ENDTRY_KEYWORD,
|
|
294
349
|
optional(';'),
|
|
350
|
+
)),
|
|
351
|
+
|
|
352
|
+
_exception_statement: ($) =>
|
|
353
|
+
choice(
|
|
354
|
+
alias($._rise_error_rethrow_statement, $.rise_error_statement),
|
|
355
|
+
$._statement,
|
|
295
356
|
),
|
|
296
357
|
|
|
358
|
+
_rise_error_rethrow_statement: ($) => seq($.RAISE_KEYWORD, ';'),
|
|
359
|
+
|
|
297
360
|
rise_error_statement: ($) =>
|
|
298
|
-
seq($.RAISE_KEYWORD, choice($.arguments, $.expression), optional(';')),
|
|
361
|
+
prec.right(seq($.RAISE_KEYWORD, choice(prec(1, $.arguments), $.expression), optional(';'))),
|
|
299
362
|
|
|
300
363
|
var_statement: ($) =>
|
|
301
|
-
seq(
|
|
364
|
+
prec.right(seq(
|
|
302
365
|
$.VAR_KEYWORD,
|
|
303
366
|
sepBy1(',', field('var_name', $.identifier)),
|
|
304
367
|
optional(';'),
|
|
305
|
-
),
|
|
368
|
+
)),
|
|
306
369
|
|
|
307
370
|
if_statement: ($) =>
|
|
308
|
-
seq(
|
|
371
|
+
prec.right(seq(
|
|
309
372
|
$.IF_KEYWORD,
|
|
310
373
|
$.expression,
|
|
311
374
|
$.THEN_KEYWORD,
|
|
@@ -314,7 +377,7 @@ module.exports = grammar({
|
|
|
314
377
|
optional($.else_clause),
|
|
315
378
|
$.ENDIF_KEYWORD,
|
|
316
379
|
optional(';'),
|
|
317
|
-
),
|
|
380
|
+
)),
|
|
318
381
|
|
|
319
382
|
elseif_clause: ($) =>
|
|
320
383
|
seq($.ELSIF_KEYWORD, $.expression, $.THEN_KEYWORD, repeat($._statement)),
|
|
@@ -331,7 +394,7 @@ module.exports = grammar({
|
|
|
331
394
|
),
|
|
332
395
|
|
|
333
396
|
for_statement: ($) =>
|
|
334
|
-
seq(
|
|
397
|
+
prec.right(seq(
|
|
335
398
|
$.FOR_KEYWORD,
|
|
336
399
|
$.identifier,
|
|
337
400
|
'=',
|
|
@@ -342,10 +405,10 @@ module.exports = grammar({
|
|
|
342
405
|
repeat($._statement),
|
|
343
406
|
$.ENDDO_KEYWORD,
|
|
344
407
|
optional(';'),
|
|
345
|
-
),
|
|
408
|
+
)),
|
|
346
409
|
|
|
347
410
|
for_each_statement: ($) =>
|
|
348
|
-
seq(
|
|
411
|
+
prec.right(seq(
|
|
349
412
|
$.FOR_KEYWORD,
|
|
350
413
|
$.EACH_KEYWORD,
|
|
351
414
|
$.identifier,
|
|
@@ -355,40 +418,41 @@ module.exports = grammar({
|
|
|
355
418
|
repeat($._statement),
|
|
356
419
|
$.ENDDO_KEYWORD,
|
|
357
420
|
optional(';'),
|
|
358
|
-
),
|
|
421
|
+
)),
|
|
359
422
|
|
|
360
|
-
continue_statement: ($) => seq($.CONTINUE_KEYWORD, optional(';')),
|
|
423
|
+
continue_statement: ($) => prec.right(seq($.CONTINUE_KEYWORD, optional(';'))),
|
|
361
424
|
|
|
362
|
-
break_statement: ($) => seq($.BREAK_KEYWORD, optional(';')),
|
|
425
|
+
break_statement: ($) => prec.right(seq($.BREAK_KEYWORD, optional(';'))),
|
|
363
426
|
|
|
364
427
|
execute_statement: ($) => choice(
|
|
365
|
-
seq(keyword('выполнить', 'execute'), $.expression, optional(';')),
|
|
366
|
-
seq(keyword('выполнить', 'execute'), '(', $.expression, ')', optional(';')),
|
|
428
|
+
prec.right(seq(keyword('выполнить', 'execute'), $.expression, optional(';'))),
|
|
429
|
+
prec.right(1, seq(keyword('выполнить', 'execute'), '(', $.expression, ')', optional(';'))),
|
|
367
430
|
),
|
|
368
431
|
|
|
369
432
|
goto_statement: ($) =>
|
|
370
|
-
seq($.GOTO_KEYWORD, '~', $.identifier, optional(';')),
|
|
433
|
+
prec.right(seq($.GOTO_KEYWORD, '~', $.identifier, optional(';'))),
|
|
371
434
|
|
|
372
|
-
label_statement: ($) => seq('~', $.identifier, ':', optional(';')),
|
|
435
|
+
label_statement: ($) => prec.right(seq('~', $.identifier, ':', optional(';'))),
|
|
373
436
|
|
|
374
437
|
add_handler_statement: ($) =>
|
|
375
|
-
seq($.ADDHANDLER_KEYWORD, $.expression, ',', $.expression, optional(';')),
|
|
438
|
+
prec.right(seq($.ADDHANDLER_KEYWORD, $.expression, ',', $.expression, optional(';'))),
|
|
376
439
|
|
|
377
440
|
remove_handler_statement: ($) =>
|
|
378
|
-
seq(
|
|
441
|
+
prec.right(seq(
|
|
379
442
|
$.REMOVEHANDLER_KEYWORD,
|
|
380
443
|
$.expression,
|
|
381
444
|
',',
|
|
382
445
|
$.expression,
|
|
383
446
|
optional(';'),
|
|
384
|
-
),
|
|
385
|
-
await_statement: ($) => seq($.await_expression, optional(';')),
|
|
447
|
+
)),
|
|
448
|
+
await_statement: ($) => prec.right(seq($.await_expression, optional(';'))),
|
|
386
449
|
|
|
387
450
|
// Expressions
|
|
388
451
|
expression: ($) =>
|
|
389
452
|
choice(
|
|
390
453
|
alias($._const_value, $.const_expression),
|
|
391
454
|
$.identifier,
|
|
455
|
+
$.parenthesized_expression,
|
|
392
456
|
$.unary_expression,
|
|
393
457
|
$.binary_expression,
|
|
394
458
|
$.ternary_expression,
|
|
@@ -409,6 +473,8 @@ module.exports = grammar({
|
|
|
409
473
|
),
|
|
410
474
|
),
|
|
411
475
|
|
|
476
|
+
parenthesized_expression: ($) => seq('(', $.expression, ')'),
|
|
477
|
+
|
|
412
478
|
binary_expression: ($) => {
|
|
413
479
|
const operations = [
|
|
414
480
|
[PREC.LOGICAL_AND, $.AND_KEYWORD],
|
|
@@ -456,7 +522,12 @@ module.exports = grammar({
|
|
|
456
522
|
new_expression_method: ($) =>
|
|
457
523
|
prec.right(
|
|
458
524
|
PREC.NEW,
|
|
459
|
-
seq(
|
|
525
|
+
seq(
|
|
526
|
+
$.NEW_KEYWORD,
|
|
527
|
+
'(',
|
|
528
|
+
field('type', $.expression),
|
|
529
|
+
choice(seq(',', field('arguments', $.expression), ')'), ')'),
|
|
530
|
+
)),
|
|
460
531
|
|
|
461
532
|
call_expression: ($) => prec(PREC.CALL - 1, $._access_call),
|
|
462
533
|
|
|
@@ -479,10 +550,20 @@ module.exports = grammar({
|
|
|
479
550
|
$.method_call,
|
|
480
551
|
),
|
|
481
552
|
),
|
|
482
|
-
_access_call: ($) =>
|
|
553
|
+
_access_call: ($) => choice(
|
|
554
|
+
seq($.access, '.', alias($._access_method_call, $.method_call)),
|
|
555
|
+
seq(choice($._access_index, $._access_call), $.arguments),
|
|
556
|
+
),
|
|
483
557
|
_access_index: ($) => seq($.access, '[', alias($.expression, $.index), ']'),
|
|
484
558
|
_access_property: ($) =>
|
|
485
|
-
seq(
|
|
559
|
+
seq(
|
|
560
|
+
$.access,
|
|
561
|
+
'.',
|
|
562
|
+
choice(
|
|
563
|
+
alias($.identifier, $.property),
|
|
564
|
+
alias($._member_keyword, $.property),
|
|
565
|
+
),
|
|
566
|
+
),
|
|
486
567
|
|
|
487
568
|
method_call: ($) =>
|
|
488
569
|
prec(
|
|
@@ -490,7 +571,36 @@ module.exports = grammar({
|
|
|
490
571
|
seq(field('name', $.identifier), field('arguments', $.arguments)),
|
|
491
572
|
),
|
|
492
573
|
|
|
493
|
-
|
|
574
|
+
_access_method_call: ($) =>
|
|
575
|
+
prec(
|
|
576
|
+
PREC.CALL,
|
|
577
|
+
seq(
|
|
578
|
+
field('name', choice($.identifier, alias($._member_keyword, $.identifier))),
|
|
579
|
+
field('arguments', $.arguments),
|
|
580
|
+
),
|
|
581
|
+
),
|
|
582
|
+
|
|
583
|
+
_member_keyword: ($) => choice(...memberNameKeywords($)),
|
|
584
|
+
|
|
585
|
+
arguments: ($) =>
|
|
586
|
+
prec(
|
|
587
|
+
1,
|
|
588
|
+
seq(
|
|
589
|
+
'(',
|
|
590
|
+
optional($._argument_list),
|
|
591
|
+
')',
|
|
592
|
+
),
|
|
593
|
+
),
|
|
594
|
+
_argument_list: ($) =>
|
|
595
|
+
prec.right(
|
|
596
|
+
1,
|
|
597
|
+
choice(
|
|
598
|
+
$.expression,
|
|
599
|
+
seq($.expression, ',', $._argument_list),
|
|
600
|
+
seq($.expression, alias(',', $.omitted_argument)),
|
|
601
|
+
seq(alias(',', $.omitted_argument), optional($._argument_list)),
|
|
602
|
+
),
|
|
603
|
+
),
|
|
494
604
|
|
|
495
605
|
// Primitive
|
|
496
606
|
...buildKeywords(),
|
|
@@ -511,7 +621,8 @@ module.exports = grammar({
|
|
|
511
621
|
null: ($) => $.NULL_KEYWORD,
|
|
512
622
|
|
|
513
623
|
number: ($) => /\d+(\.\d+)?/,
|
|
514
|
-
date: ($) =>
|
|
624
|
+
date: ($) =>
|
|
625
|
+
/'\d{4}[^0-9'\r\n]*\d{2}[^0-9'\r\n]*\d{2}([^0-9'\r\n]*\d{2}[^0-9'\r\n]*\d{2}([^0-9'\r\n]*\d{2})?)?'/,
|
|
515
626
|
string: ($) =>
|
|
516
627
|
seq(
|
|
517
628
|
'"',
|
|
@@ -536,7 +647,6 @@ module.exports = grammar({
|
|
|
536
647
|
},
|
|
537
648
|
});
|
|
538
649
|
|
|
539
|
-
|
|
540
650
|
/**
|
|
541
651
|
* Creates a rule to optionally match one or more of the rules separated by a comma
|
|
542
652
|
*
|