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
name_index_t StackOfNames::push(const variable::Variable & name)
20
name_index_t new_name_index = _stack.size();
22
return new_name_index;
25
name_index_t StackOfNames::pushRef( const variable::Variable & v,
26
const inout::TokenLocation & location,
27
const variable::VariableSet_t & spec)
29
const variable::Variable & o = v.origin();
31
return push({ o.name(), variable::VariableRef {o}, location, spec });
34
name_index_t StackOfNames::top(size_t depth) const
36
if (depth >= _stack.size())
37
throw bormental::DrBormental("StackOfNames::top",
38
inout::fmt("Attempt to handle invalid offset %1 in stack of variables (actual size = %2)")
42
return _stack.size() - depth - 1;
45
name_index_t StackOfNames::index_over_top() const
50
void StackOfNames::pop(size_t depth)
52
_stack.popAmount(depth);
55
void StackOfNames::erase(name_index_t name_index)
57
assert(name_index < _stack.size());
58
_stack.stack().erase( _stack.stack().begin()+name_index);
61
name_index_t StackOfNames::find(const std::u16string & name, BoundScope scope) const
63
assert(!_boundaries.empty());
66
name_index_t i = _stack.size()-1;
67
boundary_index_t bi = _boundaries.size()-1;
68
for( ; i < _stack.size(); --i) {
69
// Локальные границы могут дублироваться, поэтому проверяем, пока совпадает
70
for( ; _boundaries[bi].ref_to_stack > i; --bi)
71
if (scope == BoundScope::Local)
72
return UNDEFINED_NAME_INDEX;
73
else if (_boundaries[bi].type == BoundScope::Global)
74
return findGlobal(name);
76
if (_stack.at(i).name() == name)
80
return findGlobal(name);
83
variable::Variable & StackOfNames::variable(name_index_t name_index)
85
return _stack.at(name_index);
88
const variable::Variable & StackOfNames::variable(name_index_t name_index) const
90
return _stack.at(name_index);
93
void StackOfNames::setName(name_index_t name_index, const std::u16string & new_name)
95
assert(name_index < _stack.size());
96
_stack.at(name_index).setName(new_name);
99
bool StackOfNames::addGlobal(name_index_t name_index)
101
assert(name_index < _stack.size());
103
/// \todo Пока сделано так, чтобы глобальные имена (контракты) добавлялись только из файла
104
/// инициализации контрактов. Иначе пришлось бы каждый раз при сносе границ проверять глобальные
105
/// имена за этими границами.
106
if (_boundaries.size() > 2)
109
for(size_t i=0; i < _globals.size(); ++i)
110
if (_globals[i] == name_index || variable(_globals[i]).name() == variable(name_index).name())
113
_globals.push_back(name_index);
117
boundary_index_t StackOfNames::startBoundary(BoundScope type, boundary_mark_t mark)
119
boundary_index_t bi = _boundaries.size();
120
_boundaries.push_back({type, _stack.size(), mark, {}});
124
void StackOfNames::setBoundaryToGlobal(boundary_index_t bound_index)
126
assert(bound_index < _boundaries.size());
128
BoundInfo & bound = _boundaries[bound_index];
130
bound.type = BoundScope::Global;
133
bool StackOfNames::clearBoundary(boundary_index_t bound_index)
135
if (bound_index >= _boundaries.size())
138
/// \todo Тут уместно вызывать деструкторы переменных на стеке.
140
size_t bounds_count = _boundaries.size() - bound_index;
141
size_t variables_count = _stack.size() - _boundaries[bound_index].ref_to_stack;
143
_stack.popAmount(variables_count);
145
while(bounds_count--) _boundaries.pop_back();
150
std::pair<name_index_t,name_index_t> StackOfNames::boundaryLowAndTop(boundary_index_t bound_index) const
152
assert(bound_index < _boundaries.size());
154
name_index_t top_index = (bound_index == _boundaries.size()-1)
156
: _boundaries[bound_index+1].ref_to_stack;
158
return {_boundaries[bound_index].ref_to_stack, top_index};
161
boundary_index_t StackOfNames::findNearestMarkedBoundary(boundary_mark_t mark, BoundScope type) const
163
for(boundary_index_t i=_boundaries.size()-1; i < _boundaries.size(); --i) {
164
if (_boundaries[i].mark == mark)
167
if (type == BoundScope::Local && _boundaries[i].type == BoundScope::Global)
168
return UNDEFINED_BOUNDARY_INDEX;
171
return UNDEFINED_BOUNDARY_INDEX;
174
std::pair<boundary_mark_t,BoundScope> StackOfNames::getTopBoundaryMarkAndScope() const
176
assert(!_boundaries.empty());
178
return {_boundaries.back().mark, _boundaries.back().type};
181
variable::VariableSetWrapper_mutable StackOfNames::makeVariableSetWrapper()
183
assert(!_boundaries.empty());
185
size_t ref_to_args { _boundaries.back().ref_to_stack };
187
return { _stack.stack(), ref_to_args };
190
std::shared_ptr<variable::Object> StackOfNames::convertToObject(boundary_index_t bound_index)
192
variable::VariableSet_t vars;
194
auto [low_index, top_index] = boundaryLowAndTop(bound_index);
196
for(name_index_t i = low_index; i < top_index; ++i) {
197
assert(!_stack.at(i).name().empty());
198
vars.push_back(_stack.at(i));
201
return std::make_shared<variable::Object>(vars);
204
void StackOfNames::fillFromObject(std::shared_ptr<variable::Object> obj)
206
for(const variable::Variable & v : obj->variables())
207
push(v.copyVariable());
210
bool StackOfNames::isRecursiveCalls() const
212
assert(!_boundaries.empty());
214
if (_boundaries.back().mark != BOUNDARY_MARK_FUNCTION_FRAME)
217
name_index_t function_index = _boundaries.back().ref_to_stack-1;
219
assert(function_index < _stack.size());
221
const variable::Variable & function = _stack.at(function_index);
223
if (!function.origin().value().isFunction())
226
const std::shared_ptr<variable::Object> function_object = function.origin().value().getFunction();
228
assert(function_object);
230
for(boundary_index_t i = _boundaries.size()-2; i < _boundaries.size(); --i)
231
if (_boundaries[i].mark == BOUNDARY_MARK_FUNCTION_FRAME) {
232
name_index_t function_index = _boundaries[i].ref_to_stack-1;
233
const variable::Variable & function = _stack.at(function_index);
235
if (function.origin().value().isFunction()
236
&& function.origin().value().getFunction().get() == function_object.get())
243
std::vector<boundary_index_t> StackOfNames::getFunctionBounds() const
245
std::vector<boundary_index_t> bounds;
247
for(boundary_index_t i = _boundaries.size()-1; i < _boundaries.size(); --i)
248
if (_boundaries[i].mark == BOUNDARY_MARK_FUNCTION_FRAME)
251
boundary_index_t start_index = bounds.empty() ? _boundaries.size()-1 : bounds.back()-1;
253
for(boundary_index_t i = start_index; i < _boundaries.size(); --i)
254
if (_boundaries[i].type == BoundScope::Global) {
262
std::vector<name_index_t> StackOfNames::getFrameLocals(boundary_index_t frame_index) const
264
boundary_index_t upper_frame = 0;
266
for(boundary_index_t i = frame_index+1; i < _boundaries.size(); ++i)
267
if (_boundaries[i].mark == BOUNDARY_MARK_FUNCTION_FRAME) {
272
name_index_t bottom_name = _boundaries[frame_index].ref_to_stack;
273
name_index_t upper_name;
275
if (upper_frame == 0)
276
upper_name = _stack.size();
278
upper_name = _boundaries[upper_frame].ref_to_stack;
280
std::vector<name_index_t> locals;
282
for(name_index_t i = upper_name - 1; i >= bottom_name && i < _stack.size(); --i) {
283
const variable::Variable & v = variable(i);
284
if (v.type() != variable::ValueType::Ref && !v.name().empty())
291
name_index_t StackOfNames::findGlobal(const std::u16string & name) const
293
for(name_index_t i : _globals)
294
if (variable(i).name() == name)
297
return UNDEFINED_NAME_INDEX;