loom

Форк
0
/
Interpret_Expr.cpp 
568 строк · 25.3 Кб
1
/*
2
MIT License
3

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

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

9
#include "simodo/interpret/Interpret.h"
10
#include "simodo/interpret/AnalyzeException.h"
11

12
#include "simodo/loom/Loom_interface.h"
13
#include "simodo/bormental/DrBormental.h"
14
#include "simodo/inout/convert/functions.h"
15
#include "simodo/inout/format/fmt.h"
16

17
#include <algorithm>
18
#include <cassert>
19

20
#define SemanticFiber_DEBUG_no
21

22
namespace 
23
{
24
    using namespace simodo;
25

26
    void moveValue(variable::Variable & to, const variable::Variable & from)
27
    {
28
        if (to.type() == variable::ValueType::Ref) {
29
            variable::VariableRef ref = to.value().getRef();
30
            ref.setValue(from.origin().value());
31
        }
32
        else
33
            to.value() = from.origin().value();
34
    }
35

36
    void copyValue(variable::Variable & to, const variable::Variable & from)
37
    {
38
        if (to.type() == variable::ValueType::Ref) {
39
            variable::VariableRef ref = to.value().getRef();
40
            ref.setValue(from.origin().value().copy());
41
        }
42
        else
43
            to.value() = from.origin().value().copy();
44
    }
45

46
}
47

48
namespace simodo::interpret
49
{
50
    void Interpret::assignVariable(variable::Variable & target, const variable::Variable & source, bool need_copy) 
51
    {
52
        // Правила присвоения и перемещения:
53
        // 1. Если в качестве источника (правой части присваивания) выступает переменная с признаком ошибки, 
54
        // то распространяем ошибку на целевую переменную.
55
        // 2. Если в качестве целевой переменной выступает null, значит она не задана можно тупо присвоить.
56
        // 3. Если в качестве источника выступает ссылка, это значит это ссылка на уже объявленную
57
        // переменную и мы должны скопировать.
58
        // 4. Если лежит не ссылка, то это значит источником является временная переменная, которую
59
        // можно частично перенести.
60
        // 5. Если источником является ссылка с пометкой SPEC_REFERENCE, значит нужно целевую
61
        // переменную сделать ссылкой на источник.
62

63
        variable::Variable &       target_origin = target.origin();
64
        const variable::Variable & source_origin = source.origin();
65

66
        // 1.
67
        if (source_origin.value().isError()) {
68
            target_origin.value() = source_origin.value();
69
            return;
70
        }
71

72
        // 2.
73
        if (target_origin.type() == variable::ValueType::Null) {
74
            if (source_origin.type() != variable::ValueType::Null)
75
                target_origin.value() = source_origin.value();
76
            return;
77
        }
78

79
        // 3.
80
        if (source.value().isRef())
81
            need_copy = true;
82

83
        // 4. (учитывается за счёт задания need_copy = false в параметрах функции по умолчанию)
84

85
        // 5.
86
        if (source.value().isRef()) {
87
            const variable::Value & ref_value = source.spec().find(variable::SPEC_REFERENCE);
88
            if (ref_value.isBool() && ref_value.getBool()) {
89
                target_origin.value() = source_origin.value();
90
                return;
91
            }
92
        }
93

94
        switch(target_origin.type())
95
        {
96
        case variable::ValueType::Array:
97
            if (need_copy)
98
                copyValue(target, source_origin);
99
            else
100
                moveValue(target, source_origin);
101
            break;
102
        case variable::ValueType::Object:
103
            assignObject(target_origin, source_origin, need_copy);
104
            break;
105
        case variable::ValueType::Function:
106
            target_origin.value() = source_origin.value();
107
            break;
108
        default:
109
            if (need_copy)
110
                copyValue(target, convertVariable(source_origin,target_origin.type(), need_copy));
111
            else
112
                moveValue(target, convertVariable(source_origin,target_origin.type(), need_copy));
113
            break;
114
        }
115
    }
116

117
    void Interpret::assignArray(variable::Variable & /*target_origin*/, const variable::Variable & /*source_origin*/,
