loom

Форк
0
/
Interpret_Expr.cpp 
470 строк · 20.9 Кб
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
namespace 
21
{
22
    using namespace simodo;
23

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

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

44
}
45

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

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

64
        // 1.
65
        if (source_origin.value().isError()) {
66
            target_origin.setValue(source_origin.value());
67
            return;
68
        }
69

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

77
        // 3.
78
        if (source.value().isRef())
79
            need_copy = true;
80

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

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

93
        switch(target_origin.type())
94
        {
95
        case variable::ValueType::Array:
96
            if (need_copy)
97
                copyValue(target, source_origin);
98
            else
99
                moveValue(target, source_origin);
100
            break;
101
        case variable::ValueType::Object:
102
            assignObject(target_origin, source_origin, need_copy);
103
            break;
104
        case variable::ValueType::Function:
105
            target_origin.setValue(source_origin.value());
106
            target_origin.setSpec(source_origin.spec());
107
            break;
108
        default:
109
            if (need_copy)
110
                copyValue(target, convertVariable(source,target_origin.type(), need_copy));
111
            else
112
                moveValue(target, convertVariable(source,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.setValue(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::Null:
191
            break;
192
        case variable::ValueType::String:
193
            if (var.origin().variant().index() == std::variant_npos)
194
                return { var.origin().name(), type, var.location(), var.spec() };
195
            return { {}, toString(var.origin().value()), var.location(), {} };
196
        case variable::ValueType::Float:
197
            if (var.origin().type() == variable::ValueType::Int) {
198
                if (var.origin().variant().index() == std::variant_npos)
199
                    return { var.origin().name(), type, var.location(), var.spec() };
200
                else
201
                    return { {}, 
202
                            static_cast<double>(std::get<int64_t>(var.origin().value().variant())), 
203
                            var.location(), 
204
                            {} };
205
            }
206
            break;
207
        case variable::ValueType::Array:
208
            if (var.origin().type() == variable::ValueType::Null)
209
                return { {}, 
210
                        std::make_shared<variable::Array>(), 
211
                        var.location() };
212
            break;
213
        case variable::ValueType::Function:
214
            break;
215
        default:
216
            break;
217
        }
218

219
        std::u16string variable_name = var.origin().name();
220

221
        if (variable_name.empty())
222
            throw AnalyzeException("Interpret::convertVariable",
223
                                    var.location().makeLocation(files()),
224
                                    inout::fmt("Invalid type conversion from %1 to %2 of internal variable")
225
                                    .arg(getValueTypeName(var.origin().type()))
226
                                    .arg(getValueTypeName(type)));
227

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

236
    const variable::Variable & Interpret::getContextFunction() const
237
    {
238
        static variable::Variable null {};
239

240
        boundary_index_t function_bound = stack().findNearestMarkedBoundary(BOUNDARY_MARK_FUNCTION_FRAME,BoundScope::Global);
241
        if (function_bound == UNDEFINED_BOUNDARY_INDEX)
242
            return null;
243

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

248
        assert(function_variable.type() == variable::ValueType::Function);
249
        
250
        return function_variable.origin();
251
    }
252

253
    std::shared_ptr<variable::Object> Interpret::makeSelf()
254
    {
255
        boundary_index_t module_bound = stack().findNearestMarkedBoundary(BOUNDARY_MARK_MODULE_FRAME, BoundScope::Global);
256
        if (module_bound == UNDEFINED_BOUNDARY_INDEX)
257
            return {};
258

259
        auto [begin_index, end_index] = stack().boundaryLowAndTop(module_bound);
260
        variable::VariableSet_t vars;
261

262
        for(name_index_t i = begin_index; i < end_index; ++i) {
263
            variable::Variable & v = stack().variable(i);
264
            vars.push_back(v);
265
        }
266

267
        return std::make_shared<variable::Object>(vars);
268
    }
269

270
    void Interpret::callPreparedFunction(
271
                            Interpret_interface * p_fiber,
272
                            boundary_index_t boundary_index, 
273
                            Notification_interface & notify,
274
                            bool invoke)
275
    {
276
        assert(p_fiber);
277

278
        bool remote_calling;
279

280
        if(p_fiber != this) {
281
#ifndef NDEBUG
282
            [[maybe_unused]] Interpret * p_inter = static_cast<Interpret *>(p_fiber);
283
#endif
284
            auto                        [begin, end]    { stack().boundaryLowAndTop(boundary_index) };
285
            name_index_t                function_index  { begin - 1 };
286
            const variable::Variable &  function        { stack().variable(function_index) };
287

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

290
            assert(another_function_index != UNDEFINED_NAME_INDEX);
291

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

302
            stack().clearBoundary(boundary_index);
303
            stack().pop();
304
            stack().push(variable::null_variable()); // Имитируем возвращаемое значение для нашей нити
305

306
            boundary_index = another_boundary_index;
307
            remote_calling = true;
308
        }
309
        else
310
            remote_calling = false;
311

312
        auto                        [begin, end]    { p_fiber->stack().boundaryLowAndTop(boundary_index) };
313
        name_index_t                function_index  { begin - 1 };
314
        const variable::Variable &  function        { p_fiber->stack().variable(function_index) };
315

316
        variable::FunctionWrapper   func                 = function.origin();
317
        variable::ValueType         declared_return_type = func.getReturnDeclarationVariable().type();
318
        inout::TokenLocation        function_location    = func.function_variable().location();
319

320
        p_fiber->expr().callPreparedFunction(
321
                boundary_index,
322
                notify,
323
                invoke,
324
                [p_fiber, boundary_index, declared_return_type, function_location, remote_calling](const FlowLayerInfo & flow) 
325
                {
326
                    p_fiber->stack().clearBoundary(boundary_index);
327
                    p_fiber->stack().pop();
328

329
                    if (!remote_calling) {
330
                        /// \todo Наследие настроено на то, что вызывающая сторона очищает возвращаемое значение
331
                        /// со своего стека. Вызов функции в другом потоке приводит к тому, что возвращаемое значение
332
                        /// остаётся на стеке другого потока. Пока не понятно как лучше сделать.
333
                        /// На данный момент просто не выкладываю на стек, если вызов в другом потоке.
334
                        p_fiber->stack().push({u"", p_fiber->expr().return_value(), flow.code_flow.token().location()});
335
                    }
336

337
                    if (flow.error_sign) 
338
                        return;
339

340
                    if (declared_return_type != variable::ValueType::Null
341
                     && p_fiber->expr().return_value().isNull() && !p_fiber->expr().return_value().isError())
342
                        throw AnalyzeException("Interpret::callPreparedFunction", 
343
                                                function_location.makeLocation(p_fiber->files()), 
344
                                                inout::fmt("The function must return a value"));
345
                });
346
    }
347

348
    void Interpret::callPreparedFunction(
349
                            boundary_index_t boundary_index, 
350
                            Notification_interface & notify,
351
                            bool invoke,
352
                            const std::function<void(const FlowLayerInfo &)> callback)
353
    try
354
    {
355
        auto                                 [begin, end]    { stack().boundaryLowAndTop(boundary_index) };
356
        name_index_t                         function_index  { begin - 1 };
357
        const variable::Variable &           function        { stack().variable(function_index) };
358
        const variable::Variable &           function_origin { function.origin() };
359
        variable::VariableSetWrapper_mutable args            { stack().makeVariableSetWrapper() };
360
        variable::FunctionWrapper            func            { function_origin };
361
        variable::VariableSetWrapper         decl            { func.getArgumentDeclarationVariables() };
362

363
        if (args.size() != decl.size())
364
            throw AnalyzeException("Interpret::callPreparedFunction", 
365
                                    function.location().makeLocation(files()),
366
                                    inout::fmt("The function call '%1' contains an incorrect number of arguments")
367
                                    .arg(function.name()));
368

369
        for(size_t i=0; i < decl.size(); ++i) {
370
            if (args[i].origin().value().isError() && type() != InterpretType::Preview)
371
                invoke = false;
372
            else if (args[i].origin().type() != decl[i].type() && decl[i].type() != variable::ValueType::Null)
373
                args[i] = convertVariable(args[i], decl[i].type());
374

375
            args[i].setName(decl[i].name());
376
        }
377

378
        if (func.getCallingAddressVariable().type() == variable::ValueType::ExtFunction) {
379
            variable::Value return_value;
380

381
            if (invoke)
382
                return_value = func.invoke(args);
383
            else
384
                return_value = func.getReturnDeclarationVariable().value();
385

386
            stack().clearBoundary(boundary_index);
387
            stack().pop();
388
            stack().push({u"", return_value, function.location()});
389
            return;
390
        }
391

392
        assert(func.getCallingAddressVariable().type() == variable::ValueType::IntFunction);
393

394
        _return_value = {variable::ValueType::Null};
395

396
        if (invoke) {
397
            const variable::InternalFunction & internal_function 
398
                = std::get<variable::InternalFunction>(func.getCallingAddressVariable().value().variant());
399

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

402
            /// \attention Этот фрагмент необходимо целиком переписать!!!
403

404
            if (tethered_value.isBool() && tethered_value.getBool()) {
405
                boundary_index_t module_bound_index = stack().findNearestMarkedBoundary(BOUNDARY_MARK_MODULE_FRAME, BoundScope::Global);
406
                assert(module_bound_index != UNDEFINED_BOUNDARY_INDEX);  
407
                const auto [begin,end] = stack().boundaryLowAndTop(module_bound_index);              
408
                for(name_index_t i = begin; i < end; ++i)
409
                    stack().pushRef(stack().variable(i), function.location());
410
            }
411
            else
412
                for(const variable::Variable & closure : internal_function.closures.variables()) 
413
                    if (closure.name() == SELF_VARIABLE_NAME) {
414
                        std::shared_ptr<variable::Object> self_object = internal_function.parent;
415

416
                        assert(self_object);
417
                            
418
                        variable::Variable self = {SELF_VARIABLE_NAME, self_object, closure.location()};
419
                        
420
                        stack().push(self);
421
                        notify.notifyDeclared(self);
422
                    }
423
                    else {
424
                        if (closure.name() == function_origin.name())
425
                            stack().push(function_origin);
426
                        else 
427
                            stack().push(closure);
428
                            
429
                        notify.notifyDeclared(closure);
430
                    }
431

432
            stack().setBoundaryToGlobal(boundary_index);
433

434
            bool need_to_stretch = _layer_stack.empty();
435

436
            addFlowLayer(*internal_function.code, boundary_index, callback);
437

438
            notify.notifyBeforeFunctionCalling(function_origin);
439

440
            if (need_to_stretch)
441
                _loom.stretch(this);
442
        }
443
        else {
444
            stack().clearBoundary(boundary_index);
445
            stack().pop();
446
            variable::Variable return_variable = func.getReturnDeclarationVariable();
447
            stack().push(return_variable);
448
        }
449
    }
450
    catch(...) {
451
        // Перед выходом восстанавливаем ожидаемое состояние выполнения команды
452
        stack().clearBoundary(boundary_index);
453
        stack().pop();
454
        stack().push(variable::error_variable());
455
        throw;
456
    }
457

458
    void Interpret::print(bool need_detailed_report) const
459
    {
460
        const variable::Variable var = _stack.variable(_stack.top()).origin();
461
        std::u16string           str = toString(var.value(), need_detailed_report, false);
462

463
        if (need_detailed_report && !var.spec().object()->variables().empty())
464
            str += u"#" + toString(var.spec().object(), need_detailed_report);
465

466
        reporter().reportInformation(inout::toU8(str));
467
    }
468

469

470
}

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

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

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

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