4
Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
6
https://bmstu.codes/lsx/simodo/loom
9
#include "simodo/interpret/StackOfNames.h"
10
#include "simodo/interpret/AnalyzeException.h"
12
#include "simodo/inout/format/fmt.h"
16
namespace simodo::interpret
18
StackOfNames::StackOfNames(Logistics_interface & logistics)
19
: _logistics(logistics)
23
name_index_t StackOfNames::push(const variable::Variable & name)
25
name_index_t new_name_index = _stack.size();
27
return new_name_index;
30
name_index_t StackOfNames::pushRef( const variable::Variable & v,
31
const inout::TokenLocation & location,
32
const variable::VariableSet_t & spec)
34
const variable::Variable & o = v.origin();
36
return push({ o.name(), variable::VariableRef {o}, location, spec });
39
name_index_t StackOfNames::top(size_t depth) const
41
if (depth >= _stack.size())
42
throw bormental::DrBormental("StackOfNames::top",
43
inout::fmt("Attempt to handle invalid offset %1 in stack of variables (actual size = %2)")
47
return _stack.size() - depth - 1;
50
name_index_t StackOfNames::index_over_top() const
55
void StackOfNames::pop(size_t depth)
57
_stack.popAmount(depth);
60
void StackOfNames::erase(name_index_t name_index)
62
assert(name_index < _stack.size());
63
_stack.stack().erase( _stack.stack().begin()+name_index);
66
name_index_t StackOfNames::find(const std::u16string & name, BoundScope scope) const
68
assert(!_boundaries.empty());
70
// Ищем имена на стеке (с конца стека)
71
name_index_t i = _stack.size()-1;
72
boundary_index_t bi = _boundaries.size()-1;
73
for( ; i < _stack.size(); --i) {
74
// Локальные границы могут дублироваться, поэтому проверяем, пока совпадает
75
for( ; _boundaries[bi].ref_to_stack > i; --bi)
76
if (scope == BoundScope::Local)
77
return UNDEFINED_NAME_INDEX;
78
else if (_boundaries[bi].type == BoundScope::Global)
79
return findGlobal(name);
81
if (_stack.at(i).name() == name)
85
return findGlobal(name);
88
variable::Variable & StackOfNames::findVariable(const std::u16string & name)
90
static variable::Variable error = variable::error_variable();
92
assert(!_boundaries.empty());
94
// Ищем имена на стеке (с конца стека)
95
name_index_t i = _stack.size()-1;
96
boundary_index_t bi = _boundaries.size()-1;
97
for( ; i < _stack.size(); --i) {
98
// Локальные границы могут дублироваться, поэтому проверяем, пока совпадает
99
for( ; _boundaries[bi].ref_to_stack > i; --bi)
100
if (_boundaries[bi].type == BoundScope::Global) {
101
i = findGlobal(name);
102
return i != UNDEFINED_NAME_INDEX ? variable(i) : error;
105
size_t using_index = _usings.size()-1;
106
for(; using_index < _usings.size(); --using_index) {
107
UsingInfo & ui = _usings[using_index];
108
if (ui.boundary == bi) {
109
variable::Variable & v = ui.object->getVariableByName_mutable(name);
110
if (!v.name().empty())
116
if (_stack.at(i).name() == name)
120
i = findGlobal(name);
122
return i != UNDEFINED_NAME_INDEX ? variable(i) : error;
125
variable::Variable & StackOfNames::variable(name_index_t name_index)
127
return _stack.at(name_index);
130
const variable::Variable & StackOfNames::variable(name_index_t name_index) const
132
return _stack.at(name_index);
135
void StackOfNames::setName(name_index_t name_index, const std::u16string & new_name)
137
assert(name_index < _stack.size());
138
_stack.at(name_index).setName(new_name);
141
bool StackOfNames::addGlobal(name_index_t name_index)
143
assert(name_index < _stack.size());
145
/// \todo Пока сделано так, чтобы глобальные имена (контракты) добавлялись только из файла
146
/// инициализации контрактов. Иначе пришлось бы каждый раз при сносе границ проверять глобальные
147
/// имена за этими границами.
148
if (_boundaries.size() > 2)
151
for(size_t i=0; i < _globals.size(); ++i)
152
if (_globals[i] == name_index || variable(_globals[i]).name() == variable(name_index).name())
155
_globals.push_back(name_index);
159
void StackOfNames::addUsing(std::shared_ptr<variable::Object> obj, boundary_index_t bound_index)
161
_usings.push_back({obj, bound_index});
164
boundary_index_t StackOfNames::currentBoundary()
166
return _boundaries.size() > 0 ? _boundaries.size() - 1 : UNDEFINED_BOUNDARY_INDEX;
169
boundary_index_t StackOfNames::startBoundary(BoundScope type, boundary_mark_t mark)
171
boundary_index_t bi = _boundaries.size();
172
_boundaries.push_back({type, _stack.size(), mark, {}});
174
if (mark == BOUNDARY_MARK_FUNCTION_FRAME
175
|| mark == BOUNDARY_MARK_MODULE_FRAME)
176
_logistics.onEnterFunction();
181
void StackOfNames::setBoundaryToGlobal(boundary_index_t bound_index)
183
assert(bound_index < _boundaries.size());
185
BoundInfo & bound = _boundaries[bound_index];
187
bound.type = BoundScope::Global;
190
bool StackOfNames::clearBoundary(boundary_index_t bound_index)
192
assert(bound_index != UNDEFINED_BOUNDARY_INDEX);
194
if (bound_index >= _boundaries.size())
197
/// \todo Тут уместно вызывать деструкторы переменных на стеке.
199
size_t bounds_count = _boundaries.size() - bound_index;
201
assert(bounds_count < _boundaries.size());
202
assert(_boundaries[bound_index].ref_to_stack <= _stack.size());
204
if (_boundaries[bound_index].ref_to_stack < _stack.size())
205
_stack.popAmount(_stack.size() - _boundaries[bound_index].ref_to_stack);
207
while(bounds_count--) {
208
if (_boundaries.back().mark == BOUNDARY_MARK_FUNCTION_FRAME
209
|| _boundaries.back().mark == BOUNDARY_MARK_MODULE_FRAME)
210
_logistics.onExitFunction();
212
_boundaries.pop_back();
215
while(!_usings.empty())
216
if (_usings.back().boundary < bound_index)
224
std::pair<name_index_t,name_index_t> StackOfNames::boundaryLowAndTop(boundary_index_t bound_index) const
226
assert(bound_index < _boundaries.size());
228
name_index_t top_index = (bound_index == _boundaries.size()-1)
230
: _boundaries[bound_index+1].ref_to_stack;
232
return {_boundaries[bound_index].ref_to_stack, top_index};
235
boundary_index_t StackOfNames::findNearestMarkedBoundary(boundary_mark_t mark, BoundScope type) const
237
for(boundary_index_t i=_boundaries.size()-1; i < _boundaries.size(); --i) {
238
if (_boundaries[i].mark == mark && type == _boundaries[i].type)
241
if (type == BoundScope::Local && _boundaries[i].type == BoundScope::Global)
242
return UNDEFINED_BOUNDARY_INDEX;
245
return UNDEFINED_BOUNDARY_INDEX;
248
std::pair<boundary_mark_t,BoundScope> StackOfNames::getTopBoundaryMarkAndScope() const
250
assert(!_boundaries.empty());
252
return {_boundaries.back().mark, _boundaries.back().type};
255
variable::VariableSetWrapper_mutable StackOfNames::makeVariableSetWrapper()
257
assert(!_boundaries.empty());
259
size_t ref_to_args { _boundaries.back().ref_to_stack };
261
return { _stack.stack(), ref_to_args };
264
std::shared_ptr<variable::Object> StackOfNames::convertToObject(boundary_index_t bound_index)
266
variable::VariableSet_t vars;
268
auto [low_index, top_index] = boundaryLowAndTop(bound_index);
270
for(name_index_t i = low_index; i < top_index; ++i) {
271
assert(!_stack.at(i).name().empty());
272
vars.push_back(_stack.at(i));
275
return std::make_shared<variable::Object>(vars);
278
void StackOfNames::fillFromObject(std::shared_ptr<variable::Object> obj)
280
for(const variable::Variable & v : obj->variables())
281
push(v.copyVariable());
284
bool StackOfNames::isRecursiveCalls() const
286
assert(!_boundaries.empty());
288
if (_boundaries.back().mark != BOUNDARY_MARK_FUNCTION_FRAME)
291
name_index_t function_index = _boundaries.back().ref_to_stack-1;
293
assert(function_index < _stack.size());
295
const variable::Variable & function = _stack.at(function_index);
297
if (!function.origin().value().isFunction())
300
const std::shared_ptr<variable::Object> function_object = function.origin().value().getFunction();
302
assert(function_object);
304
for(boundary_index_t i = _boundaries.size()-2; i < _boundaries.size(); --i)
305
if (_boundaries[i].mark == BOUNDARY_MARK_FUNCTION_FRAME) {
306
name_index_t function_index = _boundaries[i].ref_to_stack-1;
307
const variable::Variable & function = _stack.at(function_index);
309
if (function.origin().value().isFunction()
310
&& function.origin().value().getFunction().get() == function_object.get())
317
std::vector<boundary_index_t> StackOfNames::getFunctionBounds() const
319
std::vector<boundary_index_t> bounds;
321
for(boundary_index_t i = _boundaries.size()-1; i < _boundaries.size(); --i)
322
if (_boundaries[i].mark == BOUNDARY_MARK_FUNCTION_FRAME
323
&& _boundaries[i].type == BoundScope::Global)
326
boundary_index_t start_index = bounds.empty() ? _boundaries.size()-1 : bounds.back()-1;
328
for(boundary_index_t i = start_index; i < _boundaries.size(); --i)
329
if (_boundaries[i].type == BoundScope::Global) {
337
std::vector<name_index_t> StackOfNames::getFrameLocals(boundary_index_t frame_index) const
339
boundary_index_t upper_frame = 0;
341
for(boundary_index_t i = frame_index+1; i < _boundaries.size(); ++i)
342
if (_boundaries[i].mark == BOUNDARY_MARK_FUNCTION_FRAME) {
347
name_index_t bottom_name = _boundaries[frame_index].ref_to_stack;
348
name_index_t upper_name;
350
if (upper_frame == 0)
351
upper_name = _stack.size();
353
upper_name = _boundaries[upper_frame].ref_to_stack;
355
std::vector<name_index_t> locals;
357
for(name_index_t i = upper_name - 1; i >= bottom_name && i < _stack.size(); --i) {
358
const variable::Variable & v = variable(i);
359
if (v.type() != variable::ValueType::Ref && !v.name().empty())
366
name_index_t StackOfNames::findGlobal(const std::u16string & name) const
368
for(name_index_t i : _globals)
369
if (variable(i).name() == name)
372
return UNDEFINED_NAME_INDEX;