118
                                bool /*need_copy*/) 
119
    {
120
        throw bormental::DrBormental("OperationEngine::assignArray", inout::fmt("Unsupported"));
121
    }
122

123
    void Interpret::assignObject(variable::Variable & target_origin, const variable::Variable & source_origin,
124
                                bool need_copy)
125
    {
126
        assert(target_origin.type() != variable::ValueType::Ref);
127
        assert(source_origin.type() != variable::ValueType::Ref);
128

129
        if (source_origin.type() != variable::ValueType::Object) {
130
            assignObject(target_origin, convertVariable(source_origin,variable::ValueType::Object), need_copy);
131
            return;
132
        }
133

134
        if (target_origin.type() == variable::ValueType::Null) {
135
            target_origin.value() = source_origin.value();
136
            return;
137
        }
138

139
        if (target_origin.type() != variable::ValueType::Object)
140
            throw bormental::DrBormental("assignObject", 
141
                            inout::fmt("Incorrect internal type of variable '%1'")
142
                            .arg(target_origin.name()));
143

144
        // С этого момента левая и правая части являются объектами
145

146
        const std::shared_ptr<variable::Object> rvalue_record = source_origin.value().getObject();
147
        std::shared_ptr<variable::Object>       lvalue_record = target_origin.value().getObject();
148

149
        for(const variable::Variable & rv : rvalue_record->variables()) {
150
            variable::Variable & lv = lvalue_record->getVariableByName_mutable(rv.name());
151
            if (!lv.name().empty()) {
152
                assignVariable(lv.origin(), rv.origin(), need_copy);
153
                continue;
154
            }
155

156
            /// \todo Нужно решить как лучше быть:
157
            /// 1. Добавлять недостающие элементы (как в JS/TS)
158
            /// 2. Заставлять пользователя самому добавлять не нужные ему элементы (иначе - ошибка), а потом затирать
159
            /// 3. Игнорить ситуацию
160

161
            // Пробуем найти сеттер
162
            const variable::Variable & setter = lvalue_record->getVariableByName(u"set_" + rv.name());
163

164
            if (!setter.name().empty() && setter.origin().type() == variable::ValueType::Function)
165
                throw AnalyzeException( "OperationEngine::assignObject",
166
                                        rv.location().makeLocation(files()),
167
                                        inout::fmt("Using a setter '%1' when assigning an object is not supported")
168
                                        .arg(rv.name()));
169

170
            throw AnalyzeException( "OperationEngine::assignObject",
171
                                    rv.location().makeLocation(files()),
172
                                    inout::fmt("Element '%1' was not found in the target structure")
173
                                    .arg(rv.name()));
174
        }
175
    }
176

177
    variable::Variable Interpret::convertVariable(const variable::Variable & var, variable::ValueType type,
178
                                                bool need_copy) const
