loom

Форк
0
/
StackOfNames.cpp 
300 строк · 9.6 Кб
1
/*
2
MIT License
3

4
Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
5

6
https://bmstu.codes/lsx/simodo/loom
7
*/
8

9
#include "simodo/interpret/StackOfNames.h"
10
#include "simodo/interpret/AnalyzeException.h"
11

12
#include "simodo/inout/format/fmt.h"
13

14
#include <cassert>
15

16
namespace simodo::interpret
17
{
18
    name_index_t StackOfNames::push(const variable::Variable & name)
19
    {
20
        name_index_t new_name_index = _stack.size();
21
        _stack.push(name);
22
        return new_name_index;
23
    }
24

25
    name_index_t StackOfNames::pushRef( const variable::Variable & v, 
26
                                        const inout::TokenLocation & location,
27
                                        const variable::VariableSet_t & spec)
28
    {
29
        const variable::Variable & o = v.origin();
30

31
        return push({ o.name(), variable::VariableRef {o}, location, spec });
32
    }
33

34
    name_index_t StackOfNames::top(size_t depth) const
35
    {
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)")
39
                        .arg(depth)
40
                        .arg(_stack.size()));
41

42
        return _stack.size() - depth - 1;
43
    }
44

45
    name_index_t StackOfNames::index_over_top() const 
46
    {
47
        return _stack.size();
48
    }
49

50
    void StackOfNames::pop(size_t depth)
51
    {
52
        _stack.popAmount(depth);
53
    }
54

55
    void StackOfNames::erase(name_index_t name_index)
56
    {
57
        assert(name_index < _stack.size());
58
        _stack.stack().erase( _stack.stack().begin()+name_index);
59
    }
60

61
    name_index_t StackOfNames::find(const std::u16string & name, BoundScope scope) const
62
    {
63
        assert(!_boundaries.empty());
64

65
        // Ищем с конца стека
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);
75

76
            if (_stack.at(i).name() == name)
77
                return i;
78
        }
79

80
        return findGlobal(name);
81
    }
82

83
    variable::Variable & StackOfNames::variable(name_index_t name_index)
84
    {
85
        return _stack.at(name_index);
86
    }
87

88
    const variable::Variable & StackOfNames::variable(name_index_t name_index) const
89
    {
90
        return _stack.at(name_index);
91
    }
92

93
    void StackOfNames::setName(name_index_t name_index, const std::u16string & new_name)
94
    {
95
        assert(name_index < _stack.size());
96
        _stack.at(name_index).setName(new_name);
97
    }
98

99
    bool StackOfNames::addGlobal(name_index_t name_index)
100
    {
101
        assert(name_index < _stack.size());
102

103
        /// \todo Пока сделано так, чтобы глобальные имена (контракты) добавлялись только из файла 
104
        /// инициализации контрактов. Иначе пришлось бы каждый раз при сносе границ проверять глобальные 
105
        /// имена за этими границами.
106
        if (_boundaries.size() > 2)
107
            return false;
108

109
        for(size_t i=0; i < _globals.size(); ++i)
110
            if (_globals[i] == name_index || variable(_globals[i]).name() == variable(name_index).name())
111
                return false;
112

113
        _globals.push_back(name_index);
114
        return true;
115
    }
116

117
    boundary_index_t StackOfNames::startBoundary(BoundScope type, boundary_mark_t mark)
118
    {
119
        boundary_index_t bi = _boundaries.size();
120
        _boundaries.push_back({type, _stack.size(), mark, {}});
121
        return bi;
122
    }
123

124
    void StackOfNames::setBoundaryToGlobal(boundary_index_t bound_index)
125
    {
126
        assert(bound_index < _boundaries.size());
127

128
        BoundInfo & bound = _boundaries[bound_index];
129

130
        bound.type = BoundScope::Global;
131
    }
132

133
    bool StackOfNames::clearBoundary(boundary_index_t bound_index)
134
    {
135
        if (bound_index >= _boundaries.size())
136
            return false;
137

138
        /// \todo Тут уместно вызывать деструкторы переменных на стеке. 
139

140
        size_t bounds_count    = _boundaries.size() - bound_index;
141
        size_t variables_count = _stack.size() - _boundaries[bound_index].ref_to_stack;
142

143
        _stack.popAmount(variables_count);
144

145
        while(bounds_count--) _boundaries.pop_back();
146

147
        return true;
148
    }
149

150
    std::pair<name_index_t,name_index_t> StackOfNames::boundaryLowAndTop(boundary_index_t bound_index) const
