├── .github
└── workflows
│ └── go.yml
├── .gitignore
├── LICENSE
├── README.md
├── ast
├── ast.go
├── ast_print.go
├── ast_struct.go
├── ast_test.go
├── fast_tolower
│ └── gowrap.go
├── grammar.y
├── mock
│ └── mock.go
├── testdata
├── tokens.go
├── tokens_test.go
└── y.go
├── examples
└── pretty_code
│ ├── README.md
│ └── main.go
├── go.mod
└── go.sum
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a golang project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
3 |
4 | name: Go
5 |
6 | on:
7 | push:
8 | branches: [ "master" ]
9 | pull_request:
10 | branches: [ "master" ]
11 |
12 | jobs:
13 |
14 | build:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v3
18 |
19 | - name: Set up Go
20 | uses: actions/setup-go@v4
21 | with:
22 | go-version: '1.21'
23 |
24 | - name: Build
25 | run: go build -v ./...
26 |
27 | - name: Test
28 | run: go test -v ./...
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # If you prefer the allow list template instead of the deny list, see community template:
2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3 | #
4 | # Binaries for programs and plugins
5 | *.exe
6 | *.exe~
7 | *.dll
8 | *.so
9 | *.dylib
10 | .idea
11 |
12 | # Test binary, built with `go test -c`
13 | *.test
14 |
15 | # Output of the go coverage tool, specifically when used with LiteIDE
16 | *.out
17 |
18 | # Dependency directories (remove the comment below to include it)
19 | # vendor/
20 |
21 | # Go workspace file
22 | go.work
23 |
24 | ast/y.output
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Лазаренко Артем
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### Парсер языка 1С
2 | Этот репозиторий содержит парсер для языка 1С, написанный на Go. Парсер использует yacc для эффективного синтаксического анализа и создает абстрактное синтаксическое дерево (AST) представления разобранного кода 1С.
3 |
4 | ### Использование
5 | `go get github.com/LazarenkoA/1c-language-parser@master`
6 |
7 | ```go
8 | package main
9 |
10 | import (
11 | "fmt"
12 |
13 | "github.com/LazarenkoA/1c-language-parser/ast"
14 | )
15 |
16 | func main() {
17 | code := `Процедура ПодключитьВнешнююОбработку()
18 | Если в = 1 И а = 1 или у = 3 Тогда
19 |
20 | КонецЕсли
21 | КонецПроцедуры`
22 |
23 | a := ast.NewAST(code)
24 | if err := a.Parse(); err == nil {
25 | jdata, _ := a.JSON()
26 | fmt.Println(string(jdata))
27 | }
28 | }
29 |
30 | ```
31 | ### Примеры использования
32 | * [examples/pretty_code](examples/pretty_code)
33 | * [Obfuscator-1C](https://github.com/LazarenkoA/Obfuscator-1C)
34 | * [FuncGraphView](https://github.com/LazarenkoA/FuncGraphView)
35 |
36 |
37 | ### Примеры AST
38 | Вот несколько примеров, демонстрирующих возможности парсера языка 1С:
39 | ```1C
40 | Процедура Пример()
41 | Сообщить("Привет, мир!");
42 | КонецПроцедуры
43 | ```
44 | AST:
45 | ```
46 | main.ModuleStatement{
47 | Name: "",
48 | Body: []main.Statement{
49 | main.FunctionOrProcedure{
50 | Type: 1,
51 | Name: "Пример",
52 | Body: []main.Statement{
53 | main.MethodStatement{
54 | Name: "Сообщить",
55 | Param: []main.Statement{
56 | "Привет, мир!",
57 | },
58 | },
59 | },
60 | Export: false,
61 | Params: []main.ParamStatement{},
62 | Directive: "",
63 | ExplicitVariables: map[string]main.VarStatement{},
64 | },
65 | },
66 | }
67 | ```
68 |
69 |
70 | ```1C
71 | Если a = b и c = 8 или истина Тогда
72 | Сообщить("Условие выполнено");
73 | ИначеЕсли ВтороеУсловие Тогда
74 | Сообщить("Второе условие выполнено");
75 | Иначе
76 | Сообщить("Ни одно из условий не выполнено");
77 | КонецЕсли
78 |
79 | ```
80 | AST:
81 | ```
82 | main.ModuleStatement{
83 | Name: "",
84 | Body: []main.Statement{
85 | main.FunctionOrProcedure{
86 | Type: 1,
87 | Name: "Пример",
88 | Body: []main.Statement{
89 | main.IfStatement{
90 | Expression: main.ExpStatement{
91 | Operation: 11,
92 | Left: main.ExpStatement{
93 | Operation: 12,
94 | Left: main.ExpStatement{
95 | Operation: 4,
96 | Left: main.VarStatement{
97 | Name: "a",
98 | unary: false,
99 | not: false,
100 | },
101 | Right: main.VarStatement{
102 | Name: "b",
103 | unary: false,
104 | not: false,
105 | },
106 | unary: false,
107 | not: false,
108 | },
109 | Right: main.ExpStatement{
110 | Operation: 4,
111 | Left: main.VarStatement{
112 | Name: "c",
113 | unary: false,
114 | not: false,
115 | },
116 | Right: 8.000000,
117 | unary: false,
118 | not: false,
119 | },
120 | unary: false,
121 | not: false,
122 | },
123 | Right: true,
124 | unary: false,
125 | not: false,
126 | },
127 | TrueBlock: []main.Statement{
128 | main.MethodStatement{
129 | Name: "Сообщить",
130 | Param: []main.Statement{
131 | "Условие выполнено",
132 | },
133 | },
134 | },
135 | IfElseBlock: []*main.IfStatement{
136 | &main.IfStatement{
137 | Expression: main.VarStatement{
138 | Name: "ВтороеУсловие",
139 | unary: false,
140 | not: false,
141 | },
142 | TrueBlock: []main.Statement{
143 | main.MethodStatement{
144 | Name: "Сообщить",
145 | Param: []main.Statement{
146 | "Второе условие выполнено",
147 | },
148 | },
149 | },
150 | IfElseBlock: []*main.IfStatement{},
151 | ElseBlock: []main.Statement{},
152 | },
153 | },
154 | ElseBlock: []main.Statement{
155 | main.MethodStatement{
156 | Name: "Сообщить",
157 | Param: []main.Statement{
158 | "Ни одно из условий не выполнено",
159 | },
160 | },
161 | },
162 | },
163 | },
164 | Export: false,
165 | Params: []main.ParamStatement{},
166 | Directive: "",
167 | ExplicitVariables: map[string]main.VarStatement{},
168 | },
169 | },
170 | }
171 |
172 | ```
173 |
174 |
175 | Более сложный пример (код случайный)
176 |
177 |
178 | ```1C
179 | Процедура ОткрытьНавигационнуюСсылку(НавигационнаяСсылка, Знач Оповещение = Неопределено) Экспорт
180 |
181 | Контекст = Новый Структура;
182 | Контекст.Вставить("НавигационнаяСсылка", НавигационнаяСсылка);
183 | Контекст.Вставить("Оповещение", Оповещение);
184 |
185 | ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
186 | НСтр("ru = 'Не удалось перейти по ссылке ""%1"" по причине:
187 | |Неверно задана навигационная ссылка.'"),
188 | НавигационнаяСсылка);
189 |
190 | Если Не ОбщегоНазначенияСлужебныйКлиент.ЭтоДопустимаяСсылка(НавигационнаяСсылка) Тогда
191 | ОбщегоНазначенияСлужебныйКлиент.ОткрытьНавигационнуюСсылкуОповеститьОбОшибке(ОписаниеОшибки, Контекст);
192 | Возврат;
193 | КонецЕсли;
194 |
195 | Если ОбщегоНазначенияСлужебныйКлиент.ЭтоВебСсылка(НавигационнаяСсылка)
196 | Или ОбщегоНазначенияСлужебныйКлиент.ЭтоНавигационнаяСсылка(НавигационнаяСсылка) Тогда
197 |
198 | Попытка
199 | а = а /0;
200 | Исключение
201 | ОбщегоНазначенияСлужебныйКлиент.ОткрытьНавигационнуюСсылкуОповеститьОбОшибке(ОписаниеОшибки, Контекст);
202 | Возврат;
203 | КонецПопытки;
204 |
205 | Если Оповещение <> Неопределено Тогда
206 | ПриложениеЗапущено = Истина;
207 | ВыполнитьОбработкуОповещения(Оповещение, ПриложениеЗапущено);
208 | КонецЕсли;
209 |
210 | Возврат;
211 | КонецЕсли;
212 |
213 | Если ОбщегоНазначенияСлужебныйКлиент.ЭтоСсылкаНаСправку(НавигационнаяСсылка) Тогда
214 | ОткрытьСправку(НавигационнаяСсылка);
215 | Возврат;
216 | КонецЕсли;
217 | КонецПроцедуры
218 | ```
219 |
220 |
221 |
222 |
223 | получаем такое AST
224 |
225 | ```
226 | main.ModuleStatement{
227 | Name: "",
228 | Body: []main.Statement{
229 | main.FunctionOrProcedure{
230 | Type: 1,
231 | Name: "ОткрытьНавигационнуюСсылку",
232 | Body: []main.Statement{
233 | main.ExpStatement{
234 | Operation: 4,
235 | Left: main.VarStatement{
236 | Name: "Контекст",
237 | unary: false,
238 | not: false,
239 | },
240 | Right: main.NewObjectStatement{
241 | Constructor: "Структура",
242 | Param: []main.Statement{},
243 | },
244 | unary: false,
245 | not: false,
246 | },
247 | main.CallChainStatement{
248 | Unit: main.MethodStatement{
249 | Name: "Вставить",
250 | Param: []main.Statement{
251 | "НавигационнаяСсылка",
252 | main.VarStatement{
253 | Name: "НавигационнаяСсылка",
254 | unary: false,
255 | not: false,
256 | },
257 | },
258 | },
259 | Call: main.VarStatement{
260 | Name: "Контекст",
261 | unary: false,
262 | not: false,
263 | },
264 | },
265 | main.CallChainStatement{
266 | Unit: main.MethodStatement{
267 | Name: "Вставить",
268 | Param: []main.Statement{
269 | "Оповещение",
270 | main.VarStatement{
271 | Name: "Оповещение",
272 | unary: false,
273 | not: false,
274 | },
275 | },
276 | },
277 | Call: main.VarStatement{
278 | Name: "Контекст",
279 | unary: false,
280 | not: false,
281 | },
282 | },
283 | main.ExpStatement{
284 | Operation: 4,
285 | Left: main.VarStatement{
286 | Name: "ОписаниеОшибки",
287 | unary: false,
288 | not: false,
289 | },
290 | Right: main.CallChainStatement{
291 | Unit: main.MethodStatement{
292 | Name: "ПодставитьПараметрыВСтроку",
293 | Param: []main.Statement{
294 | main.MethodStatement{
295 | Name: "НСтр",
296 | Param: []main.Statement{
297 | "ru = 'Не удалось перейти по ссылке \"\"%1\"\" по причине: \n\t\t\t |Неверно задана навигационная ссылка.'",
298 | },
299 | },
300 | main.VarStatement{
301 | Name: "НавигационнаяСсылка",
302 |
303 | unary: false,
304 | not: false,
305 | },
306 | },
307 | },
308 | Call: main.VarStatement{
309 | Name: "СтроковыеФункцииКлиентСервер",
310 | unary: false,
311 | not: false,
312 | },
313 | },
314 | unary: false,
315 | not: false,
316 | },
317 | main.IfStatement{
318 | Expression: main.CallChainStatement{
319 | Unit: main.MethodStatement{
320 | Name: "ЭтоДопустимаяСсылка",
321 | Param: []main.Statement{
322 | main.VarStatement{
323 | Name: "НавигационнаяСсылка",
324 | unary: false,
325 | not: false,
326 | },
327 | },
328 | },
329 | Call: main.VarStatement{
330 | Name: "ОбщегоНазначенияСлужебныйКлиент",
331 | unary: false,
332 | not: false,
333 | },
334 | },
335 | TrueBlock: []main.Statement{
336 | main.CallChainStatement{
337 | Unit: main.MethodStatement{
338 | Name: "ОткрытьНавигационнуюСсылкуОповеститьОбОшибке",
339 | Param: []main.Statement{
340 | main.VarStatement{
341 | Name: "ОписаниеОшибки",
342 | unary: false,
343 | not: false,
344 | },
345 | main.VarStatement{
346 | Name: "Контекст",
347 | unary: false,
348 | not: false,
349 | },
350 | },
351 | },
352 | Call: main.VarStatement{
353 | Name: "ОбщегоНазначенияСлужебныйКлиент",
354 | unary: false,
355 | not: false,
356 | },
357 | },
358 | main.ReturnStatement{
359 | Param: nil,
360 | },
361 | },
362 | IfElseBlock: []*main.IfStatement{},
363 | ElseBlock: []main.Statement{},
364 | },
365 | main.IfStatement{
366 | Expression: main.ExpStatement{
367 | Operation: 11,
368 | Left: main.CallChainStatement{
369 | Unit: main.MethodStatement{
370 | Name: "ЭтоВебСсылка",
371 | Param: []main.Statement{
372 | main.VarStatement{
373 | Name: "НавигационнаяСсылка",
374 | unary: false,
375 | not: false,
376 | },
377 | },
378 | },
379 | Call: main.VarStatement{
380 | Name: "ОбщегоНазначенияСлужебныйКлиент",
381 | unary: false,
382 | not: false,
383 | },
384 | },
385 | Right: main.CallChainStatement{
386 | Unit: main.MethodStatement{
387 | Name: "ЭтоНавигационнаяСсылка",
388 | Param: []main.Statement{
389 | main.VarStatement{
390 | Name: "НавигационнаяСсылка",
391 | unary: false,
392 | not: false,
393 | },
394 | },
395 | },
396 | Call: main.VarStatement{
397 | Name: "ОбщегоНазначенияСлужебныйКлиент",
398 | unary: false,
399 | not: false,
400 | },
401 | },
402 | unary: false,
403 | not: false,
404 | },
405 | TrueBlock: []main.Statement{
406 | main.TryStatement{
407 | Body: []main.Statement{
408 | main.ExpStatement{
409 | Operation: 4,
410 | Left: main.VarStatement{
411 | Name: "а",
412 | unary: false,
413 | not: false,
414 | },
415 | Right: main.ExpStatement{
416 | Operation: 3,
417 | Left: main.VarStatement{
418 | Name: "а",
419 | unary: false,
420 | not: false,
421 | },
422 | Right: 0.000000,
423 | unary: false,
424 | not: false,
425 | },
426 | unary: false,
427 | not: false,
428 | },
429 | },
430 | Catch: []main.Statement{
431 | main.CallChainStatement{
432 | Unit: main.MethodStatement{
433 | Name: "ОткрытьНавигационнуюСсылкуОповеститьОбОшибке",
434 | Param: []main.Statement{
435 | main.VarStatement{
436 | Name: "ОписаниеОшибки",
437 | unary: false,
438 | not: false,
439 | },
440 | main.VarStatement{
441 | Name: "Контекст",
442 | unary: false,
443 | not: false,
444 | },
445 | },
446 | },
447 | Call: main.VarStatement{
448 | Name: "ОбщегоНазначенияСлужебныйКлиент",
449 | unary: false,
450 | not: false,
451 | },
452 | },
453 | main.ReturnStatement{
454 | Param: nil,
455 | },
456 | },
457 | },
458 | main.IfStatement{
459 | Expression: main.ExpStatement{
460 | Operation: 7,
461 | Left: main.VarStatement{
462 | Name: "Оповещение",
463 | unary: false,
464 | not: false,
465 | },
466 | Right: nil,
467 | unary: false,
468 | not: false,
469 | },
470 | TrueBlock: []main.Statement{
471 | main.ExpStatement{
472 | Operation: 4,
473 | Left: main.VarStatement{
474 | Name: "ПриложениеЗапущено",
475 | unary: false,
476 | not: false,
477 | },
478 | Right: true,
479 | unary: false,
480 | not: false,
481 | },
482 | main.MethodStatement{
483 | Name: "ВыполнитьОбработкуОповещения",
484 | Param: []main.Statement{
485 | main.VarStatement{
486 | Name: "Оповещение",
487 | unary: false,
488 | not: false,
489 | },
490 | main.VarStatement{
491 | Name: "ПриложениеЗапущено",
492 | unary: false,
493 | not: false,
494 | },
495 | },
496 | },
497 | },
498 | IfElseBlock: []*main.IfStatement{},
499 | ElseBlock: []main.Statement{},
500 | },
501 | main.ReturnStatement{
502 | Param: nil,
503 | },
504 | },
505 | IfElseBlock: []*main.IfStatement{},
506 | ElseBlock: []main.Statement{},
507 | },
508 | main.IfStatement{
509 | Expression: main.CallChainStatement{
510 | Unit: main.MethodStatement{
511 | Name: "ЭтоСсылкаНаСправку",
512 | Param: []main.Statement{
513 | main.VarStatement{
514 | Name: "НавигационнаяСсылка",
515 | unary: false,
516 | not: false,
517 | },
518 | },
519 | },
520 | Call: main.VarStatement{
521 | Name: "ОбщегоНазначенияСлужебныйКлиент",
522 | unary: false,
523 | not: false,
524 | },
525 | },
526 | TrueBlock: []main.Statement{
527 | main.MethodStatement{
528 | Name: "ОткрытьСправку",
529 | Param: []main.Statement{
530 | main.VarStatement{
531 | Name: "НавигационнаяСсылка",
532 | unary: false,
533 | not: false,
534 | },
535 | },
536 | },
537 | main.ReturnStatement{
538 | Param: nil,
539 | },
540 | },
541 | IfElseBlock: []*main.IfStatement{},
542 | ElseBlock: []main.Statement{},
543 | },
544 | },
545 | Export: true,
546 | Params: []main.ParamStatement{
547 | main.ParamStatement{
548 | Name: "НавигационнаяСсылка",
549 | IsValue: false,
550 | Default: nil,
551 | },
552 | main.ParamStatement{
553 | Name: "Оповещение",
554 | IsValue: true,
555 | Default: main.UndefinedStatement{},
556 | },
557 | },
558 | Directive: "",
559 | ExplicitVariables: map[string]main.VarStatement{},
560 | },
561 | },
562 | }
563 | ```
564 |
565 |
566 | Если у вас возникнут проблемы или у вас есть предложения по улучшению, не стесняйтесь создать [issue](https://github.com/LazarenkoA/ast_parser_1c/issues). Также приветствуются ваши вклады!
567 |
--------------------------------------------------------------------------------
/ast/ast.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | // устанока go install golang.org/x/tools/cmd/goyacc
4 | //go:generate goyacc .\grammar.y
5 |
6 | import (
7 | "encoding/json"
8 | "fmt"
9 | "github.com/pkg/errors"
10 | "reflect"
11 | "strings"
12 | "sync/atomic"
13 | )
14 |
15 | type AstNode struct {
16 | err error
17 | code string
18 | ModuleStatement
19 | currentToken Token
20 | isLoop atomic.Int32
21 | isTry atomic.Int32
22 | isFunction bool
23 | }
24 |
25 | const EOF = -1 // end of file
26 | var (
27 | errVariableAlreadyDefined = fmt.Errorf("variable has already been defined")
28 | )
29 |
30 | func NewAST(code string) *AstNode {
31 | return &AstNode{
32 | code: code,
33 | }
34 | }
35 |
36 | func (ast *AstNode) Parse() error {
37 | if len(strings.TrimSpace(ast.code)) == 0 {
38 | return nil
39 | }
40 |
41 | yyParse(ast)
42 | if ast.err != nil {
43 | errors.Wrap(ast.err, "parse error")
44 | }
45 | return ast.err
46 | }
47 |
48 | func (ast *AstNode) JSON() ([]byte, error) {
49 | return json.Marshal(&ast.ModuleStatement)
50 | }
51 |
52 | func (ast *AstNode) Lex(lval *yySymType) int {
53 | if len(ast.code) == 0 {
54 | return EOF
55 | }
56 |
57 | token, err := lval.token.Next(ast)
58 | if err != nil {
59 | ast.err = errors.Wrap(err, "get token error")
60 | }
61 | if token == EOF {
62 | return EOF
63 | }
64 |
65 | ast.currentToken = lval.token
66 | return token
67 | }
68 |
69 | func (ast *AstNode) SrsCode() string {
70 | return ast.code
71 | }
72 |
73 | func (ast *AstNode) Error(s string) {
74 | pos := ast.currentToken.GetPosition()
75 | pos.Column -= len([]rune(ast.currentToken.literal)) + 1
76 |
77 | ast.err = fmt.Errorf("%s. line: %d, column: %d (unexpected literal: %q)", s, pos.Line, pos.Column, ast.currentToken.literal)
78 | }
79 |
80 | func checkLoopOperator(token Token, yylex yyLexer) {
81 | if ast, ok := yylex.(*AstNode); ok {
82 | if ast.isLoop.Load() == 0 {
83 | yylex.Error(fmt.Sprintf("operator %q can only be used inside a loop", token.literal))
84 | }
85 | }
86 | }
87 |
88 | func checkThrowParam(token Token, param Statement, yylex yyLexer) {
89 | if ast, ok := yylex.(*AstNode); ok {
90 | if ast.isTry.Load() == 0 && param == nil {
91 | yylex.Error(fmt.Sprintf("operator %q without arguments can only be used when handling an exception", token.literal))
92 | }
93 | }
94 | }
95 |
96 | func isFunction(isFunc bool, yylex yyLexer) {
97 | if ast, ok := yylex.(*AstNode); ok {
98 | ast.isFunction = isFunc
99 | }
100 | }
101 |
102 | func checkReturnParam(param Statement, yylex yyLexer) {
103 | if ast, ok := yylex.(*AstNode); ok {
104 | if !ast.isFunction && param != nil {
105 | yylex.Error("procedure cannot return a value")
106 | }
107 | }
108 | }
109 |
110 | func setLoopFlag(flag bool, yylex yyLexer) {
111 | if ast, ok := yylex.(*AstNode); ok {
112 | if flag {
113 | ast.isLoop.Add(1)
114 | } else {
115 | ast.isLoop.Add(-1)
116 | }
117 | }
118 | }
119 |
120 | func setTryFlag(flag bool, yylex yyLexer) {
121 | if ast, ok := yylex.(*AstNode); ok {
122 | if flag {
123 | ast.isTry.Add(1)
124 | } else {
125 | ast.isTry.Add(-1)
126 | }
127 | }
128 | }
129 |
130 | func createFunctionOrProcedure(Type StatementType, directive Statement, name string, params []ParamStatement, export Statement, variables map[string]VarStatement, body []Statement) *FunctionOrProcedure {
131 | result := &FunctionOrProcedure{
132 | Type: Type,
133 | Name: name,
134 | Body: body,
135 | Export: export != nil && !reflect.ValueOf(export).IsNil(),
136 | Params: params,
137 | ExplicitVariables: variables,
138 | }
139 |
140 | if tok, ok := directive.(*Token); ok && tok != nil {
141 | result.Directive = tok.literal
142 | }
143 |
144 | return result
145 | }
146 |
147 | func appendVarStatements(existingVariables map[string]VarStatement, newVariables []Token) (map[string]VarStatement, error) {
148 | for _, v := range newVariables {
149 | if _, ok := existingVariables[v.literal]; ok {
150 | return map[string]VarStatement{}, fmt.Errorf("%w: with the specified name %q", errVariableAlreadyDefined, v.literal)
151 | } else {
152 | existingVariables[v.literal] = VarStatement{Name: v.literal}
153 | }
154 | }
155 | return existingVariables, nil
156 | }
157 |
158 | func unaryMinus(iv interface{}) interface{} {
159 | switch v := iv.(type) {
160 | case int:
161 | return -v
162 | case int32:
163 | return -v
164 | case int64:
165 | return -v
166 | case float32:
167 | return -v
168 | case float64:
169 | return -v
170 | case IUnary:
171 | return v.UnaryMinus()
172 | default:
173 | return v
174 | }
175 | }
176 |
177 | func not(iv interface{}) interface{} {
178 | switch v := iv.(type) {
179 | case bool:
180 | return !v
181 | case INot:
182 | return v.Not()
183 | default:
184 | return v
185 | }
186 | }
187 |
188 | // statementPostProcessing обработка-костыль готового выражения для случаев когда нужно определить присвоение в таких случаях a = b = c = d
189 | // это нужно из-за левой ассоциативности и то что в 1с "=" используется как для сравнения так и для присвоения
190 | func (ast *AstNode) statementPostProcessing(stm Statement) Statement {
191 | switch v := stm.(type) {
192 | case *ExpStatement:
193 | if l, ok := v.Left.(*ExpStatement); ok {
194 | newExp := &ExpStatement{}
195 |
196 | if list := expStatementToList(l); len(list) > 0 {
197 | newExp.Left = list[0]
198 | newExp.Operation = OpEq
199 |
200 | v.Left = leftAssociativeExpr(list[1:])
201 | newExp.Right = v
202 | }
203 |
204 | return newExp
205 | } else {
206 | return stm
207 | }
208 | }
209 |
210 | return stm
211 | }
212 |
213 | //func recurseLeftVar(stm Statement) *VarStatement {
214 | // expStm, ok := stm.(*ExpStatement)
215 | // if !ok {
216 | // return nil
217 | // }
218 | //
219 | // if expStm.Left == nil {
220 | // return nil
221 | // }
222 | //
223 | // if l, ok := expStm.Left.(VarStatement); ok {
224 | // return &l
225 | // }
226 | //
227 | // return recurseLeftVar(expStm.Left)
228 | //}
229 |
230 | func leftAssociativeExpr(stm []Statement) Statement {
231 | if len(stm) == 1 {
232 | return stm[0]
233 | }
234 |
235 | result := &ExpStatement{
236 | Left: leftAssociativeExpr(stm[:len(stm)-1]),
237 | Right: stm[len(stm)-1],
238 | Operation: OpEq,
239 | }
240 |
241 | return result
242 | }
243 |
244 | func expStatementToList(stm Statement) []Statement {
245 | expStm, ok := stm.(*ExpStatement)
246 | if !ok {
247 | return []Statement{stm}
248 | }
249 |
250 | var result []Statement
251 | if expStm.Left != nil {
252 | result = append(result, expStatementToList(expStm.Left)...)
253 | }
254 |
255 | if expStm.Right != nil {
256 | result = append(result, expStatementToList(expStm.Right)...)
257 | }
258 |
259 | return result
260 | }
261 |
--------------------------------------------------------------------------------
/ast/ast_print.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "strings"
7 | "time"
8 | )
9 |
10 | type PrintConf struct {
11 | // Margin отступы (количество пробелов)
12 | Margin int
13 | OneLine bool
14 |
15 | // автоматически расставить скобки в выражениях
16 | // LispStyle bool
17 | }
18 |
19 | type astPrint struct {
20 | ast *AstNode
21 | conf PrintConf
22 | }
23 |
24 | func (ast *AstNode) Print(conf PrintConf) string {
25 | if ast == nil {
26 | return ""
27 | }
28 |
29 | p := &astPrint{conf: conf, ast: ast}
30 | return p.print()
31 | }
32 |
33 | func (ast *AstNode) PrintStatement(stat Statement) string {
34 | if stat == nil {
35 | return ""
36 | }
37 |
38 | return ast.PrintStatementWithConf(stat, PrintConf{Margin: 4})
39 | }
40 |
41 | func (ast *AstNode) PrintStatementWithConf(stat Statement, conf PrintConf) string {
42 | if stat == nil {
43 | return ""
44 | }
45 |
46 | p := &astPrint{conf: conf}
47 | return p.printBodyItem(stat, 0)
48 | }
49 |
50 | func (p *astPrint) print() string {
51 | if len(p.ast.ModuleStatement.Body) == 0 {
52 | return ""
53 | }
54 |
55 | builder := &strings.Builder{}
56 |
57 | for _, v := range p.ast.ModuleStatement.GlobalVariables {
58 | builder.WriteString(p.printGlobalVariables(v))
59 | builder.WriteString(p.newLine(1))
60 | }
61 |
62 | for _, node := range p.ast.ModuleStatement.Body {
63 | if pf, ok := node.(*FunctionOrProcedure); ok {
64 | builder.WriteString(p.printFunctionOrProcedure(pf))
65 | builder.WriteString(p.newLine(3))
66 | } else {
67 | builder.WriteString(p.newLine(1))
68 | builder.WriteString(p.printBodyItem(node, 0))
69 | }
70 | }
71 |
72 | return builder.String()
73 | }
74 |
75 | func (p *astPrint) printGlobalVariables(variables GlobalVariables) string {
76 | builder := strings.Builder{}
77 |
78 | export := ""
79 | if variables.Export {
80 | export = " Экспорт "
81 | }
82 |
83 | directive := ""
84 | if variables.Directive != "" {
85 | directive = "\n" + variables.Directive + "\n"
86 | }
87 |
88 | builder.WriteString(directive)
89 | builder.WriteString("Перем ")
90 | builder.WriteString(variables.Var.Name)
91 | builder.WriteString(export)
92 | builder.WriteString(";")
93 |
94 | return builder.String()
95 | }
96 |
97 | func (p *astPrint) printFunctionOrProcedure(pf *FunctionOrProcedure) (result string) {
98 | builder := &strings.Builder{}
99 | defer func() { result = builder.String() }()
100 |
101 | declaration := ""
102 | if pf.Type == PFTypeFunction {
103 | declaration = "Функция"
104 | defer func() { builder.WriteString(p.newLine(2)); builder.WriteString("КонецФункции ") }()
105 | } else if pf.Type == PFTypeProcedure {
106 | declaration = "Процедура"
107 | defer func() { builder.WriteString(p.newLine(2)); builder.WriteString("КонецПроцедуры ") }()
108 | }
109 |
110 | var params []string
111 | // buildParam := strings.Builder{}
112 | for _, param := range pf.Params {
113 | val, def := "", ""
114 | if param.IsValue {
115 | val = "Знач "
116 | }
117 |
118 | if asText := p.printVarStatement(param.Default); asText != "" {
119 | def = " = " + asText
120 | }
121 |
122 | params = append(params, val+param.Name+def)
123 | }
124 |
125 | export := ""
126 | if pf.Export {
127 | export = "Экспорт "
128 | }
129 |
130 | directive := ""
131 | if pf.Directive != "" {
132 | directive = "\n" + pf.Directive + "\n"
133 | }
134 |
135 | depth := 1
136 |
137 | builder.WriteString(directive)
138 | builder.WriteString(declaration)
139 | builder.WriteString(" ")
140 | builder.WriteString(pf.Name)
141 | builder.WriteString("(")
142 | builder.WriteString(strings.Join(params, ", "))
143 | builder.WriteString(")")
144 | builder.WriteString(" ")
145 | builder.WriteString(export)
146 | builder.WriteString(p.newLine(1))
147 | builder.WriteString(p.printBody(pf.Body, depth))
148 |
149 | return
150 | }
151 |
152 | func (p *astPrint) printVarStatement(v Statement) string {
153 | switch val := v.(type) {
154 | case float64:
155 | return strconv.FormatFloat(val, 'f', -1, 64)
156 | case string:
157 | return fmt.Sprintf("\"%s\"", val)
158 | case bool:
159 | return IF[string](val, "Истина", "Ложь")
160 | case time.Time:
161 | return fmt.Sprintf(`'%s'`, val.Format("20060102150405"))
162 | case CallChainStatement:
163 | not := IF[string](val.not, "Не ", "")
164 | return not + p.printCallChainStatement(val)
165 | case UndefinedStatement:
166 | return "Неопределено"
167 | case MethodStatement:
168 | not := IF[string](val.not, "Не ", "")
169 | return not + val.Name + "(" + p.printParams(val.Param) + ")"
170 | case VarStatement:
171 | return val.Name
172 | case ItemStatement:
173 | return p.printVarStatement(val.Object) + "[" + p.printExpression(val.Item) + "]"
174 | case TernaryStatement:
175 | return fmt.Sprintf("?(%s, %s, %s)", p.printExpression(val.Expression), p.printExpression(val.TrueBlock), p.printExpression(val.ElseBlock))
176 | case NewObjectStatement:
177 | return fmt.Sprintf("Новый %s(%s)", val.Constructor, p.printParams(val.Param))
178 | default:
179 | return ""
180 | }
181 | }
182 |
183 | func (p *astPrint) printParams(Params []Statement) string {
184 | params := make([]string, len(Params), len(Params))
185 | for i, parm := range Params {
186 | params[i] = p.printExpression(parm)
187 | }
188 |
189 | return strings.Join(params, ", ")
190 | }
191 |
192 | func (p *astPrint) printBody(items []Statement, depth int) string {
193 | builder := &strings.Builder{}
194 |
195 | for _, item := range items {
196 | builder.WriteString(p.newLine(1))
197 | builder.WriteString(p.printBodyItem(item, depth))
198 | }
199 |
200 | builder.WriteString(p.newLine(1))
201 |
202 | return builder.String()
203 | }
204 |
205 | func (p *astPrint) printBodyItem(item Statement, depth int) string {
206 | builder := &strings.Builder{}
207 |
208 | spaces := strings.Repeat(" ", p.conf.Margin*depth)
209 | builder.WriteString(spaces)
210 |
211 | switch v := item.(type) {
212 | case *IfStatement:
213 | builder.WriteString(p.printIfStatement(v, depth))
214 | builder.WriteString(";")
215 | builder.WriteString(p.newLine(1))
216 | case *ExpStatement:
217 | builder.WriteString(p.printExpression(v))
218 | builder.WriteString(";")
219 | case *LoopStatement:
220 | builder.WriteString(p.printLoopStatement(v, depth))
221 | builder.WriteString(";")
222 | builder.WriteString(p.newLine(1))
223 | case BreakStatement:
224 | builder.WriteString("Прервать;")
225 | case ContinueStatement:
226 | builder.WriteString("Продолжить;")
227 | case CallChainStatement:
228 | builder.WriteString(p.printCallChainStatement(v))
229 | builder.WriteString(";")
230 | case TryStatement:
231 | builder.WriteString(p.printTryStatement(v, depth))
232 | builder.WriteString(";")
233 | builder.WriteString(p.newLine(1))
234 | case ThrowStatement:
235 | builder.WriteString("ВызватьИсключение")
236 | if v.Param != nil {
237 | builder.WriteString(" ")
238 | builder.WriteString(p.printExpression(v.Param))
239 | }
240 | builder.WriteString(";")
241 | case *ReturnStatement:
242 | builder.WriteString("Возврат")
243 | if v.Param != nil {
244 | builder.WriteString(" ")
245 | builder.WriteString(p.printExpression(v.Param))
246 | }
247 | builder.WriteString(";")
248 | case GoToStatement, *GoToLabelStatement:
249 | builder.WriteString(p.printGoTo(v, depth))
250 | builder.WriteString(p.newLine(1))
251 | default:
252 | builder.WriteString(p.printVarStatement(v))
253 | builder.WriteString(";")
254 | }
255 |
256 | return builder.String()
257 | }
258 |
259 | func (p *astPrint) printIfStatement(expr *IfStatement, depth int) string {
260 | builder := &strings.Builder{}
261 |
262 | spaces := strings.Repeat(" ", p.conf.Margin*depth)
263 | builder.WriteString("Если ")
264 | builder.WriteString(p.printExpression(expr.Expression))
265 | builder.WriteString(" Тогда ")
266 |
267 | builder.WriteString(p.printBody(expr.TrueBlock, depth+1))
268 | for _, item := range expr.IfElseBlock {
269 | builder.WriteString(spaces)
270 | builder.WriteString("ИначеЕсли ")
271 | builder.WriteString(p.printExpression(item.(*IfStatement).Expression))
272 | builder.WriteString(" Тогда ")
273 | builder.WriteString(p.printBody(item.(*IfStatement).TrueBlock, depth+1))
274 | }
275 |
276 | if expr.ElseBlock != nil {
277 | builder.WriteString(spaces)
278 | builder.WriteString("Иначе ")
279 | builder.WriteString(p.printBody(expr.ElseBlock, depth+1))
280 | }
281 |
282 | builder.WriteString(spaces)
283 | builder.WriteString("КонецЕсли")
284 | return builder.String()
285 | }
286 |
287 | func (p *astPrint) printLoopStatement(loop *LoopStatement, depth int) string {
288 | builder := &strings.Builder{}
289 |
290 | spaces := strings.Repeat(" ", p.conf.Margin*depth)
291 | if loop.WhileExpr != nil {
292 | builder.WriteString("Пока ")
293 | builder.WriteString(p.printExpression(loop.WhileExpr))
294 | builder.WriteString(" Цикл ")
295 | } else {
296 | builder.WriteString("Для ")
297 | }
298 |
299 | if loop.In != nil {
300 | builder.WriteString("Каждого ")
301 | builder.WriteString(loop.For.(string))
302 | builder.WriteString(" Из ")
303 | builder.WriteString(p.printExpression(loop.In))
304 | builder.WriteString(" Цикл ")
305 | }
306 | if loop.To != nil {
307 | builder.WriteString(p.printExpression(loop.For))
308 | builder.WriteString(" По ")
309 | builder.WriteString(p.printExpression(loop.To))
310 | builder.WriteString(" Цикл ")
311 | }
312 |
313 | builder.WriteString(p.printBody(loop.Body, depth+1))
314 | builder.WriteString(spaces)
315 | builder.WriteString("КонецЦикла")
316 |
317 | return builder.String()
318 | }
319 |
320 | func (p *astPrint) printExpression(expr Statement) string {
321 | builder := &strings.Builder{}
322 |
323 | switch v := expr.(type) {
324 | case *ExpStatement:
325 | if v.not {
326 | builder.WriteString("Не ")
327 | }
328 | if v.unaryMinus {
329 | builder.WriteString("-")
330 | }
331 |
332 | if v.unaryMinus || v.not {
333 | builder.WriteString("(")
334 | }
335 |
336 | builder.WriteString(p.printExpression(v.Left))
337 | builder.WriteString(" ")
338 | builder.WriteString(v.Operation.String())
339 | builder.WriteString(" ")
340 | builder.WriteString(p.printExpression(v.Right))
341 |
342 | if v.unaryMinus || v.not {
343 | builder.WriteString(")")
344 | }
345 | case VarStatement:
346 | if v.not {
347 | builder.WriteString("Не ")
348 | }
349 | if v.unaryMinus {
350 | builder.WriteString("-")
351 | }
352 | builder.WriteString(p.printVarStatement(v))
353 | default:
354 | builder.WriteString(p.printVarStatement(v))
355 | }
356 |
357 | return builder.String()
358 | }
359 |
360 | func (p *astPrint) printCallChainStatement(call Statement) string {
361 | switch v := call.(type) {
362 | case CallChainStatement:
363 | if v.Call != nil {
364 | return p.printCallChainStatement(v.Call) + "." + p.printVarStatement(v.Unit)
365 | }
366 | case VarStatement, ItemStatement, MethodStatement:
367 | return p.printVarStatement(call)
368 | }
369 |
370 | return ""
371 | }
372 |
373 | func (p *astPrint) printTryStatement(try TryStatement, depth int) string {
374 | builder := &strings.Builder{}
375 |
376 | spaces := strings.Repeat(" ", p.conf.Margin*depth)
377 | builder.WriteString("Попытка")
378 |
379 | if try.Body != nil {
380 | builder.WriteString(p.printBody(try.Body, depth+1))
381 | } else {
382 | builder.WriteString(p.newLine(1))
383 | }
384 |
385 | builder.WriteString(spaces)
386 | builder.WriteString("Исключение")
387 | if try.Catch != nil {
388 | builder.WriteString(p.printBody(try.Catch, depth+1))
389 | } else {
390 | builder.WriteString(p.newLine(1))
391 | }
392 |
393 | builder.WriteString(spaces)
394 | builder.WriteString("КонецПопытки")
395 | return builder.String()
396 | }
397 |
398 | func (p *astPrint) printGoTo(gotoStat Statement, depth int) string {
399 | builder := strings.Builder{}
400 |
401 | // spaces := strings.Repeat(" ", p.conf.Margin*depth)
402 |
403 | switch v := gotoStat.(type) {
404 | case *GoToLabelStatement:
405 | // builder.WriteString(spaces)
406 | builder.WriteString("~")
407 | builder.WriteString(v.Name)
408 | builder.WriteString(":")
409 | case GoToStatement:
410 | // builder.WriteString(spaces)
411 | builder.WriteString("Перейти ")
412 | builder.WriteString("~")
413 | builder.WriteString(v.Label.Name)
414 | builder.WriteString(";")
415 | }
416 |
417 | return builder.String()
418 | }
419 |
420 | func (p *astPrint) newLine(count int) string {
421 | if p.conf.OneLine {
422 | return ""
423 | }
424 |
425 | return strings.Repeat("\n", count)
426 | }
427 |
--------------------------------------------------------------------------------
/ast/ast_struct.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import "fmt"
4 |
5 | type StatementType int
6 | type OperationType int
7 |
8 | const (
9 | PFTypeUndefined StatementType = iota
10 | PFTypeProcedure
11 | PFTypeFunction
12 | )
13 |
14 | const (
15 | OpUndefined OperationType = iota
16 | OpPlus
17 | OpMinus
18 | OpMul
19 | OpDiv
20 | OpEq // =
21 | OpGt // >
22 | OpLt // <
23 | OpNe // <>
24 | OpLe // <=
25 | OpGe // >=
26 | OpMod // % - деление по модулю
27 | OpOr
28 | OpAnd
29 | )
30 |
31 | type IUnary interface {
32 | UnaryMinus() interface{}
33 | }
34 |
35 | type INot interface {
36 | Not() interface{}
37 | }
38 |
39 | type IParams interface {
40 | Params() []Statement
41 | }
42 |
43 | type Statement interface{}
44 |
45 | type GlobalVariables struct {
46 | Directive string
47 | Var VarStatement
48 | Export bool
49 | }
50 |
51 | type ModuleStatement struct {
52 | Name string
53 | GlobalVariables map[string]GlobalVariables `json:"GlobalVariables,omitempty"`
54 | Body []Statement
55 | }
56 |
57 | type VarStatement struct {
58 | Name string
59 | addStatementField
60 | }
61 |
62 | type FunctionOrProcedure struct {
63 | ExplicitVariables map[string]VarStatement
64 | Name string
65 | Directive string
66 | Body []Statement
67 | Params []ParamStatement
68 | Type StatementType
69 | Export bool
70 | }
71 |
72 | type ParamStatement struct {
73 | Default Statement `json:"Default,omitempty"`
74 | Name string
75 | IsValue bool `json:"IsValue,omitempty"`
76 | }
77 |
78 | type addStatementField struct {
79 | unaryMinus bool
80 | unaryPlus bool
81 | not bool
82 | }
83 |
84 | type ExpStatement struct {
85 | Left interface{}
86 | Right interface{}
87 | Operation OperationType
88 | addStatementField
89 | }
90 |
91 | // type IfElseStatement struct {
92 | // Expression Statement
93 | // TrueBlock []Statement
94 | // }
95 |
96 | type IfStatement struct {
97 | Expression Statement
98 | TrueBlock []Statement
99 | IfElseBlock []Statement
100 | ElseBlock []Statement
101 | }
102 |
103 | type TryStatement struct {
104 | Body []Statement
105 | Catch []Statement
106 | }
107 |
108 | type ThrowStatement struct {
109 | Param Statement
110 | }
111 |
112 | type UndefinedStatement struct{}
113 |
114 | type ReturnStatement struct {
115 | Param Statement
116 | }
117 |
118 | type NewObjectStatement struct {
119 | Constructor string
120 | Param []Statement
121 | }
122 |
123 | type CallChainStatement struct {
124 | Unit Statement
125 | Call Statement
126 | addStatementField
127 | }
128 |
129 | type MethodStatement struct {
130 | Name string
131 | Param []Statement
132 | addStatementField
133 | }
134 |
135 | type BreakStatement struct {
136 | }
137 |
138 | type ContinueStatement struct {
139 | }
140 |
141 | type LoopStatement struct {
142 | For Statement `json:"For,omitempty"`
143 | To Statement `json:"To,omitempty"`
144 | In Statement `json:"In,omitempty"`
145 | WhileExpr Statement `json:"WhileExpr,omitempty"`
146 | Body []Statement
147 | }
148 |
149 | type TernaryStatement struct {
150 | Expression Statement
151 | TrueBlock Statement
152 | ElseBlock Statement
153 | }
154 |
155 | type ItemStatement struct {
156 | Item Statement
157 | Object Statement
158 | }
159 |
160 | type GoToStatement struct {
161 | Label *GoToLabelStatement
162 | }
163 |
164 | type GoToLabelStatement struct {
165 | Name string
166 | }
167 |
168 | func (p *ParamStatement) Fill(valueParam *Token, identifier Token) *ParamStatement {
169 | p.IsValue = valueParam != nil
170 | p.Name = identifier.literal
171 | return p
172 | }
173 |
174 | func (p *ParamStatement) DefaultValue(value Statement) *ParamStatement {
175 | if value == nil {
176 | p.Default = UndefinedStatement{}
177 | } else {
178 | p.Default = value
179 | }
180 |
181 | return p
182 | }
183 |
184 | func (e *ExpStatement) UnaryMinus() interface{} {
185 | e.unaryMinus = true
186 | return e
187 | }
188 |
189 | func (e *ExpStatement) Not() interface{} {
190 | e.not = true
191 | return e
192 | }
193 |
194 | func (e VarStatement) UnaryMinus() interface{} {
195 | e.unaryMinus = true
196 | return e
197 | }
198 |
199 | func (e VarStatement) Not() interface{} {
200 | e.not = true
201 | return e
202 | }
203 |
204 | func (e CallChainStatement) UnaryMinus() interface{} {
205 | e.unaryMinus = true
206 | return e
207 | }
208 |
209 | func (e CallChainStatement) Not() interface{} {
210 | e.not = true
211 | return e
212 | }
213 |
214 | // IsMethod вернет true в случаях Блокировка.Заблокировать() и false для Источник.Ссылка
215 | func (e CallChainStatement) IsMethod() bool {
216 | _, ok := e.Unit.(MethodStatement)
217 | return ok
218 | }
219 |
220 | func (n MethodStatement) Not() interface{} {
221 | n.not = true
222 | return n
223 | }
224 |
225 | func (n NewObjectStatement) Params() []Statement {
226 | return n.Param
227 | }
228 |
229 | func (n MethodStatement) Params() []Statement {
230 | return n.Param
231 | }
232 |
233 | func (o OperationType) String() string {
234 | switch o {
235 | case OpPlus:
236 | return "+"
237 | case OpMinus:
238 | return "-"
239 | case OpMul:
240 | return "*"
241 | case OpDiv:
242 | return "/"
243 | case OpEq:
244 | return "="
245 | case OpGt:
246 | return ">"
247 | case OpLt:
248 | return "<"
249 | case OpNe:
250 | return "<>"
251 | case OpLe:
252 | return "<="
253 | case OpGe:
254 | return ">="
255 | case OpMod:
256 | return "%"
257 | case OpOr:
258 | return "ИЛИ"
259 | case OpAnd:
260 | return "И"
261 | default:
262 | return ""
263 | }
264 | }
265 |
266 | func (m ModuleStatement) Walk(callBack func(current *FunctionOrProcedure, statement *Statement)) {
267 | StatementWalk(m.Body, callBack)
268 | }
269 |
270 | func StatementWalk(stm []Statement, callBack func(current *FunctionOrProcedure, statement *Statement)) {
271 | walkHelper(nil, stm, callBack)
272 | }
273 |
274 | func (m *ModuleStatement) Append(item Statement, yylex yyLexer) {
275 | switch v := item.(type) {
276 | case GlobalVariables:
277 | if len(m.Body) > 0 {
278 | yylex.Error("variable declarations must be placed at the beginning of the module")
279 | return
280 | }
281 |
282 | if m.GlobalVariables == nil {
283 | m.GlobalVariables = map[string]GlobalVariables{}
284 | }
285 |
286 | if _, ok := m.GlobalVariables[v.Var.Name]; ok {
287 | yylex.Error(fmt.Sprintf("%v: with the specified name %q", errVariableAlreadyDefined, v.Var.Name))
288 | } else {
289 | m.GlobalVariables[v.Var.Name] = v
290 | }
291 | case []GlobalVariables:
292 | for _, item := range v {
293 | m.Append(item, yylex)
294 | }
295 | case []Statement:
296 | m.Body = append(m.Body, v...)
297 | case *FunctionOrProcedure:
298 | // если предыдущее выражение не процедура функция, то это значит что какой-то умник вначале или в середине модуля вставил какие-то выражения, а это нельзя. 1С разрешает выражения только в конце модуля
299 | if len(m.Body) > 0 {
300 | if _, ok := m.Body[len(m.Body)-1].(*FunctionOrProcedure); !ok {
301 | yylex.Error("procedure and function definitions should be placed before the module body statements")
302 | return
303 | }
304 | }
305 |
306 | m.Body = append(m.Body, item)
307 | default:
308 | m.Body = append(m.Body, item)
309 | }
310 | }
311 |
312 | // func (m Statements) Walk(callBack func(statement *Statement)) {
313 | // walkHelper(m, callBack)
314 | // }
315 |
316 | func walkHelper(parent *FunctionOrProcedure, statements []Statement, callBack func(current *FunctionOrProcedure, statement *Statement)) {
317 | for i, item := range statements {
318 | switch v := item.(type) {
319 | case *IfStatement:
320 | walkHelper(parent, []Statement{v.Expression}, callBack)
321 | walkHelper(parent, v.TrueBlock, callBack)
322 | walkHelper(parent, v.ElseBlock, callBack)
323 | walkHelper(parent, v.IfElseBlock, callBack)
324 | case TryStatement:
325 | walkHelper(parent, v.Body, callBack)
326 | walkHelper(parent, v.Catch, callBack)
327 | case *LoopStatement:
328 | walkHelper(parent, v.Body, callBack)
329 | case *FunctionOrProcedure:
330 | walkHelper(v, v.Body, callBack)
331 | parent = v
332 | case MethodStatement:
333 | walkHelper(parent, v.Param, callBack)
334 | //case CallChainStatement:
335 | // walkHelper(parent, []Statement{v.Unit}, callBack)
336 | case *ExpStatement:
337 | walkHelper(parent, []Statement{v.Right}, callBack)
338 | walkHelper(parent, []Statement{v.Left}, callBack)
339 | case TernaryStatement:
340 | walkHelper(parent, []Statement{v.Expression}, callBack)
341 | walkHelper(parent, []Statement{v.TrueBlock}, callBack)
342 | walkHelper(parent, []Statement{v.ElseBlock}, callBack)
343 | case *ReturnStatement:
344 | walkHelper(parent, []Statement{v.Param}, callBack)
345 | }
346 |
347 | callBack(parent, &statements[i])
348 | }
349 | }
350 |
--------------------------------------------------------------------------------
/ast/ast_test.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import (
4 | "crypto/sha256"
5 | "errors"
6 | "fmt"
7 | "os"
8 | "strings"
9 | "testing"
10 | "time"
11 |
12 | "github.com/stretchr/testify/assert"
13 | )
14 |
15 | // func TestParseIF(t *testing.T) {
16 | // t.Run("parse IF", func(t *testing.T) {
17 | // code := `если test = 1 Тогда
18 | // КонецЕсли;`
19 | //
20 | // a := NewAST(code)
21 | // err := a.Parse()
22 | // assert.NoError(t, err)
23 | // })
24 | // t.Run("parse IF", func(t *testing.T) {
25 | // code := `если (test = 1) Тогда
26 | // КонецЕсли;`
27 | //
28 | // a := NewAST(code)
29 | // err := a.Parse()
30 | // assert.NoError(t, err)
31 | // })
32 | // t.Run("parse IF", func(t *testing.T) {
33 | // code := `Если test2 = 1 И test1 = 1 ИЛИ Е = 4 Тогда
34 | // КонецЕсли;`
35 | //
36 | // a := NewAST(code)
37 | // err := a.Parse()
38 | // assert.NoError(t, err)
39 | // })
40 | // t.Run("parse IF", func(t *testing.T) {
41 | // code := `Если test2 = 1 И test1 = 1 ИЛИ Тогда
42 | // КонецЕсли;`
43 | //
44 | // a := NewAST(code)
45 | // err := a.Parse()
46 | // assert.EqualError(t, err, "syntax error. line: 1, column: 32 (unexpected literal: \"Тогда\")")
47 | // })
48 | // t.Run("parse IF", func(t *testing.T) {
49 | // code := `Если тест() Тогда
50 | // КонецЕсли;`
51 | //
52 | // a := NewAST(code)
53 | // err := a.Parse()
54 | // assert.NoError(t, err)
55 | // })
56 | // t.Run("parse IF", func(t *testing.T) {
57 | // code := `Если тест(1, в) Тогда
58 | // КонецЕсли;`
59 | //
60 | // a := NewAST(code)
61 | // err := a.Parse()
62 | // assert.NoError(t, err)
63 | // })
64 | // t.Run("parse IF", func(t *testing.T) {
65 | // code := `Если тест(1,
66 | // в) Тогда
67 | // КонецЕсли;`
68 | //
69 | // a := NewAST(code)
70 | // err := a.Parse()
71 | // assert.NoError(t, err)
72 | // })
73 | // t.Run("parse IF", func(t *testing.T) {
74 | // code := `Если тест(1 в) Тогда
75 | // КонецЕсли;`
76 | //
77 | // a := NewAST(code)
78 | // err := a.Parse()
79 | // assert.EqualError(t, err, "syntax error. line: 1, column: 12 (unexpected literal: \"в\")")
80 | // })
81 | // t.Run("parse IF", func(t *testing.T) {
82 | // code := `Если (test2 = 1) И (test1 = 1 ИЛИ f = 2) Тогда
83 | // КонецЕсли;`
84 | //
85 | // a := NewAST(code)
86 | // err := a.Parse()
87 | // assert.NoError(t, err)
88 | // })
89 | // t.Run("parse IF", func(t *testing.T) {
90 | // code := `если (test = 1 Тогда
91 | // КонецЕсли;`
92 | //
93 | // a := NewAST(code)
94 | // err := a.Parse()
95 | // assert.EqualError(t, err, "syntax error. line: 1, column: 15 (unexpected literal: \"Тогда\")")
96 | // })
97 | // t.Run("parse IF", func(t *testing.T) {
98 | // code := `есл (test = 1 Тогда
99 | // КонецЕсли;`
100 | //
101 | // a := NewAST(code)
102 | // err := a.Parse()
103 | // assert.EqualError(t, err, "syntax error. line: 1, column: 0 (unexpected literal: \"есл\")")
104 | // })
105 | // t.Run("parse IF", func(t *testing.T) {
106 | // code := `есл test = 1 Тогда КонецЕсли;`
107 | //
108 | // a := NewAST(code)
109 | // err := a.Parse()
110 | // assert.EqualError(t, err, "syntax error. line: 1, column: 0 (unexpected literal: \"есл\")")
111 | // })
112 | // t.Run("parse IF", func(t *testing.T) {
113 | // code := `если test = 1 Тогда Иначе КонецЕсли;`
114 | //
115 | // a := NewAST(code)
116 | // err := a.Parse()
117 | // assert.NoError(t, err)
118 | // })
119 | // t.Run("parse IFELSE", func(t *testing.T) {
120 | // code := `если test = 1 Тогда
121 | // ИначеЕсли test = 2 И кк = 9 Тогда
122 | // КонецЕсли;`
123 | //
124 | // a := NewAST(code)
125 | // err := a.Parse()
126 | // assert.NoError(t, err)
127 | // })
128 | // }
129 |
130 | // type test111[T StatementCall | IfStatement] struct {
131 | // base T
132 | // }
133 | // tr := test111[IfStatement]{}
134 | // _ = tr.base.TrueBlock
135 |
136 | func TestParseModule(t *testing.T) {
137 | t.Run("empty", func(t *testing.T) {
138 | code := ``
139 |
140 | a := NewAST(code)
141 | err := a.Parse()
142 | assert.NoError(t, err)
143 | })
144 | t.Run("global var", func(t *testing.T) {
145 | code := `&НаСервере
146 | Перем в, e;
147 |
148 | &НаКлиенте
149 | Перем а Экспорт; Перем с;
150 |
151 | Процедура вв1()
152 |
153 | Конецпроцедуры
154 |
155 | &НаКлиенте
156 | Процедура вв2()
157 |
158 | Конецпроцедуры`
159 |
160 | a := NewAST(code)
161 | err := a.Parse()
162 | assert.NoError(t, err)
163 | })
164 | t.Run("global var error", func(t *testing.T) {
165 | code := `Перем а;
166 | Перем а;
167 |
168 | Процедура вв()
169 |
170 | Конецпроцедуры`
171 |
172 | a := NewAST(code)
173 | err := a.Parse()
174 | assert.ErrorContains(t, err, "variable has already been defined")
175 | })
176 | t.Run("global var error", func(t *testing.T) {
177 | code := `Перем в;
178 |
179 | Процедура вв()
180 |
181 | Конецпроцедуры
182 | Перем а;`
183 |
184 | a := NewAST(code)
185 | err := a.Parse()
186 | assert.ErrorContains(t, err, "variable declarations must be placed at the beginning of the module")
187 | })
188 | t.Run("without FunctionProcedure pass", func(t *testing.T) {
189 | code := `
190 | Пока Истина Цикл
191 |
192 | КонецЦикла;
193 |
194 |
195 | ВызватьИсключение "";
196 |
197 | Если Истина Тогда
198 | а = 0;
199 | КонецЕсли`
200 |
201 | a := NewAST(code)
202 | err := a.Parse()
203 | assert.NoError(t, err)
204 | })
205 | t.Run("without FunctionProcedure pass", func(t *testing.T) {
206 | code := `Перем в;
207 | Функция test1()
208 | КонецФункции
209 |
210 | Функция test1()
211 | КонецФункции
212 |
213 | Пока Истина Цикл
214 |
215 | КонецЦикла;
216 |
217 |
218 | ВызватьИсключение "";
219 |
220 | Если Истина Тогда
221 | а = 0;
222 | КонецЕсли;`
223 |
224 | a := NewAST(code)
225 | err := a.Parse()
226 | assert.NoError(t, err)
227 |
228 | // fmt.Println(a.Print(PrintConf{Margin: 4}))
229 | })
230 | t.Run("without FunctionProcedure error", func(t *testing.T) {
231 | code := `
232 | Пока Истина Цикл
233 |
234 | КонецЦикла;
235 |
236 |
237 | ВызватьИсключение "";
238 |
239 | Если Истина Тогда
240 | а = 0;
241 | КонецЕсли;
242 |
243 | Процедура test()
244 | КонецПроцедуры`
245 |
246 | a := NewAST(code)
247 | err := a.Parse()
248 | assert.Error(t, err)
249 | // assert.ErrorContains(t, err, "procedure and function definitions should be placed before the module body statements")
250 | })
251 | }
252 |
253 | func TestExecute(t *testing.T) {
254 | t.Run("Execute-1", func(t *testing.T) {
255 | code := `&НаСервере
256 | Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено)
257 | Выполнить Алгоритм;
258 | КонецПроцедуры`
259 |
260 | a := NewAST(code)
261 | err := a.Parse()
262 | if assert.NoError(t, err) {
263 | jdata, _ := a.JSON()
264 | assert.Equal(t, `{"Name":"","Body":[{"ExplicitVariables":{},"Name":"ВыполнитьВБезопасномРежиме","Directive":"\u0026НаСервере","Body":[{"Name":"Выполнить","Param":[{"Name":"Алгоритм"}]}],"Params":[{"Name":"Алгоритм","IsValue":true},{"Default":{},"Name":"Параметры","IsValue":true}],"Type":1,"Export":false}]}`, string(jdata))
265 | }
266 | })
267 | t.Run("Execute-2", func(t *testing.T) {
268 | code := `&НаСервере
269 | Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено)
270 | Выполнить(Алгоритм);
271 | КонецПроцедуры`
272 |
273 | a := NewAST(code)
274 | err := a.Parse()
275 | assert.NoError(t, err)
276 |
277 | p := a.Print(PrintConf{Margin: 4})
278 | assert.Equal(t, true, compareHashes(code, p))
279 | })
280 | t.Run("Execute-3", func(t *testing.T) {
281 | code := `&НаСервере
282 | Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено)
283 | Выполнить "Алгоритм";
284 | КонецПроцедуры`
285 |
286 | a := NewAST(code)
287 | err := a.Parse()
288 | assert.NoError(t, err)
289 | })
290 | t.Run("Execute-error", func(t *testing.T) {
291 | code := `&НаСервере
292 | Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено)
293 | Выполнить 32;
294 | КонецПроцедуры`
295 |
296 | a := NewAST(code)
297 | err := a.Parse()
298 | assert.EqualError(t, err, "syntax error. line: 3, column: 16 (unexpected literal: \"32\")")
299 | })
300 | t.Run("Execute-error", func(t *testing.T) {
301 | code := `&НаСервере
302 | Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено)
303 | Выполнить "Алгоритм", "";
304 | КонецПроцедуры`
305 |
306 | a := NewAST(code)
307 | err := a.Parse()
308 | assert.EqualError(t, err, "syntax error. line: 3, column: 26 (unexpected literal: \",\")")
309 | })
310 | t.Run("Execute-error-2", func(t *testing.T) {
311 | code := `&НаСервере
312 | Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено)
313 | Выполнить ("Алгоритм", "");
314 | КонецПроцедуры`
315 |
316 | a := NewAST(code)
317 | err := a.Parse()
318 | assert.EqualError(t, err, "syntax error. line: 3, column: 27 (unexpected literal: \",\")")
319 | })
320 | t.Run("Eval-1", func(t *testing.T) {
321 | code := `&НаСервере
322 | Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено)
323 | в = Вычислить(Алгоритм);
324 | КонецПроцедуры`
325 |
326 | a := NewAST(code)
327 | err := a.Parse()
328 | assert.NoError(t, err)
329 | })
330 | t.Run("Eval-2", func(t *testing.T) {
331 | code := `&НаСервере
332 | Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено)
333 | Вычислить Алгоритм;
334 | КонецПроцедуры`
335 |
336 | a := NewAST(code)
337 | err := a.Parse()
338 | assert.EqualError(t, err, "syntax error. line: 3, column: 16 (unexpected literal: \"Алгоритм\")")
339 | })
340 | }
341 |
342 | func TestParseIF(t *testing.T) {
343 | t.Run("pass", func(t *testing.T) {
344 | code := `Процедура ПодключитьВнешнююОбработку()
345 | Если (1 = 1) Тогда
346 |
347 | КонецЕсли;
348 | КонецПроцедуры`
349 |
350 | a := NewAST(code)
351 | err := a.Parse()
352 | assert.NoError(t, err)
353 | })
354 | t.Run("pass", func(t *testing.T) {
355 | code := `Процедура ПодключитьВнешнююОбработку()
356 | Если в = 1 И а = 1 или у = 3 Тогда
357 | test = 2+2*2;
358 | а = 7;
359 | а = 7.2;
360 | ИначеЕсли Не 4 = 3 И Не 8 = 2 И 1 <> 3 Тогда;
361 | а = 5;
362 | ИначеЕсли Ложь Тогда;
363 | Иначе
364 | а = -(1+1);
365 | а = -s;
366 | а = -1;
367 | а = -7.42;
368 | а = Не истина;
369 | КонецЕсли;
370 | КонецПроцедуры`
371 |
372 | a := NewAST(code)
373 | err := a.Parse()
374 | assert.NoError(t, err)
375 |
376 | data, err := a.JSON()
377 | assert.NoError(t, err)
378 | assert.NotEqual(t, 0, len(data))
379 | })
380 | t.Run("pass", func(t *testing.T) {
381 | code := `Процедура ПодключитьВнешнююОбработку()
382 | Если в = 1 И а = 1 или у = 3 Тогда
383 |
384 | КонецЕсли
385 |
386 | ;
387 | КонецПроцедуры`
388 |
389 | a := NewAST(code)
390 | err := a.Parse()
391 | assert.NoError(t, err)
392 | })
393 | t.Run("pass", func(t *testing.T) {
394 | code := `Процедура ПодключитьВнешнююОбработку()
395 | Если в = 1 И (а = 1 или у = 3) Тогда
396 |
397 | КонецЕсли
398 |
399 | ;
400 | КонецПроцедуры`
401 |
402 | a := NewAST(code)
403 | err := a.Parse()
404 | assert.NoError(t, err)
405 | })
406 | t.Run("pass", func(t *testing.T) {
407 | code := `Процедура ПодключитьВнешнююОбработку()
408 | Если в = 1 И (а = 1 или у = 3) Тогда
409 | Если в = 1 или у = 3 Тогда
410 |
411 | КонецЕсли;
412 | КонецЕсли;
413 | КонецПроцедуры`
414 |
415 | a := NewAST(code)
416 | err := a.Parse()
417 | assert.NoError(t, err)
418 | })
419 | t.Run("pass", func(t *testing.T) {
420 | code := `Процедура ПодключитьВнешнююОбработку()
421 | Если в = 1 И (а = 1 или у = 3) Тогда
422 | Если в = 1 или у = 3 Тогда
423 | Иначе
424 | КонецЕсли;
425 | КонецЕсли;
426 | КонецПроцедуры`
427 |
428 | a := NewAST(code)
429 | err := a.Parse()
430 | assert.NoError(t, err)
431 | })
432 | t.Run("pass", func(t *testing.T) {
433 | code := `Процедура ПодключитьВнешнююОбработку()
434 | Если в = 1 И (а = 1 или у = 3) Тогда
435 | Если в = 1 или у = 3 Тогда
436 |
437 | ИначеЕсли ввв Тогда
438 |
439 | ИначеЕсли авыав Тогда
440 |
441 | Иначе
442 |
443 | КонецЕсли;
444 | КонецЕсли;
445 | КонецПроцедуры`
446 |
447 | a := NewAST(code)
448 | err := a.Parse()
449 | assert.NoError(t, err)
450 | })
451 | t.Run("pass", func(t *testing.T) {
452 | code := `Процедура ПодключитьВнешнююОбработку()
453 | Если Истина Тогда
454 |
455 | КонецЕсли // запятой может и не быть
456 | КонецПроцедуры`
457 |
458 | a := NewAST(code)
459 | err := a.Parse()
460 | assert.NoError(t, err)
461 | })
462 | t.Run("pass", func(t *testing.T) {
463 | code := `Процедура ПодключитьВнешнююОбработку()
464 | Если (Истина или Ложь) Тогда
465 | а = 0;
466 | КонецЕсли
467 | КонецПроцедуры`
468 |
469 | a := NewAST(code)
470 | err := a.Parse()
471 | assert.NoError(t, err)
472 | })
473 | t.Run("pass", func(t *testing.T) {
474 | code := `Процедура ПодключитьВнешнююОбработку()
475 | Если (1 = 1) Тогда
476 | f = 0 // запятой может не быть
477 | КонецЕсли;
478 | КонецПроцедуры`
479 |
480 | a := NewAST(code)
481 | err := a.Parse()
482 | assert.NoError(t, err)
483 | })
484 | t.Run("pass", func(t *testing.T) {
485 | code := `Процедура ПодключитьВнешнююОбработку()
486 | Если в = 1 И (а = 1 или у = 3) Тогда
487 | Если в = 1 или у = 3 Тогда
488 |
489 | ИначеЕсли ввв Тогда
490 |
491 | ИначеЕсли авыав Тогда
492 |
493 | КонецЕсли;
494 | КонецЕсли;
495 | КонецПроцедуры`
496 |
497 | a := NewAST(code)
498 | err := a.Parse()
499 | assert.NoError(t, err)
500 | })
501 | t.Run("pass", func(t *testing.T) {
502 | code := `Процедура ПодключитьВнешнююОбработку()
503 | Если в = 1 И (а = 1 или у = 3) Тогда
504 | Если в = 1 или у = 3 Тогда
505 | а = 1 + 3 *4;
506 | ИначеЕсли ввв Тогда
507 |
508 | ИначеЕсли авыав Тогда
509 |
510 | КонецЕсли;
511 | КонецЕсли;
512 | КонецПроцедуры`
513 |
514 | a := NewAST(code)
515 | err := a.Parse()
516 | assert.NoError(t, err)
517 | })
518 | t.Run("pass", func(t *testing.T) {
519 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
520 | Если ВерсияПлатформыЧислом < 80303641 Тогда
521 | ВызватьИсключение НСтр("ru = 'Для работы обработки требуется ""1С:Предприятие"" версии 8.3.3.641 или страше.';sys= ''", "ru");
522 | КонецЕсли;
523 | КонецПроцедуры`
524 |
525 | a := NewAST(code)
526 | err := a.Parse()
527 | assert.NoError(t, err)
528 | })
529 | t.Run("error", func(t *testing.T) {
530 | code := `Процедура ПодключитьВнешнююОбработку()
531 | Если в = 1 И (а = 1 или у = 3) Тогда
532 | Если в = 1 или у = 3 Тогда
533 | а = 1 + 3 * 4
534 | b = 1
535 | ИначеЕсли ввв Тогда
536 |
537 | ИначеЕсли авыав Тогда
538 |
539 | КонецЕсли;
540 | КонецЕсли;
541 | КонецПроцедуры`
542 |
543 | a := NewAST(code)
544 | err := a.Parse()
545 | assert.EqualError(t, err, "syntax error. line: 5, column: 7 (unexpected literal: \"b\")")
546 | })
547 | t.Run("error", func(t *testing.T) {
548 | code := `Процедура ПодключитьВнешнююОбработку()
549 | Если в = 1 И (а = 1 или у = 3) Тогда
550 | Если в = 1 или у = 3 Тогда
551 |
552 | ИначеЕсли ввв Тогда
553 |
554 | ИначеЕсли авыав
555 |
556 | КонецЕсли;
557 | КонецЕсли;
558 | КонецПроцедуры`
559 |
560 | a := NewAST(code)
561 | err := a.Parse()
562 | assert.EqualError(t, err, "syntax error. line: 9, column: 6 (unexpected literal: \"КонецЕсли\")")
563 | })
564 | t.Run("error", func(t *testing.T) {
565 | code := `Процедура ПодключитьВнешнююОбработку()
566 | Если в = 1 И (а = 1 или у = 3) Тогда
567 | Если в = 1 или у = 3 Тогда
568 |
569 | КонецЕсли;
570 | КонецПроцедуры`
571 |
572 | a := NewAST(code)
573 | err := a.Parse()
574 | assert.EqualError(t, err, "syntax error. line: 6, column: 4 (unexpected literal: \"КонецПроцедуры\")")
575 | })
576 | t.Run("error", func(t *testing.T) {
577 | code := `Процедура ПодключитьВнешнююОбработку()
578 | Если Тогда
579 |
580 | КонецЕсли;
581 | КонецПроцедуры`
582 |
583 | a := NewAST(code)
584 | err := a.Parse()
585 | assert.EqualError(t, err, "syntax error. line: 2, column: 11 (unexpected literal: \"Тогда\")")
586 | })
587 | t.Run("error", func(t *testing.T) {
588 | code := `Процедура ПодключитьВнешнююОбработку()
589 | Если f Тогд
590 |
591 | КонецЕсли;
592 | КонецПроцедуры`
593 |
594 | a := NewAST(code)
595 | err := a.Parse()
596 | assert.EqualError(t, err, "syntax error. line: 2, column: 12 (unexpected literal: \"Тогд\")")
597 | })
598 | t.Run("error", func(t *testing.T) {
599 | code := `Процедура ПодключитьВнешнююОбработку()
600 | Если ав f Тогда
601 |
602 | КонецЕсли;
603 | КонецПроцедуры`
604 |
605 | a := NewAST(code)
606 | err := a.Parse()
607 | assert.EqualError(t, err, "syntax error. line: 2, column: 13 (unexpected literal: \"f\")")
608 | })
609 | t.Run("\"not\" pass", func(t *testing.T) {
610 | code := `Процедура ПодключитьВнешнююОбработку()
611 | Если Не f Тогда
612 |
613 | КонецЕсли;
614 |
615 | Если Не f Тогда
616 | d = 0;
617 | ИначеЕсли 3 = 9 Тогда
618 | Если тогоСего Тогда
619 |
620 | КонецЕсли;
621 | Иначе
622 | Если Не f И не 1 = 1 ИЛИ не (а = 2 ИЛИ Истина) Тогда
623 |
624 | КонецЕсли;
625 | КонецЕсли;
626 | КонецПроцедуры`
627 |
628 | a := NewAST(code)
629 | err := a.Parse()
630 | assert.NoError(t, err)
631 | })
632 | }
633 |
634 | func TestParseLoop(t *testing.T) {
635 | t.Run("pass", func(t *testing.T) {
636 | code := `Процедура ПодключитьВнешнююОбработку()
637 | Для Каждого ИзмененныйОбъект Из ОбъектыНазначения Цикл
638 | Тип = ТипЗнч(ИзмененныйОбъект);
639 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
640 | ТипыИзмененныхОбъектов = 0;
641 | КонецЕсли;
642 | КонецЦикла;
643 |
644 | КонецПроцедуры`
645 |
646 | a := NewAST(code)
647 | err := a.Parse()
648 | assert.NoError(t, err)
649 |
650 | data, err := a.JSON()
651 | assert.NoError(t, err)
652 | assert.NotEqual(t, 0, len(data))
653 | })
654 | t.Run("pass", func(t *testing.T) {
655 | code := `Процедура ПодключитьВнешнююОбработку()
656 | Для а = 0 По 100 Цикл
657 | Тип = ТипЗнч(ИзмененныйОбъект);
658 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
659 | ТипыИзмененныхОбъектов = 0;
660 | КонецЕсли;
661 | КонецЦикла;
662 |
663 | КонецПроцедуры`
664 |
665 | a := NewAST(code)
666 | err := a.Parse()
667 | assert.NoError(t, err)
668 | })
669 | t.Run("pass", func(t *testing.T) {
670 | code := `Процедура ПодключитьВнешнююОбработку()
671 | Для а = 0 По 100 Цикл
672 | Тип = ТипЗнч(ИзмененныйОбъект);
673 | Продолжить;
674 |
675 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
676 | Продолжить;
677 | Иначе
678 | Прервать;
679 | КонецЕсли;
680 | КонецЦикла;
681 | КонецПроцедуры`
682 |
683 | a := NewAST(code)
684 | err := a.Parse()
685 | assert.NoError(t, err)
686 | })
687 | t.Run("pass", func(t *testing.T) {
688 | code := `Процедура ПодключитьВнешнююОбработку()
689 | Для а = 0 По 100 Цикл
690 | Для а = 0 По 100 Цикл
691 | Если Истина Тогда
692 | Прервать;
693 | КонецЕсли;
694 | КонецЦикла;
695 |
696 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
697 | Продолжить;
698 | Иначе
699 | Прервать;
700 | КонецЕсли;
701 | КонецЦикла;
702 |
703 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
704 | Для а = 0 По 100 Цикл
705 | Если Истина Тогда
706 | Прервать;
707 | КонецЕсли;
708 | КонецЦикла;
709 | КонецЕсли;
710 | КонецПроцедуры`
711 |
712 | a := NewAST(code)
713 | err := a.Parse()
714 | assert.NoError(t, err)
715 | })
716 | t.Run("pass", func(t *testing.T) {
717 | code := `Процедура ПодключитьВнешнююОбработку()
718 | Для Каждого КлючЗначение Из Новый Структура(СписокКолонок) Цикл
719 |
720 | КонецЦикла;
721 | Для Каждого КлючЗначение Из (Новый Структура(СписокКолонок2)) Цикл
722 |
723 | КонецЦикла;
724 | КонецПроцедуры`
725 |
726 | a := NewAST(code)
727 | err := a.Parse()
728 | assert.NoError(t, err)
729 | if !t.Failed() {
730 | p := a.Print(PrintConf{Margin: 0})
731 | assert.Equal(t, "Процедура ПодключитьВнешнююОбработку() \nДля Каждого КлючЗначение Из Новый Структура(СписокКолонок) Цикл \nКонецЦикла;\nДля Каждого КлючЗначение Из Новый Структура(СписокКолонок2) Цикл \nКонецЦикла;\nКонецПроцедуры", deleteEmptyLine(p))
732 | }
733 | })
734 | t.Run("error", func(t *testing.T) {
735 | code := `Процедура ПодключитьВнешнююОбработку()
736 | Для а = 0 По 100 Цикл
737 | Для а = 0 По 100 Цикл
738 | Если Истина Тогда
739 | Прервать;
740 | КонецЕсли;
741 | КонецЦикла;
742 |
743 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
744 | Продолжить;
745 | Иначе
746 | Прервать;
747 | КонецЕсли;
748 | КонецЦикла;
749 |
750 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
751 | Для а = 0 По 100 Цикл
752 | Если Истина Тогда
753 | Прервать;
754 | КонецЕсли;
755 | КонецЦикла;
756 |
757 | Продолжить; // вне цикла нельзя
758 | КонецЕсли;
759 | КонецПроцедуры`
760 |
761 | a := NewAST(code)
762 | err := a.Parse()
763 | assert.EqualError(t, err, "operator \"Продолжить\" can only be used inside a loop. line: 23, column: 6 (unexpected literal: \"Продолжить\")")
764 | })
765 | t.Run("error", func(t *testing.T) {
766 | code := `Функция ПодключитьВнешнююОбработку()
767 | Если 1 = 1 Тогда
768 | f = 1+1;
769 | Прервать; // вне цикла нельзя
770 | КонецЕсли;
771 |
772 | Для Каждого ИзмененныйОбъект Из ОбъектыНазначения Цикл
773 | Если 1 = 1 Тогда
774 | f = 1+1;
775 | Прервать;
776 | КонецЕсли;
777 | КонецЦикла;
778 | КонецФункции`
779 |
780 | a := NewAST(code)
781 | err := a.Parse()
782 | assert.EqualError(t, err, "operator \"Прервать\" can only be used inside a loop. line: 4, column: 7 (unexpected literal: \"Прервать\")")
783 | })
784 | t.Run("error", func(t *testing.T) {
785 | code := `Функция ПодключитьВнешнююОбработку()
786 | Если 1 = 1 Тогда
787 | f = 1+1;
788 | Прервать;
789 | КонецЕсли;
790 | КонецФункции`
791 |
792 | a := NewAST(code)
793 | err := a.Parse()
794 | assert.EqualError(t, err, "operator \"Прервать\" can only be used inside a loop. line: 4, column: 7 (unexpected literal: \"Прервать\")")
795 | })
796 | t.Run("error", func(t *testing.T) {
797 | code := `Функция ПодключитьВнешнююОбработку()
798 | Для Каждого ИзмененныйОбъект Из ОбъектыНазначения Цикл
799 | Если 1 = 1 Тогда
800 | f = 1+1;
801 | Прервать;
802 | КонецЕсли;
803 | продолжить;
804 | КонецЦикла;
805 |
806 | Если 1 = 1 Тогда
807 | f = 1+1;
808 | Прервать;
809 | КонецЕсли;
810 | КонецФункции`
811 |
812 | a := NewAST(code)
813 | err := a.Parse()
814 | assert.EqualError(t, err, "operator \"Прервать\" can only be used inside a loop. line: 12, column: 7 (unexpected literal: \"Прервать\")")
815 | })
816 | t.Run("error", func(t *testing.T) {
817 | code := `Процедура ПодключитьВнешнююОбработку()
818 | Продолжить; // вне цикла нельзя
819 | Для а = 0 По 100 Цикл
820 | Тип = ТипЗнч(ИзмененныйОбъект);
821 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
822 | Продолжить;
823 | Иначе
824 | Прервать;
825 | КонецЕсли;
826 | КонецЦикла;
827 |
828 | КонецПроцедуры`
829 |
830 | a := NewAST(code)
831 | err := a.Parse()
832 | assert.EqualError(t, err, "operator \"Продолжить\" can only be used inside a loop. line: 2, column: 5 (unexpected literal: \"Продолжить\")")
833 | })
834 | t.Run("error", func(t *testing.T) {
835 | code := `Процедура ПодключитьВнешнююОбработку()
836 | Прервать; // вне цикла нельзя
837 | Для а = 0 По 100 Цикл
838 | Тип = ТипЗнч(ИзмененныйОбъект);
839 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
840 | Продолжить;
841 | Иначе
842 | Прервать;
843 | КонецЕсли;
844 | КонецЦикла;
845 |
846 | КонецПроцедуры`
847 |
848 | a := NewAST(code)
849 | err := a.Parse()
850 | assert.EqualError(t, err, "operator \"Прервать\" can only be used inside a loop. line: 2, column: 5 (unexpected literal: \"Прервать\")")
851 | })
852 | t.Run("error", func(t *testing.T) {
853 | code := `Процедура ПодключитьВнешнююОбработку()
854 | Для а = 0 По Цикл
855 | Тип = ТипЗнч(ИзмененныйОбъект);
856 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
857 | ТипыИзмененныхОбъектов = 0;
858 | КонецЕсли;
859 | КонецЦикла;
860 |
861 | КонецПроцедуры`
862 |
863 | a := NewAST(code)
864 | err := a.Parse()
865 | assert.EqualError(t, err, "syntax error. line: 2, column: 19 (unexpected literal: \"Цикл\")")
866 | })
867 | t.Run("error", func(t *testing.T) {
868 | code := `Процедура ПодключитьВнешнююОбработку()
869 | Для ИзмененныйОбъект Из ОбъектыНазначения Цикл
870 | Тип = ТипЗнч(ИзмененныйОбъект);
871 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
872 | ТипыИзмененныхОбъектов = 0;
873 | КонецЕсли;
874 | КонецЦикла;
875 |
876 | КонецПроцедуры`
877 |
878 | a := NewAST(code)
879 | err := a.Parse()
880 | assert.EqualError(t, err, "syntax error. line: 2, column: 26 (unexpected literal: \"Из\")")
881 | })
882 | }
883 |
884 | func TestTryCatch(t *testing.T) {
885 | t.Run("throw", func(t *testing.T) {
886 | t.Run("pass", func(t *testing.T) {
887 | code := `Процедура ПодключитьВнешнююОбработку()
888 | Если в = 1 И (а = 1 или у = 3) Тогда
889 | f = 0;
890 | ВызватьИсключение "dsdsd dsds";
891 | f = 0;
892 | f = 0;
893 | КонецЕсли;
894 | КонецПроцедуры`
895 |
896 | a := NewAST(code)
897 | err := a.Parse()
898 | assert.NoError(t, err)
899 | })
900 | t.Run("error", func(t *testing.T) {
901 | code := `Процедура ПодключитьВнешнююОбработку()
902 | Если в = 1 И (а = 1 или у = 3) Тогда
903 | f = 0;
904 | ВызватьИсключение; // без параметров нельзя
905 | КонецЕсли;
906 | КонецПроцедуры`
907 |
908 | a := NewAST(code)
909 | err := a.Parse()
910 | assert.EqualError(t, err, "operator \"ВызватьИсключение\" without arguments can only be used when handling an exception. line: 4, column: 24 (unexpected literal: \";\")")
911 | })
912 | })
913 | t.Run("pass", func(t *testing.T) {
914 | code := `Процедура ПодключитьВнешнююОбработку()
915 | Попытка
916 | а = 1+1;
917 | Исключение
918 | ВызватьИсключение "";
919 | КонецПопытки;
920 | КонецПроцедуры`
921 |
922 | a := NewAST(code)
923 | err := a.Parse()
924 | assert.NoError(t, err)
925 | })
926 | t.Run("pass", func(t *testing.T) {
927 | code := `Процедура ПодключитьВнешнююОбработку()
928 | Попытка
929 | Попытка
930 | а = 1+1;
931 | Исключение
932 | ВызватьИсключение;
933 | КонецПопытки;
934 | Исключение
935 | ВызватьИсключение
936 | КонецПопытки;
937 | КонецПроцедуры`
938 |
939 | a := NewAST(code)
940 | err := a.Parse()
941 | assert.NoError(t, err)
942 | })
943 | t.Run("pass", func(t *testing.T) {
944 | code := `Процедура ПодключитьВнешнююОбработку()
945 | Попытка
946 | а = 1+1;
947 | ВызватьИсключение("dsdsd dsds");
948 | f = 0;
949 | f = 0
950 | Исключение
951 | а = 1+1;
952 | а = 1+1;
953 | ВызватьИсключение; // в блоке Исключение можно вызывать без параметров
954 | а = 1+1;
955 |
956 | Если истина Тогда
957 | ВызватьИсключение; // в блоке Исключение можно вызывать без параметров
958 | КонецЕсли
959 | КонецПопытки;
960 | КонецПроцедуры`
961 |
962 | a := NewAST(code)
963 | err := a.Parse()
964 | assert.NoError(t, err)
965 | })
966 | t.Run("pass", func(t *testing.T) {
967 | code := `Процедура ПодключитьВнешнююОбработку()
968 | Попытка
969 | а = 1+1;
970 | Если в = 1 И (а = 1 или у = 3) Тогда
971 | ВызватьИсключение "SDSDSD";
972 | КонецЕсли;
973 | Исключение
974 | а = 1+1;
975 | ВызватьИсключение "dsd";
976 | а = 1+1;
977 | КонецПопытки;
978 | КонецПроцедуры`
979 |
980 | a := NewAST(code)
981 | err := a.Parse()
982 | assert.NoError(t, err)
983 | })
984 | t.Run("error", func(t *testing.T) {
985 | code := `Процедура ПодключитьВнешнююОбработку()
986 | Попытка
987 | Попытка
988 | а = 1+1;
989 | Исключение
990 | ВызватьИсключение;
991 | КонецПопытки;
992 |
993 | ВызватьИсключение ;
994 | Исключение
995 | ВызватьИсключение
996 | КонецПопытки;
997 | КонецПроцедуры`
998 |
999 | a := NewAST(code)
1000 | err := a.Parse()
1001 | assert.EqualError(t, err, "operator \"ВызватьИсключение\" without arguments can only be used when handling an exception. line: 9, column: 25 (unexpected literal: \";\")")
1002 | })
1003 | t.Run("error", func(t *testing.T) {
1004 | code := `Процедура ПодключитьВнешнююОбработку()
1005 | Попытка
1006 | Попытка
1007 | а = 1+1;
1008 | Исключение
1009 | ВызватьИсключение;
1010 | КонецПопытки;
1011 | Исключение
1012 | ВызватьИсключение
1013 | КонецПопытки;
1014 | ВызватьИсключение
1015 | КонецПроцедуры`
1016 |
1017 | a := NewAST(code)
1018 | err := a.Parse()
1019 | assert.EqualError(t, err, "operator \"ВызватьИсключение\" without arguments can only be used when handling an exception. line: 12, column: 5 (unexpected literal: \"КонецПроцедуры\")")
1020 | })
1021 | }
1022 |
1023 | func TestParseMethod(t *testing.T) {
1024 | t.Run("pass", func(t *testing.T) {
1025 | code := `Процедура ПодключитьВнешнююОбработку()
1026 | а = ТипыИзмененныхОбъектов.Найти(Тип)
1027 | КонецПроцедуры`
1028 |
1029 | a := NewAST(code)
1030 | err := a.Parse()
1031 | assert.NoError(t, err)
1032 | })
1033 | t.Run("pass", func(t *testing.T) {
1034 | code := `Процедура ПодключитьВнешнююОбработку()
1035 | а = ТипыИзмененныхОбъектов.Test.Найти(Тип)
1036 | КонецПроцедуры`
1037 |
1038 | a := NewAST(code)
1039 | err := a.Parse()
1040 | assert.NoError(t, err)
1041 | })
1042 | t.Run("pass", func(t *testing.T) {
1043 | code := `Процедура ПодключитьВнешнююОбработку()
1044 | а = ТипыИзмененныхОбъектов(Тип);
1045 | КонецПроцедуры`
1046 |
1047 | a := NewAST(code)
1048 | err := a.Parse()
1049 | assert.NoError(t, err)
1050 | })
1051 | t.Run("error", func(t *testing.T) {
1052 | code := `Процедура ПодключитьВнешнююОбработку()
1053 | а = ТипыИзмененныхОбъектов..Найти(Тип)
1054 | КонецПроцедуры`
1055 |
1056 | a := NewAST(code)
1057 | err := a.Parse()
1058 | assert.EqualError(t, err, "syntax error. line: 2, column: 32 (unexpected literal: \".\")")
1059 | })
1060 | }
1061 |
1062 | func TestParseFunctionProcedure(t *testing.T) {
1063 | t.Run("Function", func(t *testing.T) {
1064 | t.Run("ast", func(t *testing.T) {
1065 | code := `&НасервереБезКонтекста
1066 | Функция ПодключитьВнешнююОбработку(Ссылка)
1067 | f = 1 + gggg - (fd +1 / 3);
1068 | КонецФункции`
1069 |
1070 | a := NewAST(code)
1071 | err := a.Parse()
1072 | assert.NoError(t, err)
1073 |
1074 | data, err := a.JSON()
1075 | assert.NoError(t, err)
1076 | assert.NotEqual(t, 0, len(data))
1077 | })
1078 | t.Run("ast", func(t *testing.T) {
1079 | code := `&НасервереБезКонтекста
1080 | Функция ПодключитьВнешнююОбработку(Ссылка)
1081 | f = парапапапам;
1082 | КонецФункции`
1083 |
1084 | a := NewAST(code)
1085 | err := a.Parse()
1086 | if assert.NoError(t, err) {
1087 | expr := a.ModuleStatement.Body[0].(*FunctionOrProcedure).Body[0].(*ExpStatement)
1088 | assert.Equal(t, OpEq, expr.Operation)
1089 | assert.Equal(t, "f", expr.Left.(VarStatement).Name)
1090 | assert.Equal(t, "парапапапам", expr.Right.(VarStatement).Name)
1091 | }
1092 | })
1093 | t.Run("ast", func(t *testing.T) {
1094 | code := `&НасервереБезКонтекста
1095 | Функция ПодключитьВнешнююОбработку(Ссылка)
1096 | f = 221;
1097 | возврат 2+2;
1098 | КонецФункции`
1099 |
1100 | a := NewAST(code)
1101 | err := a.Parse()
1102 | fmt.Println(a.Print(PrintConf{Margin: 2}))
1103 | assert.NoError(t, err)
1104 | assert.Equal(t, OpEq, a.ModuleStatement.Body[0].(*FunctionOrProcedure).Body[0].(*ExpStatement).Operation)
1105 | assert.Equal(t, float64(221), a.ModuleStatement.Body[0].(*FunctionOrProcedure).Body[0].(*ExpStatement).Right.(float64))
1106 | })
1107 | t.Run("ast", func(t *testing.T) {
1108 | code := `&НасервереБезКонтекста
1109 | Функция ПодключитьВнешнююОбработку(Ссылка)
1110 | f = "вававава авава";
1111 | КонецФункции`
1112 |
1113 | a := NewAST(code)
1114 | err := a.Parse()
1115 | assert.NoError(t, err)
1116 | assert.Equal(t, "вававава авава", a.ModuleStatement.Body[0].(*FunctionOrProcedure).Body[0].(*ExpStatement).Right.(string))
1117 | })
1118 | t.Run("ast", func(t *testing.T) {
1119 | code := `&НасервереБезКонтекста
1120 | Функция ПодключитьВнешнююОбработку(Ссылка)
1121 | f = Истина;
1122 | КонецФункции`
1123 |
1124 | a := NewAST(code)
1125 | err := a.Parse()
1126 | assert.NoError(t, err)
1127 | assert.Equal(t, true, a.ModuleStatement.Body[0].(*FunctionOrProcedure).Body[0].(*ExpStatement).Right.(bool))
1128 | })
1129 | t.Run("ast", func(t *testing.T) {
1130 | code := `&НасервереБезКонтекста
1131 | Функция ПодключитьВнешнююОбработку(Ссылка)
1132 | f = Ложь;
1133 | КонецФункции`
1134 |
1135 | a := NewAST(code)
1136 | err := a.Parse()
1137 | assert.NoError(t, err)
1138 | assert.Equal(t, false, a.ModuleStatement.Body[0].(*FunctionOrProcedure).Body[0].(*ExpStatement).Right.(bool))
1139 | })
1140 | t.Run("bad directive", func(t *testing.T) {
1141 | code := `&НасервереБез
1142 | Функция ПодключитьВнешнююОбработку(Ссылка)
1143 |
1144 | КонецФункции`
1145 |
1146 | a := NewAST(code)
1147 | err := a.Parse()
1148 | assert.EqualError(t, err, "syntax error. line: 1, column: 0 (unexpected literal: \"&\")")
1149 | })
1150 | t.Run("without directive", func(t *testing.T) {
1151 | code := `Функция ПодключитьВнешнююОбработку(Ссылка, вы, выыыыы)
1152 |
1153 | КонецФункции`
1154 |
1155 | a := NewAST(code)
1156 | err := a.Parse()
1157 | assert.NoError(t, err)
1158 | })
1159 | t.Run("return", func(t *testing.T) {
1160 | code := `Функция ПодключитьВнешнююОбработку(Ссылка, вы, выыыыы)
1161 | Перем а;
1162 | Перем вы, в;
1163 |
1164 | Если истина Тогда
1165 | ВызватьИсключение вызов("");
1166 | ИначеЕсли 1 = 1 Тогда
1167 | ИначеЕсли 2 = 2 Тогда
1168 | Иначе
1169 | б = а;
1170 | КонецЕсли;
1171 | КонецФункции`
1172 |
1173 | a := NewAST(code)
1174 | err := a.Parse()
1175 | assert.NoError(t, err)
1176 |
1177 | // fmt.Println(a.Print(&PrintConf{Margin: 2}))
1178 | })
1179 | t.Run("return", func(t *testing.T) {
1180 | code := `Функция ПодключитьВнешнююОбработку(Ссылка, вы, выыыыы)
1181 | Перем а;
1182 | Перем вы, в;
1183 |
1184 | Если истина Тогда
1185 | Возврат;
1186 | КонецЕсли;
1187 | КонецФункции`
1188 |
1189 | a := NewAST(code)
1190 | err := a.Parse()
1191 | assert.NoError(t, err)
1192 | })
1193 | t.Run("export", func(t *testing.T) {
1194 | code := `Функция ПодключитьВнешнююОбработку(Ссылка) Экспорт
1195 |
1196 | КонецФункции`
1197 |
1198 | a := NewAST(code)
1199 | err := a.Parse()
1200 | assert.NoError(t, err)
1201 | })
1202 | t.Run("error", func(t *testing.T) {
1203 | code := `Функция ПодключитьВнешнююОбработку(Ссылка)
1204 |
1205 | КонецФунки`
1206 |
1207 | a := NewAST(code)
1208 | err := a.Parse()
1209 | assert.EqualError(t, err, "syntax error. line: 3, column: 5 (unexpected literal: \"КонецФунки\")")
1210 | })
1211 | t.Run("error", func(t *testing.T) {
1212 | code := `Функция ПодключитьВнешнююОбработку(Ссылка)
1213 |
1214 | КонецПроцедуры`
1215 |
1216 | a := NewAST(code)
1217 | err := a.Parse()
1218 | assert.EqualError(t, err, "syntax error. line: 3, column: 5 (unexpected literal: \"КонецПроцедуры\")")
1219 | })
1220 | t.Run("params def value", func(t *testing.T) {
1221 | code := `Функция ПодключитьВнешнююОбработку(Парам1, Парам2 = Неопределено, Знач Парам3 = "вывыв", парам4 = 4)
1222 |
1223 | КонецФункции`
1224 |
1225 | a := NewAST(code)
1226 | err := a.Parse()
1227 | assert.NoError(t, err)
1228 | })
1229 | })
1230 | t.Run("Procedure", func(t *testing.T) {
1231 | t.Run("with directive", func(t *testing.T) {
1232 | code := `&НасервереБезКонтекста
1233 | Процедура ПодключитьВнешнююОбработку()
1234 |
1235 | КонецПроцедуры`
1236 |
1237 | a := NewAST(code)
1238 | err := a.Parse()
1239 | assert.NoError(t, err)
1240 | })
1241 | t.Run("bad directive", func(t *testing.T) {
1242 | code := `&НасервереБез
1243 | Процедура ПодключитьВнешнююОбработку(Ссылка)
1244 |
1245 | КонецПроцедуры`
1246 |
1247 | a := NewAST(code)
1248 | err := a.Parse()
1249 | assert.EqualError(t, err, "syntax error. line: 1, column: 0 (unexpected literal: \"&\")")
1250 | })
1251 | t.Run("export", func(t *testing.T) {
1252 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка) Экспорт
1253 |
1254 | КонецПроцедуры`
1255 |
1256 | a := NewAST(code)
1257 | err := a.Parse()
1258 | assert.NoError(t, err)
1259 | })
1260 | t.Run("error", func(t *testing.T) {
1261 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1262 |
1263 | КонецФункции`
1264 |
1265 | a := NewAST(code)
1266 | err := a.Parse()
1267 | assert.EqualError(t, err, "syntax error. line: 3, column: 5 (unexpected literal: \"КонецФункции\")")
1268 | })
1269 | t.Run("with var pass", func(t *testing.T) {
1270 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1271 | Перем а;
1272 | Перем вы, в;
1273 |
1274 | Если истина Тогда
1275 | ВызватьИсключение "";
1276 | КонецЕсли;
1277 | КонецПроцедуры`
1278 |
1279 | a := NewAST(code)
1280 | err := a.Parse()
1281 | assert.NoError(t, err)
1282 | assert.Equal(t, 3, len(a.ModuleStatement.Body[0].(*FunctionOrProcedure).ExplicitVariables))
1283 | })
1284 | t.Run("with var error", func(t *testing.T) {
1285 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1286 | Перем а;
1287 | Перем а, вы, в;
1288 |
1289 | Если истина Тогда
1290 | ВызватьИсключение "";
1291 | КонецЕсли;
1292 | КонецПроцедуры`
1293 |
1294 | a := NewAST(code)
1295 | err := a.Parse()
1296 | assert.ErrorContains(t, err, "variable has already been defined")
1297 | })
1298 | t.Run("return", func(t *testing.T) {
1299 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1300 | Перем а;
1301 | Перем вы, в;
1302 |
1303 | Если истина Тогда
1304 | возврат;
1305 | КонецЕсли;
1306 | КонецПроцедуры`
1307 |
1308 | a := NewAST(code)
1309 | err := a.Parse()
1310 | assert.NoError(t, err)
1311 | })
1312 | t.Run("return error", func(t *testing.T) {
1313 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1314 | Перем а;
1315 | Перем а, вы, в;
1316 |
1317 | Если истина Тогда
1318 | возврат "";
1319 | КонецЕсли;
1320 | КонецПроцедуры`
1321 |
1322 | a := NewAST(code)
1323 | err := a.Parse()
1324 | assert.ErrorContains(t, err, "procedure cannot return a value")
1325 | })
1326 | t.Run("with var error", func(t *testing.T) {
1327 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1328 | Перем а;
1329 | Перем а, вы, в
1330 |
1331 | Если истина Тогда
1332 | ВызватьИсключение "";
1333 | КонецЕсли;
1334 | КонецПроцедуры`
1335 |
1336 | a := NewAST(code)
1337 | err := a.Parse()
1338 | assert.EqualError(t, err, "syntax error. line: 5, column: 6 (unexpected literal: \"Если\")")
1339 | })
1340 | t.Run("with var error", func(t *testing.T) {
1341 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1342 | Если истина Тогда
1343 | ВызватьИсключение "";
1344 | КонецЕсли;
1345 |
1346 | Перем а, вы, в;
1347 | КонецПроцедуры`
1348 |
1349 | a := NewAST(code)
1350 | err := a.Parse()
1351 | assert.EqualError(t, err, "syntax error. line: 6, column: 6 (unexpected literal: \"Перем\")")
1352 | })
1353 | t.Run("with region", func(t *testing.T) {
1354 | code := `#Область ПрограммныйИнтерфейс
1355 | // hg
1356 | #Область ПрограммныйИнтерфейс
1357 | &НасервереБезКонтекста
1358 | Процедура ПодключитьВнешнююОбработку()
1359 | ТипЗначенияСтрокой = XMLТипЗнч(КлючДанных).ИмяТипа;
1360 |
1361 | КонецПроцедуры
1362 | #КонецОбласти
1363 | #КонецОбласти
1364 |
1365 | #Область СлужебныеПроцедурыИФункции
1366 | &НасервереБезКонтекста
1367 | Функция ПодключитьВнешнююОбработку()
1368 | ВызватьИсключение "Нет соответствия шаблону! " + СтрокаТекста;
1369 |
1370 | КонецФункции
1371 | #КонецОбласти`
1372 |
1373 | a := NewAST(code)
1374 | err := a.Parse()
1375 | assert.NoError(t, err)
1376 | })
1377 | t.Run("through_dot pass", func(t *testing.T) {
1378 | code := `Процедура ЗагрузитьОбъекты(Задание, Отказ = Ложь) Экспорт
1379 | Перем СоответствиеРеквизитовШапки;
1380 |
1381 | Организация = Задание.Организация.ВыполнитьМетодСПараметрами(1, "ав", авава);
1382 | Организация = Задание.Организация.ВыполнитьМетодБезПараметров();
1383 | Организация = Задание.Организация.Код;
1384 |
1385 | КонецПроцедуры`
1386 |
1387 | a := NewAST(code)
1388 | err := a.Parse()
1389 | assert.NoError(t, err)
1390 |
1391 | data, err := a.JSON()
1392 | assert.NoError(t, err)
1393 | assert.NotEqual(t, 0, len(data))
1394 | })
1395 | })
1396 | t.Run("many", func(t *testing.T) {
1397 | code := `&Насервере
1398 | Процедура ПодключитьВнешнююОбработку()
1399 | Возврат
1400 | КонецПроцедуры
1401 |
1402 | &НаКлиенте
1403 | Функция ОчиститьПараметрыТЖ(парам1 = 1, парам2 = Неопределено, парам3 = -1) Экспорт
1404 | Возврат 100;
1405 | КонецФункции
1406 |
1407 | Функция ПарамТарам(Знач парам1)
1408 | возврат +1;
1409 | КонецФункции`
1410 |
1411 | a := NewAST(code)
1412 | err := a.Parse()
1413 | assert.NoError(t, err)
1414 | if !t.Failed() {
1415 | p := a.Print(PrintConf{Margin: 0})
1416 | assert.Equal(t, "&Насервере\nПроцедура ПодключитьВнешнююОбработку() \nВозврат;\nКонецПроцедуры \n&НаКлиенте\nФункция ОчиститьПараметрыТЖ(парам1 = 1, парам2 = Неопределено, парам3 = -1) Экспорт \nВозврат 100;\nКонецФункции \nФункция ПарамТарам(Знач парам1) \nВозврат 1;\nКонецФункции", deleteEmptyLine(p))
1417 | }
1418 | })
1419 | }
1420 |
1421 | func TestParseBaseExpression(t *testing.T) {
1422 | t.Run("pass", func(t *testing.T) {
1423 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка) ds; КонецПроцедуры`
1424 |
1425 | a := NewAST(code)
1426 | err := a.Parse()
1427 | assert.NoError(t, err)
1428 | })
1429 | t.Run("pass", func(t *testing.T) {
1430 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка) ds = 222; uu = 9; КонецПроцедуры`
1431 |
1432 | a := NewAST(code)
1433 | err := a.Parse()
1434 | assert.NoError(t, err)
1435 | })
1436 | t.Run("pass", func(t *testing.T) {
1437 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1438 | ds = 222; ds = 222; uu = 9
1439 | КонецПроцедуры`
1440 |
1441 | a := NewAST(code)
1442 | err := a.Parse()
1443 | assert.NoError(t, err)
1444 | })
1445 | t.Run("pass", func(t *testing.T) {
1446 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1447 | ds = 222
1448 |
1449 |
1450 |
1451 | ; uu = 9;
1452 | КонецПроцедуры`
1453 |
1454 | a := NewAST(code)
1455 | err := a.Parse()
1456 | assert.NoError(t, err)
1457 | })
1458 | t.Run("pass", func(t *testing.T) {
1459 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1460 | ds = 222;
1461 | uu = 9;
1462 | КонецПроцедуры`
1463 |
1464 | a := NewAST(code)
1465 | err := a.Parse()
1466 | assert.NoError(t, err)
1467 | })
1468 | t.Run("error", func(t *testing.T) {
1469 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1470 | ds = 222
1471 | uu = 9;
1472 | КонецПроцедуры`
1473 |
1474 | a := NewAST(code)
1475 | err := a.Parse()
1476 | assert.EqualError(t, err, "syntax error. line: 3, column: 5 (unexpected literal: \"uu\")")
1477 | })
1478 | t.Run("pass", func(t *testing.T) {
1479 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1480 | ds = ИспользуемыеНастройки[0].Структура[0].Структура;
1481 | fdfd = СтруктураКонтрагент();
1482 | fdfd = f.СтруктураКонтрагент(gf, ghf);
1483 | СтруктураКонтрагент.Наименование = СтрокаВывода[РезультатВывода.Колонки.Найти("СтруктураКонтрагентНаименование").Имя];
1484 | СтрокаСпискаПП[ТекКолонка.Ключ]["РасшифровкаПлатежа"].Добавить(ВременнаяСтруктура);
1485 | КонецПроцедуры`
1486 |
1487 | a := NewAST(code)
1488 | err := a.Parse()
1489 | assert.NoError(t, err)
1490 | })
1491 | t.Run("error", func(t *testing.T) {
1492 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1493 | ds = ИспользуемыеНастройки[0].Структура[0].Структура;
1494 | fdfd = СтруктураКонтрагент();
1495 | fdfd = f.СтруктураКонтрагент(gf, ghf);
1496 | СтруктураКонтрагент.Наименование = СтрокаВывода[РезультатВывода.Колонки.Найти("СтруктураКонтрагентНаименование.Имя];
1497 | КонецПроцедуры`
1498 |
1499 | a := NewAST(code)
1500 | err := a.Parse()
1501 | assert.Error(t, err)
1502 | })
1503 | t.Run("new pass", func(t *testing.T) {
1504 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1505 | Контекст = Новый Структура;
1506 | Контекст = Новый Структура();
1507 | Контекст = Новый Структура("выыыы");
1508 | Контекст = Новый Структура(какойтофункшин());
1509 | Контекст = Новый Структура("какойтоимя", чето);
1510 | Запрос = Новый Запрос(ТекстЗапросаЗадание());
1511 | Оповещение = Новый ОписаниеОповещения(,, Контекст,
1512 | "ОткрытьНавигационнуюСсылкуПриОбработкеОшибки", ОбщегоНазначенияСлужебныйКлиент);
1513 | КонецПроцедуры`
1514 |
1515 | a := NewAST(code)
1516 | err := a.Parse()
1517 | assert.NoError(t, err)
1518 | })
1519 | t.Run("new error", func(t *testing.T) {
1520 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1521 | Контекст = Новый Структура(;
1522 | КонецПроцедуры`
1523 |
1524 | a := NewAST(code)
1525 | err := a.Parse()
1526 | assert.EqualError(t, err, "syntax error. line: 2, column: 32 (unexpected literal: \";\")")
1527 | })
1528 | t.Run("new error", func(t *testing.T) {
1529 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1530 | Контекст = Новый Структура("выыыы);
1531 | КонецПроцедуры`
1532 |
1533 | a := NewAST(code)
1534 | err := a.Parse()
1535 | assert.Error(t, err)
1536 | })
1537 | }
1538 |
1539 | func TestParseAST(t *testing.T) {
1540 | code := `
1541 |
1542 | Процедура ОткрытьНавигационнуюСсылку(НавигационнаяСсылка, Знач Оповещение = Неопределено) Экспорт
1543 |
1544 | ПустаяДата = '00010101000000';
1545 | ПустаяДата = '20131231235959';
1546 |
1547 | КлючЗаписиРегистра = Новый("РегистрСведенийКлючЗаписи.СостоянияОригиналовПервичныхДокументов", ПараметрыМассив);
1548 | МассаДМ = ВыборкаЕдИзм.МассаДМ/Количество;
1549 |
1550 | стр = новый Структура("Цикл", 1);
1551 | стр.Цикл = 0;
1552 |
1553 | Если КодСимвола < 1040 ИЛИ КодСимвола > 1103 И КодыДопустимыхСимволов.Найти(КодСимвола) = Неопределено И Не (Не УчитыватьРазделителиСлов И ЭтоРазделительСлов(КодСимвола)) Тогда
1554 | Возврат ;
1555 | КонецЕсли;
1556 |
1557 | перейти ~метка;
1558 |
1559 | МассивСтроки.Добавить(Новый ФорматированнаяСтрока(ЧастьСтроки.Значение, Новый Шрифт(,,Истина)));
1560 |
1561 | Позиция = Найти(Строка, Разделитель);
1562 | Пока Позиция > 0 Цикл
1563 | Подстрока = Лев(Строка, Позиция - 1);
1564 | Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Подстрока) Тогда
1565 | Если СокращатьНепечатаемыеСимволы Тогда
1566 | Результат.Добавить(СокрЛП(Подстрока));
1567 | Иначе
1568 | Результат.Добавить(Подстрока);
1569 | КонецЕсли;
1570 | КонецЕсли;
1571 | Строка = Сред(Строка, Позиция + СтрДлина(Разделитель));
1572 | Позиция = Найти(Строка, Разделитель);
1573 | КонецЦикла;
1574 |
1575 | ~метка:
1576 |
1577 |
1578 |
1579 | вы = ввывыв[0];
1580 | СтрокаСпискаПП[ТекКолонка.Ключ].Вставить(ТекКолонкаЗначение.Ключ, УровеньГруппировки3[ПрефиксПоля + СтрЗаменить(ТекКолонкаЗначение.Значение, ".", "")]);
1581 |
1582 | Контекст = Новый Структура();
1583 | Контекст.Вставить("НавигационнаяСсылка", НавигационнаяСсылка);
1584 | Контекст.Вставить("Оповещение", Оповещение);
1585 |
1586 | ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
1587 | НСтр("ru = 'Не удалось перейти по ссылке ""%1"" по причине:
1588 | |Неверно задана навигационная ссылка.'"),
1589 | НавигационнаяСсылка);
1590 |
1591 | Если Не ОбщегоНазначенияСлужебныйКлиент.ЭтоДопустимаяСсылка(НавигационнаяСсылка) Тогда
1592 | ОбщегоНазначенияСлужебныйКлиент.ОткрытьНавигационнуюСсылкуОповеститьОбОшибке(ОписаниеОшибки, Контекст);
1593 | Возврат;
1594 | КонецЕсли;
1595 |
1596 | Если ОбщегоНазначенияСлужебныйКлиент.ЭтоВебСсылка(НавигационнаяСсылка)
1597 | Или ОбщегоНазначенияСлужебныйКлиент.ЭтоНавигационнаяСсылка(НавигационнаяСсылка) Тогда
1598 |
1599 | Попытка
1600 | а = а /0;
1601 | Исключение
1602 | ОбщегоНазначенияСлужебныйКлиент.ОткрытьНавигационнуюСсылкуОповеститьОбОшибке(ОписаниеОшибки, Контекст);
1603 | Возврат;
1604 | КонецПопытки;
1605 |
1606 | Если Оповещение <> Неопределено Тогда
1607 | ПриложениеЗапущено = Истина;
1608 | ВыполнитьОбработкуОповещения(Оповещение, ПриложениеЗапущено);
1609 | КонецЕсли;
1610 |
1611 | Возврат;
1612 | КонецЕсли;
1613 |
1614 | Если ОбщегоНазначенияСлужебныйКлиент.ЭтоСсылкаНаСправку(НавигационнаяСсылка) Тогда
1615 | ОткрытьСправку(НавигационнаяСсылка);
1616 | Возврат;
1617 | КонецЕсли;
1618 | КонецПроцедуры
1619 |
1620 | Если Оповещение <> Неопределено Тогда
1621 | ПриложениеЗапущено = Истина;
1622 | ВыполнитьОбработкуОповещения(Оповещение, ПриложениеЗапущено);
1623 | КонецЕсли;`
1624 |
1625 | a := NewAST(code)
1626 | err := a.Parse()
1627 | assert.NoError(t, err)
1628 |
1629 | p := a.Print(PrintConf{Margin: 4})
1630 | assert.Equal(t, true, compareHashes(code, p))
1631 | }
1632 |
1633 | func TestParseEmpty(t *testing.T) {
1634 | code := `
1635 |
1636 | `
1637 |
1638 | a := NewAST(code)
1639 | err := a.Parse()
1640 | assert.NoError(t, err)
1641 | }
1642 |
1643 | func TestBigProcedure(t *testing.T) {
1644 | if _, err := os.Stat("testdata"); errors.Is(err, os.ErrNotExist) {
1645 | t.Fatal("testdata file not found")
1646 | }
1647 |
1648 | fileData, err := os.ReadFile("testdata")
1649 | assert.NoError(t, err)
1650 |
1651 | a := NewAST(string(fileData))
1652 | s := time.Now()
1653 | err = a.Parse()
1654 | fmt.Println("milliseconds -", time.Since(s).Milliseconds())
1655 | assert.NoError(t, err)
1656 |
1657 | // p := a.Print(&PrintConf{Margin: 4})
1658 | // fmt.Println(p)
1659 | }
1660 |
1661 | func TestTernaryOperator(t *testing.T) {
1662 | code := `Процедура ПодключитьВнешнююОбработку(Ссылка)
1663 | ds = ?(Истина, ?(dd = 3, а = 1, Наименование), СтруктураКонтрагент.Наименование);
1664 | КонецПроцедуры`
1665 | a := NewAST(code)
1666 | err := a.Parse()
1667 | assert.NoError(t, err)
1668 |
1669 | data, err := a.JSON()
1670 | assert.NoError(t, err)
1671 | assert.NotEqual(t, 0, len(data))
1672 | }
1673 |
1674 | func TestArrayStruct(t *testing.T) {
1675 | code := `Процедура ПодключитьВнешнююОбработку()
1676 | м = Новый Массив();
1677 | в = м[4];
1678 |
1679 | м = Новый Структура("ав", уцуцу);
1680 | в = м["вывыв"];
1681 | КонецПроцедуры`
1682 |
1683 | a := NewAST(code)
1684 | err := a.Parse()
1685 | assert.NoError(t, err)
1686 |
1687 | data, err := a.JSON()
1688 | assert.NoError(t, err)
1689 | assert.NotEqual(t, 0, len(data))
1690 | }
1691 |
1692 | func TestPrint(t *testing.T) {
1693 | code := `&НаКлиенте
1694 | Процедура Проба()
1695 | Если в = 1 или у = 3 И 0 <> 3 и не гоого и Истина и ав = неопределено Тогда
1696 | а=1 + 3 *4;
1697 | а=1 + 3 *4;
1698 | fgd = 1
1699 | ИначеЕсли ввв Тогда Если в = 1 Тогда
1700 | а = -(1 + 3 *4);
1701 | Если в = 1 Тогда
1702 | а = 1 + 3 *4;
1703 | КонецЕсли
1704 | КонецЕсли
1705 | ИначеЕсли авыав Тогда
1706 |
1707 | Иначе
1708 | ваывы = 1 + 3 *4;
1709 | ваывы = 1 + 3 *4
1710 | КонецЕсли;
1711 |
1712 | а = 1 + 3 *4
1713 | КонецПроцедуры
1714 |
1715 | Функция авава(пар1, пар2) экспорт
1716 | Для Каждого ИзмененныйОбъект Из ОбъектыНазначения Цикл
1717 | Тип = ТипЗнч(ИзмененныйОбъект);
1718 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
1719 | ТипыИзмененныхОбъектов.Добавить(Тип);
1720 | КонецЕсли;
1721 |
1722 | Для Каждого ИзмененныйОбъект Из ОбъектыНазначения Цикл
1723 | Тип = ТипЗнч(ИзмененныйОбъект);
1724 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
1725 | ТипыИзмененныхОбъектов.Добавить(Тип);
1726 | Иначе
1727 | КонецЕсли;
1728 | КонецЦикла;
1729 |
1730 | КонецЦикла;
1731 |
1732 | Для а = 0 По 100 Цикл
1733 | Тип = ТипЗнч(ИзмененныйОбъект);
1734 | Если ТипыИзмененныхОбъектов = Неопределено Тогда
1735 | Продолжить; Иначе Прервать;
1736 | КонецЕсли;
1737 | КонецЦикла;
1738 | Конецфункции
1739 |
1740 | Процедура Опрпп(пар1, Знач пар2 = 2.2, пар1 = Неопределено, Пар3 = "авава")
1741 |
1742 | Попытка
1743 | а = 1+1;
1744 | ВызватьИсключение ававава();
1745 | Исключение
1746 | ВызватьИсключение "";
1747 | ВызватьИсключение ;
1748 | КонецПопытки;
1749 | Конецпроцедуры`
1750 |
1751 | a := NewAST(code)
1752 | err := a.Parse()
1753 | assert.NoError(t, err)
1754 |
1755 | // p := a.Print(&PrintConf{Margin: 4})
1756 | // fmt.Println(p)
1757 | }
1758 |
1759 | func TestExpPriority(t *testing.T) {
1760 | code := `А = d = 2 = d ИЛИ в = 3;
1761 | Если 1 = 1 = 2 = 3 Тогда
1762 | ПриКомпоновкеРезультата();
1763 | КонецЕсли`
1764 | a := NewAST(code)
1765 | err := a.Parse()
1766 | if assert.NoError(t, err) {
1767 | jdata, _ := a.JSON()
1768 | assert.Equal(t, `{"Name":"","Body":[{"Left":{"Name":"А"},"Right":{"Left":{"Left":{"Left":{"Name":"d"},"Right":2,"Operation":5},"Right":{"Name":"d"},"Operation":5},"Right":{"Left":{"Name":"в"},"Right":3,"Operation":5},"Operation":12},"Operation":5},{"Expression":{"Left":{"Left":{"Left":1,"Right":1,"Operation":5},"Right":2,"Operation":5},"Right":3,"Operation":5},"TrueBlock":[{"Name":"ПриКомпоновкеРезультата","Param":[null]}],"IfElseBlock":[],"ElseBlock":null}]}`, string(jdata))
1769 | }
1770 | }
1771 |
1772 | func BenchmarkString(b *testing.B) {
1773 | b.Run("string", func(b *testing.B) {
1774 | for i := 0; i < b.N; i++ {
1775 | test("rdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs rdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfd dfdf dsfd")
1776 | }
1777 | })
1778 | b.Run("ptr string", func(b *testing.B) {
1779 | str := "rdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs rdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfd dfdf dsfd"
1780 | for i := 0; i < b.N; i++ {
1781 | testPt(&str)
1782 | }
1783 | })
1784 | b.Run("string count - 1", func(b *testing.B) {
1785 | str := "rdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs rdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfd dfdf dsfd"
1786 | for i := 0; i < b.N; i++ {
1787 | strings.Count(str, "df")
1788 | }
1789 | })
1790 | //b.Run("string count - 2", func(b *testing.B) {
1791 | // str := "rdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs rdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfd rdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfdrdedfs dfdf dsfd dfdf dsfd"
1792 | // for i := 0; i < b.N; i++ {
1793 | // stringCount(str, "df")
1794 | // }
1795 | //})
1796 | }
1797 |
1798 | func test(str string) {
1799 |
1800 | }
1801 |
1802 | func testPt(str *string) {
1803 |
1804 | }
1805 |
1806 | func compareHashes(str1, str2 string) bool {
1807 | str1 = strings.ReplaceAll(str1, " ", "")
1808 | str1 = strings.ReplaceAll(str1, "\t", "")
1809 | str1 = strings.ReplaceAll(str1, "\n", "")
1810 |
1811 | str2 = strings.ReplaceAll(str2, " ", "")
1812 | str2 = strings.ReplaceAll(str2, "\t", "")
1813 | str2 = strings.ReplaceAll(str2, "\n", "")
1814 |
1815 | hash1 := sha256.Sum256([]byte(fastToLower(str1)))
1816 | hash2 := sha256.Sum256([]byte(fastToLower(str2)))
1817 |
1818 | return hash1 == hash2
1819 | }
1820 |
1821 | func deleteEmptyLine(str string) string {
1822 | result := strings.Builder{}
1823 | for _, line := range strings.Split(str, "\n") {
1824 | if strings.TrimSpace(line) != "" {
1825 | result.WriteString(line + "\n")
1826 | }
1827 | }
1828 |
1829 | return strings.TrimSpace(result.String())
1830 | }
1831 |
--------------------------------------------------------------------------------
/ast/fast_tolower/gowrap.go:
--------------------------------------------------------------------------------
1 | package fast_tolower
2 |
3 | /*
4 | #cgo CFLAGS: -std=c99
5 | #include // for free
6 | #include // for tolower
7 | #include
8 | #include // for printf
9 |
10 | void fastToLower(char* str) {
11 | for (int i = 0; str[i] != '\0';) {
12 | unsigned char byte = str[i];
13 | int currentChar = 0;
14 |
15 | if (byte <= 0x7F) {
16 | currentChar = byte; // Один байт (ASCII)
17 | i++;
18 | } else if (byte >= 0xC0 && byte <= 0xDF) {
19 | currentChar = (str[i] & 0x1F) << 6 | (str[i+1] & 0x3F);
20 | i += 2;
21 | } else if (byte >= 0xE0 && byte <= 0xEF) {
22 | currentChar = (str[i] & 0x0F) << 12 | (str[i+1] & 0x3F) << 6 | (str[i+2] & 0x3F);
23 | i += 3;
24 | } else if (byte >= 0xF0 && byte <= 0xF7) {
25 | currentChar = (str[i] & 0x07) << 18 | (str[i+1] & 0x3F) << 12 | (str[i+2] & 0x3F) << 6 | (str[i+3] & 0x3F);
26 | i += 4;
27 | }
28 |
29 | if (currentChar >= 'A' && currentChar <= 'Z') {
30 | str[i-1] = tolower(str[i]);
31 | } else if (currentChar >= 1040 && currentChar <= 1071) { // диапазон А - Я
32 | int codepoint = currentChar + 32;
33 | str[i-2] = 0xC0 | (codepoint >> 6); // Старший байт
34 | str[i-1] = 0x80 | (codepoint & 0x3F); // Младший байт
35 | } else if (currentChar == 1025) { // Ё
36 | str[i-2] = 209;
37 | str[i-1] = 145;
38 | }
39 | }
40 |
41 | }
42 |
43 | */
44 | import "C"
45 | import "unsafe"
46 |
47 | // Go-обертка для вызова C функции
48 | func FastToLower(str string) string {
49 | cs := C.CString(str)
50 |
51 | C.fastToLower(cs)
52 | result := C.GoString(cs)
53 | C.free(unsafe.Pointer(cs))
54 |
55 | return result // *(*string)(unsafe.Pointer(&runes))
56 | }
57 |
58 | /*
59 | void fastToLower(char* str) {
60 | for (int i = 0; str[i] != '\0';) {
61 | unsigned char byte = str[i];
62 | if (byte <= 0x7F) {
63 | printf("%d ", byte); // Один байт (ASCII)
64 | i++;
65 | } else if (byte >= 0xC0 && byte <= 0xDF) {
66 | printf("%d ", (str[i] & 0x1F) << 6 | (str[i+1] & 0x3F));
67 | i += 2;
68 | } else if (byte >= 0xE0 && byte <= 0xEF) {
69 | printf("%d ", (str[i] & 0x0F) << 12 | (str[i+1] & 0x3F) << 6 | (str[i+2] & 0x3F));
70 | i += 3;
71 | } else if (byte >= 0xF0 && byte <= 0xF7) {
72 | printf("%d ", (str[i] & 0x07) << 18 | (str[i+1] & 0x3F) << 12 | (str[i+2] & 0x3F) << 6 | (str[i+3] & 0x3F));
73 | i += 4;
74 | }
75 | }
76 | printf("\n");
77 | }
78 |
79 |
80 | // передача рун
81 | #include // fFor free
82 | #include // for tolower
83 | #include
84 | // #include // for printf
85 |
86 | void fastToLower(int32_t* runes, int length) {
87 | for (int i = 0; i < length; i++) {
88 | if (runes[i] >= 'A' && runes[i] <= 'Z') {
89 | runes[i] = tolower(runes[i]);
90 | } else if (runes[i] >= 1040 && runes[i] <= 1071) { // диапазон А - Я
91 | runes[i] += 32;
92 | } else if (runes[i] == 1025) { // Ё
93 | runes[i] = 1105;
94 | }
95 | }
96 | }
97 |
98 | */
99 |
--------------------------------------------------------------------------------
/ast/grammar.y:
--------------------------------------------------------------------------------
1 | %{
2 | package ast
3 | %}
4 |
5 | %type body
6 | %type opt_body
7 | %type stmt
8 | %type stmt_loop
9 | %type funcProc
10 | %type stmt_if
11 | %type opt_elseif_list
12 | %type opt_else
13 | %type opt_stmt
14 | %type opt_param
15 | %type exprs
16 | %type expr
17 | %type opt_export
18 | %type opt_directive
19 | %type simple_expr
20 | %type declarations_method_params
21 | %type declarations_method_param
22 | %type opt_expr
23 | %type execute_param
24 | %type through_dot
25 | %type loopExp
26 | %type new_object
27 | %type ternary
28 | %type opt_explicit_variables
29 | %type explicit_variables
30 | %type identifiers
31 | %type stmt_tryCatch
32 | %type identifier
33 | %type goToLabel
34 | %type separator
35 | %type semicolon
36 | %type colon
37 | %type ':'
38 | %type ';'
39 | %type global_variables
40 |
41 |
42 |
43 | %union {
44 | token Token
45 | stmt_if *IfStatement
46 | opt_elseif_list []Statement
47 | opt_else []Statement
48 | stmt Statement
49 | stmt_loop *LoopStatement
50 | funcProc *FunctionOrProcedure
51 | body []Statement
52 | opt_body []Statement
53 | declarations_method_params []ParamStatement
54 | declarations_method_param ParamStatement
55 | exprs []Statement
56 | opt_export *Token
57 | opt_directive *Token
58 | explicit_variables map[string]VarStatement
59 | global_variables []GlobalVariables
60 | opt_explicit_variables map[string]VarStatement
61 | identifiers []Token
62 | goToLabel *GoToLabelStatement
63 | opt_goToLabel *GoToLabelStatement
64 | }
65 |
66 | %token Directive Identifier Procedure Var EndProcedure If Then ElseIf Else EndIf For Each In To Loop EndLoop Break Not ValueParam While GoToLabel
67 | %token Continue Try Catch EndTry Number String New Function EndFunction Return Throw NeEQ EQUAL LE GE OR And True False Undefind Export Date GoTo Execute
68 |
69 |
70 | %left OR
71 | %left And
72 | %left NeEQ
73 | %left LE
74 | %left GE
75 | %left Not
76 |
77 | %left EQUAL
78 | %left Identifier
79 | //%nonassoc COMPARE
80 |
81 | %left '>' '<'
82 | %left '+' '-'
83 | %left '*' '/' '%'
84 | %right UNARMinus UNARYPlus
85 |
86 |
87 | %%
88 |
89 | module: body {
90 | if ast, ok := yylex.(*AstNode); ok {
91 | ast.ModuleStatement.Append($1, yylex)
92 | }
93 | }
94 | | main_items opt_body {
95 | if ast, ok := yylex.(*AstNode); ok {
96 | ast.ModuleStatement.Append($2, yylex)
97 | }
98 | };
99 |
100 | main_items: main
101 | | main_items main
102 | ;
103 |
104 | main: global_variables {
105 | if ast, ok := yylex.(*AstNode); ok {
106 | ast.ModuleStatement.Append($1, yylex)
107 | }
108 | }
109 | | funcProc {
110 | if ast, ok := yylex.(*AstNode); ok {
111 | ast.ModuleStatement.Append($1, yylex)
112 | }
113 | }
114 | ;
115 |
116 | opt_directive: { $$ = nil}
117 | | Directive { $$ = &$1}
118 | ;
119 |
120 | opt_export: { $$ = nil}
121 | | Export { $$ = &$1}
122 | ;
123 |
124 | global_variables: opt_directive Var identifiers opt_export semicolon {
125 | $$ = make([]GlobalVariables, len($3), len($3))
126 | for i, v := range $3 {
127 | if $1 != nil {
128 | $$[i].Directive = $1.literal
129 | }
130 |
131 | $$[i].Export = $4 != nil
132 | $$[i].Var = VarStatement { Name: v.literal }
133 | }
134 | };
135 |
136 |
137 | funcProc: opt_directive Function Identifier '(' declarations_method_params ')' opt_export { isFunction(true, yylex) } opt_explicit_variables opt_body EndFunction
138 | {
139 | $$ = createFunctionOrProcedure(PFTypeFunction, $1, $3.literal, $5, $7, $9, $10)
140 | isFunction(false, yylex)
141 | }
142 | | opt_directive Procedure Identifier '(' declarations_method_params ')' opt_export opt_explicit_variables opt_body EndProcedure
143 | {
144 | $$ = createFunctionOrProcedure(PFTypeProcedure, $1, $3.literal, $5, $7, $8, $9)
145 | }
146 | ;
147 |
148 | opt_body: { $$ = nil }
149 | | body { $$ = $1 }
150 | ;
151 |
152 |
153 | body: stmt {
154 | if ast, ok := yylex.(*AstNode); ok {
155 | $$ = []Statement{ast.statementPostProcessing($1)}
156 | } else {
157 | $$ = []Statement{$1}
158 | }
159 | }
160 | | opt_body separator opt_stmt {
161 | if $2.literal == ":" && len($1) > 0 {
162 | if _, ok := $1[len($1)-1].(*GoToLabelStatement); !ok {
163 | yylex.Error("semicolon (;) is expected")
164 | }
165 | }
166 | if $3 != nil {
167 | $$ = append($$, $3)
168 | }
169 | }
170 |
171 | ;
172 |
173 | opt_stmt: { $$ = nil }
174 | | stmt {
175 | if ast, ok := yylex.(*AstNode); ok {
176 | $$ = ast.statementPostProcessing($1)
177 | } else {
178 | $$ = $1
179 | }
180 | }
181 | ;
182 |
183 | separator: semicolon { $$ = $1} | colon { $$ = $1};
184 |
185 |
186 | /* переменные */
187 | opt_explicit_variables: { $$ = map[string]VarStatement{} }
188 | | explicit_variables { $$ = $1 }
189 | ;
190 |
191 | explicit_variables: Var identifiers semicolon {
192 | if vars, err := appendVarStatements(map[string]VarStatement{}, $2); err != nil {
193 | yylex.Error(err.Error())
194 | } else {
195 | $$ = vars
196 | }
197 | }
198 | | explicit_variables Var identifiers semicolon {
199 | if vars, err := appendVarStatements($1, $3); err != nil {
200 | yylex.Error(err.Error())
201 | } else {
202 | $$ = vars
203 | }
204 | }
205 | ;
206 |
207 |
208 | /* Если Конецесли */
209 | stmt_if : If expr Then opt_body opt_elseif_list opt_else EndIf {
210 | $$ = &IfStatement {
211 | Expression: $2,
212 | TrueBlock: $4,
213 | IfElseBlock: $5,
214 | ElseBlock: $6,
215 | }
216 | };
217 |
218 | /* ИначеЕсли */
219 | opt_elseif_list : { $$ = []Statement{} }
220 | | ElseIf expr Then opt_body opt_elseif_list {
221 | $$ = append($5, &IfStatement{
222 | Expression: $2,
223 | TrueBlock: $4,
224 | })
225 | };
226 |
227 | /* Иначе */
228 | opt_else : { $$ = nil }
229 | | Else opt_body { $$ = $2 };
230 |
231 | /* тернарный оператор */
232 | ternary: '?' '(' expr comma expr comma expr ')' {
233 | $$ = TernaryStatement{
234 | Expression: $3,
235 | TrueBlock: $5,
236 | ElseBlock: $7,
237 | }
238 | };
239 |
240 | /* циклы */
241 | stmt_loop: For Each Identifier In loopExp Loop { setLoopFlag(true, yylex) } opt_body EndLoop {
242 | $$ = &LoopStatement{
243 | For: $3.literal,
244 | In: $5,
245 | Body: $8,
246 | }
247 | setLoopFlag(false, yylex)
248 | }
249 | | For expr To expr Loop { setLoopFlag(true, yylex) } opt_body EndLoop {
250 | $$ = &LoopStatement{
251 | For: $2,
252 | To: $4,
253 | Body: $7,
254 | }
255 | setLoopFlag(false, yylex)
256 | }
257 | |While expr Loop { setLoopFlag(true, yylex) } opt_body EndLoop {
258 | $$ = &LoopStatement{
259 | WhileExpr: $2,
260 | Body: $5,
261 | }
262 | };
263 |
264 |
265 | /* описыввает выражения которые можно использовать в циккле Для Каждого */
266 | loopExp: through_dot { $$ = $1 }
267 | | new_object { $$ = $1 }
268 | |'(' new_object ')' { $$ = $2 }
269 | ;
270 |
271 | stmt : expr { $$ = $1 }
272 | | stmt_if { $$ = $1 }
273 | | stmt_loop {$$ = $1 }
274 | | stmt_tryCatch { $$ = $1 }
275 | | Continue { $$ = ContinueStatement{}; checkLoopOperator($1, yylex) }
276 | | Break { $$ = BreakStatement{}; checkLoopOperator($1, yylex) }
277 | | Throw opt_param { $$ = ThrowStatement{ Param: $2 }; checkThrowParam($1, $2, yylex) }
278 | | Return opt_expr { $$ = &ReturnStatement{ Param: $2 }; checkReturnParam($2, yylex) }
279 | ;
280 |
281 | opt_param: { $$ = nil }
282 | | expr { $$ = $1 }
283 | ;
284 |
285 |
286 | /* вызовы через точку */
287 | through_dot: identifier { $$ = $1 }
288 | | through_dot dot identifier { $$ = CallChainStatement{ Unit: $3, Call: $1 } }
289 | ;
290 |
291 | /* вызовы процедур, функций */
292 | /* вызовы выполнить */
293 | /* выполнить может вызываться так выполнить("что-то") или так выполнить "что-то" */
294 | identifier: Identifier { $$ = VarStatement{ Name: $1.literal } }
295 | | Identifier '(' exprs ')' { $$ = MethodStatement{ Name: $1.literal, Param: $3 } }
296 | | identifier '[' expr ']' { $$ = ItemStatement{ Object: $1, Item: $3 } }
297 | | Execute execute_param { $$ = MethodStatement{ Name: $1.literal, Param: []Statement{$2} } }
298 | | Execute '(' expr ')' { $$ = MethodStatement{ Name: $1.literal, Param: []Statement{$3} } }
299 | ;
300 |
301 | execute_param: String { $$ = $1.value }
302 | | Identifier { $$ = VarStatement{ Name: $1.literal }};
303 |
304 | /* попытка */
305 | stmt_tryCatch: Try opt_body Catch { setTryFlag(true, yylex) } opt_body EndTry {
306 | $$ = TryStatement{ Body: $2, Catch: $5 }
307 | setTryFlag(false, yylex)
308 | };
309 |
310 | /* выражения */
311 | expr : simple_expr { $$ = $1 }
312 | |'(' expr ')' { $$ = $2 }
313 | | expr '+' expr { $$ = &ExpStatement{Operation: OpPlus, Left: $1, Right: $3} }
314 | | expr '-' expr { $$ = &ExpStatement{Operation: OpMinus, Left: $1, Right: $3} }
315 | | expr '*' expr { $$ = &ExpStatement{Operation: OpMul, Left: $1, Right: $3} }
316 | | expr '/' expr { $$ = &ExpStatement{Operation: OpDiv, Left: $1, Right: $3} }
317 | | expr '%' expr { $$ = &ExpStatement{Operation: OpMod, Left: $1, Right: $3} }
318 | | expr '>' expr { $$ = &ExpStatement{Operation: OpGt, Left: $1, Right: $3} }
319 | | expr '<' expr { $$ = &ExpStatement{Operation: OpLt, Left: $1, Right: $3} }
320 | | expr EQUAL expr {$$ = &ExpStatement{Operation: OpEq, Left: $1, Right: $3 }}
321 | | expr OR expr { $$ = &ExpStatement{Operation: OpOr, Left: $1, Right: $3 } }
322 | | expr And expr { $$ = &ExpStatement{Operation: OpAnd, Left: $1, Right: $3 } }
323 | | expr NeEQ expr { $$ = &ExpStatement{Operation: OpNe, Left: $1, Right: $3 } }
324 | | expr LE expr { $$ = &ExpStatement{Operation: OpLe, Left: $1, Right: $3 } }
325 | | expr GE expr { $$ = &ExpStatement{Operation: OpGe, Left: $1, Right: $3 } }
326 | | Not expr { $$ = not($2) }
327 | | new_object { $$ = $1 }
328 | | GoTo goToLabel { $$ = GoToStatement{ Label: $2 } }
329 | | ternary { $$ = $1 } /* тернарный оператор */
330 | | through_dot {
331 | if tok, ok := $1.(Token); ok {
332 | $$ = tok.literal
333 | } else {
334 | $$ = $1
335 | }
336 | }
337 | ;
338 |
339 | opt_expr: { $$ = nil } | expr { $$ = $1 };
340 |
341 | // опиасываются правила по которым можно объявлять параметры в функции или процедуре
342 | declarations_method_param: Identifier { $$ = *(&ParamStatement{}).Fill(nil, $1) } // обычный параметр
343 | | ValueParam Identifier { $$ = *(&ParamStatement{}).Fill(&$1, $2) } // знач
344 | | declarations_method_param EQUAL simple_expr { $$ = *($$.DefaultValue($3)) } // необязательный параметр
345 | ;
346 |
347 | declarations_method_params : { $$ = []ParamStatement{} }
348 | | declarations_method_param { $$ = []ParamStatement{$1} }
349 | | declarations_method_params comma declarations_method_param { $$ = append($1, $3) }
350 | ;
351 |
352 | // для ключевого слова Новый
353 | // 1С допускает такие конструкции
354 | // новый Структура(), новый Массив() ...
355 | // но так же и такие
356 | // Новый("РегистрСведенийКлючЗаписи.СостоянияОригиналовПервичныхДокументов", ПараметрыМассив);
357 | new_object: New Identifier { $$ = NewObjectStatement{ Constructor: $2.literal } }
358 | | New Identifier '(' exprs ')' { $$ = NewObjectStatement{ Constructor: $2.literal, Param: $4 } }
359 | | New '(' exprs ')' { $$ = NewObjectStatement{ Param: $3 } }
360 | ;
361 |
362 | simple_expr: String { $$ = $1.value }
363 | | Number { $$ = $1.value }
364 | | '-' expr %prec UNARMinus { $$ = unaryMinus($2) }
365 | | '+' expr %prec UNARYPlus { $$ = $2 }
366 | | True { $$ = $1.value }
367 | | False { $$ = $1.value }
368 | | Date { $$ = $1.value }
369 | | Undefind { $$ = UndefinedStatement{} }
370 | | goToLabel { $$ = $1}
371 | ;
372 |
373 | goToLabel: GoToLabel { $$ = &GoToLabelStatement{ Name: $1.literal } }
374 |
375 | exprs : opt_expr {$$ = []Statement{$1} }
376 | | exprs comma opt_expr { $$ = append($$, $3); }
377 | ;
378 |
379 | identifiers: Identifier { $$ = []Token{$1} }
380 | | identifiers comma Identifier {$$ = append($$, $3) }
381 | ;
382 |
383 | semicolon: ';' {$$ = $1};
384 | colon: ':'{$$ = $1};
385 | comma: ',';
386 | dot: '.';
387 |
388 | %%
--------------------------------------------------------------------------------
/ast/mock/mock.go:
--------------------------------------------------------------------------------
1 | // Code generated by MockGen. DO NOT EDIT.
2 | // Source: tokens.go
3 |
4 | // Package mock_ast is a generated GoMock package.
5 | package mock_ast
6 |
7 | import (
8 | reflect "reflect"
9 |
10 | gomock "github.com/golang/mock/gomock"
11 | )
12 |
13 | // MockIast is a mock of Iast interface.
14 | type MockIast struct {
15 | ctrl *gomock.Controller
16 | recorder *MockIastMockRecorder
17 | }
18 |
19 | // MockIastMockRecorder is the mock recorder for MockIast.
20 | type MockIastMockRecorder struct {
21 | mock *MockIast
22 | }
23 |
24 | // NewMockIast creates a new mock instance.
25 | func NewMockIast(ctrl *gomock.Controller) *MockIast {
26 | mock := &MockIast{ctrl: ctrl}
27 | mock.recorder = &MockIastMockRecorder{mock}
28 | return mock
29 | }
30 |
31 | // EXPECT returns an object that allows the caller to indicate expected use.
32 | func (m *MockIast) EXPECT() *MockIastMockRecorder {
33 | return m.recorder
34 | }
35 |
36 | // SrsCode mocks base method.
37 | func (m *MockIast) SrsCode() string {
38 | m.ctrl.T.Helper()
39 | ret := m.ctrl.Call(m, "SrsCode")
40 | ret0, _ := ret[0].(string)
41 | return ret0
42 | }
43 |
44 | // SrsCode indicates an expected call of SrsCode.
45 | func (mr *MockIastMockRecorder) SrsCode() *gomock.Call {
46 | mr.mock.ctrl.T.Helper()
47 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SrsCode", reflect.TypeOf((*MockIast)(nil).SrsCode))
48 | }
49 |
--------------------------------------------------------------------------------
/ast/tokens.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "strconv"
7 | "strings"
8 | "time"
9 | "unicode"
10 | "unicode/utf8"
11 | "unsafe"
12 | )
13 |
14 | //go:generate mockgen -source=$GOFILE -destination=./mock/mock.go
15 | type Iast interface {
16 | SrsCode() string
17 | }
18 |
19 | type Position struct {
20 | Line int
21 | Column int
22 | }
23 |
24 | type Token struct {
25 | ast Iast
26 | value interface{}
27 | literal string
28 | position Position
29 | offset int
30 | prevDot bool
31 | }
32 |
33 | const (
34 | EOL = '\n' // end of line.
35 | emptyLit = ""
36 | )
37 |
38 | var (
39 | tokens = map[string]int{
40 | "процедура": Procedure,
41 | "перем": Var,
42 | "перейти": GoTo,
43 | "конецпроцедуры": EndProcedure,
44 | "знач": ValueParam,
45 | "если": If,
46 | "тогда": Then,
47 | "иначеесли": ElseIf,
48 | "иначе": Else,
49 | "конецесли": EndIf,
50 | "для": For,
51 | "каждого": Each,
52 | "из": In,
53 | "по": To,
54 | "цикл": Loop,
55 | "конеццикла": EndLoop,
56 | "прервать": Break,
57 | "продолжить": Continue,
58 | "попытка": Try,
59 | "новый": New,
60 | "исключение": Catch,
61 | "пока": While,
62 | "конецпопытки": EndTry,
63 | "функция": Function,
64 | "конецфункции": EndFunction,
65 | "возврат": Return,
66 | "вызватьисключение": Throw,
67 | "и": And,
68 | "или": OR,
69 | "истина": True,
70 | "ложь": False,
71 | "неопределено": Undefind,
72 | "не": Not,
73 | "экспорт": Export,
74 | "выполнить": Execute,
75 | //"вычислить": Eval,
76 | // "массив": Array,
77 | // "структура": Struct,
78 | // "соответствие": Dictionary,
79 | }
80 |
81 | directives = map[string]int{
82 | "&наклиенте": Directive,
83 | "&насервере": Directive,
84 | "&насерверебезконтекста": Directive,
85 | "&наклиентенасерверебезконтекста": Directive,
86 | "&наклиентенасервере": Directive,
87 | }
88 | )
89 |
90 | func (t *Token) Next(ast Iast) (token int, err error) {
91 | t.ast = ast
92 | token, t.literal, err = t.next()
93 |
94 | switch token {
95 | case Number:
96 | t.value, err = strconv.ParseFloat(t.literal, 64)
97 | case String:
98 | t.value = t.literal
99 | case Date:
100 | formats := []string{"20060102", "200601021504", "20060102150405"} // Допускается опускать либо время целиком, либо только секунды.
101 | for _, f := range formats {
102 | // если все 0 это равносильно пустой дате
103 | if strings.Count(t.literal, "0") == len(t.literal) {
104 | t.value = time.Time{}
105 | return
106 | }
107 |
108 | if t.value, err = time.Parse(f, t.literal); err == nil {
109 | break
110 | }
111 | }
112 | case Undefind:
113 | t.value = nil
114 | case True:
115 | t.value = true
116 | case False:
117 | t.value = false
118 | }
119 |
120 | return
121 | }
122 |
123 | func (t *Token) next() (int, string, error) {
124 | t.skipSpace()
125 | t.skipComment()
126 | t.skipRegions()
127 |
128 | if t.prevDot {
129 | defer func() { t.prevDot = false }()
130 | }
131 |
132 | switch let := t.currentLet(); {
133 | case isLetter(let):
134 | literal := t.scanIdentifier()
135 | lowLit := fastToLower(literal)
136 |
137 | if tName, ok := tokens[lowLit]; ok && !t.prevDot {
138 | return tName, literal, nil
139 | } else {
140 | return Identifier, literal, nil
141 | }
142 | case let == '.':
143 | // если после точки у нас следует идентификатор то нам нужно читать его обычным идентификатором
144 | // Могут быть таие случаи стр.Истина = 1 или стр.Функция = 2 (стр в данном случае какой-то объект, например структура)
145 | // нам нужно что бы то что следует после точки считалось Identifier, а не определенным зарезервированным токеном
146 | t.prevDot = true
147 |
148 | t.nextPos()
149 | return int(let), string(let), nil
150 | case isDigit(let):
151 | if literal, err := t.scanNumber(); err != nil {
152 | return EOF, emptyLit, err
153 | } else {
154 | return Number, literal, nil
155 | }
156 |
157 | case let == 0x27:
158 | literal, err := t.scanString(let)
159 | if err != nil {
160 | return EOF, emptyLit, err
161 | }
162 |
163 | // В литерале даты игнорируются все значения, отличные от цифр.
164 | if literal = extractDigits(literal); literal == "" {
165 | return EOF, emptyLit, fmt.Errorf("incorrect Date type constant")
166 | }
167 |
168 | return Date, literal, nil
169 | case let == '/' || let == ';' || let == '(' || let == ')' || let == ',' || let == '-' || let == '+' || let == '*' || let == '?' || let == '[' || let == ']' || let == ':' || let == '%':
170 | t.nextPos()
171 | return int(let), string(let), nil
172 | case let == '=':
173 | t.nextPos()
174 | return EQUAL, string(let), nil
175 | case let == '"':
176 | literal, err := t.scanString(let)
177 | if err != nil {
178 | return EOF, emptyLit, err
179 | }
180 |
181 | return String, literal, nil
182 | case let == '<':
183 | if t.nextLet() == '>' {
184 | t.nextPos()
185 | t.nextPos()
186 | return NeEQ, "<>", nil
187 | } else if t.nextLet() == '=' {
188 | t.nextPos()
189 | t.nextPos()
190 | return LE, "<=", nil
191 | } else {
192 | t.nextPos()
193 | return int(let), string(let), nil
194 | }
195 | case let == '>':
196 | if t.nextLet() == '=' {
197 | t.nextPos()
198 | t.nextPos()
199 | return GE, ">=", nil
200 | } else {
201 | t.nextPos()
202 | return int(let), string(let), nil
203 | }
204 |
205 | // case let == '#':
206 | // literal, err := t.scanIdentifier()
207 | // if err != nil {
208 | // return EOF, emptyLit, err
209 | // }
210 |
211 | case let == '&':
212 | t.nextPos()
213 | pos := t.offset
214 |
215 | literal := t.scanIdentifier()
216 | lowLit := fastToLower("&" + literal)
217 |
218 | if tName, ok := directives[lowLit]; ok {
219 | return tName, "&" + literal, nil
220 | } else {
221 | t.offset = pos
222 | return int(let), string(let), fmt.Errorf(`syntax error %q`, string(let))
223 | }
224 | case let == '~':
225 | t.nextPos()
226 | return GoToLabel, t.scanIdentifier(), nil
227 | default:
228 | switch let {
229 | case EOF:
230 | t.nextPos()
231 | return EOF, emptyLit, nil
232 | // case '\n':
233 | // t.nextPos()
234 | // return int(let), string(let), nil
235 | default:
236 | t.nextPos()
237 | return int(let), string(let), fmt.Errorf(`syntax error %q`, string(let))
238 | }
239 | }
240 | }
241 |
242 | func (t *Token) scanIdentifier() string {
243 | ret := make([]rune, 0, 10) // как правило встречаются короткие идентификаторы и лучше предаллоцировать, это сильный буст дает
244 |
245 | for {
246 | let := t.currentLet()
247 | if !isLetter(let) && !isDigit(let) {
248 | break
249 | }
250 |
251 | ret = append(ret, let)
252 | t.nextPos()
253 | }
254 |
255 | return string(ret)
256 | }
257 |
258 | func (t *Token) scanString(end rune) (string, error) {
259 | var ret []rune
260 |
261 | eos:
262 | for {
263 | t.nextPos()
264 |
265 | switch cl := t.currentLet(); {
266 | case cl == EOL:
267 | t.nextPos()
268 | if cl = t.currentLet(); cl != '|' && !isSpace(cl) {
269 | return "", fmt.Errorf("unexpected EOL")
270 | }
271 |
272 | ret = append(append(ret, EOL), cl)
273 | case cl == EOF:
274 | return "", fmt.Errorf("unexpected EOF")
275 | case cl == end:
276 | // пропускаем двойные "
277 | if t.nextLet() == '"' {
278 | t.nextPos()
279 | ret = append(ret, '"', '"')
280 | continue
281 | }
282 |
283 | t.nextPos()
284 | break eos
285 | default:
286 | ret = append(ret, cl)
287 | }
288 | }
289 |
290 | return string(ret), nil
291 | }
292 |
293 | func (t *Token) skipSpace() {
294 | for isSpace(t.currentLet()) {
295 | t.nextPos()
296 | }
297 | }
298 |
299 | func (t *Token) skipComment() {
300 | if t.currentLet() == '/' && t.nextLet() == '/' {
301 | for ch := t.currentLet(); ch != EOL && ch != EOF; ch = t.currentLet() {
302 | t.nextPos()
303 | }
304 | t.skipSpace()
305 | } else {
306 | return
307 | }
308 |
309 | // проверяем что на новой строке нет комментария или новой области, если есть, рекурсия
310 | if cl := t.currentLet(); cl == '/' {
311 | t.skipComment()
312 | } else if cl := t.currentLet(); cl == '#' {
313 | t.skipRegions()
314 | }
315 | }
316 |
317 | func (t *Token) skipRegions() {
318 | // todo пока будут пропускаться и условия типа #Если Не ВебКлиент Тогда, потом надо будет доработать
319 | if t.currentLet() == '#' {
320 | for ch := t.currentLet(); ch != EOL && ch != EOF; ch = t.currentLet() {
321 | t.nextPos()
322 | }
323 | t.skipSpace()
324 | }
325 |
326 | // проверяем что на новой строке нет комментария или новой области, если есть, рекурсия
327 | if cl := t.currentLet(); cl == '/' {
328 | t.skipComment()
329 | } else if cl := t.currentLet(); cl == '#' {
330 | t.skipRegions()
331 | }
332 | }
333 |
334 | func (t *Token) nextLet() rune {
335 | srsCode := t.ast.SrsCode()
336 | _, size := utf8.DecodeRuneInString(srsCode[t.offset:])
337 | t.offset += size
338 | defer func() { t.offset -= size }()
339 |
340 | return t.currentLet()
341 | }
342 |
343 | func (t *Token) currentLet() rune {
344 | srsCode := t.ast.SrsCode()
345 |
346 | if t.offset >= len(srsCode) {
347 | return EOF
348 | }
349 |
350 | char, _ := utf8.DecodeRuneInString(srsCode[t.offset:])
351 | if char == utf8.RuneError {
352 | fmt.Println(fmt.Errorf("error decoding the character"))
353 | return char
354 | }
355 |
356 | return char
357 | }
358 |
359 | func (t *Token) GetPosition() Position {
360 | srsCode := t.ast.SrsCode()
361 | eol := strings.LastIndex(srsCode[:t.offset], "\n") + 1
362 | lineBegin := IF[int](eol < 0, 0, eol)
363 |
364 | return Position{
365 | Line: strings.Count(srsCode[:t.offset], "\n") + 1,
366 | Column: len([]rune(srsCode[lineBegin:t.offset])) + 1,
367 | }
368 | }
369 |
370 | func (t *Token) nextPos() {
371 | srsCode := t.ast.SrsCode()
372 | _, size := utf8.DecodeRuneInString(srsCode[t.offset:])
373 | t.offset += size
374 | }
375 |
376 | func (t *Token) scanNumber() (string, error) {
377 | var ret []rune
378 |
379 | let := t.currentLet()
380 | for ; isDigit(let) || let == '.'; let = t.currentLet() {
381 | ret = append(ret, let)
382 | t.nextPos()
383 | }
384 |
385 | if isLetter(let) {
386 | return "", fmt.Errorf("identifier immediately follow the number")
387 | }
388 |
389 | return string(ret), nil
390 | }
391 |
392 | func isLetter(ch rune) bool {
393 | return unicode.IsLetter(ch) || ch == '_'
394 | }
395 |
396 | func isDigit(ch rune) bool {
397 | return '0' <= ch && ch <= '9'
398 | }
399 |
400 | func isSpace(ch rune) bool {
401 | return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'
402 | }
403 |
404 | func IF[T any](condition bool, a, b T) T {
405 | if condition {
406 | return a
407 | } else {
408 | return b
409 | }
410 | }
411 |
412 | func IsDigit(str string) bool {
413 | for _, c := range str {
414 | if c < '0' || c > '9' {
415 | return false
416 | }
417 | }
418 | return true
419 | }
420 |
421 | func extractDigits(str string) string {
422 | result := make([]rune, 0, len(str))
423 | for _, c := range str {
424 | if c >= '0' && c <= '9' {
425 | result = append(result, c)
426 | }
427 | }
428 | return string(result)
429 | }
430 |
431 | func fastToLower_old(s string) string {
432 | rs := bytes.NewBuffer(make([]byte, 0, len(s)))
433 | for _, rn := range s {
434 | switch {
435 | case (rn >= 'А' && rn <= 'Я') || (rn >= 'A' && rn <= 'Z'):
436 | rs.WriteRune(rn + 0x20)
437 | case rn == 'Ё':
438 | rs.WriteRune('ё')
439 | default:
440 | rs.WriteRune(rn)
441 | }
442 | }
443 | return rs.String()
444 | }
445 |
446 | func fastToLower(s string) string {
447 | b := []byte(s)
448 | for i, r := range s {
449 | switch {
450 | case r >= 'A' && r <= 'Z':
451 | b[i] = s[i] + ('a' - 'A')
452 | case r >= 'А' && r <= 'Я':
453 | if s[i] == 208 && r > 'П' { // от "П" и дальше
454 | b[i], b[i+1] = b[i]+1, s[i+1]-('а'-'А')
455 | } else {
456 | b[i+1] = s[i+1] + ('а' - 'А')
457 | }
458 | case r == 'Ё':
459 | b[i], b[i+1] = 209, 145
460 | }
461 | }
462 |
463 | return unsafe.String(unsafe.SliceData(b), len(b))
464 | }
465 |
--------------------------------------------------------------------------------
/ast/tokens_test.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import (
4 | "crypto/rand"
5 | "fmt"
6 | //"github.com/LazarenkoA/1c-language-parser/ast/fast_tolower"
7 | mock_ast "github.com/LazarenkoA/1c-language-parser/ast/mock"
8 | "github.com/golang/mock/gomock"
9 | "regexp"
10 | "strings"
11 | "testing"
12 |
13 | "github.com/stretchr/testify/assert"
14 | )
15 |
16 | func Test_Next(t *testing.T) {
17 | c := gomock.NewController(t)
18 | defer c.Finish()
19 |
20 | t.Run("var & Identifier", func(t *testing.T) {
21 | ast := mock_ast.NewMockIast(c)
22 | ast.EXPECT().SrsCode().Return(` Перем ввв; ввв = 3;`).AnyTimes()
23 | tok := new(Token)
24 | token, err := tok.Next(ast)
25 | assert.NoError(t, err)
26 | assert.Equal(t, "Перем", tok.literal)
27 | assert.Equal(t, token, Var)
28 |
29 | token, err = tok.Next(ast)
30 | assert.NoError(t, err)
31 | assert.Equal(t, "ввв", tok.literal)
32 | assert.Equal(t, token, Identifier)
33 | })
34 |
35 | t.Run("error", func(t *testing.T) {
36 | ast := mock_ast.NewMockIast(c)
37 | ast.EXPECT().SrsCode().Return(` 2ввв`).AnyTimes()
38 | tok := new(Token)
39 | _, err := tok.Next(ast)
40 | assert.EqualError(t, err, "identifier immediately follow the number")
41 | })
42 |
43 | t.Run("Number", func(t *testing.T) {
44 | ast := mock_ast.NewMockIast(c)
45 | ast.EXPECT().SrsCode().Return(`32323 `).AnyTimes()
46 | tok := new(Token)
47 | token, err := tok.Next(ast)
48 | assert.NoError(t, err)
49 | assert.Equal(t, "32323", tok.literal)
50 | assert.Equal(t, token, Number)
51 | })
52 |
53 | t.Run("String", func(t *testing.T) {
54 | t.Run("", func(t *testing.T) {
55 | tok := new(Token)
56 | ast := mock_ast.NewMockIast(c)
57 | ast.EXPECT().SrsCode().Return(`тестПерем = "тест тест"`).AnyTimes()
58 |
59 | token, err := tok.Next(ast)
60 | assert.NoError(t, err)
61 | assert.Equal(t, "тестПерем", tok.literal)
62 | assert.Equal(t, token, Identifier)
63 |
64 | token, err = tok.Next(ast)
65 | assert.NoError(t, err)
66 | assert.Equal(t, "=", tok.literal)
67 | assert.Equal(t, token, EQUAL)
68 |
69 | token, err = tok.Next(ast)
70 | assert.NoError(t, err)
71 | assert.Equal(t, "тест тест", tok.literal)
72 | assert.Equal(t, token, String)
73 | })
74 | t.Run("", func(t *testing.T) {
75 | ast := mock_ast.NewMockIast(c)
76 | ast.EXPECT().SrsCode().Return(`тестПерем = "тест ""тест"" fd"`).AnyTimes()
77 | tok := new(Token)
78 |
79 | token, err := tok.Next(ast)
80 | assert.NoError(t, err)
81 | assert.Equal(t, "тестПерем", tok.literal)
82 | assert.Equal(t, token, Identifier)
83 |
84 | token, err = tok.Next(ast)
85 | assert.NoError(t, err)
86 | assert.Equal(t, "=", tok.literal)
87 | assert.Equal(t, token, EQUAL)
88 |
89 | token, err = tok.Next(ast)
90 | assert.NoError(t, err)
91 | assert.Equal(t, "тест \"\"тест\"\" fd", tok.literal)
92 | assert.Equal(t, token, String)
93 | })
94 | t.Run("date", func(t *testing.T) {
95 | t.Run("pass", func(t *testing.T) {
96 | ast := mock_ast.NewMockIast(c)
97 | ast.EXPECT().SrsCode().Return(`тестПерем = '00010101'`).AnyTimes()
98 | tok := new(Token)
99 |
100 | token, err := tok.Next(ast)
101 | assert.NoError(t, err)
102 | assert.Equal(t, "тестПерем", tok.literal)
103 | assert.Equal(t, token, Identifier)
104 |
105 | token, err = tok.Next(ast)
106 | assert.NoError(t, err)
107 | assert.Equal(t, "=", tok.literal)
108 | assert.Equal(t, token, EQUAL)
109 |
110 | token, err = tok.Next(ast)
111 | assert.NoError(t, err)
112 | assert.Equal(t, "00010101", tok.literal)
113 | assert.Equal(t, token, Date)
114 | })
115 | t.Run("error", func(t *testing.T) {
116 | ast := mock_ast.NewMockIast(c)
117 | ast.EXPECT().SrsCode().Return(`тестПерем = 'gfdgfg'`).AnyTimes()
118 | tok := new(Token)
119 |
120 | token, err := tok.Next(ast)
121 | assert.NoError(t, err)
122 | assert.Equal(t, "тестПерем", tok.literal)
123 | assert.Equal(t, token, Identifier)
124 |
125 | token, err = tok.Next(ast)
126 | assert.NoError(t, err)
127 | assert.Equal(t, "=", tok.literal)
128 | assert.Equal(t, token, EQUAL)
129 |
130 | token, err = tok.Next(ast)
131 | assert.EqualError(t, err, "incorrect Date type constant")
132 | })
133 | })
134 | })
135 |
136 | t.Run("String error", func(t *testing.T) {
137 | tok := new(Token)
138 | ast := mock_ast.NewMockIast(c)
139 | ast.EXPECT().SrsCode().Return(`тестПерем = "тест тест`).AnyTimes()
140 |
141 | token, err := tok.Next(ast)
142 | assert.NoError(t, err)
143 | assert.Equal(t, "тестПерем", tok.literal)
144 | assert.Equal(t, token, Identifier)
145 |
146 | token, err = tok.Next(ast)
147 | assert.NoError(t, err)
148 | assert.Equal(t, "=", tok.literal)
149 | assert.Equal(t, token, EQUAL)
150 |
151 | token, err = tok.Next(ast)
152 | assert.EqualError(t, err, "unexpected EOF")
153 | })
154 |
155 | t.Run("String error", func(t *testing.T) {
156 | ast := mock_ast.NewMockIast(c)
157 | ast.EXPECT().SrsCode().Return(`тестПерем = "тест тест
158 | `).AnyTimes()
159 | tok := new(Token)
160 | token, err := tok.Next(ast)
161 | assert.NoError(t, err)
162 | assert.Equal(t, "тестПерем", tok.literal)
163 | assert.Equal(t, token, Identifier)
164 |
165 | token, err = tok.Next(ast)
166 | assert.NoError(t, err)
167 | assert.Equal(t, "=", tok.literal)
168 | assert.Equal(t, token, EQUAL)
169 |
170 | token, err = tok.Next(ast)
171 | assert.EqualError(t, err, "unexpected EOL")
172 | })
173 |
174 | t.Run("String", func(t *testing.T) {
175 | ast := mock_ast.NewMockIast(c)
176 | ast.EXPECT().SrsCode().Return(`тестПерем = "тест тест
177 | |ааа fd
178 | | wqwq ww"`).AnyTimes()
179 | tok := new(Token)
180 |
181 | token, err := tok.Next(ast)
182 | assert.NoError(t, err)
183 | assert.Equal(t, "тестПерем", tok.literal)
184 | assert.Equal(t, token, Identifier)
185 |
186 | token, err = tok.Next(ast)
187 | assert.NoError(t, err)
188 | assert.Equal(t, "=", tok.literal)
189 | assert.Equal(t, token, EQUAL)
190 |
191 | token, err = tok.Next(ast)
192 | assert.NoError(t, err)
193 | assert.Equal(t, `тест тест
194 | |ааа fd
195 | | wqwq ww`, tok.literal)
196 | assert.Equal(t, token, String)
197 | })
198 |
199 | t.Run("String error", func(t *testing.T) {
200 | ast := mock_ast.NewMockIast(c)
201 | ast.EXPECT().SrsCode().Return(`тестПерем = "тест тест
202 | |ааа fd
203 | | wqwq ww`).AnyTimes()
204 |
205 | tok := new(Token)
206 |
207 | token, err := tok.Next(ast)
208 | assert.NoError(t, err)
209 | assert.Equal(t, "тестПерем", tok.literal)
210 | assert.Equal(t, token, Identifier)
211 |
212 | token, err = tok.Next(ast)
213 | assert.NoError(t, err)
214 | assert.Equal(t, "=", tok.literal)
215 | assert.Equal(t, token, EQUAL)
216 |
217 | token, err = tok.Next(ast)
218 | assert.EqualError(t, err, "unexpected EOF")
219 | })
220 |
221 | t.Run("operators", func(t *testing.T) {
222 | ast := mock_ast.NewMockIast(c)
223 | ast.EXPECT().SrsCode().Return(`Если РЗ <> Неопределено И ппп или ррр Тогда`).AnyTimes()
224 |
225 | tok := new(Token)
226 |
227 | token, err := tok.Next(ast)
228 | assert.NoError(t, err)
229 | assert.Equal(t, "Если", tok.literal)
230 | assert.Equal(t, token, If)
231 |
232 | token, err = tok.Next(ast)
233 | assert.NoError(t, err)
234 | assert.Equal(t, "РЗ", tok.literal)
235 | assert.Equal(t, token, Identifier)
236 |
237 | token, err = tok.Next(ast)
238 | assert.NoError(t, err)
239 | assert.Equal(t, "<>", tok.literal)
240 | assert.Equal(t, token, NeEQ)
241 |
242 | token, err = tok.Next(ast)
243 | assert.NoError(t, err)
244 | assert.Equal(t, "Неопределено", tok.literal)
245 | assert.Equal(t, token, Undefind)
246 |
247 | token, err = tok.Next(ast)
248 | assert.NoError(t, err)
249 | assert.Equal(t, "И", tok.literal)
250 | assert.Equal(t, token, And)
251 |
252 | token, err = tok.Next(ast)
253 | assert.NoError(t, err)
254 | assert.Equal(t, "ппп", tok.literal)
255 | assert.Equal(t, token, Identifier)
256 |
257 | token, err = tok.Next(ast)
258 | assert.NoError(t, err)
259 | assert.Equal(t, "или", tok.literal)
260 | assert.Equal(t, token, OR)
261 |
262 | token, err = tok.Next(ast)
263 | assert.NoError(t, err)
264 | assert.Equal(t, "ррр", tok.literal)
265 | assert.Equal(t, token, Identifier)
266 |
267 | token, err = tok.Next(ast)
268 | assert.NoError(t, err)
269 | assert.Equal(t, "Тогда", tok.literal)
270 | assert.Equal(t, token, Then)
271 | })
272 |
273 | t.Run("comment", func(t *testing.T) {
274 | ast := mock_ast.NewMockIast(c)
275 | ast.EXPECT().SrsCode().Return(` Перем ввв;
276 | // ввв = 3;
277 | d = 0;`).AnyTimes()
278 | tok := new(Token)
279 |
280 | result := []string{"Перем", "ввв", ";", "d", "=", "0", ";"}
281 |
282 | i := 0
283 | for token, err := tok.Next(ast); err == nil && token > 0; token, err = tok.Next(ast) {
284 | assert.Equal(t, result[i], tok.literal)
285 | i++
286 | }
287 | })
288 |
289 | t.Run("math", func(t *testing.T) {
290 | ast := mock_ast.NewMockIast(c)
291 | ast.EXPECT().SrsCode().Return(`тест = 2+2*2+(2-1);`).AnyTimes()
292 |
293 | tok := new(Token)
294 |
295 | result := []string{"тест", "=", "2", "+", "2", "*", "2", "+", "(", "2", "-", "1", ")", ";"}
296 |
297 | i := 0
298 | for token, err := tok.Next(ast); err == nil && token > 0; token, err = tok.Next(ast) {
299 | assert.Equal(t, result[i], tok.literal)
300 | i++
301 | }
302 | })
303 |
304 | t.Run("directive", func(t *testing.T) {
305 | ast := mock_ast.NewMockIast(c)
306 | ast.EXPECT().SrsCode().Return(`&НаСервере
307 | Процедура ДобавитьРегистрНаСервере()
308 |
309 | КонецПроцедуры`).AnyTimes()
310 |
311 | tok := new(Token)
312 |
313 | result := map[string]int{
314 | "&НаСервере": Directive,
315 | "Процедура": Procedure,
316 | "ДобавитьРегистрНаСервере": Identifier,
317 | "КонецПроцедуры": EndProcedure,
318 | "(": '(',
319 | ")": ')',
320 | "\n": 10,
321 | }
322 |
323 | for token, err := tok.Next(ast); err == nil && token > 0; token, err = tok.Next(ast) {
324 | assert.Equal(t, token, result[tok.literal])
325 | }
326 | })
327 |
328 | t.Run("goto", func(t *testing.T) {
329 | ast := mock_ast.NewMockIast(c)
330 | ast.EXPECT().SrsCode().Return(`Процедура ДобавитьРегистрНаСервере()
331 | перейти ~метка;
332 | ~метка:
333 | КонецПроцедуры`).AnyTimes()
334 |
335 | tok := new(Token)
336 |
337 | result := map[string]int{
338 | "Процедура": Procedure,
339 | "ДобавитьРегистрНаСервере": Identifier,
340 | "КонецПроцедуры": EndProcedure,
341 | "(": '(',
342 | ")": ')',
343 | "перейти": GoTo,
344 | "метка": GoToLabel,
345 | ";": ';',
346 | ":": ':',
347 | }
348 |
349 | for token, err := tok.Next(ast); err == nil && token > 0; token, err = tok.Next(ast) {
350 | assert.Equal(t, token, result[tok.literal])
351 | }
352 | })
353 |
354 | t.Run("date", func(t *testing.T) {
355 | t.Run("test1", func(t *testing.T) {
356 | ast := mock_ast.NewMockIast(c)
357 | ast.EXPECT().SrsCode().Return(`test = '20241111'`).AnyTimes()
358 |
359 | tok := new(Token)
360 |
361 | token, err := tok.Next(ast)
362 | assert.NoError(t, err)
363 | assert.Equal(t, "test", tok.literal)
364 | assert.Equal(t, token, Identifier)
365 |
366 | token, err = tok.Next(ast)
367 | assert.NoError(t, err)
368 | assert.Equal(t, "=", tok.literal)
369 |
370 | token, err = tok.Next(ast)
371 | assert.NoError(t, err)
372 | assert.Equal(t, "20241111", tok.literal)
373 | assert.Equal(t, token, Date)
374 | })
375 | t.Run("test2", func(t *testing.T) {
376 | ast := mock_ast.NewMockIast(c)
377 | ast.EXPECT().SrsCode().Return(`test = '00000000'`).AnyTimes()
378 |
379 | tok := new(Token)
380 |
381 | token, err := tok.Next(ast)
382 | assert.NoError(t, err)
383 | assert.Equal(t, "test", tok.literal)
384 | assert.Equal(t, token, Identifier)
385 |
386 | token, err = tok.Next(ast)
387 | assert.NoError(t, err)
388 | assert.Equal(t, "=", tok.literal)
389 |
390 | token, err = tok.Next(ast)
391 | assert.NoError(t, err)
392 | assert.Equal(t, "00000000", tok.literal)
393 | assert.Equal(t, token, Date)
394 | })
395 | })
396 | }
397 |
398 | func Benchmark(b *testing.B) {
399 | c := gomock.NewController(b)
400 | defer c.Finish()
401 |
402 | ast := mock_ast.NewMockIast(c)
403 |
404 | b.Run("isDigit", func(b *testing.B) {
405 | str := "12324567376566736kl"
406 | b.Run("tLoop", func(b *testing.B) {
407 | for i := 0; i < b.N; i++ {
408 | IsDigit(str)
409 | }
410 | })
411 | b.Run("RegExp1", func(b *testing.B) {
412 | for i := 0; i < b.N; i++ {
413 | IsDigitRegExp(str)
414 | }
415 | })
416 | b.Run("RegExp2", func(b *testing.B) {
417 | re := regexp.MustCompile(`[0-9]+`)
418 | for i := 0; i < b.N; i++ {
419 | re.MatchString(str)
420 | }
421 | })
422 | })
423 | b.Run("string concatenation", func(b *testing.B) {
424 | var test string
425 | b.Run("strings.Builder", func(b *testing.B) {
426 | builder := strings.Builder{}
427 | for i := 0; i < b.N; i++ {
428 | builder.WriteString(generateRandomString(50))
429 | }
430 | test = builder.String()
431 | })
432 | b.Run("fmt.Sprintf", func(b *testing.B) {
433 | for i := 0; i < b.N; i++ {
434 | test = fmt.Sprintf("%s%s", test, generateRandomString(50))
435 | }
436 | })
437 | b.Run("concatenation", func(b *testing.B) {
438 | for i := 0; i < b.N; i++ {
439 | test += generateRandomString(50)
440 | }
441 | })
442 | _ = test
443 | })
444 | b.Run("next", func(b *testing.B) {
445 | ast.EXPECT().SrsCode().Return(`
446 |
447 | Процедура ОткрытьНавигационнуюСсылку(НавигационнаяСсылка, Знач Оповещение = Неопределено) Экспорт
448 |
449 | ПустаяДата = '00010101000000';
450 | ПустаяДата = '20131231235959';
451 |
452 | КлючЗаписиРегистра = Новый("РегистрСведенийКлючЗаписи.СостоянияОригиналовПервичныхДокументов", ПараметрыМассив);
453 | МассаДМ = ВыборкаЕдИзм.МассаДМ/Количество;
454 |
455 | стр = новый Структура("Цикл", 1);
456 | стр.Цикл = 0;
457 |
458 | Если КодСимвола < 1040 ИЛИ КодСимвола > 1103 И КодыДопустимыхСимволов.Найти(КодСимвола) = Неопределено И Не (Не УчитыватьРазделителиСлов И ЭтоРазделительСлов(КодСимвола)) Тогда
459 | Возврат ;
460 | КонецЕсли;
461 |
462 | перейти ~метка;
463 |
464 | МассивСтроки.Добавить(Новый ФорматированнаяСтрока(ЧастьСтроки.Значение, Новый Шрифт(,,Истина)));
465 |
466 | Позиция = Найти(Строка, Разделитель);
467 | Пока Позиция > 0 Цикл
468 | Подстрока = Лев(Строка, Позиция - 1);
469 | Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Подстрока) Тогда
470 | Если СокращатьНепечатаемыеСимволы Тогда
471 | Результат.Добавить(СокрЛП(Подстрока));
472 | Иначе
473 | Результат.Добавить(Подстрока);
474 | КонецЕсли;
475 | КонецЕсли;
476 | Строка = Сред(Строка, Позиция + СтрДлина(Разделитель));
477 | Позиция = Найти(Строка, Разделитель);
478 | КонецЦикла;
479 |
480 | ~метка:
481 |
482 |
483 |
484 | вы = ввывыв[0];
485 | СтрокаСпискаПП[ТекКолонка.Ключ].Вставить(ТекКолонкаЗначение.Ключ, УровеньГруппировки3[ПрефиксПоля + СтрЗаменить(ТекКолонкаЗначение.Значение, ".", "")]);
486 |
487 | Контекст = Новый Структура();
488 | Контекст.Вставить("НавигационнаяСсылка", НавигационнаяСсылка);
489 | Контекст.Вставить("Оповещение", Оповещение);
490 |
491 | ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
492 | НСтр("ru = 'Не удалось перейти по ссылке ""%1"" по причине:
493 | |Неверно задана навигационная ссылка.'"),
494 | НавигационнаяСсылка);
495 |
496 | Если Не ОбщегоНазначенияСлужебныйКлиент.ЭтоДопустимаяСсылка(НавигационнаяСсылка) Тогда
497 | ОбщегоНазначенияСлужебныйКлиент.ОткрытьНавигационнуюСсылкуОповеститьОбОшибке(ОписаниеОшибки, Контекст);
498 | Возврат;
499 | КонецЕсли;
500 |
501 | Если ОбщегоНазначенияСлужебныйКлиент.ЭтоВебСсылка(НавигационнаяСсылка)
502 | Или ОбщегоНазначенияСлужебныйКлиент.ЭтоНавигационнаяСсылка(НавигационнаяСсылка) Тогда
503 |
504 | Попытка
505 | а = а /0;
506 | Исключение
507 | ОбщегоНазначенияСлужебныйКлиент.ОткрытьНавигационнуюСсылкуОповеститьОбОшибке(ОписаниеОшибки, Контекст);
508 | Возврат;
509 | КонецПопытки;
510 |
511 | Если Оповещение <> Неопределено Тогда
512 | ПриложениеЗапущено = Истина;
513 | ВыполнитьОбработкуОповещения(Оповещение, ПриложениеЗапущено);
514 | КонецЕсли;
515 |
516 | Возврат;
517 | КонецЕсли;
518 |
519 | Если ОбщегоНазначенияСлужебныйКлиент.ЭтоСсылкаНаСправку(НавигационнаяСсылка) Тогда
520 | ОткрытьСправку(НавигационнаяСсылка);
521 | Возврат;
522 | КонецЕсли;
523 | КонецПроцедуры`)
524 |
525 | tok := new(Token)
526 | tok.ast = ast
527 | for i := 0; i < b.N; i++ {
528 | for _, _, err := tok.next(); err != nil; _, _, err = tok.next() {
529 |
530 | }
531 | }
532 | })
533 | }
534 |
535 | func IsDigitRegExp(str string) bool {
536 | re := regexp.MustCompile(`[0-9]+`)
537 | if re.MatchString(str) {
538 | return true
539 | }
540 | return false
541 | }
542 |
543 | func generateRandomString(length int) string {
544 | b := make([]byte, length)
545 | _, err := rand.Read(b)
546 | if err != nil {
547 | return ""
548 | }
549 | return strings.TrimRight(string(b), "\x00")
550 | }
551 |
552 | func Benchmark_fastToLower(b *testing.B) {
553 | str := "ЫСВАМВАОЛОРИИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHЫСВАМВАОЛОРЫСВАМВАОЛОРИИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJЫСВАМВАОЛОРИЫСВАМВАОЛОРИИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJЫСВАМВАОЛОРИИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJЫСВАМВАОЛОРИИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJЫСВАМВАОЛОРИИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJЫСВАМВАОЛОРИИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJЫСВАМВАОЛОРИИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJЫСВАМВАОЛОРИИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJЫСВАМВАОЛОРИИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJЫСВАМВАОЛОРИИОРОВИЫОРСЫВРООЫОРВЫРОJHDSDHSDSJDDSHDSJHDJSDERKRVEKVJDSJHDJSDERKRVEKVJ"
554 |
555 | b.Run("sdk", func(b *testing.B) {
556 | for i := 0; i < b.N; i++ {
557 | strings.ToLower(str)
558 | }
559 | })
560 | b.Run("fastToLower-old", func(b *testing.B) {
561 | for i := 0; i < b.N; i++ {
562 | fastToLower_old(str)
563 | }
564 | })
565 | b.Run("fastToLower", func(b *testing.B) {
566 | for i := 0; i < b.N; i++ {
567 | fastToLower(str)
568 | }
569 | })
570 | //b.Run("fastToLowerС", func(b *testing.B) {
571 | // for i := 0; i < b.N; i++ {
572 | // fast_tolower.FastToLower(str)
573 | // }
574 | //})
575 | }
576 |
577 | //func Test_fastToLower(t *testing.T) {
578 | // str := "АаБбСсДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮюЯяAaZz"
579 | //
580 | // assert.Equal(t, fastToLower(str), strings.ToLower(str))
581 | // assert.Equal(t, fast_tolower.FastToLower(str), strings.ToLower(str))
582 | //}
583 |
--------------------------------------------------------------------------------
/ast/y.go:
--------------------------------------------------------------------------------
1 | // Code generated by goyacc .\grammar.y. DO NOT EDIT.
2 |
3 | //line .\grammar.y:1
4 |
5 | package ast
6 |
7 | import __yyfmt__ "fmt"
8 |
9 | //line .\grammar.y:3
10 |
11 | //line .\grammar.y:43
12 | type yySymType struct {
13 | yys int
14 | token Token
15 | stmt_if *IfStatement
16 | opt_elseif_list []Statement
17 | opt_else []Statement
18 | stmt Statement
19 | stmt_loop *LoopStatement
20 | funcProc *FunctionOrProcedure
21 | body []Statement
22 | opt_body []Statement
23 | declarations_method_params []ParamStatement
24 | declarations_method_param ParamStatement
25 | exprs []Statement
26 | opt_export *Token
27 | opt_directive *Token
28 | explicit_variables map[string]VarStatement
29 | global_variables []GlobalVariables
30 | opt_explicit_variables map[string]VarStatement
31 | identifiers []Token
32 | goToLabel *GoToLabelStatement
33 | opt_goToLabel *GoToLabelStatement
34 | }
35 |
36 | const Directive = 57346
37 | const Identifier = 57347
38 | const Procedure = 57348
39 | const Var = 57349
40 | const EndProcedure = 57350
41 | const If = 57351
42 | const Then = 57352
43 | const ElseIf = 57353
44 | const Else = 57354
45 | const EndIf = 57355
46 | const For = 57356
47 | const Each = 57357
48 | const In = 57358
49 | const To = 57359
50 | const Loop = 57360
51 | const EndLoop = 57361
52 | const Break = 57362
53 | const Not = 57363
54 | const ValueParam = 57364
55 | const While = 57365
56 | const GoToLabel = 57366
57 | const Continue = 57367
58 | const Try = 57368
59 | const Catch = 57369
60 | const EndTry = 57370
61 | const Number = 57371
62 | const String = 57372
63 | const New = 57373
64 | const Function = 57374
65 | const EndFunction = 57375
66 | const Return = 57376
67 | const Throw = 57377
68 | const NeEQ = 57378
69 | const EQUAL = 57379
70 | const LE = 57380
71 | const GE = 57381
72 | const OR = 57382
73 | const And = 57383
74 | const True = 57384
75 | const False = 57385
76 | const Undefind = 57386
77 | const Export = 57387
78 | const Date = 57388
79 | const GoTo = 57389
80 | const Execute = 57390
81 | const UNARMinus = 57391
82 | const UNARYPlus = 57392
83 |
84 | var yyToknames = [...]string{
85 | "$end",
86 | "error",
87 | "$unk",
88 | "':'",
89 | "';'",
90 | "Directive",
91 | "Identifier",
92 | "Procedure",
93 | "Var",
94 | "EndProcedure",
95 | "If",
96 | "Then",
97 | "ElseIf",
98 | "Else",
99 | "EndIf",
100 | "For",
101 | "Each",
102 | "In",
103 | "To",
104 | "Loop",
105 | "EndLoop",
106 | "Break",
107 | "Not",
108 | "ValueParam",
109 | "While",
110 | "GoToLabel",
111 | "Continue",
112 | "Try",
113 | "Catch",
114 | "EndTry",
115 | "Number",
116 | "String",
117 | "New",
118 | "Function",
119 | "EndFunction",
120 | "Return",
121 | "Throw",
122 | "NeEQ",
123 | "EQUAL",
124 | "LE",
125 | "GE",
126 | "OR",
127 | "And",
128 | "True",
129 | "False",
130 | "Undefind",
131 | "Export",
132 | "Date",
133 | "GoTo",
134 | "Execute",
135 | "'>'",
136 | "'<'",
137 | "'+'",
138 | "'-'",
139 | "'*'",
140 | "'/'",
141 | "'%'",
142 | "UNARMinus",
143 | "UNARYPlus",
144 | "'('",
145 | "')'",
146 | "'?'",
147 | "'['",
148 | "']'",
149 | "','",
150 | "'.'",
151 | }
152 |
153 | var yyStatenames = [...]string{}
154 |
155 | const yyEofCode = 1
156 | const yyErrCode = 2
157 | const yyInitialStackSize = 16
158 |
159 | //line .\grammar.y:388
160 |
161 | //line yacctab:1
162 | var yyExca = [...]int8{
163 | -1, 0,
164 | 4, 15,
165 | 5, 15,
166 | -2, 7,
167 | -1, 1,
168 | 1, -1,
169 | -2, 0,
170 | -1, 2,
171 | 1, 1,
172 | -2, 16,
173 | -1, 3,
174 | 8, 7,
175 | 9, 7,
176 | 34, 7,
177 | -2, 15,
178 | }
179 |
180 | const yyPrivate = 57344
181 |
182 | const yyLast = 593
183 |
184 | var yyAct = [...]uint8{
185 | 7, 5, 49, 193, 116, 45, 157, 145, 132, 17,
186 | 20, 156, 133, 122, 67, 69, 23, 40, 51, 70,
187 | 71, 74, 121, 88, 182, 75, 77, 78, 68, 79,
188 | 137, 136, 83, 84, 63, 60, 64, 65, 61, 62,
189 | 176, 172, 161, 120, 135, 135, 135, 58, 59, 53,
190 | 54, 55, 56, 57, 96, 97, 98, 99, 100, 101,
191 | 102, 103, 104, 105, 106, 107, 108, 63, 60, 64,
192 | 65, 61, 62, 143, 134, 139, 43, 135, 135, 135,
193 | 58, 59, 53, 54, 55, 56, 57, 69, 123, 124,
194 | 69, 110, 126, 134, 135, 58, 59, 53, 54, 55,
195 | 56, 57, 38, 85, 4, 93, 174, 89, 87, 43,
196 | 60, 135, 125, 127, 129, 55, 56, 57, 38, 44,
197 | 42, 69, 58, 59, 53, 54, 55, 56, 57, 150,
198 | 92, 158, 152, 153, 140, 154, 141, 167, 140, 149,
199 | 128, 69, 163, 138, 178, 148, 37, 166, 159, 160,
200 | 165, 140, 44, 95, 162, 201, 86, 195, 91, 52,
201 | 51, 168, 53, 54, 55, 56, 57, 179, 72, 173,
202 | 117, 183, 175, 173, 52, 51, 177, 131, 188, 155,
203 | 185, 184, 189, 190, 186, 187, 119, 118, 112, 51,
204 | 207, 82, 80, 41, 43, 200, 199, 197, 24, 115,
205 | 202, 203, 73, 25, 130, 206, 205, 6, 208, 12,
206 | 19, 46, 26, 42, 11, 27, 169, 81, 30, 29,
207 | 38, 52, 51, 14, 13, 52, 51, 52, 51, 52,
208 | 51, 33, 34, 36, 181, 35, 21, 44, 198, 43,
209 | 32, 31, 192, 24, 191, 3, 170, 18, 25, 39,
210 | 1, 171, 52, 51, 12, 19, 15, 26, 42, 11,
211 | 27, 146, 50, 30, 29, 38, 52, 51, 14, 13,
212 | 52, 51, 204, 48, 43, 10, 33, 34, 36, 194,
213 | 35, 21, 44, 22, 76, 32, 31, 47, 2, 147,
214 | 19, 90, 18, 42, 39, 28, 66, 94, 30, 29,
215 | 38, 164, 8, 16, 9, 0, 43, 0, 0, 0,
216 | 0, 33, 34, 36, 0, 35, 21, 44, 0, 0,
217 | 32, 31, 19, 0, 60, 42, 65, 18, 0, 39,
218 | 30, 29, 38, 0, 0, 0, 58, 59, 53, 54,
219 | 55, 56, 57, 33, 34, 36, 0, 35, 21, 44,
220 | 0, 0, 32, 31, 0, 63, 60, 64, 65, 18,
221 | 62, 39, 63, 60, 64, 65, 61, 62, 58, 59,
222 | 53, 54, 55, 56, 57, 58, 59, 53, 54, 55,
223 | 56, 57, 63, 60, 64, 65, 61, 62, 142, 0,
224 | 0, 0, 0, 0, 0, 58, 59, 53, 54, 55,
225 | 56, 57, 0, 0, 0, 196, 63, 60, 64, 65,
226 | 61, 62, 0, 0, 0, 0, 0, 0, 0, 58,
227 | 59, 53, 54, 55, 56, 57, 0, 0, 180, 144,
228 | 63, 60, 64, 65, 61, 62, 0, 0, 0, 0,
229 | 0, 0, 0, 58, 59, 53, 54, 55, 56, 57,
230 | 0, 0, 0, 109, 63, 60, 64, 65, 61, 62,
231 | 151, 0, 0, 0, 0, 0, 0, 58, 59, 53,
232 | 54, 55, 56, 57, 0, 0, 0, 0, 63, 60,
233 | 64, 65, 61, 62, 114, 0, 0, 0, 0, 0,
234 | 113, 58, 59, 53, 54, 55, 56, 57, 0, 0,
235 | 0, 0, 63, 60, 64, 65, 61, 62, 111, 63,
236 | 60, 64, 65, 61, 62, 58, 59, 53, 54, 55,
237 | 56, 57, 58, 59, 53, 54, 55, 56, 57, 0,
238 | 0, 0, 0, 0, 63, 60, 64, 65, 61, 62,
239 | 0, 63, 60, 64, 65, 0, 0, 58, 59, 53,
240 | 54, 55, 56, 57, 58, 59, 53, 54, 55, 56,
241 | 57, 60, 64, 65, 42, 0, 0, 0, 0, 30,
242 | 29, 0, 0, 58, 59, 53, 54, 55, 56, 57,
243 | 0, 0, 33, 34, 36, 0, 35, 0, 0, 0,
244 | 0, 32, 31,
245 | }
246 |
247 | var yyPact = [...]int16{
248 | 187, -1000, -1000, 187, -1000, 266, -1000, -4, -1000, -1000,
249 | -1000, -1000, -1000, 299, 299, -1000, -1000, -1000, 299, 299,
250 | -1000, 94, -1000, -45, 299, 267, 299, 232, 183, -1000,
251 | -1000, 299, 299, -1000, -1000, -1000, -1000, -1000, 96, 48,
252 | -40, -1000, -1000, 47, 98, 266, -1000, -1000, 232, -1000,
253 | -1000, -1000, -1000, 299, 299, 299, 299, 299, 299, 299,
254 | 299, 299, 299, 299, 299, 299, -1000, -4, -1000, -4,
255 | 392, 71, -1000, 102, -1000, 496, 181, 471, 464, 170,
256 | 163, 180, 179, -1000, -1000, -17, 299, 299, 299, 299,
257 | -1000, 299, -1000, -1000, -1000, -1000, 60, 60, -1000, -1000,
258 | -1000, 109, 109, 44, 317, 503, 522, 285, 71, -1000,
259 | -40, 232, 122, 299, -1000, -1000, 46, -1000, -29, -30,
260 | 299, 14, -1000, 29, 324, 12, 368, 248, 69, 440,
261 | 232, 232, 184, 172, -1000, -1000, 124, 124, -19, -1000,
262 | 299, 299, -1000, -1000, -1000, 136, 299, 117, -45, -1000,
263 | 85, -1000, 225, 221, -1000, -1000, -20, 67, -1000, 165,
264 | -21, -1000, -1000, 29, 129, 232, 416, -1000, -37, 232,
265 | -1000, -1000, 27, 124, 538, -1000, 27, 299, -1000, 266,
266 | 232, 232, -1000, 223, -1000, 67, -1000, 148, 344, 248,
267 | 217, -1000, 148, 232, 146, 163, -1000, -1000, -1000, 232,
268 | 262, 163, 13, 155, -1000, 13, -1000, -1000, -1000,
269 | }
270 |
271 | var yyPgo = [...]int16{
272 | 0, 287, 1, 104, 304, 303, 302, 7, 301, 297,
273 | 296, 22, 0, 8, 295, 9, 11, 6, 13, 291,
274 | 16, 289, 10, 283, 3, 279, 4, 275, 17, 146,
275 | 273, 2, 262, 256, 250, 245, 207, 242, 12, 234,
276 | 216, 204, 202, 177,
277 | }
278 |
279 | var yyR1 = [...]int8{
280 | 0, 34, 34, 35, 35, 36, 36, 14, 14, 13,
281 | 13, 33, 37, 5, 5, 2, 2, 1, 1, 9,
282 | 9, 30, 30, 24, 24, 25, 25, 6, 7, 7,
283 | 8, 8, 23, 39, 4, 40, 4, 41, 4, 21,
284 | 21, 21, 3, 3, 3, 3, 3, 3, 3, 3,
285 | 10, 10, 20, 20, 28, 28, 28, 28, 28, 19,
286 | 19, 43, 27, 12, 12, 12, 12, 12, 12, 12,
287 | 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
288 | 12, 12, 12, 18, 18, 17, 17, 17, 16, 16,
289 | 16, 22, 22, 22, 15, 15, 15, 15, 15, 15,
290 | 15, 15, 15, 29, 11, 11, 26, 26, 31, 32,
291 | 38, 42,
292 | }
293 |
294 | var yyR2 = [...]int8{
295 | 0, 1, 2, 1, 2, 1, 1, 0, 1, 0,
296 | 1, 5, 0, 11, 10, 0, 1, 1, 3, 0,
297 | 1, 1, 1, 0, 1, 3, 4, 7, 0, 5,
298 | 0, 2, 8, 0, 9, 0, 8, 0, 6, 1,
299 | 1, 3, 1, 1, 1, 1, 1, 1, 2, 2,
300 | 0, 1, 1, 3, 1, 4, 4, 2, 4, 1,
301 | 1, 0, 6, 1, 3, 3, 3, 3, 3, 3,
302 | 3, 3, 3, 3, 3, 3, 3, 3, 2, 1,
303 | 2, 1, 1, 0, 1, 1, 2, 3, 0, 1,
304 | 3, 2, 5, 4, 1, 1, 2, 2, 1, 1,
305 | 1, 1, 1, 1, 1, 3, 1, 3, 1, 1,
306 | 1, 1,
307 | }
308 |
309 | var yyChk = [...]int16{
310 | -1000, -34, -1, -35, -3, -2, -36, -12, -6, -4,
311 | -27, 27, 22, 37, 36, -33, -5, -15, 60, 23,
312 | -22, 49, -23, -20, 11, 16, 25, 28, -14, 32,
313 | 31, 54, 53, 44, 45, 48, 46, -29, 33, 62,
314 | -28, 6, 26, 7, 50, -2, -36, -1, -30, -31,
315 | -32, 5, 4, 53, 54, 55, 56, 57, 51, 52,
316 | 39, 42, 43, 38, 40, 41, -10, -12, -18, -12,
317 | -12, -12, -29, -42, 66, -12, 17, -12, -12, -2,
318 | 9, 34, 8, -12, -12, 7, 60, 60, 63, 60,
319 | -19, 60, 32, 7, -9, -3, -12, -12, -12, -12,
320 | -12, -12, -12, -12, -12, -12, -12, -12, -12, 61,
321 | -28, 12, 7, 19, 20, 29, -26, 7, 7, 7,
322 | 60, -11, -18, -12, -12, -11, -12, -2, 18, -12,
323 | -41, -43, -13, -38, 47, 65, 60, 60, -11, 61,
324 | -38, -38, 64, 61, 61, -7, 13, -21, -20, -22,
325 | 60, 20, -2, -2, -31, 7, -16, -17, 7, 24,
326 | -16, 61, -18, -12, -8, 14, -12, 20, -22, -40,
327 | 21, 30, 61, -38, 39, 7, 61, -38, 15, -2,
328 | 12, -39, 61, -2, -13, -17, -15, -13, -12, -2,
329 | -2, 21, -37, -24, -25, 9, 61, -7, 21, -24,
330 | -2, 9, -26, -2, 10, -26, -31, 35, -31,
331 | }
332 |
333 | var yyDef = [...]int8{
334 | -2, -2, -2, -2, 17, 0, 3, 42, 43, 44,
335 | 45, 46, 47, 50, 83, 5, 6, 63, 0, 0,
336 | 79, 0, 81, 82, 0, 0, 0, 15, 0, 94,
337 | 95, 0, 0, 98, 99, 100, 101, 102, 0, 0,
338 | 52, 8, 103, 54, 0, 2, 4, 16, 19, 21,
339 | 22, 108, 109, 0, 0, 0, 0, 0, 0, 0,
340 | 0, 0, 0, 0, 0, 0, 48, 51, 49, 84,
341 | 0, 78, 80, 0, 111, 0, 0, 0, 0, 0,
342 | 0, 0, 0, 96, 97, 91, 83, 0, 0, 83,
343 | 57, 0, 59, 60, 18, 20, 65, 66, 67, 68,
344 | 69, 70, 71, 72, 73, 74, 75, 76, 77, 64,
345 | 53, 15, 0, 0, 37, 61, 9, 106, 0, 0,
346 | 83, 0, 104, 0, 0, 0, 0, 28, 0, 0,
347 | 15, 15, 0, 0, 10, 110, 88, 88, 0, 93,
348 | 83, 0, 56, 55, 58, 30, 0, 0, 39, 40,
349 | 0, 35, 0, 0, 11, 107, 0, 89, 85, 0,
350 | 0, 92, 105, 0, 0, 15, 0, 33, 0, 15,
351 | 38, 62, 9, 0, 0, 86, 9, 0, 27, 31,
352 | 15, 15, 41, 0, 12, 90, 87, 23, 0, 28,
353 | 0, 36, 23, 15, 24, 0, 32, 29, 34, 15,
354 | 0, 0, 0, 0, 14, 0, 25, 13, 26,
355 | }
356 |
357 | var yyTok1 = [...]int8{
358 | 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
359 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
360 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
361 | 3, 3, 3, 3, 3, 3, 3, 57, 3, 3,
362 | 60, 61, 55, 53, 65, 54, 66, 56, 3, 3,
363 | 3, 3, 3, 3, 3, 3, 3, 3, 4, 5,
364 | 52, 3, 51, 62, 3, 3, 3, 3, 3, 3,
365 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
366 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
367 | 3, 63, 3, 64,
368 | }
369 |
370 | var yyTok2 = [...]int8{
371 | 2, 3, 6, 7, 8, 9, 10, 11, 12, 13,
372 | 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
373 | 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
374 | 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
375 | 44, 45, 46, 47, 48, 49, 50, 58, 59,
376 | }
377 |
378 | var yyTok3 = [...]int8{
379 | 0,
380 | }
381 |
382 | var yyErrorMessages = [...]struct {
383 | state int
384 | token int
385 | msg string
386 | }{}
387 |
388 | //line yaccpar:1
389 |
390 | /* parser for yacc output */
391 |
392 | var (
393 | yyDebug = 0
394 | yyErrorVerbose = false
395 | )
396 |
397 | type yyLexer interface {
398 | Lex(lval *yySymType) int
399 | Error(s string)
400 | }
401 |
402 | type yyParser interface {
403 | Parse(yyLexer) int
404 | Lookahead() int
405 | }
406 |
407 | type yyParserImpl struct {
408 | lval yySymType
409 | stack [yyInitialStackSize]yySymType
410 | char int
411 | }
412 |
413 | func (p *yyParserImpl) Lookahead() int {
414 | return p.char
415 | }
416 |
417 | func yyNewParser() yyParser {
418 | return &yyParserImpl{}
419 | }
420 |
421 | const yyFlag = -1000
422 |
423 | func yyTokname(c int) string {
424 | if c >= 1 && c-1 < len(yyToknames) {
425 | if yyToknames[c-1] != "" {
426 | return yyToknames[c-1]
427 | }
428 | }
429 | return __yyfmt__.Sprintf("tok-%v", c)
430 | }
431 |
432 | func yyStatname(s int) string {
433 | if s >= 0 && s < len(yyStatenames) {
434 | if yyStatenames[s] != "" {
435 | return yyStatenames[s]
436 | }
437 | }
438 | return __yyfmt__.Sprintf("state-%v", s)
439 | }
440 |
441 | func yyErrorMessage(state, lookAhead int) string {
442 | const TOKSTART = 4
443 |
444 | if !yyErrorVerbose {
445 | return "syntax error"
446 | }
447 |
448 | for _, e := range yyErrorMessages {
449 | if e.state == state && e.token == lookAhead {
450 | return "syntax error: " + e.msg
451 | }
452 | }
453 |
454 | res := "syntax error: unexpected " + yyTokname(lookAhead)
455 |
456 | // To match Bison, suggest at most four expected tokens.
457 | expected := make([]int, 0, 4)
458 |
459 | // Look for shiftable tokens.
460 | base := int(yyPact[state])
461 | for tok := TOKSTART; tok-1 < len(yyToknames); tok++ {
462 | if n := base + tok; n >= 0 && n < yyLast && int(yyChk[int(yyAct[n])]) == tok {
463 | if len(expected) == cap(expected) {
464 | return res
465 | }
466 | expected = append(expected, tok)
467 | }
468 | }
469 |
470 | if yyDef[state] == -2 {
471 | i := 0
472 | for yyExca[i] != -1 || int(yyExca[i+1]) != state {
473 | i += 2
474 | }
475 |
476 | // Look for tokens that we accept or reduce.
477 | for i += 2; yyExca[i] >= 0; i += 2 {
478 | tok := int(yyExca[i])
479 | if tok < TOKSTART || yyExca[i+1] == 0 {
480 | continue
481 | }
482 | if len(expected) == cap(expected) {
483 | return res
484 | }
485 | expected = append(expected, tok)
486 | }
487 |
488 | // If the default action is to accept or reduce, give up.
489 | if yyExca[i+1] != 0 {
490 | return res
491 | }
492 | }
493 |
494 | for i, tok := range expected {
495 | if i == 0 {
496 | res += ", expecting "
497 | } else {
498 | res += " or "
499 | }
500 | res += yyTokname(tok)
501 | }
502 | return res
503 | }
504 |
505 | func yylex1(lex yyLexer, lval *yySymType) (char, token int) {
506 | token = 0
507 | char = lex.Lex(lval)
508 | if char <= 0 {
509 | token = int(yyTok1[0])
510 | goto out
511 | }
512 | if char < len(yyTok1) {
513 | token = int(yyTok1[char])
514 | goto out
515 | }
516 | if char >= yyPrivate {
517 | if char < yyPrivate+len(yyTok2) {
518 | token = int(yyTok2[char-yyPrivate])
519 | goto out
520 | }
521 | }
522 | for i := 0; i < len(yyTok3); i += 2 {
523 | token = int(yyTok3[i+0])
524 | if token == char {
525 | token = int(yyTok3[i+1])
526 | goto out
527 | }
528 | }
529 |
530 | out:
531 | if token == 0 {
532 | token = int(yyTok2[1]) /* unknown char */
533 | }
534 | if yyDebug >= 3 {
535 | __yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char))
536 | }
537 | return char, token
538 | }
539 |
540 | func yyParse(yylex yyLexer) int {
541 | return yyNewParser().Parse(yylex)
542 | }
543 |
544 | func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int {
545 | var yyn int
546 | var yyVAL yySymType
547 | var yyDollar []yySymType
548 | _ = yyDollar // silence set and not used
549 | yyS := yyrcvr.stack[:]
550 |
551 | Nerrs := 0 /* number of errors */
552 | Errflag := 0 /* error recovery flag */
553 | yystate := 0
554 | yyrcvr.char = -1
555 | yytoken := -1 // yyrcvr.char translated into internal numbering
556 | defer func() {
557 | // Make sure we report no lookahead when not parsing.
558 | yystate = -1
559 | yyrcvr.char = -1
560 | yytoken = -1
561 | }()
562 | yyp := -1
563 | goto yystack
564 |
565 | ret0:
566 | return 0
567 |
568 | ret1:
569 | return 1
570 |
571 | yystack:
572 | /* put a state and value onto the stack */
573 | if yyDebug >= 4 {
574 | __yyfmt__.Printf("char %v in %v\n", yyTokname(yytoken), yyStatname(yystate))
575 | }
576 |
577 | yyp++
578 | if yyp >= len(yyS) {
579 | nyys := make([]yySymType, len(yyS)*2)
580 | copy(nyys, yyS)
581 | yyS = nyys
582 | }
583 | yyS[yyp] = yyVAL
584 | yyS[yyp].yys = yystate
585 |
586 | yynewstate:
587 | yyn = int(yyPact[yystate])
588 | if yyn <= yyFlag {
589 | goto yydefault /* simple state */
590 | }
591 | if yyrcvr.char < 0 {
592 | yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval)
593 | }
594 | yyn += yytoken
595 | if yyn < 0 || yyn >= yyLast {
596 | goto yydefault
597 | }
598 | yyn = int(yyAct[yyn])
599 | if int(yyChk[yyn]) == yytoken { /* valid shift */
600 | yyrcvr.char = -1
601 | yytoken = -1
602 | yyVAL = yyrcvr.lval
603 | yystate = yyn
604 | if Errflag > 0 {
605 | Errflag--
606 | }
607 | goto yystack
608 | }
609 |
610 | yydefault:
611 | /* default state action */
612 | yyn = int(yyDef[yystate])
613 | if yyn == -2 {
614 | if yyrcvr.char < 0 {
615 | yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval)
616 | }
617 |
618 | /* look through exception table */
619 | xi := 0
620 | for {
621 | if yyExca[xi+0] == -1 && int(yyExca[xi+1]) == yystate {
622 | break
623 | }
624 | xi += 2
625 | }
626 | for xi += 2; ; xi += 2 {
627 | yyn = int(yyExca[xi+0])
628 | if yyn < 0 || yyn == yytoken {
629 | break
630 | }
631 | }
632 | yyn = int(yyExca[xi+1])
633 | if yyn < 0 {
634 | goto ret0
635 | }
636 | }
637 | if yyn == 0 {
638 | /* error ... attempt to resume parsing */
639 | switch Errflag {
640 | case 0: /* brand new error */
641 | yylex.Error(yyErrorMessage(yystate, yytoken))
642 | Nerrs++
643 | if yyDebug >= 1 {
644 | __yyfmt__.Printf("%s", yyStatname(yystate))
645 | __yyfmt__.Printf(" saw %s\n", yyTokname(yytoken))
646 | }
647 | fallthrough
648 |
649 | case 1, 2: /* incompletely recovered error ... try again */
650 | Errflag = 3
651 |
652 | /* find a state where "error" is a legal shift action */
653 | for yyp >= 0 {
654 | yyn = int(yyPact[yyS[yyp].yys]) + yyErrCode
655 | if yyn >= 0 && yyn < yyLast {
656 | yystate = int(yyAct[yyn]) /* simulate a shift of "error" */
657 | if int(yyChk[yystate]) == yyErrCode {
658 | goto yystack
659 | }
660 | }
661 |
662 | /* the current p has no shift on "error", pop stack */
663 | if yyDebug >= 2 {
664 | __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys)
665 | }
666 | yyp--
667 | }
668 | /* there is no state on the stack with an error shift ... abort */
669 | goto ret1
670 |
671 | case 3: /* no shift yet; clobber input char */
672 | if yyDebug >= 2 {
673 | __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yytoken))
674 | }
675 | if yytoken == yyEofCode {
676 | goto ret1
677 | }
678 | yyrcvr.char = -1
679 | yytoken = -1
680 | goto yynewstate /* try again in the same state */
681 | }
682 | }
683 |
684 | /* reduction by production yyn */
685 | if yyDebug >= 2 {
686 | __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate))
687 | }
688 |
689 | yynt := yyn
690 | yypt := yyp
691 | _ = yypt // guard against "declared and not used"
692 |
693 | yyp -= int(yyR2[yyn])
694 | // yyp is now the index of $0. Perform the default action. Iff the
695 | // reduced production is ε, $1 is possibly out of range.
696 | if yyp+1 >= len(yyS) {
697 | nyys := make([]yySymType, len(yyS)*2)
698 | copy(nyys, yyS)
699 | yyS = nyys
700 | }
701 | yyVAL = yyS[yyp+1]
702 |
703 | /* consult goto table to find next state */
704 | yyn = int(yyR1[yyn])
705 | yyg := int(yyPgo[yyn])
706 | yyj := yyg + yyS[yyp].yys + 1
707 |
708 | if yyj >= yyLast {
709 | yystate = int(yyAct[yyg])
710 | } else {
711 | yystate = int(yyAct[yyj])
712 | if int(yyChk[yystate]) != -yyn {
713 | yystate = int(yyAct[yyg])
714 | }
715 | }
716 | // dummy call; replaced with literal code
717 | switch yynt {
718 |
719 | case 1:
720 | yyDollar = yyS[yypt-1 : yypt+1]
721 | //line .\grammar.y:89
722 | {
723 | if ast, ok := yylex.(*AstNode); ok {
724 | ast.ModuleStatement.Append(yyDollar[1].body, yylex)
725 | }
726 | }
727 | case 2:
728 | yyDollar = yyS[yypt-2 : yypt+1]
729 | //line .\grammar.y:94
730 | {
731 | if ast, ok := yylex.(*AstNode); ok {
732 | ast.ModuleStatement.Append(yyDollar[2].opt_body, yylex)
733 | }
734 | }
735 | case 5:
736 | yyDollar = yyS[yypt-1 : yypt+1]
737 | //line .\grammar.y:104
738 | {
739 | if ast, ok := yylex.(*AstNode); ok {
740 | ast.ModuleStatement.Append(yyDollar[1].global_variables, yylex)
741 | }
742 | }
743 | case 6:
744 | yyDollar = yyS[yypt-1 : yypt+1]
745 | //line .\grammar.y:109
746 | {
747 | if ast, ok := yylex.(*AstNode); ok {
748 | ast.ModuleStatement.Append(yyDollar[1].funcProc, yylex)
749 | }
750 | }
751 | case 7:
752 | yyDollar = yyS[yypt-0 : yypt+1]
753 | //line .\grammar.y:116
754 | {
755 | yyVAL.opt_directive = nil
756 | }
757 | case 8:
758 | yyDollar = yyS[yypt-1 : yypt+1]
759 | //line .\grammar.y:117
760 | {
761 | yyVAL.opt_directive = &yyDollar[1].token
762 | }
763 | case 9:
764 | yyDollar = yyS[yypt-0 : yypt+1]
765 | //line .\grammar.y:120
766 | {
767 | yyVAL.opt_export = nil
768 | }
769 | case 10:
770 | yyDollar = yyS[yypt-1 : yypt+1]
771 | //line .\grammar.y:121
772 | {
773 | yyVAL.opt_export = &yyDollar[1].token
774 | }
775 | case 11:
776 | yyDollar = yyS[yypt-5 : yypt+1]
777 | //line .\grammar.y:124
778 | {
779 | yyVAL.global_variables = make([]GlobalVariables, len(yyDollar[3].identifiers), len(yyDollar[3].identifiers))
780 | for i, v := range yyDollar[3].identifiers {
781 | if yyDollar[1].opt_directive != nil {
782 | yyVAL.global_variables[i].Directive = yyDollar[1].opt_directive.literal
783 | }
784 |
785 | yyVAL.global_variables[i].Export = yyDollar[4].opt_export != nil
786 | yyVAL.global_variables[i].Var = VarStatement{Name: v.literal}
787 | }
788 | }
789 | case 12:
790 | yyDollar = yyS[yypt-7 : yypt+1]
791 | //line .\grammar.y:137
792 | {
793 | isFunction(true, yylex)
794 | }
795 | case 13:
796 | yyDollar = yyS[yypt-11 : yypt+1]
797 | //line .\grammar.y:138
798 | {
799 | yyVAL.funcProc = createFunctionOrProcedure(PFTypeFunction, yyDollar[1].opt_directive, yyDollar[3].token.literal, yyDollar[5].declarations_method_params, yyDollar[7].opt_export, yyDollar[9].opt_explicit_variables, yyDollar[10].opt_body)
800 | isFunction(false, yylex)
801 | }
802 | case 14:
803 | yyDollar = yyS[yypt-10 : yypt+1]
804 | //line .\grammar.y:143
805 | {
806 | yyVAL.funcProc = createFunctionOrProcedure(PFTypeProcedure, yyDollar[1].opt_directive, yyDollar[3].token.literal, yyDollar[5].declarations_method_params, yyDollar[7].opt_export, yyDollar[8].opt_explicit_variables, yyDollar[9].opt_body)
807 | }
808 | case 15:
809 | yyDollar = yyS[yypt-0 : yypt+1]
810 | //line .\grammar.y:148
811 | {
812 | yyVAL.opt_body = nil
813 | }
814 | case 16:
815 | yyDollar = yyS[yypt-1 : yypt+1]
816 | //line .\grammar.y:149
817 | {
818 | yyVAL.opt_body = yyDollar[1].body
819 | }
820 | case 17:
821 | yyDollar = yyS[yypt-1 : yypt+1]
822 | //line .\grammar.y:153
823 | {
824 | if ast, ok := yylex.(*AstNode); ok {
825 | yyVAL.body = []Statement{ast.statementPostProcessing(yyDollar[1].stmt)}
826 | } else {
827 | yyVAL.body = []Statement{yyDollar[1].stmt}
828 | }
829 | }
830 | case 18:
831 | yyDollar = yyS[yypt-3 : yypt+1]
832 | //line .\grammar.y:160
833 | {
834 | if yyDollar[2].token.literal == ":" && len(yyDollar[1].opt_body) > 0 {
835 | if _, ok := yyDollar[1].opt_body[len(yyDollar[1].opt_body)-1].(*GoToLabelStatement); !ok {
836 | yylex.Error("semicolon (;) is expected")
837 | }
838 | }
839 | if yyDollar[3].stmt != nil {
840 | yyVAL.body = append(yyVAL.body, yyDollar[3].stmt)
841 | }
842 | }
843 | case 19:
844 | yyDollar = yyS[yypt-0 : yypt+1]
845 | //line .\grammar.y:173
846 | {
847 | yyVAL.stmt = nil
848 | }
849 | case 20:
850 | yyDollar = yyS[yypt-1 : yypt+1]
851 | //line .\grammar.y:174
852 | {
853 | if ast, ok := yylex.(*AstNode); ok {
854 | yyVAL.stmt = ast.statementPostProcessing(yyDollar[1].stmt)
855 | } else {
856 | yyVAL.stmt = yyDollar[1].stmt
857 | }
858 | }
859 | case 21:
860 | yyDollar = yyS[yypt-1 : yypt+1]
861 | //line .\grammar.y:183
862 | {
863 | yyVAL.token = yyDollar[1].token
864 | }
865 | case 22:
866 | yyDollar = yyS[yypt-1 : yypt+1]
867 | //line .\grammar.y:183
868 | {
869 | yyVAL.token = yyDollar[1].token
870 | }
871 | case 23:
872 | yyDollar = yyS[yypt-0 : yypt+1]
873 | //line .\grammar.y:187
874 | {
875 | yyVAL.opt_explicit_variables = map[string]VarStatement{}
876 | }
877 | case 24:
878 | yyDollar = yyS[yypt-1 : yypt+1]
879 | //line .\grammar.y:188
880 | {
881 | yyVAL.opt_explicit_variables = yyDollar[1].explicit_variables
882 | }
883 | case 25:
884 | yyDollar = yyS[yypt-3 : yypt+1]
885 | //line .\grammar.y:191
886 | {
887 | if vars, err := appendVarStatements(map[string]VarStatement{}, yyDollar[2].identifiers); err != nil {
888 | yylex.Error(err.Error())
889 | } else {
890 | yyVAL.explicit_variables = vars
891 | }
892 | }
893 | case 26:
894 | yyDollar = yyS[yypt-4 : yypt+1]
895 | //line .\grammar.y:198
896 | {
897 | if vars, err := appendVarStatements(yyDollar[1].explicit_variables, yyDollar[3].identifiers); err != nil {
898 | yylex.Error(err.Error())
899 | } else {
900 | yyVAL.explicit_variables = vars
901 | }
902 | }
903 | case 27:
904 | yyDollar = yyS[yypt-7 : yypt+1]
905 | //line .\grammar.y:209
906 | {
907 | yyVAL.stmt_if = &IfStatement{
908 | Expression: yyDollar[2].stmt,
909 | TrueBlock: yyDollar[4].opt_body,
910 | IfElseBlock: yyDollar[5].opt_elseif_list,
911 | ElseBlock: yyDollar[6].opt_else,
912 | }
913 | }
914 | case 28:
915 | yyDollar = yyS[yypt-0 : yypt+1]
916 | //line .\grammar.y:219
917 | {
918 | yyVAL.opt_elseif_list = []Statement{}
919 | }
920 | case 29:
921 | yyDollar = yyS[yypt-5 : yypt+1]
922 | //line .\grammar.y:220
923 | {
924 | yyVAL.opt_elseif_list = append(yyDollar[5].opt_elseif_list, &IfStatement{
925 | Expression: yyDollar[2].stmt,
926 | TrueBlock: yyDollar[4].opt_body,
927 | })
928 | }
929 | case 30:
930 | yyDollar = yyS[yypt-0 : yypt+1]
931 | //line .\grammar.y:228
932 | {
933 | yyVAL.opt_else = nil
934 | }
935 | case 31:
936 | yyDollar = yyS[yypt-2 : yypt+1]
937 | //line .\grammar.y:229
938 | {
939 | yyVAL.opt_else = yyDollar[2].opt_body
940 | }
941 | case 32:
942 | yyDollar = yyS[yypt-8 : yypt+1]
943 | //line .\grammar.y:232
944 | {
945 | yyVAL.stmt = TernaryStatement{
946 | Expression: yyDollar[3].stmt,
947 | TrueBlock: yyDollar[5].stmt,
948 | ElseBlock: yyDollar[7].stmt,
949 | }
950 | }
951 | case 33:
952 | yyDollar = yyS[yypt-6 : yypt+1]
953 | //line .\grammar.y:241
954 | {
955 | setLoopFlag(true, yylex)
956 | }
957 | case 34:
958 | yyDollar = yyS[yypt-9 : yypt+1]
959 | //line .\grammar.y:241
960 | {
961 | yyVAL.stmt_loop = &LoopStatement{
962 | For: yyDollar[3].token.literal,
963 | In: yyDollar[5].stmt,
964 | Body: yyDollar[8].opt_body,
965 | }
966 | setLoopFlag(false, yylex)
967 | }
968 | case 35:
969 | yyDollar = yyS[yypt-5 : yypt+1]
970 | //line .\grammar.y:249
971 | {
972 | setLoopFlag(true, yylex)
973 | }
974 | case 36:
975 | yyDollar = yyS[yypt-8 : yypt+1]
976 | //line .\grammar.y:249
977 | {
978 | yyVAL.stmt_loop = &LoopStatement{
979 | For: yyDollar[2].stmt,
980 | To: yyDollar[4].stmt,
981 | Body: yyDollar[7].opt_body,
982 | }
983 | setLoopFlag(false, yylex)
984 | }
985 | case 37:
986 | yyDollar = yyS[yypt-3 : yypt+1]
987 | //line .\grammar.y:257
988 | {
989 | setLoopFlag(true, yylex)
990 | }
991 | case 38:
992 | yyDollar = yyS[yypt-6 : yypt+1]
993 | //line .\grammar.y:257
994 | {
995 | yyVAL.stmt_loop = &LoopStatement{
996 | WhileExpr: yyDollar[2].stmt,
997 | Body: yyDollar[5].opt_body,
998 | }
999 | }
1000 | case 39:
1001 | yyDollar = yyS[yypt-1 : yypt+1]
1002 | //line .\grammar.y:266
1003 | {
1004 | yyVAL.stmt = yyDollar[1].stmt
1005 | }
1006 | case 40:
1007 | yyDollar = yyS[yypt-1 : yypt+1]
1008 | //line .\grammar.y:267
1009 | {
1010 | yyVAL.stmt = yyDollar[1].stmt
1011 | }
1012 | case 41:
1013 | yyDollar = yyS[yypt-3 : yypt+1]
1014 | //line .\grammar.y:268
1015 | {
1016 | yyVAL.stmt = yyDollar[2].stmt
1017 | }
1018 | case 42:
1019 | yyDollar = yyS[yypt-1 : yypt+1]
1020 | //line .\grammar.y:271
1021 | {
1022 | yyVAL.stmt = yyDollar[1].stmt
1023 | }
1024 | case 43:
1025 | yyDollar = yyS[yypt-1 : yypt+1]
1026 | //line .\grammar.y:272
1027 | {
1028 | yyVAL.stmt = yyDollar[1].stmt_if
1029 | }
1030 | case 44:
1031 | yyDollar = yyS[yypt-1 : yypt+1]
1032 | //line .\grammar.y:273
1033 | {
1034 | yyVAL.stmt = yyDollar[1].stmt_loop
1035 | }
1036 | case 45:
1037 | yyDollar = yyS[yypt-1 : yypt+1]
1038 | //line .\grammar.y:274
1039 | {
1040 | yyVAL.stmt = yyDollar[1].stmt
1041 | }
1042 | case 46:
1043 | yyDollar = yyS[yypt-1 : yypt+1]
1044 | //line .\grammar.y:275
1045 | {
1046 | yyVAL.stmt = ContinueStatement{}
1047 | checkLoopOperator(yyDollar[1].token, yylex)
1048 | }
1049 | case 47:
1050 | yyDollar = yyS[yypt-1 : yypt+1]
1051 | //line .\grammar.y:276
1052 | {
1053 | yyVAL.stmt = BreakStatement{}
1054 | checkLoopOperator(yyDollar[1].token, yylex)
1055 | }
1056 | case 48:
1057 | yyDollar = yyS[yypt-2 : yypt+1]
1058 | //line .\grammar.y:277
1059 | {
1060 | yyVAL.stmt = ThrowStatement{Param: yyDollar[2].stmt}
1061 | checkThrowParam(yyDollar[1].token, yyDollar[2].stmt, yylex)
1062 | }
1063 | case 49:
1064 | yyDollar = yyS[yypt-2 : yypt+1]
1065 | //line .\grammar.y:278
1066 | {
1067 | yyVAL.stmt = &ReturnStatement{Param: yyDollar[2].stmt}
1068 | checkReturnParam(yyDollar[2].stmt, yylex)
1069 | }
1070 | case 50:
1071 | yyDollar = yyS[yypt-0 : yypt+1]
1072 | //line .\grammar.y:281
1073 | {
1074 | yyVAL.stmt = nil
1075 | }
1076 | case 51:
1077 | yyDollar = yyS[yypt-1 : yypt+1]
1078 | //line .\grammar.y:282
1079 | {
1080 | yyVAL.stmt = yyDollar[1].stmt
1081 | }
1082 | case 52:
1083 | yyDollar = yyS[yypt-1 : yypt+1]
1084 | //line .\grammar.y:287
1085 | {
1086 | yyVAL.stmt = yyDollar[1].stmt
1087 | }
1088 | case 53:
1089 | yyDollar = yyS[yypt-3 : yypt+1]
1090 | //line .\grammar.y:288
1091 | {
1092 | yyVAL.stmt = CallChainStatement{Unit: yyDollar[3].stmt, Call: yyDollar[1].stmt}
1093 | }
1094 | case 54:
1095 | yyDollar = yyS[yypt-1 : yypt+1]
1096 | //line .\grammar.y:294
1097 | {
1098 | yyVAL.stmt = VarStatement{Name: yyDollar[1].token.literal}
1099 | }
1100 | case 55:
1101 | yyDollar = yyS[yypt-4 : yypt+1]
1102 | //line .\grammar.y:295
1103 | {
1104 | yyVAL.stmt = MethodStatement{Name: yyDollar[1].token.literal, Param: yyDollar[3].exprs}
1105 | }
1106 | case 56:
1107 | yyDollar = yyS[yypt-4 : yypt+1]
1108 | //line .\grammar.y:296
1109 | {
1110 | yyVAL.stmt = ItemStatement{Object: yyDollar[1].stmt, Item: yyDollar[3].stmt}
1111 | }
1112 | case 57:
1113 | yyDollar = yyS[yypt-2 : yypt+1]
1114 | //line .\grammar.y:297
1115 | {
1116 | yyVAL.stmt = MethodStatement{Name: yyDollar[1].token.literal, Param: []Statement{yyDollar[2].stmt}}
1117 | }
1118 | case 58:
1119 | yyDollar = yyS[yypt-4 : yypt+1]
1120 | //line .\grammar.y:298
1121 | {
1122 | yyVAL.stmt = MethodStatement{Name: yyDollar[1].token.literal, Param: []Statement{yyDollar[3].stmt}}
1123 | }
1124 | case 59:
1125 | yyDollar = yyS[yypt-1 : yypt+1]
1126 | //line .\grammar.y:301
1127 | {
1128 | yyVAL.stmt = yyDollar[1].token.value
1129 | }
1130 | case 60:
1131 | yyDollar = yyS[yypt-1 : yypt+1]
1132 | //line .\grammar.y:302
1133 | {
1134 | yyVAL.stmt = VarStatement{Name: yyDollar[1].token.literal}
1135 | }
1136 | case 61:
1137 | yyDollar = yyS[yypt-3 : yypt+1]
1138 | //line .\grammar.y:305
1139 | {
1140 | setTryFlag(true, yylex)
1141 | }
1142 | case 62:
1143 | yyDollar = yyS[yypt-6 : yypt+1]
1144 | //line .\grammar.y:305
1145 | {
1146 | yyVAL.stmt = TryStatement{Body: yyDollar[2].opt_body, Catch: yyDollar[5].opt_body}
1147 | setTryFlag(false, yylex)
1148 | }
1149 | case 63:
1150 | yyDollar = yyS[yypt-1 : yypt+1]
1151 | //line .\grammar.y:311
1152 | {
1153 | yyVAL.stmt = yyDollar[1].stmt
1154 | }
1155 | case 64:
1156 | yyDollar = yyS[yypt-3 : yypt+1]
1157 | //line .\grammar.y:312
1158 | {
1159 | yyVAL.stmt = yyDollar[2].stmt
1160 | }
1161 | case 65:
1162 | yyDollar = yyS[yypt-3 : yypt+1]
1163 | //line .\grammar.y:313
1164 | {
1165 | yyVAL.stmt = &ExpStatement{Operation: OpPlus, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1166 | }
1167 | case 66:
1168 | yyDollar = yyS[yypt-3 : yypt+1]
1169 | //line .\grammar.y:314
1170 | {
1171 | yyVAL.stmt = &ExpStatement{Operation: OpMinus, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1172 | }
1173 | case 67:
1174 | yyDollar = yyS[yypt-3 : yypt+1]
1175 | //line .\grammar.y:315
1176 | {
1177 | yyVAL.stmt = &ExpStatement{Operation: OpMul, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1178 | }
1179 | case 68:
1180 | yyDollar = yyS[yypt-3 : yypt+1]
1181 | //line .\grammar.y:316
1182 | {
1183 | yyVAL.stmt = &ExpStatement{Operation: OpDiv, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1184 | }
1185 | case 69:
1186 | yyDollar = yyS[yypt-3 : yypt+1]
1187 | //line .\grammar.y:317
1188 | {
1189 | yyVAL.stmt = &ExpStatement{Operation: OpMod, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1190 | }
1191 | case 70:
1192 | yyDollar = yyS[yypt-3 : yypt+1]
1193 | //line .\grammar.y:318
1194 | {
1195 | yyVAL.stmt = &ExpStatement{Operation: OpGt, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1196 | }
1197 | case 71:
1198 | yyDollar = yyS[yypt-3 : yypt+1]
1199 | //line .\grammar.y:319
1200 | {
1201 | yyVAL.stmt = &ExpStatement{Operation: OpLt, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1202 | }
1203 | case 72:
1204 | yyDollar = yyS[yypt-3 : yypt+1]
1205 | //line .\grammar.y:320
1206 | {
1207 | yyVAL.stmt = &ExpStatement{Operation: OpEq, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1208 | }
1209 | case 73:
1210 | yyDollar = yyS[yypt-3 : yypt+1]
1211 | //line .\grammar.y:321
1212 | {
1213 | yyVAL.stmt = &ExpStatement{Operation: OpOr, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1214 | }
1215 | case 74:
1216 | yyDollar = yyS[yypt-3 : yypt+1]
1217 | //line .\grammar.y:322
1218 | {
1219 | yyVAL.stmt = &ExpStatement{Operation: OpAnd, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1220 | }
1221 | case 75:
1222 | yyDollar = yyS[yypt-3 : yypt+1]
1223 | //line .\grammar.y:323
1224 | {
1225 | yyVAL.stmt = &ExpStatement{Operation: OpNe, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1226 | }
1227 | case 76:
1228 | yyDollar = yyS[yypt-3 : yypt+1]
1229 | //line .\grammar.y:324
1230 | {
1231 | yyVAL.stmt = &ExpStatement{Operation: OpLe, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1232 | }
1233 | case 77:
1234 | yyDollar = yyS[yypt-3 : yypt+1]
1235 | //line .\grammar.y:325
1236 | {
1237 | yyVAL.stmt = &ExpStatement{Operation: OpGe, Left: yyDollar[1].stmt, Right: yyDollar[3].stmt}
1238 | }
1239 | case 78:
1240 | yyDollar = yyS[yypt-2 : yypt+1]
1241 | //line .\grammar.y:326
1242 | {
1243 | yyVAL.stmt = not(yyDollar[2].stmt)
1244 | }
1245 | case 79:
1246 | yyDollar = yyS[yypt-1 : yypt+1]
1247 | //line .\grammar.y:327
1248 | {
1249 | yyVAL.stmt = yyDollar[1].stmt
1250 | }
1251 | case 80:
1252 | yyDollar = yyS[yypt-2 : yypt+1]
1253 | //line .\grammar.y:328
1254 | {
1255 | yyVAL.stmt = GoToStatement{Label: yyDollar[2].goToLabel}
1256 | }
1257 | case 81:
1258 | yyDollar = yyS[yypt-1 : yypt+1]
1259 | //line .\grammar.y:329
1260 | {
1261 | yyVAL.stmt = yyDollar[1].stmt
1262 | }
1263 | case 82:
1264 | yyDollar = yyS[yypt-1 : yypt+1]
1265 | //line .\grammar.y:330
1266 | {
1267 | if tok, ok := yyDollar[1].stmt.(Token); ok {
1268 | yyVAL.stmt = tok.literal
1269 | } else {
1270 | yyVAL.stmt = yyDollar[1].stmt
1271 | }
1272 | }
1273 | case 83:
1274 | yyDollar = yyS[yypt-0 : yypt+1]
1275 | //line .\grammar.y:339
1276 | {
1277 | yyVAL.stmt = nil
1278 | }
1279 | case 84:
1280 | yyDollar = yyS[yypt-1 : yypt+1]
1281 | //line .\grammar.y:339
1282 | {
1283 | yyVAL.stmt = yyDollar[1].stmt
1284 | }
1285 | case 85:
1286 | yyDollar = yyS[yypt-1 : yypt+1]
1287 | //line .\grammar.y:342
1288 | {
1289 | yyVAL.declarations_method_param = *(&ParamStatement{}).Fill(nil, yyDollar[1].token)
1290 | }
1291 | case 86:
1292 | yyDollar = yyS[yypt-2 : yypt+1]
1293 | //line .\grammar.y:343
1294 | {
1295 | yyVAL.declarations_method_param = *(&ParamStatement{}).Fill(&yyDollar[1].token, yyDollar[2].token)
1296 | }
1297 | case 87:
1298 | yyDollar = yyS[yypt-3 : yypt+1]
1299 | //line .\grammar.y:344
1300 | {
1301 | yyVAL.declarations_method_param = *(yyVAL.declarations_method_param.DefaultValue(yyDollar[3].stmt))
1302 | }
1303 | case 88:
1304 | yyDollar = yyS[yypt-0 : yypt+1]
1305 | //line .\grammar.y:347
1306 | {
1307 | yyVAL.declarations_method_params = []ParamStatement{}
1308 | }
1309 | case 89:
1310 | yyDollar = yyS[yypt-1 : yypt+1]
1311 | //line .\grammar.y:348
1312 | {
1313 | yyVAL.declarations_method_params = []ParamStatement{yyDollar[1].declarations_method_param}
1314 | }
1315 | case 90:
1316 | yyDollar = yyS[yypt-3 : yypt+1]
1317 | //line .\grammar.y:349
1318 | {
1319 | yyVAL.declarations_method_params = append(yyDollar[1].declarations_method_params, yyDollar[3].declarations_method_param)
1320 | }
1321 | case 91:
1322 | yyDollar = yyS[yypt-2 : yypt+1]
1323 | //line .\grammar.y:357
1324 | {
1325 | yyVAL.stmt = NewObjectStatement{Constructor: yyDollar[2].token.literal}
1326 | }
1327 | case 92:
1328 | yyDollar = yyS[yypt-5 : yypt+1]
1329 | //line .\grammar.y:358
1330 | {
1331 | yyVAL.stmt = NewObjectStatement{Constructor: yyDollar[2].token.literal, Param: yyDollar[4].exprs}
1332 | }
1333 | case 93:
1334 | yyDollar = yyS[yypt-4 : yypt+1]
1335 | //line .\grammar.y:359
1336 | {
1337 | yyVAL.stmt = NewObjectStatement{Param: yyDollar[3].exprs}
1338 | }
1339 | case 94:
1340 | yyDollar = yyS[yypt-1 : yypt+1]
1341 | //line .\grammar.y:362
1342 | {
1343 | yyVAL.stmt = yyDollar[1].token.value
1344 | }
1345 | case 95:
1346 | yyDollar = yyS[yypt-1 : yypt+1]
1347 | //line .\grammar.y:363
1348 | {
1349 | yyVAL.stmt = yyDollar[1].token.value
1350 | }
1351 | case 96:
1352 | yyDollar = yyS[yypt-2 : yypt+1]
1353 | //line .\grammar.y:364
1354 | {
1355 | yyVAL.stmt = unaryMinus(yyDollar[2].stmt)
1356 | }
1357 | case 97:
1358 | yyDollar = yyS[yypt-2 : yypt+1]
1359 | //line .\grammar.y:365
1360 | {
1361 | yyVAL.stmt = yyDollar[2].stmt
1362 | }
1363 | case 98:
1364 | yyDollar = yyS[yypt-1 : yypt+1]
1365 | //line .\grammar.y:366
1366 | {
1367 | yyVAL.stmt = yyDollar[1].token.value
1368 | }
1369 | case 99:
1370 | yyDollar = yyS[yypt-1 : yypt+1]
1371 | //line .\grammar.y:367
1372 | {
1373 | yyVAL.stmt = yyDollar[1].token.value
1374 | }
1375 | case 100:
1376 | yyDollar = yyS[yypt-1 : yypt+1]
1377 | //line .\grammar.y:368
1378 | {
1379 | yyVAL.stmt = yyDollar[1].token.value
1380 | }
1381 | case 101:
1382 | yyDollar = yyS[yypt-1 : yypt+1]
1383 | //line .\grammar.y:369
1384 | {
1385 | yyVAL.stmt = UndefinedStatement{}
1386 | }
1387 | case 102:
1388 | yyDollar = yyS[yypt-1 : yypt+1]
1389 | //line .\grammar.y:370
1390 | {
1391 | yyVAL.stmt = yyDollar[1].goToLabel
1392 | }
1393 | case 103:
1394 | yyDollar = yyS[yypt-1 : yypt+1]
1395 | //line .\grammar.y:373
1396 | {
1397 | yyVAL.goToLabel = &GoToLabelStatement{Name: yyDollar[1].token.literal}
1398 | }
1399 | case 104:
1400 | yyDollar = yyS[yypt-1 : yypt+1]
1401 | //line .\grammar.y:375
1402 | {
1403 | yyVAL.exprs = []Statement{yyDollar[1].stmt}
1404 | }
1405 | case 105:
1406 | yyDollar = yyS[yypt-3 : yypt+1]
1407 | //line .\grammar.y:376
1408 | {
1409 | yyVAL.exprs = append(yyVAL.exprs, yyDollar[3].stmt)
1410 | }
1411 | case 106:
1412 | yyDollar = yyS[yypt-1 : yypt+1]
1413 | //line .\grammar.y:379
1414 | {
1415 | yyVAL.identifiers = []Token{yyDollar[1].token}
1416 | }
1417 | case 107:
1418 | yyDollar = yyS[yypt-3 : yypt+1]
1419 | //line .\grammar.y:380
1420 | {
1421 | yyVAL.identifiers = append(yyVAL.identifiers, yyDollar[3].token)
1422 | }
1423 | case 108:
1424 | yyDollar = yyS[yypt-1 : yypt+1]
1425 | //line .\grammar.y:383
1426 | {
1427 | yyVAL.token = yyDollar[1].token
1428 | }
1429 | case 109:
1430 | yyDollar = yyS[yypt-1 : yypt+1]
1431 | //line .\grammar.y:384
1432 | {
1433 | yyVAL.token = yyDollar[1].token
1434 | }
1435 | }
1436 | goto yystack /* stack new state and value */
1437 | }
1438 |
--------------------------------------------------------------------------------
/examples/pretty_code/README.md:
--------------------------------------------------------------------------------
1 | ### Пример использования парсера языка 1С
2 |
3 | Имеем на входе код 1С в одну строку
4 | ```
5 | Процедура УстановитьОтображениеЗаголовковГрупп(Форма, ИменаГрупп = "") Экспорт Если ВариантИнтерфейсаКлиентскогоПриложения= ВариантИнтерфейсаКлиентскогоПриложения.Версия8_2 Тогда ЖирныйШрифт = Новый Шрифт(,, Истина); Если НЕ ЗначениеЗаполнено(ИменаГрупп) Тогда Для Каждого Элемент Из Форма.Элементы Цикл Если Тип(Элемент) = Тип("ГруппаФормы") И Элемент.Вид = ВидГруппыФормы.ОбычнаяГруппа И Элемент.ОтображатьЗаголовок = Истина И (Элемент.Отображение = ОтображениеОбычнойГруппы.ОбычноеВыделение Или Элемент.Отображение = ОтображениеОбычнойГруппы.Нет) Тогда Элемент.ШрифтЗаголовка = ЖирныйШрифт; КонецЕсли; КонецЦикла; Иначе МассивЗаголовков = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ИменаГрупп,,, Истина); Для Каждого ИмяЗаголовка Из МассивЗаголовков Цикл Элемент = Форма.Элементы[ИмяЗаголовка]; Если Элемент.Отображение = ОтображениеОбычнойГруппы.ОбычноеВыделение ИЛИ Элемент.Отображение = ОтображениеОбычнойГруппы.Нет Тогда Элемент.ШрифтЗаголовка = ЖирныйШрифт; КонецЕсли; КонецЦикла; КонецЕсли; КонецЕсли;КонецПроцедуры
6 | ```
7 |
8 | После прогона через парсер получаем
9 | ```
10 | Процедура УстановитьОтображениеЗаголовковГрупп(Форма, ИменаГрупп = "") Экспорт
11 |
12 | Если ВариантИнтерфейсаКлиентскогоПриложения = ВариантИнтерфейсаКлиентскогоПриложения.Версия8_2 Тогда
13 | ЖирныйШрифт = Новый Шрифт(, , Истина);
14 | Если Не ЗначениеЗаполнено(ИменаГрупп) Тогда
15 | Для Каждого Элемент Из Форма.Элементы Цикл
16 | Если Тип(Элемент) = Тип("ГруппаФормы") И Элемент.Вид = ВидГруппыФормы.ОбычнаяГруппа И Элемент.ОтображатьЗаголовок = Истина И Элемент.Отображение = ОтображениеОбычнойГруппы.ОбычноеВыделение ИЛИ Элемент.Отображе
17 | ние = ОтображениеОбычнойГруппы.Нет Тогда
18 | Элемент.ШрифтЗаголовка = ЖирныйШрифт;
19 | КонецЕсли;
20 |
21 | КонецЦикла;
22 |
23 | Иначе
24 | МассивЗаголовков = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ИменаГрупп, , , Истина);
25 | Для Каждого ИмяЗаголовка Из МассивЗаголовков Цикл
26 | Элемент = Форма.Элементы[ИмяЗаголовка];
27 | Если Элемент.Отображение = ОтображениеОбычнойГруппы.ОбычноеВыделение ИЛИ Элемент.Отображение = ОтображениеОбычнойГруппы.Нет Тогда
28 | Элемент.ШрифтЗаголовка = ЖирныйШрифт;
29 | КонецЕсли;
30 |
31 | КонецЦикла;
32 |
33 | КонецЕсли;
34 |
35 | КонецЕсли;
36 | КонецПроцедуры
37 |
38 | ```
--------------------------------------------------------------------------------
/examples/pretty_code/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/LazarenkoA/1c-language-parser/ast"
7 | )
8 |
9 | func main() {
10 | code := `Процедура УстановитьОтображениеЗаголовковГрупп(Форма, ИменаГрупп = "") Экспорт Если ВариантИнтерфейсаКлиентскогоПриложения= ВариантИнтерфейсаКлиентскогоПриложения.Версия8_2 Тогда ЖирныйШрифт = Новый Шрифт(,, Истина); Если НЕ ЗначениеЗаполнено(ИменаГрупп) Тогда Для Каждого Элемент Из Форма.Элементы Цикл Если Тип(Элемент) = Тип("ГруппаФормы") И Элемент.Вид = ВидГруппыФормы.ОбычнаяГруппа И Элемент.ОтображатьЗаголовок = Истина И (Элемент.Отображение = ОтображениеОбычнойГруппы.ОбычноеВыделение Или Элемент.Отображение = ОтображениеОбычнойГруппы.Нет) Тогда Элемент.ШрифтЗаголовка = ЖирныйШрифт; КонецЕсли; КонецЦикла; Иначе МассивЗаголовков = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ИменаГрупп,,, Истина); Для Каждого ИмяЗаголовка Из МассивЗаголовков Цикл Элемент = Форма.Элементы[ИмяЗаголовка]; Если Элемент.Отображение = ОтображениеОбычнойГруппы.ОбычноеВыделение ИЛИ Элемент.Отображение = ОтображениеОбычнойГруппы.Нет Тогда Элемент.ШрифтЗаголовка = ЖирныйШрифт; КонецЕсли; КонецЦикла; КонецЕсли; КонецЕсли;КонецПроцедуры`
11 |
12 | a := ast.NewAST(code)
13 | if err := a.Parse(); err != nil {
14 | fmt.Println(err)
15 | return
16 | }
17 |
18 | fmt.Println(a.Print(ast.PrintConf{Margin: 4}))
19 | }
20 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/LazarenkoA/1c-language-parser
2 |
3 | go 1.23.1
4 |
5 | toolchain go1.23.4
6 |
7 | require (
8 | github.com/golang/mock v1.6.0
9 | github.com/pkg/errors v0.9.1
10 | github.com/stretchr/testify v1.10.0
11 | )
12 |
13 | require (
14 | github.com/crecentmoon/googlesql-parser v0.0.0-20240105044612-eb1da72ff091 // indirect
15 | github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
16 | github.com/davecgh/go-spew v1.1.1 // indirect
17 | github.com/kr/pretty v0.3.1 // indirect
18 | github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
19 | github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 // indirect
20 | github.com/pmezard/go-difflib v1.0.0 // indirect
21 | github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
22 | go.uber.org/atomic v1.7.0 // indirect
23 | go.uber.org/multierr v1.6.0 // indirect
24 | go.uber.org/zap v1.18.1 // indirect
25 | golang.org/x/text v0.3.6 // indirect
26 | golang.org/x/tools v0.31.0 // indirect
27 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
28 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
29 | gopkg.in/yaml.v3 v3.0.1 // indirect
30 | )
31 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
2 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
3 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
4 | github.com/crecentmoon/googlesql-parser v0.0.0-20240105044612-eb1da72ff091 h1:WGphB8cehezk1s7DYGueVCmt/MSBkrke9Cg8NIfj77k=
5 | github.com/crecentmoon/googlesql-parser v0.0.0-20240105044612-eb1da72ff091/go.mod h1:DSP8aPn2ApXmxOyoBaK1bLWon8UbCclIzu5hQyxLOYE=
6 | github.com/cznic/golex v0.0.0-20181122101858-9c343928389c/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc=
7 | github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
8 | github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
9 | github.com/cznic/parser v0.0.0-20160622100904-31edd927e5b1/go.mod h1:2B43mz36vGZNZEwkWi8ayRSSUXLfjL8OkbzwW4NcPMM=
10 | github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
11 | github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
12 | github.com/cznic/y v0.0.0-20170802143616-045f81c6662a/go.mod h1:1rk5VM7oSnA4vjp+hrLQ3HWHa+Y4yPCa3/CsJrcNnvs=
13 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
14 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
15 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
16 | github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
17 | github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
18 | github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
19 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
20 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
21 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
22 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
23 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
24 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
25 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
26 | github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ=
27 | github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
28 | github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 h1:+FZIDR/D97YOPik4N4lPDaUcLDF/EQPogxtlHB2ZZRM=
29 | github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg=
30 | github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 h1:k2BbABz9+TNpYRwsCCFS8pEEnFVOdbgEjL/kTlLuzZQ=
31 | github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7/go.mod h1:8AanEdAHATuRurdGxZXBz0At+9avep+ub7U1AGYLIMM=
32 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
33 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
34 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
35 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
36 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
37 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
38 | github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
39 | github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
40 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
41 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
42 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
43 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
44 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
45 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
46 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
47 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
48 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
49 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
50 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
51 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
52 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
53 | go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
54 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
55 | go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
56 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
57 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
58 | go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4=
59 | go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
60 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
61 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
62 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
63 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
64 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
65 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
66 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
67 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
68 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
69 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
70 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
71 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
72 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
73 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
74 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
75 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
76 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
77 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
78 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
79 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
80 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
81 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
82 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
83 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
84 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
85 | golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
86 | golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
87 | golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
88 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
89 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
90 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
91 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
92 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
93 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
94 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
95 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
96 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
97 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
98 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
99 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
100 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
101 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
102 |
--------------------------------------------------------------------------------