179
    {
180
        if (var.origin().type() == type) {
181
            /// \todo Нужно оптимизировать!?
182
            if (need_copy)
183
                return var.copyVariable();
184

185
            return var;
186
        }
187

188
        switch(type)
189
        {
190
        case variable::ValueType::String:
191
            if (var.origin().variant().index() == std::variant_npos)
192
                return { var.origin().name(), type, var.location(), var.spec() };
193
            return { {}, toString(var.origin().value()), var.location(), {} };
194
        case variable::ValueType::Float:
195
            if (var.origin().type() == variable::ValueType::Int) {
196
                if (var.origin().variant().index() == std::variant_npos)
197
                    return { var.origin().name(), type, var.location(), var.spec() };
198
                else
199
                    return { {}, 
200
                            static_cast<double>(std::get<int64_t>(var.origin().value().variant())), 
201
                            var.location(), 
202
                            {} };
203
            }
204
            break;
205
        case variable::ValueType::Array:
206
            // return { {}, 
207
            //         std::make_shared<variable::Array>(var.type(), std::vector<variable::index_t> {1}, std::vector<variable::Value> {var.origin().value()}), 
208
            //         var.location(), 
209
            //         {}};
210
            break;
211
        case variable::ValueType::Function:
212
            // if (var.origin().type() == variable::ValueType::Object) {
213
            //     std::shared_ptr<variable::Object> object    = var.origin().value().getObject();
214
            //     const variable::Variable          init_func = object->getVariableByName(u"__init__");
215
            //     if (!init_func.name().empty()) {
216
            //         if (init_func.type() == variable::ValueType::Function) {
217
            //             std::shared_ptr<variable::Object> function_object  = init_func.value().getObject();
218
            //             if (function_object->variables().size() > 1
219
            //              && function_object->variables()[0].type() == variable::ValueType::IntFunction)
220
            //                 function_object->variables()[0].value().getIntFunctionParent() = object;
221
            //         }
222
            //         return init_func;
223
            //     }
224
            // }
225
            break;
226
        default:
227
            break;
228
        }
229

230
        throw AnalyzeException("Interpret::convertVariable",
231
                                var.location().makeLocation(files()),
232
                                inout::fmt("Invalid type conversion from %1 to %2")
233
                                .arg(getValueTypeName(var.origin().type()))
234
                                .arg(getValueTypeName(type)));
235
    }
236

237
    std::shared_ptr<variable::Object> Interpret::self()
238
    {
239
        boundary_index_t function_bound = stack().findNearestMarkedBoundary(BOUNDARY_MARK_FUNCTION_FRAME);
240
        if (function_bound == UNDEFINED_BOUNDARY_INDEX)
241
            return {};
242

243
        const auto           [begin,end]       = stack().boundaryLowAndTop(function_bound);
244
        name_index_t         function_index    = begin-1;
245
        variable::Variable & function_variable = stack().variable(function_index).origin();
246

247
        assert(function_variable.type() == variable::ValueType::Function);
248
        
249
        std::shared_ptr<variable::Object> function_object = function_variable.value().getFunction();
250

251
        assert(!function_object->variables().empty()
252
             && function_object->variables()[0].type() == variable::ValueType::IntFunction);
253

254
        return function_object->variables()[0].value().getIntFunctionParent();
255
    }
256

257
    std::shared_ptr<variable::Object> Interpret::makeSelf()
258
    {
259
        boundary_index_t module_bound = stack().findNearestMarkedBoundary(BOUNDARY_MARK_MODULE_FRAME, BoundScope::Global);
260
        if (module_bound == UNDEFINED_BOUNDARY_INDEX)
261
            return {};
262

263
        auto [begin_index, end_index] = stack().boundaryLowAndTop(module_bound);
264
        variable::VariableSet_t vars;
265

266
        for(name_index_t i = begin_index; i < end_index; ++i) {
267
            variable::Variable & v = stack().variable(i);
268
            vars.push_back(v);
269
        }
270

271
        return std::make_shared<variable::Object>(vars);
272
    }
273

274
    void Interpret::callPreparedFunction(
275
                            Interpret_interface * p_fiber,
276
                            boundary_index_t boundary_index, 
277
                            Notification_interface & notify,
278
                            bool invoke)
