4
Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
6
https://bmstu.codes/lsx/simodo
9
#include "simodo/interpret/Interpret.h"
10
#include "simodo/interpret/AnalyzeException.h"
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"
20
#define SemanticFiber_DEBUG_no
24
using namespace simodo;
26
void moveValue(variable::Variable & to, const variable::Variable & from)
28
if (to.type() == variable::ValueType::Ref) {
29
variable::VariableRef ref = to.value().getRef();
30
ref.setValue(from.origin().value());
33
to.value() = from.origin().value();
36
void copyValue(variable::Variable & to, const variable::Variable & from)
38
if (to.type() == variable::ValueType::Ref) {
39
variable::VariableRef ref = to.value().getRef();
40
ref.setValue(from.origin().value().copy());
43
to.value() = from.origin().value().copy();
48
namespace simodo::interpret
50
void Interpret::assignVariable(variable::Variable & target, const variable::Variable & source, bool need_copy)
52
// Правила присвоения и перемещения:
53
// 1. Если в качестве источника (правой части присваивания) выступает переменная с признаком ошибки,
54
// то распространяем ошибку на целевую переменную.
55
// 2. Если в качестве целевой переменной выступает null, значит она не задана можно тупо присвоить.
56
// 3. Если в качестве источника выступает ссылка, это значит это ссылка на уже объявленную
57
// переменную и мы должны скопировать.
58
// 4. Если лежит не ссылка, то это значит источником является временная переменная, которую
59
// можно частично перенести.
60
// 5. Если источником является ссылка с пометкой SPEC_REFERENCE, значит нужно целевую
61
// переменную сделать ссылкой на источник.
63
variable::Variable & target_origin = target.origin();
64
const variable::Variable & source_origin = source.origin();
67
if (source_origin.value().isError()) {
68
target_origin.value() = source_origin.value();
73
if (target_origin.type() == variable::ValueType::Null) {
74
if (source_origin.type() != variable::ValueType::Null)
75
target_origin.value() = source_origin.value();
80
if (source.value().isRef())
83
// 4. (учитывается за счёт задания need_copy = false в параметрах функции по умолчанию)
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();
94
switch(target_origin.type())
96
case variable::ValueType::Array:
98
copyValue(target, source_origin);
100
moveValue(target, source_origin);
102
case variable::ValueType::Object:
103
assignObject(target_origin, source_origin, need_copy);
105
case variable::ValueType::Function:
106
target_origin.value() = source_origin.value();
110
copyValue(target, convertVariable(source_origin,target_origin.type(), need_copy));
112
moveValue(target, convertVariable(source_origin,target_origin.type(), need_copy));
117
void Interpret::assignArray(variable::Variable & /*target_origin*/, const variable::Variable & /*source_origin*/,
120
throw bormental::DrBormental("OperationEngine::assignArray", inout::fmt("Unsupported"));
123
void Interpret::assignObject(variable::Variable & target_origin, const variable::Variable & source_origin,
126
assert(target_origin.type() != variable::ValueType::Ref);
127
assert(source_origin.type() != variable::ValueType::Ref);
129
if (source_origin.type() != variable::ValueType::Object) {
130
assignObject(target_origin, convertVariable(source_origin,variable::ValueType::Object), need_copy);
134
if (target_origin.type() == variable::ValueType::Null) {
135
target_origin.value() = source_origin.value();
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()));
144
// С этого момента левая и правая части являются объектами
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();
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);
156
/// \todo Нужно решить как лучше быть:
157
/// 1. Добавлять недостающие элементы (как в JS/TS)
158
/// 2. Заставлять пользователя самому добавлять не нужные ему элементы (иначе - ошибка), а потом затирать
159
/// 3. Игнорить ситуацию
161
// Пробуем найти сеттер
162
const variable::Variable & setter = lvalue_record->getVariableByName(u"set_" + rv.name());
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")
170
throw AnalyzeException( "OperationEngine::assignObject",
171
rv.location().makeLocation(files()),
172
inout::fmt("Element '%1' was not found in the target structure")
177
variable::Variable Interpret::convertVariable(const variable::Variable & var, variable::ValueType type,
178
bool need_copy) const
180
if (var.origin().type() == type) {
181
/// \todo Нужно оптимизировать!?
183
return var.copyVariable();
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() };
200
static_cast<double>(std::get<int64_t>(var.origin().value().variant())),
205
case variable::ValueType::Array:
207
// std::make_shared<variable::Array>(var.type(), std::vector<variable::index_t> {1}, std::vector<variable::Value> {var.origin().value()}),
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;
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)));
237
std::shared_ptr<variable::Object> Interpret::self()
239
boundary_index_t function_bound = stack().findNearestMarkedBoundary(BOUNDARY_MARK_FUNCTION_FRAME);
240
if (function_bound == UNDEFINED_BOUNDARY_INDEX)
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();
247
assert(function_variable.type() == variable::ValueType::Function);
249
std::shared_ptr<variable::Object> function_object = function_variable.value().getFunction();
251
assert(!function_object->variables().empty()
252
&& function_object->variables()[0].type() == variable::ValueType::IntFunction);
254
return function_object->variables()[0].value().getIntFunctionParent();
257
std::shared_ptr<variable::Object> Interpret::makeSelf()
259
boundary_index_t module_bound = stack().findNearestMarkedBoundary(BOUNDARY_MARK_MODULE_FRAME, BoundScope::Global);
260
if (module_bound == UNDEFINED_BOUNDARY_INDEX)
263
auto [begin_index, end_index] = stack().boundaryLowAndTop(module_bound);
264
variable::VariableSet_t vars;
266
for(name_index_t i = begin_index; i < end_index; ++i) {
267
variable::Variable & v = stack().variable(i);
271
return std::make_shared<variable::Object>(vars);
274
void Interpret::callPreparedFunction(
275
Interpret_interface * p_fiber,
276
boundary_index_t boundary_index,
277
Notification_interface & notify,
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) };
287
name_index_t another_function_index = p_fiber->stack().find(function.origin().name());
289
assert(another_function_index != UNDEFINED_NAME_INDEX);
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());
298
p_fiber->stack().push(v.copyVariable());
301
stack().clearBoundary(boundary_index);
304
boundary_index = another_boundary_index;
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) };
311
variable::FunctionWrapper func = function.origin();
312
variable::ValueType declared_return_type = func.getReturnDeclarationVariable().type();
313
inout::TokenLocation function_location = func.function_variable().location();
315
p_fiber->expr().callPreparedFunction(
319
[p_fiber, boundary_index, declared_return_type, function_location](const FlowLayerInfo & flow)
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()});
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"));
336
void Interpret::callPreparedFunction(
337
boundary_index_t boundary_index,
338
Notification_interface & notify,
340
const std::function<void(const FlowLayerInfo &)> callback)
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() };
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()));
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());
361
args[i].setName(decl[i].name());
364
if (func.getCallingAddressVariable().type() == variable::ValueType::ExtFunction) {
365
variable::Value return_value;
368
return_value = func.invoke(args);
370
return_value = func.getReturnDeclarationVariable().value();
372
stack().clearBoundary(boundary_index);
374
stack().push({u"", return_value, function.location()}); //, {{{variable::SPEC_REFERENCE, true}}}});
378
assert(func.getCallingAddressVariable().type() == variable::ValueType::IntFunction);
380
_return_value = {variable::ValueType::Null};
383
const variable::InternalFunction & internal_function
384
= std::get<variable::InternalFunction>(func.getCallingAddressVariable().value().variant());
386
const variable::Value & tethered_value = function_origin.spec().object()->find(variable::SPEC_TETHERED);
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());
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();
401
self_object = makeSelf();
403
variable::Variable self = {{}, self_object, closure.location()};
407
if (closure.name() == function_origin.name())
408
stack().push(function_origin);
410
stack().push(closure);
412
notify.notifyDeclared(closure);
415
stack().setBoundaryToGlobal(boundary_index);
417
bool need_to_stretch = _layer_stack.empty();
419
addFlowLayer( *internal_function.code, boundary_index, callback);
421
notify.notifyBeforeFunctionCalling(function_origin);
427
stack().clearBoundary(boundary_index);
429
variable::Variable return_variable = func.getReturnDeclarationVariable();
430
stack().push(return_variable);
434
// Перед выходом восстанавливаем ожидаемое состояние выполнения команды
435
stack().clearBoundary(boundary_index);
437
stack().push(variable::error_variable());
441
void Interpret::print(bool need_detailed_report) const
443
const variable::Variable var = _stack.variable(_stack.top()).origin();
444
std::u16string str = toString(var.value(), need_detailed_report);
446
if (need_detailed_report && !var.spec().object()->variables().empty())
447
str += u"#" + toString(var.spec().object(), need_detailed_report);
449
reporter().reportInformation(inout::toU8(str));
452
std::u16string Interpret::toString(const variable::Value & value, bool need_whole_info, bool quote_strings) const
458
case variable::ValueType::String:
459
if (!std::holds_alternative<std::u16string>(value.variant()))
460
str = u"<"+inout::toU16(variable::getValueTypeName(value.type()))+ u">";
462
std::u16string text = std::get<std::u16string>(value.variant());
465
inout::replaceAll(text, u"\\", u"\\\\");
466
inout::replaceAll(text, u"\"", u"\\\"");
467
text = u"\""+text+u"\"";
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">";
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">";
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">";
487
// case ValueType::Undefined:
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);
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">";
505
const variable::VariableSet_t & record = std::get<std::shared_ptr<variable::Object>>(value.variant())->variables();
508
for(const variable::Variable & n : record) {
509
const variable::Variable & n_origin = n.origin();
511
if (n_origin.type() == variable::ValueType::Function && n.name().substr(0,4) == u"set_" && !need_whole_info)
514
if (n_origin.type() == variable::ValueType::Function && n.name().substr(0,4) != u"get_" && !need_whole_info)
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);
525
str += n.name() + u":" + toString(n.origin().value(), need_whole_info, true);
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">";
537
const variable::Array & array = *value.getArray();
540
for(size_t i=0; i < array.values().size(); ++i)
542
if (!first) str += u", ";
543
str += toString(array.values()[i], need_whole_info, true);
551
str = u"<" + inout::toU16(getValueTypeName(value.type()));
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"{}"; // Обозначаем непустую (определённую) функцию
562
// if (need_whole_info && !origin.spec().variables().empty())
563
// str += u"#" + toString({{}, origin.spec(), {}, {}}, need_whole_info);