loom

Форк
0
/
ScriptSemantics_operation.cpp 
1605 строк · 72.3 Кб
1
/*
2
MIT License
3

4
Copyright (c) 2022 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
5

6
https://bmstu.codes/lsx/simodo/loom
7
*/
8

9
#include "ScriptSemantics_abstract.h"
10
#include "simodo/interpret/AnalyzeException.h"
11
#include "simodo/variable/Module_interface.h"
12
#include "simodo/inout/convert/functions.h"
13
#include "simodo/inout/format/fmt.h"
14
#include "simodo/bormental/DrBormental.h"
15

16
#ifndef NDEBUG
17
#define DEBUG
18
#endif
19

20
#ifdef DEBUG
21
    #include "simodo/interpret/Interpret.h"
22
#endif
23

24
#include <functional>
25
#include <iterator>
26
#include <cassert>
27

28
#if __cplusplus >= __cpp_2017
29
#include <filesystem>
30
namespace fs = std::filesystem;
31
#else
32
#include <experimental/filesystem>
33
namespace fs = std::filesystem::experimental;
34
#endif
35

36
namespace simodo::interpret
37
{
38
    InterpretState ScriptSemantics_abstract::executeNone()
39
    {
40
        return InterpretState::Flow;
41
    }
42

43
    InterpretState ScriptSemantics_abstract::executePushConstant(const ast::Node & op)
44
    {
45
        variable::Variable   constant_variable;
46
        [[maybe_unused]] size_t index = 0;
47

48
        switch(op.token().type())
49
        {
50
        case inout::LexemeType::Id:
51
        case inout::LexemeType::Annotation:
52
            constant_variable = { u"", op.token().lexeme(), op.token().location() };
53
            break;
54
        case inout::LexemeType::Number:
55
            if (op.token().lexeme().substr(0,2) == u"0b") 
56
                constant_variable = { u"", 
57
                        static_cast<int64_t>(std::stoll(inout::toU8(op.token().lexeme().substr(2)),nullptr,2)), 
58
                        op.token().location() };
59
            else if (op.token().lexeme().substr(0,2) == u"0o") 
60
                constant_variable = { u"", 
61
                        static_cast<int64_t>(std::stoll(inout::toU8(op.token().lexeme().substr(2)),nullptr,8)), 
62
                        op.token().location() };
63
            else if (op.token().lexeme().substr(0,2) == u"0x") 
64
                constant_variable = { u"", 
65
                        static_cast<int64_t>(std::stoll(inout::toU8(op.token().lexeme().substr(2)),nullptr,16)), 
66
                        op.token().location() };
67
            else if (op.token().qualification() == inout::TokenQualification::Integer)
68
                constant_variable = { u"", static_cast<int64_t>(std::stoll(inout::toU8(op.token().lexeme()))), op.token().location() };
69
            else
70
                constant_variable = { u"", std::stod(inout::toU8(op.token().lexeme())), op.token().location() };
71
            break;
72
        case inout::LexemeType::Punctuation:
73
            if (op.token().lexeme() == u"true" || op.token().lexeme() == u"false")
74
                constant_variable = { u"", op.token().lexeme() == u"true", op.token().location() };
75
            else if (op.token().lexeme() == u"null") {
76
                constant_variable = variable::null_variable(op.token().location());
77
                index = constant_variable.value().variant().index();
78
            }
79
            break;
80
        default:
81
            throw bormental::DrBormental("ScriptSemantics_abstract::executePushConstant", 
82
                                        inout::fmt("Invalid internal type of constant to convert (%1)")
83
                                            .arg(getLexemeTypeName(op.token().type())));
84
        }
85

86
        if (!op.branches().empty()) {
87
            std::vector<variable::Value> unit_parts;
88

89
            for(const ast::Node & n : op.branches())
90
                unit_parts.push_back(n.token().lexeme());
91

92
            constant_variable.spec().set(u"unit", unit_parts);
93
        }
94

95
        stack().push(constant_variable);
96

97
        return InterpretState::Flow;
98
    }
99

100
    InterpretState ScriptSemantics_abstract::executePushVariable(const inout::Token & token)
101
    {
102
#ifdef DEBUG
103
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
104
#endif
105
        variable::Variable var = prepareVariableByToken(token);
106

107
        if (var.name().empty() && var.origin().name().empty()) {
108
            stack().push({token.lexeme(), {}, token.location(), {}}); 
109
            throw AnalyzeException("ScriptSemantics_abstract::executePushVariable", 
110
                                    token.location().makeLocation(inter().files()),
111
                                    inout::fmt("Variable '%1' not found")
112
                                        .arg(token.lexeme()));
113
        }
114

115
        if (token.lexeme() == SELF_VARIABLE_NAME) {
116
            var.setName(u"");
117
            notifyDeclared(var);
118
        }
119
        else
120
            notifyNameUsed(var.origin(), token.location());
121

122
        stack().push(var);
123

124
        return InterpretState::Flow;
125
    }
126

127
    InterpretState ScriptSemantics_abstract::executeObjectElement(const ast::Node & op)
128
    try
129
    {
130
#ifdef DEBUG
131
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
132
#endif
133
        variable::Variable & candid = stack().variable(stack().top());
134
        variable::Variable & origin = candid.origin();
135

136
        variable::Variable super_element = makeSuperElement(origin, op.token());
137

138
        if (!super_element.name().empty()) {
139
            stack().pop();
140
            stack().push(super_element);
141
            notifyDeclared(super_element);
142
            return InterpretState::Flow;
143
        }
144

145
        if (origin.value().isNull()) {
146
            stack().pop();
147
            stack().push(variable::error_variable(op.token().location(),op.token().lexeme()));
148
            return InterpretState::Flow;
149
        }
150

151
        variable::Variable obj_variable = origin;
152

153
        if (!obj_variable.value().isObject())
154
            obj_variable = inter().expr().convertVariable(candid, variable::ValueType::Object);
155

156
        assert(obj_variable.value().isObject());
157

158
        std::shared_ptr<variable::Object> object  = obj_variable.value().getObject();
159
        variable::Variable &              element = object->getVariableByName_mutable(op.token().lexeme());
160

161
        if (!element.name().empty() && !hidden(element)) {
162
            variable::VariableSet_t ref_spec;
163
            if (element.type() == variable::ValueType::Function) {
164
                if (object->flags().isSet(variable::ObjectFlag::Fiber)
165
                 && _fiber_flow_mode == FiberFlowMode::InDemand) {
166
                    ref_spec.push_back({variable::SPEC_FLOW, object});
167
                    _fiber_flow_mode = FiberFlowMode::Prepared;
168
                }
169
            }
170

171
            stack().pop();
172
            stack().pushRef(element, op.token().location(), ref_spec);
173
            notifyNameUsed(element, op.token().location());
174

175
            return InterpretState::Flow;
176
        }
177

178
        const ast::Node * p_next_node = inter().lookupOperationNode(+1);
179

180
        if (p_next_node
181
         && checkSemanticName(p_next_node->host()) 
182
         && ScriptOperationCode(p_next_node->operation()) == ScriptOperationCode::Assignment) {
183
            variable::Variable & setter = object->getVariableByName_mutable(u"set_" + op.token().lexeme());
184

185
            if (!setter.name().empty() && !hidden(setter) && setter.type() == variable::ValueType::Function) {
186
                stack().pop();
187
                stack().pushRef(setter, op.token().location());
188
                notifyNameUsed(setter, op.token().location());
189
                _setter_in_stack = true;
190
                return InterpretState::Flow;
191
            }
192
        }
193
        else {
194
            variable::Variable & getter = object->getVariableByName_mutable(u"get_" + op.token().lexeme());
195

196
            if (!getter.name().empty() && !hidden(getter) && getter.type() == variable::ValueType::Function) {
197
                stack().pop();
198
                stack().pushRef(getter, op.token().location());
199
                notifyNameUsed(getter, op.token().location());
200
                return executeFunctionCall({});
201
            }
202
        }
203

204
        if (hidden(element))
205
            throw AnalyzeException("ScriptSemantics_abstract::executeObjectElement", 
206
                                    op.token().location().makeLocation(inter().files()),
207
                                    inout::fmt("Property '%1' is hidden in '%2' and have not getter 'get_%3'")
208
                                        .arg(op.token().lexeme())
209
                                        .arg(obj_variable.name())
210
                                        .arg(op.token().lexeme()));
211

212
        throw AnalyzeException("ScriptSemantics_abstract::executeObjectElement", 
213
                                op.token().location().makeLocation(inter().files()),
214
                                inout::fmt("Property '%1' not found in '%2'")
215
                                    .arg(op.token().lexeme())
216
                                    .arg(obj_variable.name()));
217

218
    }
219
    catch (...)
220
    {
221
        stack().pop();
222
        stack().push(variable::error_variable());
223
        throw;
224
    }
225

226
    InterpretState ScriptSemantics_abstract::executeFunctionCall(const ast::Node & op)
227
    {
228
#ifdef DEBUG
229
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
230
#endif
231
        name_index_t       function_index  { stack().top() };
232
        variable::Variable function        { stack().variable(function_index) };
233

234
        if (function.origin().type() != variable::ValueType::Function) {
235
            if (function.origin().type() == variable::ValueType::Object) {
236
                std::shared_ptr<variable::Object> object    = function.origin().value().getObject();
237
                const variable::Variable          init_func = object->getVariableByName(u"__init__");
238

239
                if (!init_func.name().empty())
240
                    function = init_func;
241
            }
242

243
            if (function.origin().type() != variable::ValueType::Function) {
244
                if (function.origin().type() == variable::ValueType::Null
245
                 && checkInterpretType(InterpretType::Analyzer))
246
                    {}
247
                else
248
                    function = inter().expr().convertVariable(function, variable::ValueType::Function);
249
            }
250

251
            stack().pop();
252
            stack().push(function);
253
        }
254

255
        boundary_index_t   boundary_index  { stack().startBoundary(BoundScope::Local, BOUNDARY_MARK_FUNCTION_FRAME) };
256

257
        // Вычисляем аргументы функции, а потом вызываем функцию
258
        inter().addFlowLayer(
259
                op, 
260
                [this, boundary_index, function](const FlowLayerInfo & flow) 
261
                {
262
                    if (flow.error_sign) {
263
                        stack().clearBoundary(boundary_index);
264
                        stack().pop();
265
                        stack().push(variable::error_variable()); 
266
                        return;
267
                    }
268

269
                    if (!function.origin().value().isFunction()
270
                     && checkInterpretType(InterpretType::Analyzer)) {
271
                        stack().clearBoundary(boundary_index);
272
                        stack().pop();
273
                        stack().push(variable::error_variable()); 
274
                        return;
275
                    }
276

277
                    bool                  invoke      = true;
278
                    Interpret_interface * p_interpret = nullptr;
279

280
                    if (_fiber_flow_mode == FiberFlowMode::Prepared) {
281
                        if (checkInterpretType(InterpretType::Preview)) {
282
                            const variable::Variable & flow_variable = function.spec().object()->getVariableByName(variable::SPEC_FLOW);
283
                            assert(!flow_variable.name().empty());
284
                            const ChildFlowInfo * info = inter().parallelize().findChildFlowInfo(flow_variable);
285
                            assert(info);
286
                            if (info->child->ready()) {
287
                                stack().clearBoundary(boundary_index);
288
                                stack().pop();
289
                                stack().push(variable::error_variable()); 
290
                                
291
                                throw bormental::DrBormental("ScriptSemantics_abstract::executeFunctionCall", 
292
                                            inout::fmt("Unacceptable use of an already working fiber"));
293
                            }
294
                            p_interpret = info->child;
295
                        }
296
                        else {
297
                            p_interpret = _interpret;
298
                            invoke = false;
299
                        }
300

301
                        _fiber_flow_mode = FiberFlowMode::Launched;
302
                        notifyRemoteFunctionLaunch(function.location());
303
                    }
304
                    else
305
                        p_interpret = _interpret;
306

307
                    if (invoke && checkInterpretType(InterpretType::Analyzer)) {
308
                        std::shared_ptr<variable::Object> our_function_object = function.origin().value().getFunction();
309
                        auto it = std::find_if( _functions_for_analyze.begin(), _functions_for_analyze.end(),
310
                                [our_function_object] (const variable::Variable & f) {
311
                                    std::shared_ptr<variable::Object> f_object = f.origin().value().getFunction();
312
                                    return f_object.get() == our_function_object.get();
313
                                });
314

315
                        if (it != _functions_for_analyze.end())
316
                            _functions_for_analyze.erase(it);
317
                        else if (stack().isRecursiveCalls()) {
318
                            const auto [begin,end] = stack().boundaryLowAndTop(boundary_index);
319
                            variable::Variable & function_origin = stack().variable(begin-1).origin();
320
                            assert(function_origin.value().isFunction());
321
                            function_origin.origin().spec().set(variable::SPEC_RECURSIVE, true);
322
                            invoke = false;
323
                        }
324
                    }
325

326
                    // Очистка границы вызова (stack().clearBoundary(boundary_index))
327
                    // выполняется внутри callPreparedFunction
328
                    inter().expr().callPreparedFunction(
329
                            p_interpret,
330
                            boundary_index,
331
                            notification(),
332
                            invoke);
333
                });
334

335
        return InterpretState::Flow;
336
    }
337

338
    InterpretState ScriptSemantics_abstract::executeProcedureCheck()
339
    {
340
        /// \todo Проверять, что была вызвана не функция, а процедура? Или как в C/C++?
341

342
        stack().pop();
343
        return InterpretState::Flow;
344
    }
345

346
    InterpretState ScriptSemantics_abstract::executePrint(bool need_detailed_report)
347
    {
348
        inter().expr().print(need_detailed_report);
349
        stack().pop();
350

351
        return InterpretState::Flow;
352
    }
353

354
    InterpretState ScriptSemantics_abstract::executeBlock(bool is_beginning_of_block, const ast::Node & op)
355
    {
356
        if (is_beginning_of_block) {
357
            boundary_index_t boundary_index = stack().startBoundary(BoundScope::Local);
358

359
            inter().addFlowLayer(
360
                    op,
361
                    [this, boundary_index](const FlowLayerInfo & ) 
362
                    {
363
                        stack().clearBoundary(boundary_index);
364
                    });
365
        }
366

367
        return InterpretState::Flow;
368
    }
369

370
    InterpretState ScriptSemantics_abstract::executePop()
371
    {
372
        stack().pop();
373

374
        return InterpretState::Flow;
375
    }
376

377
    InterpretState ScriptSemantics_abstract::executeFunctionDefinition( 
378
                                            const ast::Node * pop_closure, 
379
                                            const ast::Node * pop_params,
380
                                            const ast::Node * pop_return_type,
381
                                            const ast::Node & op_body)
382
    {
383
        boundary_index_t boundary_index = stack().startBoundary();
384

385
        std::function<void(const FlowLayerInfo &)> call_back = 
386
                [this, boundary_index](const FlowLayerInfo & flow)
387
                {
388
                    if (flow.error_sign) {
389
                        _function_definition_data.setReturnType({});
390
                        stack().clearBoundary(boundary_index);
391
                        _function_definition_mode = false;
392
                        stack().push(variable::error_variable());
393
                        return;
394
                    }
395

396
                    if (_function_definition_data.state() == FunctionDefinition_data::State::Params) {
397
                        auto [begin_index,end_index] = stack().boundaryLowAndTop(boundary_index);
398
                        assert(end_index-begin_index > 0);
399

400
                        variable::Object params;
401

402
                        for(name_index_t i=begin_index; i < end_index; ++i) {
403
                            const variable::Variable & param   = stack().variable(i);
404
                            const variable::Variable & closure = _function_definition_data.closures().getVariableByName(param.name());
405
                            if (!closure.name().empty()) {
406
                                inout::TokenLocation location = param.location();
407

408
                                _function_definition_data.setReturnType({});
409
                                stack().clearBoundary(boundary_index);
410
                                _function_definition_mode = false;
411
                                stack().push(variable::error_variable());
412

413
                                throw AnalyzeException("ScriptSemantics_abstract::executeFunctionDefinition", 
414
                                                        location.makeLocation(inter().files()), 
415
                                                        inout::fmt("The argument and closure have the same names"));
416
                            }
417
                            params.add(param);
418
                        }
419

420
                        stack().pop(end_index - begin_index);
421

422
                        _function_definition_data.setParams(params);
423

424
                        if (_function_definition_data.pop_return_type()) {
425
                            inter().addFlowLayer(*_function_definition_data.pop_return_type(), flow.on_layer_end);
426
                            return;
427
                        }
428

429
                        _function_definition_data.setReturnType({});
430
                        stack().clearBoundary(boundary_index);
431
                        _function_definition_mode = false;
432
                        stack().push(_function_definition_data.createFunction());
433
                        return;
434
                    }
435

436
                    assert(_function_definition_data.state() == FunctionDefinition_data::State::Return_Type);
437

438
                    _function_definition_data.setReturnType(
439
                                createVariable(stack().accumulator(), flow.code_flow.token(), variable::SPEC_ORIGIN_TYPE));
440
                    stack().clearBoundary(boundary_index);
441
                    _function_definition_mode = false;
442
                    stack().push(_function_definition_data.createFunction());
443
                    return;
444
                };
445

446
        variable::Object closures;
447

448
        if (pop_closure)
449
            for(const ast::Node & n : pop_closure->branches()) 
450
                try
451
                {
452
                    variable::Variable v;
453

454
                    if (n.token().lexeme() == u"*")
455
                        v = {u"*", {}, n.token().location()};
456
                    else if (n.token().lexeme() == SELF_VARIABLE_NAME)
457
                        v = {n.token().lexeme(), {}, n.token().location()};
458
                    else {
459
                        v = prepareVariableByToken(n.token());
460

461
                        if (v.name().empty() && v.origin().name().empty())
462
                            throw AnalyzeException("ScriptSemantics_abstract::executeFunctionDefinition", 
463
                                                    n.token().location().makeLocation(inter().files()),
464
                                                    inout::fmt("Variable '%1' not found")
465
                                                        .arg(n.token().lexeme()));
466

467
                        notifyNameUsed(v.origin(), n.token().location());
468
                    }
469
                    closures.add(v.origin());
470
                }
471
                catch(...)
472
                {
473
                    stack().clearBoundary(boundary_index);
474
                    _function_definition_mode = false;
475
                    stack().push(variable::error_variable());
476
                    throw;
477
                }
478

479
        _function_definition_data.initiate(closures, pop_return_type, &op_body);
480
        _function_definition_mode = true;
481

482
        if (pop_params) {
483
            inter().addFlowLayer(*pop_params, call_back);
484
            return InterpretState::Flow;
485
        }
486

487
        variable::Object params;
488
        _function_definition_data.setParams(params);
489

490
        if (pop_return_type) {
491
            inter().addFlowLayer(*pop_return_type, call_back);
492
            return InterpretState::Flow;
493
        }
494

495
        _function_definition_data.setReturnType({});
496
        stack().clearBoundary(boundary_index);
497
        _function_definition_mode = false;
498
        stack().push(_function_definition_data.createFunction());
499

500
        return InterpretState::Flow;
501
    }
502

503
    InterpretState ScriptSemantics_abstract::executeFunctionDefinitionEnd(const ast::Node & )
504
    {
505
        name_index_t         func_index    = stack().top();
506
        variable::Variable & func_variable = stack().variable(func_index).origin();
507

508
        assert(func_variable.value().isFunction());
509

510
        func_variable.value().setInternalParent(inter().expr().makeSelf());
511

512
        _functions_for_closures.push_back(func_variable.value().getFunction());
513

514
        return InterpretState::Flow;
515
    }
516

517
    InterpretState ScriptSemantics_abstract::executePostAssignment(const ast::Node & )
518
    {
519
        while(!_functions_for_closures.empty()) {
520
            std::shared_ptr<variable::Object> function_object = _functions_for_closures.back();
521
            _functions_for_closures.pop_back();
522

523
            assert(!function_object->variables().empty());
524

525
            variable::Variable & function_core = function_object->getVariableByIndex_mutable(0);
526
            variable::Object &   closures      = function_core.value().getIntFunctionClosures();
527
            variable::Object     tmp_closures;
528

529
            for(const variable::Variable & closure : closures.variables())
530
                if (closure.name() == u"*") {
531
                    boundary_index_t module_bound = stack().findNearestMarkedBoundary(BOUNDARY_MARK_MODULE_FRAME, BoundScope::Global);
532
                    if (module_bound != UNDEFINED_BOUNDARY_INDEX) {
533
                        auto [begin_index, end_index] = stack().boundaryLowAndTop(module_bound);
534
                        for(name_index_t i = begin_index; i < end_index; ++i) {
535
                            variable::Variable & v = stack().variable(i);
536
                            tmp_closures.add(v.origin());
537
                        }
538
                    }
539
                }
540
                else {
541
                    variable::Variable v = prepareVariableByToken({closure.name(), closure.location()});
542
                    if (v.name().empty() && v.origin().name().empty())
543
                        tmp_closures.add(closure);
544
                    else {
545
                        tmp_closures.add(v.origin());
546

547
                    if (closure.name() == SELF_VARIABLE_NAME)
548
                        notifyDeclared(v);
549
                    else
550
                        notifyNameUsed(v.origin(), closure.location());
551
                    }
552
                }
553

554
            closures.swap(tmp_closures);
555
        }
556

557
        return InterpretState::Flow;
558
    }
559

560
    InterpretState ScriptSemantics_abstract::executeFunctionTethered(const ast::Node & )
561
    {
562
        name_index_t         func_index    = stack().top();
563
        variable::Variable & func_variable = stack().variable(func_index).origin();
564
        assert(func_variable.value().isFunction());
565

566
        func_variable.spec().set(variable::SPEC_TETHERED, true);
567

568
        return InterpretState::Flow;
569
    }
570

571
    InterpretState ScriptSemantics_abstract::executeReturn(const ast::Node & op)
572
    {
573
        ScriptOperationCode operation_code    = static_cast<ScriptOperationCode>(op.operation());
574
        boundary_index_t    function_boundary = stack().findNearestMarkedBoundary(BOUNDARY_MARK_FUNCTION_FRAME,BoundScope::Global);
575

576
        if (operation_code == ScriptOperationCode::ReturnExpression) {
577
            variable::Variable & top = stack().variable(stack().top());
578
            inter().expr().setReturnValue(top.origin().value());
579
            stack().pop();
580
        }
581

582
        if (function_boundary == UNDEFINED_BOUNDARY_INDEX)
583
            throw AnalyzeException( "ScriptSemantics_abstract::executeReturn", 
584
                                    op.token().makeLocation(inter().files()), 
585
                                    inout::fmt("Inappropriate use of the return statement"));
586

587
        const auto [begin,end]      = stack().boundaryLowAndTop(function_boundary);
588

589
        name_index_t                function_index       { begin-1 };
590
        variable::Variable &        function             { stack().variable(function_index).origin() };
591
        variable::FunctionWrapper   func                 { function };
592
        variable::ValueType         return_declared_type { func.getReturnDeclarationVariable().type() };
593

594
        if (return_declared_type != variable::ValueType::Null && inter().expr().return_value().type() != variable::ValueType::Null
595
         && return_declared_type != inter().expr().return_value().type())
596
            inter().expr().setReturnValue(inter().expr().convertVariable({u"", inter().expr().return_value(), op.token().location()},return_declared_type).value());
597

598
        if (return_declared_type != variable::ValueType::Null && operation_code == ScriptOperationCode::Return)
599
            throw AnalyzeException( "ScriptSemantics_abstract::executeReturn", 
600
                                    op.token().makeLocation(inter().files()), 
601
                                    inout::fmt("The function must return a value"));
602

603
        if (checkInterpretType(InterpretType::Preview)
604
         || function.name().substr(0,2) == u"__"
605
        ) {
606
            while(!_cycle_data_stack.empty() && _cycle_data_stack.back().boundary_index > function_boundary)
607
                _cycle_data_stack.pop_back();
608

609
            const ast::Node * code = std::get<variable::InternalFunction>(func.getCallingAddressVariable().variant()).code;
610
            bool returned = inter().flushLayers(*code, true);
611
            assert(returned);
612
        }
613

614
        return InterpretState::Flow;
615
    }
616

617
    InterpretState ScriptSemantics_abstract::executeFor(const inout::Token & ,
618
                                                      const ast::Node * pop_variable, 
619
                                                      const ast::Node * pop_source, 
620
                                                      const ast::Node * pop_body)
621
    {
622
        assert(pop_variable);
623
        assert(pop_source);
624
        assert(pop_body);
625

626
        boundary_index_t boundary_index = stack().startBoundary(BoundScope::Local, BOUNDARY_MARK_CYCLE_FRAME);
627

628
        _cycle_data_stack.push_back({boundary_index, pop_variable, pop_source, pop_body});
629

630
        inter().addFlowLayer(
631
                *_cycle_data_stack.back().pop_variable, 
632
                [this, boundary_index](const FlowLayerInfo & flow)
633
                {
634
                    if (flow.error_sign) {
635
                        stack().clearBoundary(boundary_index);
636
                        _cycle_data_stack.pop_back();
637
                        return;
638
                    }
639

640
                    _cycle_data_stack.back().variable_index = stack().top();
641
                    _cycle_data_stack.back().typed_variable = stack().variable(_cycle_data_stack.back().variable_index).origin();
642

643
                    inter().addFlowLayer(*_cycle_data_stack.back().pop_source, _for_source_callback);
644
                });
645

646
        return InterpretState::Flow;
647
    }
648

649
    InterpretState ScriptSemantics_abstract::executeWhile(const inout::Token & ,
650
                                                        const ast::Node * pop_expression, 
651
                                                        const ast::Node * pop_body)
652
    {
653
        assert(pop_expression);
654
        assert(pop_body);
655

656
        boundary_index_t boundary_index = stack().startBoundary(BoundScope::Local, BOUNDARY_MARK_CYCLE_FRAME);
657

658
        _cycle_data_stack.push_back({boundary_index, pop_expression, pop_body});
659

660
        inter().addFlowLayer(*_cycle_data_stack.back().pop_expression, _cycle_condition_callback);
661

662
        return InterpretState::Flow;
663
    }
664

665
    InterpretState ScriptSemantics_abstract::executeDoWhile(const inout::Token & ,
666
                                                          const ast::Node * pop_body, 
667
                                                          const ast::Node * pop_expression)
668
    {
669
        assert(pop_body);
670
        assert(pop_expression);
671

672
        boundary_index_t boundary_index = stack().startBoundary(BoundScope::Local, BOUNDARY_MARK_CYCLE_FRAME);
673

674
        _cycle_data_stack.push_back({boundary_index, pop_expression, pop_body});
675

676
        inter().addFlowLayer(*_cycle_data_stack.back().pop_body, _cycle_body_callback);
677

678
        return InterpretState::Flow;
679
    }
680

681
    InterpretState ScriptSemantics_abstract::executeBreak(const ast::Node & op)
682
    {
683
        if (_cycle_data_stack.empty()
684
         || UNDEFINED_BOUNDARY_INDEX == stack().findNearestMarkedBoundary(BOUNDARY_MARK_CYCLE_FRAME))
685
            throw AnalyzeException( "ScriptSemantics_abstract::executeBreak",    
686
                                    op.token().makeLocation(inter().files()), 
687
                                    inout::fmt("Inappropriate use of the 'break' statement"));
688

689
        if (checkInterpretType(InterpretType::Preview)) {
690
            inter().flushLayers(*_cycle_data_stack.back().pop_body,false);
691
            stack().clearBoundary(_cycle_data_stack.back().boundary_index);
692
            _cycle_data_stack.pop_back();
693
        }
694

695
        return InterpretState::Flow;
696
    }
697

698
    InterpretState ScriptSemantics_abstract::executeContinue(const ast::Node & op)
699
    {
700
        if (_cycle_data_stack.empty()
701
         || UNDEFINED_BOUNDARY_INDEX == stack().findNearestMarkedBoundary(BOUNDARY_MARK_CYCLE_FRAME))
702
            throw AnalyzeException( "ScriptSemantics_abstract::executeContinue", 
703
                                    op.token().makeLocation(inter().files()), 
704
                                    inout::fmt("Inappropriate use of the 'continue' statement"));
705

706
        if (checkInterpretType(InterpretType::Preview))
707
            inter().flushLayers(*_cycle_data_stack.back().pop_body,true);
708

709
        return InterpretState::Flow;
710
    }
711

712
    InterpretState ScriptSemantics_abstract::executeReference(const ast::Node & )
713
    {
714
        name_index_t         var_index  = stack().top();
715
        variable::Variable & var        = stack().variable(var_index);
716

717
        if (!var.value().isRef())
718
            throw AnalyzeException("ScriptSemantics_abstract::executeReference", 
719
                                    var.location().makeLocation(inter().files()), 
720
                                    inout::fmt("It is unacceptable to take a reference for a temporary value"));
721

722
        var.spec().set(variable::SPEC_REFERENCE, true);
723

724
        return InterpretState::Flow;
725
    }
726

727
    InterpretState ScriptSemantics_abstract::executeArrayElement(const ast::Node & op)
728
    {
729
        name_index_t     array_index    = stack().top();
730
        boundary_index_t boundary_index = stack().startBoundary();
731

732
        inter().addFlowLayer(
733
                op, 
734
                [this, array_index, boundary_index](const FlowLayerInfo & flow) 
735
                {
736
#ifdef DEBUG
737
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
738
#endif
739
                    if (flow.error_sign) {
740
                        stack().clearBoundary(boundary_index);
741
                        stack().pop();
742
                        stack().push(variable::error_variable(flow.code_flow.bound().location()));
743
                        return;
744
                    }
745

746
                    const variable::Variable & array_variable = stack().variable(array_index);
747
                    const variable::Variable & array_origin   = array_variable.origin();
748
                    variable::VariableRef      ref;
749

750
                    try
751
                    {
752
                        auto [begin_index, end_index] = stack().boundaryLowAndTop(boundary_index);
753

754
                        if (array_origin.type() == variable::ValueType::Object) {
755
                            if (end_index-begin_index != 1)
756
                                throw AnalyzeException("ScriptSemantics_abstract::executeArrayElement", 
757
                                                        array_variable.location().makeLocation(inter().files()), 
758
                                                        inout::fmt("Unable to multi-index variable '%1'")
759
                                                        .arg(array_origin.name()));
760

761
                            std::shared_ptr<variable::Object> object         = array_origin.value().getObject();
762
                            const variable::Variable &        index_variable = stack().variable(begin_index);
763

764
                            if (index_variable.origin().type() == variable::ValueType::Int) {
765
                                ref = object->getVariableByIndex(index_variable.origin().value().getInt()).makeReference();
766
                            }
767
                            else if (index_variable.origin().type() == variable::ValueType::String) {
768
                                std::u16string       name = index_variable.origin().value().getString();
769
                                variable::Variable & var  = object->getVariableByName_mutable(name);
770

771
                                if (var.name().empty()) {
772
                                    const ast::Node * p_next_node = inter().lookupOperationNode(+1);
773

774
                                    if (p_next_node
775
                                     && checkSemanticName(p_next_node->host()) 
776
                                     && ScriptOperationCode(p_next_node->operation()) == ScriptOperationCode::Assignment) {
777
                                        object->add({name, {}, index_variable.location()});
778
                                        variable::Variable & v = object->getVariableByName_mutable(name);
779
                                        assert(!v.name().empty());
780
                                        ref = v.makeReference();
781
                                    }
782
                                    else {
783
                                        // Оставляем ref пустым, а далее для этого случая кладём на стек null
784
                                    }
785
                                }
786
                                else
787
                                    ref = var.makeReference();
788
                            }
789
                            else
790
                                throw AnalyzeException("ScriptSemantics_abstract::executeArrayElement", 
791
                                                        index_variable.location().makeLocation(inter().files()), 
792
                                                        inout::fmt("Incorrect index type '%1'")
793
                                                        .arg(variable::getValueTypeName(index_variable.origin().type())));
794
                        }
795
                        else if (array_origin.type() == variable::ValueType::Array) {
796
                            std::vector<variable::index_t> indexes;
797

798
                            for(name_index_t i = begin_index; i < end_index; ++i) {
799
                                const variable::Variable & index_variable = stack().variable(i);
800
                                if (index_variable.origin().type() == variable::ValueType::Int) {
801
                                    int64_t index = index_variable.origin().value().getInt();
802

803
                                    if (index >= 0 && index < std::numeric_limits<variable::index_t>::max()) {
804
                                        indexes.push_back(variable::index_t(index));
805
                                        continue;
806
                                    }
807
                                }
808

809
                                throw AnalyzeException("ScriptSemantics_abstract::executeArrayElement", 
810
                                        stack().variable(i).location().makeLocation(inter().files()), 
811
                                        inout::fmt("The index must be a positive integer number and not exceed %1")
812
                                            .arg(std::numeric_limits<variable::index_t>::max()));
813
                            }
814

815
                            ref = array_origin.value().getArray()->getRefByIndex(indexes);
816
                        }
817
                        else
818
                            throw AnalyzeException("ScriptSemantics_abstract::executeArrayElement", 
819
                                                    array_variable.location().makeLocation(inter().files()), 
820
                                                    inout::fmt("Invalid type %1 for indexing. The indexing operation is only available for arrays and objects")
821
                                                    .arg(variable::getValueTypeName(array_origin.type())));
822
                    }
823
                    catch(...)
824
                    {
825
                        stack().clearBoundary(boundary_index);
826
                        stack().pop();
827
                        stack().push(variable::error_variable(flow.code_flow.bound().location()));
828
                        throw;
829
                    }
830

831
                    stack().clearBoundary(boundary_index);
832
                    stack().pop();
833
                    
834
                    if (ref.empty())
835
                        stack().push({{}, {}, flow.code_flow.bound().location()});
836
                    else
837
                        stack().push({{}, ref, flow.code_flow.bound().location()});
838
                });
839

840
        return InterpretState::Flow;
841
    }
842

843
    InterpretState ScriptSemantics_abstract::executeObjectStructure(const ast::Node & op)
844
    {
845
        if (op.branches().empty()) {
846
            stack().push({ {}, variable::VariableSet_t {}, op.token().location(), 
847
                         variable::VariableSet_t { {{variable::SPEC_ORIGIN, variable::SPEC_ORIGIN_STRUCTURE}, }} });
848
            return InterpretState::Flow;
849
        }
850

851
        _executeRecordStructure_stack.push_back({stack().startBoundary(), op});
852

853
        inter().addFlowLayer(
854
                op.branches().front(),                 
855
                [this](const FlowLayerInfo & flow) 
856
                {
857
                    boundary_index_t  boundary_index    = _executeRecordStructure_stack.back().boundary_index;
858
                    const ast::Node & op                = _executeRecordStructure_stack.back().op;
859
                    size_t &          op_branches_index = _executeRecordStructure_stack.back().op_branches_index;
860

861
                    try
862
                    {
863
                        // Проверяем уникальность имени
864
                        auto [begin_index, end_index] = stack().boundaryLowAndTop(boundary_index);
865
                        for(name_index_t i=begin_index; i < end_index; ++i)
866
                            if (stack().variable(i).name() == flow.code_flow.token().lexeme())
867
                                throw AnalyzeException("ScriptSemantics_abstract::executeObjectStructure", 
868
                                                flow.code_flow.token().makeLocation(inter().files()),
869
                                                inout::fmt("Duplicate object element name '%1'")
870
                                                    .arg(flow.code_flow.token().lexeme()));
871

872
                        variable::Variable         param             = { flow.code_flow.token().lexeme(), {}, flow.code_flow.token().location() };
873
                        name_index_t               param_value_index = stack().top();
874
                        const variable::Variable & param_value       = stack().variable(param_value_index);
875

876
                        param.setValue(param_value.value());
877
                        param.spec().clone(param_value.spec());
878

879
                        stack().pop();
880
                        stack().push(param);
881

882
                        notifyDeclared(param);
883

884
                        // Переключаемся на следующий элемент объекта
885
                        op_branches_index += 1;
886

887
                        if (op_branches_index >= op.branches().size()) {
888
                            // Элементы закончились
889
                            std::shared_ptr<variable::Object> obj = stack().convertToObject(boundary_index);
890
                            stack().clearBoundary(boundary_index);
891
                            stack().push({ {}, obj, op.token().location(), 
892
                                         variable::VariableSet_t { {{variable::SPEC_ORIGIN, variable::SPEC_ORIGIN_STRUCTURE}, }} });
893
                            _executeRecordStructure_stack.pop_back();
894
                        }
895
                        else
896
                            // Ставим на обработку выражение справа от очередной переменной объекта
897
                            inter().addFlowLayer(op.branches()[op_branches_index], flow.on_layer_end);
898
                    }
899
                    catch(...)
900
                    {
901
                        if (stack().clearBoundary(boundary_index))
902
                            stack().push(variable::error_variable());
903
                        _executeRecordStructure_stack.pop_back();
904
                        throw;
905
                    }
906
                });
907

908
        return InterpretState::Flow;
909
    }
910

911
    InterpretState ScriptSemantics_abstract::executeArrayStructure(const ast::Node & op)
912
    {
913
        boundary_index_t boundary_index = stack().startBoundary();
914

915
        inter().addFlowLayer(
916
                op, 
917
                [this, boundary_index](const FlowLayerInfo & flow) 
918
                {
919
                    std::vector<variable::Value> values;
920

921
                    try
922
                    {
923
                        auto [begin_index,end_index] = stack().boundaryLowAndTop(boundary_index);
924
                        for(name_index_t i=begin_index; i < end_index; ++i)
925
                            values.push_back(stack().variable(i).origin().value());
926
                    }
927
                    catch(...)
928
                    {
929
                        stack().clearBoundary(boundary_index);
930
                        stack().push(variable::error_variable());
931
                        throw;
932
                    }
933

934
                    stack().clearBoundary(boundary_index);
935
                    std::shared_ptr<variable::Array> array = std::make_shared<variable::Array>(
936
                                                                variable::ValueType::Null, 
937
                                                                std::vector<variable::index_t> {static_cast<variable::index_t>(values.size())}, 
938
                                                                values);
939

940
                    stack().push({{}, array, flow.code_flow.token().location(), {}});
941
                });
942

943
        return InterpretState::Flow;
944
    }
945

946
    InterpretState ScriptSemantics_abstract::executeImport(const inout::Token & path)
947
    try
948
    {
949
#ifdef DEBUG
950
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
951
#endif
952
        std::string module_path = makeModulePath(path, inter().files().at(path.location().uri_index()));
953

954
        if (path.type() == inout::LexemeType::Annotation && !_module_management.isTheModuleLoaded(module_path)) {
955
            if (!fs::exists(module_path))
956
                throw AnalyzeException("ScriptSemantics_abstract::executeImport", 
957
                                path.makeLocation(inter().files()),
958
                                inout::fmt("File '%1' was not found")
959
                                    .arg(module_path));
960

961
            notifyRef(path, inout::toU16(module_path));
962
            inter().addFile(module_path);
963

964
            const ast::Node * node = _module_management.getCode(module_path,inter().files());
965
            if (node == nullptr)
966
                throw interpret::AnalyzeException("ScriptSemantics_abstract::executeImport", 
967
                                            path.makeLocation(inter().files()),
968
                                            inout::fmt("Unable to load module '%1'")
969
                                                .arg(module_path));
970

971
            boundary_index_t boundary_index = stack().startBoundary(BoundScope::Global, BOUNDARY_MARK_MODULE_FRAME);
972

973
            inter().addFlowLayer(
974
                    *node, 
975
                    [this,boundary_index,path,module_path](const FlowLayerInfo &)
976
                    {
977
#ifdef DEBUG
978
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
979
#endif
980
                        std::shared_ptr<variable::Object> record;
981

982
                        try
983
                        {
984
                            std::shared_ptr<variable::Object> module_object = stack().convertToObject(boundary_index);
985
                            if (module_object) {
986
                                std::shared_ptr<variable::Module_interface> module 
987
                                                = _module_management.registerSoftModule(module_path,module_object);
988
                                if (module)
989
                                    /// \todo Пересмотреть странную передачу самого себя в свой же метод.
990
                                    /// PVS Studio: warn V678 An object is used as an argument to its own method.
991
                                    /// Consider checking the first actual argument of the 'instantiate' function.
992
                                    record = module->instantiate(module).getObject();
993
                            }
994

995
                            if (!record)
996
                                throw AnalyzeException("ScriptSemantics_abstract::executeImport", 
997
                                                path.makeLocation(inter().files()),
998
                                                inout::fmt("Unable to load module '%1'")
999
                                                    .arg(module_path));
1000
                        }
1001
                        catch(...)
1002
                        {
1003
                            stack().clearBoundary(boundary_index);
1004
                            stack().push({ {}, {}, path.location(), 
1005
                                        variable::VariableSet_t {{{variable::SPEC_ORIGIN, variable::SPEC_ORIGIN_MODULE}, }} });
1006
                            throw;
1007
                        }
1008

1009
                        stack().clearBoundary(boundary_index);
1010
                        stack().push({ {}, record, path.location(), 
1011
                                    variable::VariableSet_t {{{variable::SPEC_ORIGIN, variable::SPEC_ORIGIN_MODULE}, }} });
1012
                    });
1013
        }
1014
        else {
1015
            // =====================================================================================================
1016
            // =====================================================================================================
1017
            // =====================================================================================================
1018
            // =====================================================================================================
1019
            // =====================================================================================================
1020
            // =====================================================================================================
1021
            // =====================================================================================================
1022
            // =====================================================================================================
1023
            // =====================================================================================================
1024
            // =====================================================================================================
1025
            // =====================================================================================================
1026
            // =====================================================================================================
1027
            // =====================================================================================================
1028
            // =====================================================================================================
1029
            // =====================================================================================================
1030
            // =====================================================================================================
1031
            // =====================================================================================================
1032
            // =====================================================================================================
1033
            // =====================================================================================================
1034
            // =====================================================================================================
1035
            std::shared_ptr<variable::Object> object = _module_management.produceObject(module_path,&inter());
1036
            if (!object)
1037
                throw interpret::AnalyzeException("ScriptSemantics_abstract::executeImport", 
1038
                                            path.makeLocation(inter().files()),
1039
                                            inout::fmt("Unable to load module '%1'")
1040
                                                .arg(module_path));
1041

1042
            stack().push({ {}, object, path.location(), 
1043
                        variable::VariableSet_t {{{variable::SPEC_ORIGIN, variable::SPEC_ORIGIN_MODULE}, }} });
1044
        }
1045

1046
        return InterpretState::Flow;
1047
    }
1048
    catch(...)
1049
    {
1050
        stack().push({ {}, variable::VariableSet_t {}, path.location(), 
1051
                    variable::VariableSet_t {{{variable::SPEC_ORIGIN, variable::SPEC_ORIGIN_MODULE}, }} });
1052
        throw;
1053
    }
1054

1055
    InterpretState ScriptSemantics_abstract::executeAnnouncement()
1056
    {
1057
        name_index_t               top      = stack().top();
1058
        const variable::Variable & contract = stack().variable(top);
1059

1060
        appendContractProperties(contract, stack().accumulator());
1061
        stack().pop();
1062

1063
        return InterpretState::Flow;
1064
    }
1065

1066
    InterpretState ScriptSemantics_abstract::executeContract(const ast::Node & op)
1067
    {
1068
        if (stack().find(op.token().lexeme(),interpret::BoundScope::Local) != UNDEFINED_NAME_INDEX) {
1069
            stack().push(variable::error_variable());
1070
            throw AnalyzeException( "ScriptSemantics_abstract::executeContract", 
1071
                                    op.token().location().makeLocation(inter().files()), 
1072
                                    inout::fmt("The name '%1' has already been declared in the local scope")
1073
                                        .arg(op.token().lexeme()));
1074
        }
1075

1076
        variable::Variable new_contract {op.token().lexeme(), {}, op.token().location()};
1077

1078
        appendContractProperties(stack().accumulator(), new_contract);
1079

1080
        if (new_contract.type() == variable::ValueType::Null
1081
         && new_contract.spec().object()->getVariableByName(variable::SPEC_NAME_INITIAL_VALUE).name().empty()
1082
         && new_contract.spec().object()->getVariableByName(variable::SPEC_NAME_BUILT_IN_TYPE).name().empty()) {
1083
            if (ScriptOperationCode(op.operation()) == ScriptOperationCode::Type)
1084
                throw AnalyzeException( "ScriptSemantics_abstract::executeContract", 
1085
                                        op.token().location().makeLocation(inter().files()), 
1086
                                        inout::fmt("Type '%1' is not typed")
1087
                                            .arg(op.token().lexeme()));
1088
            new_contract.spec().set(variable::SPEC_ORIGIN, variable::SPEC_ORIGIN_CONTRACT);
1089
        }
1090
        else
1091
            new_contract.spec().set(variable::SPEC_ORIGIN, variable::SPEC_ORIGIN_TYPE);
1092

1093
        stack().push(new_contract);
1094
        notifyDeclared(new_contract);
1095

1096
        return InterpretState::Flow;
1097
    }
1098

1099
    InterpretState ScriptSemantics_abstract::executeDeclaration(const ast::Node & op)
1100
    {
1101
#ifdef DEBUG
1102
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
1103
#endif
1104
        if (stack().find(op.token().lexeme(),interpret::BoundScope::Local) != UNDEFINED_NAME_INDEX) {
1105
            stack().push(variable::error_variable());
1106
            throw AnalyzeException( "ScriptSemantics_abstract::executeDeclaration", 
1107
                                    op.token().location().makeLocation(inter().files()), 
1108
                                    inout::fmt("The name '%1' has already been declared in the local scope")
1109
                                        .arg(op.token().lexeme()));
1110
        }
1111

1112
        if (ScriptOperationCode(op.operation()) == ScriptOperationCode::AutoDeclaration) {
1113
            stack().accumulator() = {u"", {variable::ValueType::Null}, op.token().location()};
1114
            stack().accumulator().spec().set(variable::SPEC_NAME_INITIAL_VALUE, variable::ValueType::Null);
1115
        }
1116

1117
        variable::Variable var = createVariable(stack().accumulator(), op.token(), variable::SPEC_ORIGIN_VARIABLE);
1118

1119
        if (_function_definition_mode)
1120
            var.spec().set(variable::SPEC_PARAMETER, true);
1121
        else if (stack().getTopBoundaryMarkAndScope().first == BOUNDARY_MARK_MODULE_FRAME)
1122
            var.spec().set(variable::SPEC_PROPERTY, true);
1123

1124
        stack().push(var);
1125
        notifyDeclared(stack().variable(stack().top()));
1126

1127
        return InterpretState::Flow;
1128
    }
1129

1130
    InterpretState ScriptSemantics_abstract::executeDeclarationOnce(const ast::Node & op)
1131
    {
1132
#ifdef DEBUG
1133
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
1134
#endif
1135
        const variable::Variable & var = stack().findVariable(op.token().lexeme());
1136

1137
        if (var.name().empty())
1138
            return executeDeclaration(op);
1139

1140
        return InterpretState::Flow;
1141
    }
1142

1143
    InterpretState ScriptSemantics_abstract::executeDeclarationCompletion()
1144
    {
1145
        stack().accumulator() = {};
1146
        return InterpretState::Flow;
1147
    }
1148

1149
    InterpretState ScriptSemantics_abstract::executeAssignment(const ast::Node & op)
1150
    {
1151
#ifdef DEBUG
1152
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
1153
#endif
1154
        bool iteration = false;
1155
        switch (ScriptOperationCode(op.operation()))
1156
        {
1157
        case ScriptOperationCode::AssignmentAddition:
1158
        case ScriptOperationCode::AssignmentSubtraction:
1159
        case ScriptOperationCode::AssignmentMultiplication:
1160
        case ScriptOperationCode::AssignmentDivision:
1161
        case ScriptOperationCode::AssignmentModulo:
1162
            stack().pushRef(stack().variable(stack().top()), op.token().location());
1163
            iteration = true;
1164
            break;
1165
        default:
1166
            break;
1167
        }
1168

1169
        if (_setter_in_stack) {
1170
            _setter_in_stack = false;
1171
            if (iteration) {
1172
                stack().pop();
1173
                stack().push(variable::error_variable(op.token().location()));             
1174
                throw AnalyzeException( "ScriptSemantics_abstract::executeAssignment", 
1175
                                        op.token().location().makeLocation(inter().files()), 
1176
                                        inout::fmt("Assignment-iteration is not allowed for the setter"));
1177
            }
1178
            return executeFunctionCall(op);
1179
        }
1180

1181
        inter().addFlowLayer(
1182
                op, 
1183
                [this, iteration](const FlowLayerInfo & flow) 
1184
                {
1185
#ifdef DEBUG
1186
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
1187
#endif
1188
                    if (flow.error_sign) {
1189
                        stack().pop();
1190
                        return;
1191
                    }
1192

1193
                    if (iteration)
1194
                        try
1195
                        {
1196
                            arithmetic(ScriptOperationCode(flow.code_flow.operation()), flow.code_flow.token().location());
1197
                        }
1198
                        catch(...)
1199
                        {
1200
                            stack().pop();
1201
                            throw;
1202
                        }
1203

1204
                    name_index_t         source_index    = stack().top(0);
1205
                    variable::Variable & source_variable = stack().variable(source_index);
1206
                    name_index_t         target_index    = stack().top(1);
1207
                    variable::Variable & target_variable = stack().variable(target_index);
1208
                    ScriptOperationCode  operation_code  = ScriptOperationCode(flow.code_flow.operation());
1209

1210
                    /// \todo Нужно переделать ВСЕ методы присваивания и копирования 
1211
                    /// с учётом нового self!!!
1212

1213
                    inter().expr().assignVariable(target_variable, source_variable);
1214
                    stack().pop(); // правая часть присваивания
1215

1216
                    if (operation_code == ScriptOperationCode::Initialize)
1217
                        notifyInitiated(target_variable.origin());
1218
                    else
1219
                        stack().pop(); // ссылка на переменную
1220

1221
                    name_index_t                var_index   = stack().top(0);
1222
                    const variable::Variable &  var         = stack().variable(var_index);
1223

1224
                    notifyNameUsed(var.origin(), var.location());
1225
                });
1226

1227
        return InterpretState::Flow;
1228
    }
1229

1230
    InterpretState ScriptSemantics_abstract::executeUnary(const ast::Node & op)
1231
    {
1232
        unary(static_cast<ScriptOperationCode>(op.operation()), op.bound().location());
1233
        return InterpretState::Flow;
1234
    }
1235

1236
    InterpretState ScriptSemantics_abstract::executeLogical(const ast::Node & op)
1237
    {
1238
        name_index_t top_name_index = stack().top();
1239

1240
        try
1241
        {
1242
            logical(static_cast<ScriptOperationCode>(op.operation()), op.bound().location());
1243
        }
1244
        catch(...)
1245
        {
1246
            stack().pop(stack().top()+1-top_name_index);
1247
            stack().variable(stack().top()) = variable::error_variable().copyVariable();
1248
            throw;
1249
        }
1250

1251
        return InterpretState::Flow;
1252
    }
1253

1254
    InterpretState ScriptSemantics_abstract::executeCompare(const ast::Node & op)
1255
    {
1256
        name_index_t top_name_index = stack().top();
1257

1258
        try
1259
        {
1260
            compare(static_cast<ScriptOperationCode>(op.operation()), op.bound().location());
1261
        }
1262
        catch(...)
1263
        {
1264
            stack().pop(stack().top()+1-top_name_index);
1265
            stack().variable(stack().top()) = variable::error_variable().copyVariable();
1266
            throw;
1267
        }
1268

1269
        return InterpretState::Flow;
1270
    }
1271

1272
    InterpretState ScriptSemantics_abstract::executeArithmetic(const ast::Node & op)
1273
    {
1274
        name_index_t top_name_index = stack().top();
1275

1276
        try
1277
        {
1278
            arithmetic(static_cast<ScriptOperationCode>(op.operation()), op.bound().location());
1279
        }
1280
        catch(...)
1281
        {
1282
            name_index_t current_top_name_index = stack().top();
1283
            size_t       pop_count              = current_top_name_index - top_name_index + 1;
1284
            
1285
            stack().pop(pop_count);
1286
            stack().variable(stack().top()) = variable::error_variable().copyVariable();
1287
            throw;
1288
        }
1289

1290
        return InterpretState::Flow;
1291
    }
1292

1293
    InterpretState ScriptSemantics_abstract::executeConditional(ScriptOperationCode code, const ast::Node & op_true, const ast::Node * op_false)
1294
    {
1295
        name_index_t       condition_index    = stack().top();
1296
        variable::Variable condition_variable = stack().variable(condition_index).origin();
1297

1298
        try
1299
        {
1300
            bool condition;
1301

1302
            if (condition_variable.type() == variable::ValueType::Bool) {
1303
                condition = condition_variable.value().getBool();
1304
            }
1305
            else {
1306
                condition_variable = inter().expr().convertVariable(condition_variable, variable::ValueType::Bool);
1307
                condition          = condition_variable.value().getBool();
1308
            }
1309

1310
            stack().pop();
1311

1312
            if (condition)
1313
                inter().addFlowLayer(op_true);
1314
            else if (op_false != nullptr)
1315
                inter().addFlowLayer(*op_false);
1316

1317
            return InterpretState::Flow;
1318
        }
1319
        catch(...)
1320
        {
1321
            if (code == ScriptOperationCode::Ternary)
1322
                stack().pop(stack().top() - condition_index);
1323

1324
            throw;
1325
        }
1326

1327
        return InterpretState::Flow;
1328
    }
1329

1330
    InterpretState ScriptSemantics_abstract::executeCommon(const ast::Node & , const std::vector<inout::Token> & names)
1331
    {
1332
        for(const inout::Token & t : names) {
1333
            name_index_t name_index = stack().find(t.lexeme());
1334
            if (name_index == UNDEFINED_NAME_INDEX)
1335
                throw AnalyzeException( "ScriptSemantics_abstract::executeCommon", 
1336
                                        t.location().makeLocation(inter().files()), 
1337
                                        inout::fmt("The name '%1' not found")
1338
                                            .arg(t.lexeme()));
1339

1340
            if (stack().addGlobal(name_index))
1341
                notifyNameUsed(stack().variable(name_index), t.location());
1342
            else
1343
                throw AnalyzeException( "ScriptSemantics_abstract::executeCommon", 
1344
                                        t.location().makeLocation(inter().files()), 
1345
                                        inout::fmt("Unable to make the name '%1' global")
1346
                                            .arg(t.lexeme()));
1347
        }
1348

1349
        return InterpretState::Flow;
1350
    }
1351

1352
    InterpretState ScriptSemantics_abstract::executeUsing(const ast::Node & , const ast::Node & body)
1353
    {
1354
        name_index_t               using_index    = stack().top();
1355
        const variable::Variable & using_variable = stack().variable(using_index);
1356
        const variable::Variable & using_origin   = stack().variable(using_index).origin();
1357

1358
        if (using_origin.type() != variable::ValueType::Object)
1359
            throw AnalyzeException( "ScriptSemantics_abstract::executeUsing", 
1360
                                    using_variable.location().makeLocation(inter().files()), 
1361
                                    inout::fmt("Unable to use not object '%1'")
1362
                                        .arg(using_origin.name()));
1363

1364
        boundary_index_t using_bound = stack().startBoundary();
1365

1366
        stack().addUsing(using_origin.value().getObject(), using_bound);
1367

1368
        inter().addFlowLayer(
1369
                body, 
1370
                [this, using_bound](const FlowLayerInfo & ) 
1371
                {
1372
                    stack().clearBoundary(using_bound);
1373
                    stack().pop();
1374
                });
1375

1376
        return InterpretState::Flow;
1377
    }
1378

1379
    InterpretState ScriptSemantics_abstract::executeFiberMake(const ast::Node & op)
1380
    {
1381
        inter().addFlowLayer(
1382
                op, 
1383
                [this](const FlowLayerInfo & flow) 
1384
                {
1385
                    if (flow.error_sign) {
1386
                        stack().pop();
1387
                        return;
1388
                    }
1389

1390
                    try {
1391
                        variable::Variable & fiber_variable_ref    = stack().variable(stack().top());
1392
                        variable::Variable & fiber_variable_origin = fiber_variable_ref.origin();
1393

1394
                        if (!fiber_variable_origin.value().isObject())
1395
                            throw AnalyzeException( "ScriptSemantics_abstract::executeFiberOperation", 
1396
                                                    fiber_variable_ref.location().makeLocation(inter().files()), 
1397
                                                    inout::fmt("Only a variable with an object type can act as a fiber"));
1398

1399
                        std::shared_ptr<variable::Object> object = fiber_variable_origin.value().getObject();
1400

1401
                        if (object->flags().isSet(variable::ObjectFlag::Fiber)) {
1402
                            std::string object_name_text = fiber_variable_ref.name().empty()
1403
                                                         ? inout::toU8(fiber_variable_origin.name()) 
1404
                                                         : inout::toU8(fiber_variable_ref.name());
1405

1406
                            if (!object_name_text.empty())
1407
                                object_name_text = " '" + object_name_text + "'";
1408

1409
                            throw AnalyzeException( "ScriptSemantics_abstract::executeFiberOperation", 
1410
                                                    fiber_variable_ref.location().makeLocation(inter().files()), 
1411
                                                    inout::fmt("Object %1 has already been declared as a fiber")
1412
                                                        .arg(object_name_text));
1413
                        }
1414

1415
                        if (!inter().parallelize().addChildFiber(fiber_variable_origin))
1416
                            throw bormental::DrBormental("ScriptSemantics_abstract::executeFiberOperation",
1417
                                                inout::fmt("Unable to create fiber"));
1418

1419
                        object->setFlag(variable::ObjectFlag::Fiber);
1420
                    }
1421
                    catch(...) {
1422
                        stack().pop();
1423
                        throw;
1424
                    }
1425

1426
                    stack().pop();
1427
                });
1428

1429
        return InterpretState::Flow;
1430
    }
1431

1432
    InterpretState ScriptSemantics_abstract::executeFiberWait(const ast::Node & op)
1433
    {
1434
        inter().addFlowLayer(
1435
                op, 
1436
                [this](const FlowLayerInfo & flow) 
1437
                {
1438
                    if (flow.error_sign) {
1439
                        stack().pop();
1440
                        return;
1441
                    }
1442

1443
                    try {
1444
                        if (checkInterpretType(InterpretType::Preview))
1445
                            if (!inter().parallelize().wait(prepareFiberVariableOrigin()))
1446
                                throw bormental::DrBormental("ScriptSemantics_abstract::executeFiberWait",
1447
                                                    inout::fmt("Unable to wait fiber"));
1448
                    }
1449
                    catch(...) {
1450
                        stack().pop();
1451
                        throw;
1452
                    }
1453

1454
                    stack().pop();
1455
                });
1456

1457
        return InterpretState::Flow;
1458
    }
1459

1460
    InterpretState ScriptSemantics_abstract::executeFiberPushPull(const ast::Node & op)
1461
    {
1462
        inter().addFlowLayer(
1463
                op, 
1464
                [this](const FlowLayerInfo & flow) 
1465
                {
1466
                    if (flow.error_sign) {
1467
                        stack().pop();
1468
                        return;
1469
                    }
1470

1471
                    try {
1472
                        switch(ScriptOperationCode(flow.code_flow.operation()))
1473
                        {
1474
                        case ScriptOperationCode::FiberPush:
1475
                            if (checkInterpretType(InterpretType::Preview))
1476
                                if (!inter().parallelize().push(prepareFiberVariableOrigin()))
1477
                                    throw bormental::DrBormental("ScriptSemantics_abstract::executeFiberPushPull",
1478
                                                                inout::fmt("Unable to push fiber"));
1479
                            break;
1480
                        case ScriptOperationCode::FiberPull:
1481
                            if (checkInterpretType(InterpretType::Preview))
1482
                                if (!inter().parallelize().pull(prepareFiberVariableOrigin()))
1483
                                    throw bormental::DrBormental("ScriptSemantics_abstract::executeFiberPushPull",
1484
                                                                inout::fmt("Unable to pull fiber"));
1485
                            break;
1486
                        default:
1487
                            throw bormental::DrBormental("ScriptSemantics_abstract::executeFiberPushPull",
1488
                                                        inout::fmt("Unexpected operation"));
1489
                        }
1490
                    }
1491
                    catch(...) {
1492
                        stack().pop();
1493
                        throw;
1494
                    }
1495

1496
                    stack().pop();
1497
                });
1498

1499
        return InterpretState::Flow;
1500
    }
1501

1502
    InterpretState ScriptSemantics_abstract::executeFiberFlow(const ast::Node & op)
1503
    {
1504
        _fiber_flow_mode = FiberFlowMode::InDemand;
1505

1506
        inter().addFlowLayer(
1507
                op, 
1508
                [this](const FlowLayerInfo & flow) 
1509
                {
1510
                    if (_fiber_flow_mode != FiberFlowMode::Launched)
1511
                        throw AnalyzeException( "ScriptSemantics_abstract::executeFiberOperation", 
1512
                                                flow.code_flow.token().location().makeLocation(inter().files()), 
1513
                                                inout::fmt("Unable to launch remote procedure"));
1514

1515
                    _fiber_flow_mode = FiberFlowMode::None;
1516
                });
1517

1518
        return InterpretState::Flow;
1519
    }
1520

1521
    InterpretState ScriptSemantics_abstract::executeCheckState(const ast::Node & )
1522
    {
1523
        return InterpretState::Flow;
1524
    }
1525

1526
    InterpretState ScriptSemantics_abstract::executeArrayPush(const ast::Node & )
1527
    {
1528
#ifdef DEBUG
1529
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
1530
#endif
1531
        try
1532
        {
1533
            name_index_t         source_index    = stack().top(0);
1534
            variable::Variable & source_variable = stack().variable(source_index);
1535
            name_index_t         target_index    = stack().top(1);
1536
            variable::Variable & target_variable = stack().variable(target_index);
1537

1538
            if (!target_variable.origin().value().isArray())
1539
                throw AnalyzeException("ScriptSemantics_abstract::executeArrayPush", 
1540
                                        target_variable.location().makeLocation(inter().files()), 
1541
                                        inout::fmt("For working with slices, the variable %1 is not an array")
1542
                                        .arg(target_variable.origin().name()));
1543

1544
            std::shared_ptr<variable::Array> array = target_variable.origin().value().getArray();
1545

1546
            if (array->dimensions().size() > 1)
1547
                throw AnalyzeException("ScriptSemantics_abstract::executeArrayPush", 
1548
                                        target_variable.location().makeLocation(inter().files()), 
1549
                                        inout::fmt("Slice operations are implemented only for vectors"));
1550

1551
            array->add(source_variable.origin().value());
1552
            notifyNameUsed(target_variable.origin(), target_variable.location());
1553
            stack().pop(2);
1554
        }
1555
        catch(...)
1556
        {
1557
            stack().pop(2);
1558
            throw;
1559
        }
1560

1561
        return InterpretState::Flow;
1562
    }
1563

1564
    InterpretState ScriptSemantics_abstract::executeArrayPop(const ast::Node & )
1565
    {
1566
#ifdef DEBUG
1567
        [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(&inter());
1568
#endif
1569
        try
1570
        {
1571
            name_index_t         target_index    = stack().top(0);
1572
            variable::Variable & target_variable = stack().variable(target_index);
1573

1574
            if (!target_variable.origin().value().isArray())
1575
                throw AnalyzeException("ScriptSemantics_abstract::executeArrayPop", 
1576
                                        target_variable.location().makeLocation(inter().files()), 
1577
                                        inout::fmt("For working with slices, the variable %1 is not an array")
1578
                                        .arg(target_variable.origin().name()));
1579

1580
            std::shared_ptr<variable::Array> array = target_variable.origin().value().getArray();
1581

1582
            if (array->dimensions().size() > 1)
1583
                throw AnalyzeException("ScriptSemantics_abstract::executeArrayPop", 
1584
                                        target_variable.location().makeLocation(inter().files()), 
1585
                                        inout::fmt("Slice operations are implemented only for vectors"));
1586

1587
            if (array->values().empty())
1588
                throw bormental::DrBormental("ScriptSemantics_abstract::executeArrayPop", 
1589
                                        inout::fmt("Attempt to take a slice of an empty array"));
1590

1591
            array->pop();
1592
            notifyNameUsed(target_variable.origin(), target_variable.location());
1593
            stack().pop();
1594
        }
1595
        catch(...)
1596
        {
1597
            stack().pop();
1598
            throw;
1599
        }
1600

1601
        return InterpretState::Flow;
1602
    }
1603

1604

1605
}
1606

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.