279
    {
280
        assert(p_fiber);
281

282
        if(p_fiber != this) {
283
            auto                        [begin, end]    { stack().boundaryLowAndTop(boundary_index) };
284
            name_index_t                function_index  { begin - 1 };
285
            const variable::Variable &  function        { stack().variable(function_index) };
286

287
            name_index_t another_function_index = p_fiber->stack().find(function.origin().name());
288

289
            assert(another_function_index != UNDEFINED_NAME_INDEX);
290

291
            p_fiber->stack().push({u"", p_fiber->stack().variable(another_function_index).makeReference(), function.location()});
292
            boundary_index_t another_boundary_index = p_fiber->stack().startBoundary();
293
            for(name_index_t i=begin; i < end; ++i) {
294
                variable::Variable & v = stack().variable(i);
295
                if (v.origin().value().isFunction())
296
                    p_fiber->stack().push(v.origin());
297
                else
298
                    p_fiber->stack().push(v.copyVariable());
299
            }
300

301
            stack().clearBoundary(boundary_index);
302
            stack().pop();
303

304
            boundary_index = another_boundary_index;
305
        }
306

307
        auto                        [begin, end]    { p_fiber->stack().boundaryLowAndTop(boundary_index) };
308
        name_index_t                function_index  { begin - 1 };
309
        const variable::Variable &  function        { p_fiber->stack().variable(function_index) };
310

311
        variable::FunctionWrapper   func                 = function.origin();
312
        variable::ValueType         declared_return_type = func.getReturnDeclarationVariable().type();
313
        inout::TokenLocation        function_location    = func.function_variable().location();
314

315
        p_fiber->expr().callPreparedFunction(
316
                boundary_index,
317
                notify,
318
                invoke,
319
                [p_fiber, boundary_index, declared_return_type, function_location](const FlowLayerInfo & flow) 
320
                {
321
                    p_fiber->stack().clearBoundary(boundary_index);
322
                    p_fiber->stack().pop();
323
                    p_fiber->stack().push({u"", p_fiber->expr().return_value(), flow.code.token().location()});
324

325
                    if (flow.error_sign) 
326
                        return;
327

328
                    if (declared_return_type != variable::ValueType::Null
329
                     && p_fiber->expr().return_value().isNull() && !p_fiber->expr().return_value().isError())
330
                        throw AnalyzeException("Interpret::callPreparedFunction", 
331
                                                function_location.makeLocation(p_fiber->files()), 
332
                                                inout::fmt("The function must return a value"));
333
                });
334
    }
335

336
    void Interpret::callPreparedFunction(
337
                            boundary_index_t boundary_index, 
338
                            Notification_interface & notify,
339
                            bool invoke,
340
                            const std::function<void(const FlowLayerInfo &)> callback)
341
    try