151
    {
152
        assert(bound_index < _boundaries.size());
153

154
        name_index_t top_index = (bound_index == _boundaries.size()-1) 
155
                               ? _stack.size()
156
                               : _boundaries[bound_index+1].ref_to_stack;
157

158
        return {_boundaries[bound_index].ref_to_stack, top_index};
159
    }
160

161
    boundary_index_t StackOfNames::findNearestMarkedBoundary(boundary_mark_t mark, BoundScope type) const
162
    {
163
        for(boundary_index_t i=_boundaries.size()-1; i < _boundaries.size(); --i) {
164
            if (_boundaries[i].mark == mark)
165
                return i;
166

167
            if (type == BoundScope::Local && _boundaries[i].type == BoundScope::Global)
168
                return UNDEFINED_BOUNDARY_INDEX;
169
        }
170

171
        return UNDEFINED_BOUNDARY_INDEX;
172
    }
173

174
    std::pair<boundary_mark_t,BoundScope> StackOfNames::getTopBoundaryMarkAndScope() const
175
    {
176
        assert(!_boundaries.empty());
177

178
        return {_boundaries.back().mark, _boundaries.back().type};
179
    }
180

181
    variable::VariableSetWrapper_mutable StackOfNames::makeVariableSetWrapper()
182
    {
183
        assert(!_boundaries.empty());
184

185
        size_t ref_to_args { _boundaries.back().ref_to_stack };
186

187
        return { _stack.stack(), ref_to_args };
188
    }
189

190
    std::shared_ptr<variable::Object> StackOfNames::convertToObject(boundary_index_t bound_index)
191
    {
192
        variable::VariableSet_t vars;
193

194
        auto [low_index, top_index] = boundaryLowAndTop(bound_index);
195

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));
199
        }
200

201
        return std::make_shared<variable::Object>(vars);
202
    }
203

204
    void StackOfNames::fillFromObject(std::shared_ptr<variable::Object> obj)
205
    {
206
        for(const variable::Variable & v : obj->variables())
207
            push(v.copyVariable());
208
    }
209

210
    bool StackOfNames::isRecursiveCalls() const
211
    {
212
        assert(!_boundaries.empty());
213

214
        if (_boundaries.back().mark != BOUNDARY_MARK_FUNCTION_FRAME)
215
            return false;
216

217
        name_index_t function_index = _boundaries.back().ref_to_stack-1;
218

219
        assert(function_index < _stack.size());
220

221
        const variable::Variable & function = _stack.at(function_index);
222

223
        if (!function.origin().value().isFunction())
224
            return false;
225

226
        const std::shared_ptr<variable::Object> function_object = function.origin().value().getFunction();
227

228
        assert(function_object);
229

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);
234

235
                if (function.origin().value().isFunction()
236
                 && function.origin().value().getFunction().get() == function_object.get())
237
                    return true;
238
            }
239
        
240
        return false;
241
    }
242

243
    std::vector<boundary_index_t> StackOfNames::getFunctionBounds() const
244
    {
245
        std::vector<boundary_index_t> bounds;
246

247
        for(boundary_index_t i = _boundaries.size()-1; i < _boundaries.size(); --i)
248
            if (_boundaries[i].mark == BOUNDARY_MARK_FUNCTION_FRAME)
249
                bounds.push_back(i);
250

251
        boundary_index_t start_index = bounds.empty() ? _boundaries.size()-1 : bounds.back()-1;
252

253
        for(boundary_index_t i = start_index; i < _boundaries.size(); --i)
254
            if (_boundaries[i].type == BoundScope::Global) {
255
                bounds.push_back(i);
256
                break;
257
            }
258

259
        return bounds;
260
    }
261

262
    std::vector<name_index_t> StackOfNames::getFrameLocals(boundary_index_t frame_index) const
263
    {
264
        boundary_index_t upper_frame = 0;
265

266
        for(boundary_index_t i = frame_index+1; i < _boundaries.size(); ++i)
267
            if (_boundaries[i].mark == BOUNDARY_MARK_FUNCTION_FRAME) {
268
                upper_frame = i;
269
                break;
270
            }
271

272
        name_index_t bottom_name = _boundaries[frame_index].ref_to_stack;
273
        name_index_t upper_name;
274

275
        if (upper_frame == 0)
276
            upper_name = _stack.size();
277
        else
278
            upper_name = _boundaries[upper_frame].ref_to_stack;
279

280
        std::vector<name_index_t> locals;
281

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())
285
                locals.push_back(i);
286
        }
287

288
        return locals;
289
    }
290

291
    name_index_t StackOfNames::findGlobal(const std::u16string & name) const
292
    {
293
        for(name_index_t i : _globals)
294
            if (variable(i).name() == name)
295
                return i;
296

297
        return UNDEFINED_NAME_INDEX;
298
    }
299

300
}
301

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

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

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

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