4
Copyright (c) 2022 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
6
https://bmstu.codes/lsx/simodo/loom
9
#include "ScriptSemantics_abstract.h"
10
#include "simodo/interpret/AnalyzeException.h"
12
#include "simodo/inout/convert/functions.h"
13
#include "simodo/inout/format/fmt.h"
17
namespace simodo::interpret
21
// static const variable::Variable error = variable::error_variable();
24
void ScriptSemantics_abstract::appendContractProperties(const variable::Variable & from, variable::Variable & to)
26
/// \note Спецификация (Variable::spec) передаётся переменной только слева направо, т.е. не через
27
/// инициализацию и не через присвоение.
28
/// Информация о типе хранится только в спецификации (Variable::spec), а значит, если она была задана
29
/// в структуре, то её нужно перенести в спеку контракта.
31
const variable::Variable & from_origin = from.origin();
32
const std::shared_ptr<variable::Object> from_spec = from_origin.spec().object();
33
const bool spec_in_body = from_origin.value().isObject()
34
&& from_spec->find(variable::SPEC_ORIGIN).isString()
35
&& from_spec->find(variable::SPEC_ORIGIN).getString()
36
== variable::SPEC_ORIGIN_STRUCTURE;
38
const std::shared_ptr<variable::Object> spec_source = spec_in_body
39
? from_origin.value().getObject()
43
if (from_origin.value().isObject()
44
&& (!to.spec().object()->getVariableByName(variable::SPEC_NAME_INITIAL_VALUE).name().empty()
45
|| !to.spec().object()->getVariableByName(variable::SPEC_NAME_BUILT_IN_TYPE).name().empty()))
46
throw AnalyzeException( "ScriptSemantics_abstract::appendContractProperties",
47
from.location().makeLocation(inter().files()),
48
inout::fmt("Invalid addition of a non-scalar type to a scalar sequence"));
50
if (to.type() != variable::ValueType::Null
51
&& from_origin.type() != variable::ValueType::Null)
52
if (to.type() != from_origin.type() || from_origin.value().isArray())
53
throw AnalyzeException( "ScriptSemantics_abstract::appendContractProperties",
54
from.location().makeLocation(inter().files()),
55
inout::fmt("Multiple addition of a non-scalar type"));
57
if (from_origin.value().isObject()) {
58
// Наполняем структуру типа объекта
59
if (to.type() == variable::ValueType::Null)
60
to.setValue(from_origin.value());
61
else if (to.value().isObject()) {
62
std::shared_ptr<variable::Object> to_object = to.value().getObject();
64
for(const variable::Variable & p : from_origin.value().getObject()->variables()) {
65
variable::Variable & existing_contract = to_object->getVariableByName_mutable(p.name());
66
if (existing_contract.name().empty())
69
existing_contract.setValue(p.value());
73
else if (from_origin.value().isArray())
74
to.setValue(from_origin.value());
77
// Наполняем структуру спецификации
78
for(const variable::Variable & spec : spec_source->variables()) {
79
if (spec.name() == variable::SPEC_ORIGIN) {
80
// Происхождение спецификации не имеет значения
85
inout::TokenLocation err_loc = spec_in_body ? spec.location() : from.location();
87
if ((spec.name() == variable::SPEC_NAME_INITIAL_VALUE && !spec.value().isNull())
88
|| spec.name() == variable::SPEC_NAME_BUILT_IN_TYPE) {
89
if (to.value().isObject())
90
throw AnalyzeException( "ScriptSemantics_abstract::appendContractProperties",
91
err_loc.makeLocation(inter().files()),
92
inout::fmt("Invalid addition of a scalar type to a non-scalar sequence"));
94
if (!to.spec().object()->getVariableByName(variable::SPEC_NAME_INITIAL_VALUE).name().empty()
95
|| !to.spec().object()->getVariableByName(variable::SPEC_NAME_BUILT_IN_TYPE).name().empty())
96
throw AnalyzeException( "ScriptSemantics_abstract::appendContractProperties",
97
err_loc.makeLocation(inter().files()),
98
inout::fmt("Type overriding"));
100
if (spec.name() == variable::SPEC_NAME_BUILT_IN_TYPE) {
101
int64_t built_it_type = spec.value().getInt();
102
// if (built_it_type < static_cast<int64_t>(variable::ValueType::Null)
103
// || built_it_type > static_cast<int64_t>(variable::ValueType::Array))
104
if (built_it_type > static_cast<int64_t>(variable::ValueType::Array))
105
throw AnalyzeException( "ScriptSemantics_abstract::appendContractProperties",
106
err_loc.makeLocation(inter().files()),
107
inout::fmt("Invalid built-in type value"));
109
const variable::Variable & existing_spec = to.spec().object()->getVariableByName(spec.name());
110
/// \todo Проверять на неравенство!
111
if (!existing_spec.name().empty())
112
throw AnalyzeException( "ScriptSemantics_abstract::appendContractProperties",
113
err_loc.makeLocation(inter().files()),
114
inout::fmt("Duplication of specification '%1'")
116
if (spec.name() == variable::SPEC_HIDDEN && spec.value().isBool() && spec.value().getBool()) {
117
if (stack().getTopBoundaryMarkAndScope().first != BOUNDARY_MARK_MODULE_FRAME)
118
throw AnalyzeException( "ScriptSemantics_abstract::appendContractProperties",
119
err_loc.makeLocation(inter().files()),
120
inout::fmt("The internal variables of the module are already hidden"));
123
// Копируем спецификацию (std::shared_ptr для объектов и массивов сохраняются)
124
to.spec().set(spec.name(),spec.value());
128
variable::Variable ScriptSemantics_abstract::createVariable( const variable::Variable & contract,
129
const inout::Token & token,
130
const std::u16string & origin)
132
variable::Variable var { token.lexeme(), {}, token.location(), contract.spec().copy() };
134
if (contract.value().isObject()) // модуль
135
var.setValue(contract.value().copy()); // явное копирование - отвязка от контракта (иначе, работает std::shared_ptr для объектов и массивов)
136
else if (contract.value().isArray())
137
var.setValue(contract.value().copy());
139
if (!contract.spec().object()->getVariableByName(variable::SPEC_NAME_INITIAL_VALUE).name().empty())
140
var.setValue(contract.spec().object()->find(variable::SPEC_NAME_INITIAL_VALUE));
141
else if (!contract.spec().object()->getVariableByName(variable::SPEC_NAME_BUILT_IN_TYPE).name().empty()) {
142
int64_t index = contract.spec().object()->find(variable::SPEC_NAME_BUILT_IN_TYPE).getInt();
144
var.setValue({}); // error || empty
146
var.setValue({variable::ValueType(index)});
149
throw AnalyzeException( "ScriptSemantics_abstract::createVariable",
150
token.location().makeLocation(inter().files()),
151
inout::fmt("Unable to create variable '%1' without type specification")
152
.arg(token.lexeme()));
155
var.spec().set(variable::SPEC_ORIGIN, origin);