342
    {
343
        auto                                 [begin, end]    { stack().boundaryLowAndTop(boundary_index) };
344
        name_index_t                         function_index  { begin - 1 };
345
        const variable::Variable &           function        { stack().variable(function_index) };
346
        const variable::Variable &           function_origin { function.origin() };
347
        variable::VariableSetWrapper_mutable args            { stack().makeVariableSetWrapper() };
348
        variable::FunctionWrapper            func            { function_origin };
349
        variable::VariableSetWrapper         decl            { func.getArgumentDeclarationVariables() };
350

351
        if (args.size() != decl.size())
352
            throw AnalyzeException("Interpret::callPreparedFunction", 
353
                                    function.location().makeLocation(files()),
354
                                    inout::fmt("The function call '%1' contains an incorrect number of arguments")
355
                                    .arg(function.name()));
356

357
        for(size_t i=0; i < decl.size(); ++i) {
358
            if (args[i].origin().type() != decl[i].type() && decl[i].type() != variable::ValueType::Null)
359
                args[i] = convertVariable(args[i], decl[i].type());
360

361
            args[i].setName(decl[i].name());
362
        }
363

364
        if (func.getCallingAddressVariable().type() == variable::ValueType::ExtFunction) {
365
            variable::Value return_value;
366

367
            if (invoke)
368
                return_value = func.invoke(args);
369
            else
370
                return_value = func.getReturnDeclarationVariable().value();
371

372
            stack().clearBoundary(boundary_index);
373
            stack().pop();
374
            stack().push({u"", return_value, function.location()}); //, {{{variable::SPEC_REFERENCE, true}}}});
375
            return;
376
        }
377

378
        assert(func.getCallingAddressVariable().type() == variable::ValueType::IntFunction);
379

380
        _return_value = {variable::ValueType::Null};
381

382
        if (invoke) {
383
            const variable::InternalFunction & internal_function 
384
                = std::get<variable::InternalFunction>(func.getCallingAddressVariable().value().variant());
385

386
            const variable::Value & tethered_value = function_origin.spec().object()->find(variable::SPEC_TETHERED);
387

388
            if (tethered_value.isBool() && tethered_value.getBool()) {
389
                boundary_index_t module_bound_index = stack().findNearestMarkedBoundary(BOUNDARY_MARK_MODULE_FRAME, BoundScope::Global);
390
                assert(module_bound_index != UNDEFINED_BOUNDARY_INDEX);  
391
                const auto [begin,end] = stack().boundaryLowAndTop(module_bound_index);              
392
                for(name_index_t i = begin; i < end; ++i)
393
                    stack().pushRef(stack().variable(i), function.location());
394
            }
395
            else
396
                for(const variable::Variable & closure : internal_function.closures.variables()) 
397
                    if (closure.name() == SELF_VARIABLE_NAME) {
398
                        std::shared_ptr<variable::Object> self_object = self();
399

400
                        if (!self_object)
401
                            self_object = makeSelf();
402
                            
403
                        variable::Variable self = {{}, self_object, closure.location()};
404
                        stack().push(self);
405
                    }
406
                    else {
407
                        if (closure.name() == function_origin.name())
408
                            stack().push(function_origin);
409
                        else 
410
                            stack().push(closure);
411
                            
412
                        notify.notifyDeclared(closure);
413
                    }
414

415
            stack().setBoundaryToGlobal(boundary_index);
416

417
            bool need_to_stretch = _layer_stack.empty();
418

419
            addFlowLayer( *internal_function.code, boundary_index, callback);
420

421
            notify.notifyBeforeFunctionCalling(function_origin);
422

423
            if (need_to_stretch)
424
                _loom.stretch(this);
425
        }
426
        else {
427
            stack().clearBoundary(boundary_index);
428
            stack().pop();
429
            variable::Variable return_variable = func.getReturnDeclarationVariable();
430
            stack().push(return_variable);
431
        }
432
    }
433
    catch(...) {
434
        // Перед выходом восстанавливаем ожидаемое состояние выполнения команды
435
        stack().clearBoundary(boundary_index);
436
        stack().pop();
437
        stack().push(variable::error_variable());
438
        throw;
439
    }
440

441
    void Interpret::print(bool need_detailed_report) const
442
    {
443
        const variable::Variable var = _stack.variable(_stack.top()).origin();
444
        std::u16string           str = toString(var.value(), need_detailed_report);
445

446
        if (need_detailed_report && !var.spec().object()->variables().empty())
447
            str += u"#" + toString(var.spec().object(), need_detailed_report);
448

449
        reporter().reportInformation(inout::toU8(str));
450
    }
451

452
    std::u16string Interpret::toString(const variable::Value & value, bool need_whole_info, bool quote_strings) const
