├── .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 | --------------------------------------------------------------------------------