453
    {
454
        std::u16string str;
455

456
        switch(value.type())
457
        {
458
        case variable::ValueType::String:
459
            if (!std::holds_alternative<std::u16string>(value.variant()))
460
                str = u"<"+inout::toU16(variable::getValueTypeName(value.type()))+ u">";
461
            else {
462
                std::u16string text = std::get<std::u16string>(value.variant());
463

464
                if (quote_strings) {
465
                    inout::replaceAll(text, u"\\", u"\\\\");
466
                    inout::replaceAll(text, u"\"", u"\\\"");
467
                    text = u"\""+text+u"\"";
468
                }
469
                str = text;
470
            }
471
            break;
472
        case variable::ValueType::Bool:
473
            str = std::holds_alternative<bool>(value.variant())
474
                    ? (std::get<bool>(value.variant()) ? u"true" : u"false")
475
                    : u"<"+inout::toU16(variable::getValueTypeName(value.type()))+ u">";
476
            break;
477
        case variable::ValueType::Int:
478
            str = std::holds_alternative<int64_t>(value.variant())
479
                    ? inout::toU16(std::to_string(std::get<int64_t>(value.variant())))
480
                    : u"<"+inout::toU16(variable::getValueTypeName(value.type()))+ u">";
481
            break;
482
        case variable::ValueType::Float:
483
            str = std::holds_alternative<double>(value.variant())
484
                    ? inout::toU16(inout::clearNumberFractionalPart(std::to_string(std::get<double>(value.variant()))))
485
                    : u"<"+inout::toU16(variable::getValueTypeName(value.type()))+ u">";
486
            break;
487
        // case ValueType::Undefined:
488
        //     str = u"undef";
489
        //     break;
490
        // case ValueType::Function:
491
        //     if (name.substr(0,4) == u"get_") {
492
        //         const VariableSet_t & params = get<shared_ptr<Record>>(value.variant())->variables();
493
        //         assert(params.size() >= 2);
494
        //         if(params.size() == 2 && params[1].declared != DeclaredType::Error) {
495
        //             callFunction(var,{},InterpreterMode::FullExecution);
496
        //             return toString(_return_value, need_whole_info, true);
497
        //         }
498
        //     }
499
        //     [[fallthrough]];
500
        case variable::ValueType::Object:
501
            if (!std::holds_alternative<std::shared_ptr<variable::Object>>(value.variant()))
502
                str = u"<" + inout::toU16(getValueTypeName(value.type())) + u">";
503
            else {
504
                str   = u"{";
505
                const variable::VariableSet_t & record = std::get<std::shared_ptr<variable::Object>>(value.variant())->variables();
506
                bool                            first = true;
507

508
                for(const variable::Variable & n : record) {
509
                    const variable::Variable & n_origin = n.origin();
510

511
                    if (n_origin.type() == variable::ValueType::Function && n.name().substr(0,4) == u"set_" && !need_whole_info)
512
                        continue;
513

514
                    if (n_origin.type() == variable::ValueType::Function && n.name().substr(0,4) != u"get_" && !need_whole_info)
515
                        continue;
516

517
                    if (!first)
518
                        str += u", ";
519

520
                    if (n.name().empty())
521
                        str += u"\"\":" + toString(n.origin().value(), need_whole_info);
522
                    else if (n_origin.type() == variable::ValueType::Function && n.name().substr(0,4) == u"get_")
523
                        str += n.name().substr(4) + u":" + toString(n.origin().value(), need_whole_info);
524
                    else
525
                        str += n.name() + u":" + toString(n.origin().value(), need_whole_info, true);
526

527
                    first = false;
528
                }
529
                str += u"}";
530
            }
531
            break;
532
        case variable::ValueType::Array:
533
            if (!std::holds_alternative<std::shared_ptr<variable::Array>>(value.variant()))
534
                str = u"<"+inout::toU16(variable::getValueTypeName(value.type()))+ u">";
535
            else {
536
                str = u"[";
537
                const variable::Array & array = *value.getArray();
538
                bool first = true;
539

540
                for(size_t i=0; i < array.values().size(); ++i)
541
                {
542
                    if (!first) str += u", ";
543
                    str += toString(array.values()[i], need_whole_info, true);
544
                    first = false;
545
                }
546
                str += u"]";
547
            }
548
            break;
549
        default:
550
            {
551
                str = u"<" + inout::toU16(getValueTypeName(value.type()));
552

553
                if ((value.type() == variable::ValueType::IntFunction && std::holds_alternative<variable::InternalFunction>(value.variant()))
554
                || (value.type() == variable::ValueType::ExtFunction && std::holds_alternative<variable::ExternalFunction>(value.variant())))
555
                    str += u"{}"; // Обозначаем непустую (определённую) функцию
556

557
                str+=u">";
558
            }
559
            break;
560
        }
561

562
        // if (need_whole_info && !origin.spec().variables().empty())
563
        //     str += u"#" + toString({{}, origin.spec(), {}, {}}, need_whole_info);
564

565
        return str;
566
    }
567

568
}

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

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

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

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