loom

Форк
0
/
StackOfNames.cpp 
375 строк · 12.4 Кб
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
    StackOfNames::StackOfNames(Logistics_interface & logistics)
19
        : _logistics(logistics)
20
    {
21
    }
22

23
    name_index_t StackOfNames::push(const variable::Variable & name)
24
    {
25
        name_index_t new_name_index = _stack.size();
26
        _stack.push(name);
27
        return new_name_index;
28
    }
29

30
    name_index_t StackOfNames::pushRef( const variable::Variable & v, 
31
                                        const inout::TokenLocation & location,
32
                                        const variable::VariableSet_t & spec)
33
    {
34
        const variable::Variable & o = v.origin();
35

36
        return push({ o.name(), variable::VariableRef {o}, location, spec });
37
    }
38

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

47
        return _stack.size() - depth - 1;
48
    }
49

50
    name_index_t StackOfNames::index_over_top() const 
51
    {
52
        return _stack.size();
53
    }
54

55
    void StackOfNames::pop(size_t depth)
56
    {
57
        _stack.popAmount(depth);
58
    }
59

60
    void StackOfNames::erase(name_index_t name_index)
61
    {
62
        assert(name_index < _stack.size());
63
        _stack.stack().erase( _stack.stack().begin()+name_index);
64
    }
65

66
    name_index_t StackOfNames::find(const std::u16string & name, BoundScope scope) const
67
    {
68
        assert(!_boundaries.empty());
69

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

81
            if (_stack.at(i).name() == name)
82
                return i;
83
        }
84

85
        return findGlobal(name);
86
    }
87

88
    variable::Variable & StackOfNames::findVariable(const std::u16string & name)
89
    {
90
        static variable::Variable error = variable::error_variable();
91

92
        assert(!_boundaries.empty());
93

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;
103
                }
104
                else {
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())
111
                                return v;
112
                        }
113
                    }
114
                }
115

116
            if (_stack.at(i).name() == name)
117
                return variable(i);
118
        }
119

120
        i = findGlobal(name);
121

122
        return i != UNDEFINED_NAME_INDEX ? variable(i) : error;
123
    }
124

125
    variable::Variable & StackOfNames::variable(name_index_t name_index)
126
    {
127
        return _stack.at(name_index);
128
    }
129

130
    const variable::Variable & StackOfNames::variable(name_index_t name_index) const
131
    {
132
        return _stack.at(name_index);
133
    }
134

135
    void StackOfNames::setName(name_index_t name_index, const std::u16string & new_name)
136
    {
137
        assert(name_index < _stack.size());
138
        _stack.at(name_index).setName(new_name);
139
    }
140

141
    bool StackOfNames::addGlobal(name_index_t name_index)
142
    {
143
        assert(name_index < _stack.size());
144

145
        /// \todo Пока сделано так, чтобы глобальные имена (контракты) добавлялись только из файла 
146
        /// инициализации контрактов. Иначе пришлось бы каждый раз при сносе границ проверять глобальные 
147
        /// имена за этими границами.
148
        if (_boundaries.size() > 2)
149
            return false;
150

151
        for(size_t i=0; i < _globals.size(); ++i)
152
            if (_globals[i] == name_index || variable(_globals[i]).name() == variable(name_index).name())
153
                return false;
154

155
        _globals.push_back(name_index);
156
        return true;
157
    }
158

159
    void StackOfNames::addUsing(std::shared_ptr<variable::Object> obj, boundary_index_t bound_index)
160
    {
161
        _usings.push_back({obj, bound_index});
162
    }
163

164
    boundary_index_t StackOfNames::currentBoundary()
165
    {
166
        return _boundaries.size() > 0 ? _boundaries.size() - 1 : UNDEFINED_BOUNDARY_INDEX;
167
    }
168

169
    boundary_index_t StackOfNames::startBoundary(BoundScope type, boundary_mark_t mark)
170
    {
171
        boundary_index_t bi = _boundaries.size();
172
        _boundaries.push_back({type, _stack.size(), mark, {}});
173

174
        if (mark == BOUNDARY_MARK_FUNCTION_FRAME
175
         || mark == BOUNDARY_MARK_MODULE_FRAME)
176
            _logistics.onEnterFunction();
177

178
        return bi;
179
    }
180

181
    void StackOfNames::setBoundaryToGlobal(boundary_index_t bound_index)
182
    {
183
        assert(bound_index < _boundaries.size());
184

185
        BoundInfo & bound = _boundaries[bound_index];
186

187
        bound.type = BoundScope::Global;
188
    }
189

190
    bool StackOfNames::clearBoundary(boundary_index_t bound_index)
191
    {
192
        assert(bound_index != UNDEFINED_BOUNDARY_INDEX);
193

194
        if (bound_index >= _boundaries.size())
195
            return true;
196

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

199
        size_t bounds_count = _boundaries.size() - bound_index;
200

201
        assert(bounds_count < _boundaries.size());
202
        assert(_boundaries[bound_index].ref_to_stack <= _stack.size());
203

204
        if (_boundaries[bound_index].ref_to_stack < _stack.size())
205
            _stack.popAmount(_stack.size() - _boundaries[bound_index].ref_to_stack);
206

207
        while(bounds_count--) {
208
            if (_boundaries.back().mark == BOUNDARY_MARK_FUNCTION_FRAME
209
             || _boundaries.back().mark == BOUNDARY_MARK_MODULE_FRAME)
210
                _logistics.onExitFunction();
211

212
            _boundaries.pop_back();
213
        }
214

215
        while(!_usings.empty())
216
            if (_usings.back().boundary < bound_index)
217
                break;
218
            else
219
                _usings.pop_back();
220

221
        return true;
222
    }
223

224
    std::pair<name_index_t,name_index_t> StackOfNames::boundaryLowAndTop(boundary_index_t bound_index) const
225
    {
226
        assert(bound_index < _boundaries.size());
227

228
        name_index_t top_index = (bound_index == _boundaries.size()-1) 
229
                               ? _stack.size()
230
                               : _boundaries[bound_index+1].ref_to_stack;
231

232
        return {_boundaries[bound_index].ref_to_stack, top_index};
233
    }
234

235
    boundary_index_t StackOfNames::findNearestMarkedBoundary(boundary_mark_t mark, BoundScope type) const
236
    {
237
        for(boundary_index_t i=_boundaries.size()-1; i < _boundaries.size(); --i) {
238
            if (_boundaries[i].mark == mark && type == _boundaries[i].type)
239
                return i;
240

241
            if (type == BoundScope::Local && _boundaries[i].type == BoundScope::Global)
242
                return UNDEFINED_BOUNDARY_INDEX;
243
        }
244

245
        return UNDEFINED_BOUNDARY_INDEX;
246
    }
247

248
    std::pair<boundary_mark_t,BoundScope> StackOfNames::getTopBoundaryMarkAndScope() const
249
    {
250
        assert(!_boundaries.empty());
251

252
        return {_boundaries.back().mark, _boundaries.back().type};
253
    }
254

255
    variable::VariableSetWrapper_mutable StackOfNames::makeVariableSetWrapper()
256
    {
257
        assert(!_boundaries.empty());
258

259
        size_t ref_to_args { _boundaries.back().ref_to_stack };
260

261
        return { _stack.stack(), ref_to_args };
262
    }
263

264
    std::shared_ptr<variable::Object> StackOfNames::convertToObject(boundary_index_t bound_index)
265
    {
266
        variable::VariableSet_t vars;
267

268
        auto [low_index, top_index] = boundaryLowAndTop(bound_index);
269

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));
273
        }
274

275
        return std::make_shared<variable::Object>(vars);
276
    }
277

278
    void StackOfNames::fillFromObject(std::shared_ptr<variable::Object> obj)
279
    {
280
        for(const variable::Variable & v : obj->variables())
281
            push(v.copyVariable());
282
    }
283

284
    bool StackOfNames::isRecursiveCalls() const
285
    {
286
        assert(!_boundaries.empty());
287

288
        if (_boundaries.back().mark != BOUNDARY_MARK_FUNCTION_FRAME)
289
            return false;
290

291
        name_index_t function_index = _boundaries.back().ref_to_stack-1;
292

293
        assert(function_index < _stack.size());
294

295
        const variable::Variable & function = _stack.at(function_index);
296

297
        if (!function.origin().value().isFunction())
298
            return false;
299

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

302
        assert(function_object);
303

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

309
                if (function.origin().value().isFunction()
310
                 && function.origin().value().getFunction().get() == function_object.get())
311
                    return true;
312
            }
313
        
314
        return false;
315
    }
316

317
    std::vector<boundary_index_t> StackOfNames::getFunctionBounds() const
318
    {
319
        std::vector<boundary_index_t> bounds;
320

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)
324
                bounds.push_back(i);
325

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

328
        for(boundary_index_t i = start_index; i < _boundaries.size(); --i)
329
            if (_boundaries[i].type == BoundScope::Global) {
330
                bounds.push_back(i);
331
                break;
332
            }
333

334
        return bounds;
335
    }
336

337
    std::vector<name_index_t> StackOfNames::getFrameLocals(boundary_index_t frame_index) const
338
    {
339
        boundary_index_t upper_frame = 0;
340

341
        for(boundary_index_t i = frame_index+1; i < _boundaries.size(); ++i)
342
            if (_boundaries[i].mark == BOUNDARY_MARK_FUNCTION_FRAME) {
343
                upper_frame = i;
344
                break;
345
            }
346

347
        name_index_t bottom_name = _boundaries[frame_index].ref_to_stack;
348
        name_index_t upper_name;
349

350
        if (upper_frame == 0)
351
            upper_name = _stack.size();
352
        else
353
            upper_name = _boundaries[upper_frame].ref_to_stack;
354

355
        std::vector<name_index_t> locals;
356

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())
360
                locals.push_back(i);
361
        }
362

363
        return locals;
364
    }
365

366
    name_index_t StackOfNames::findGlobal(const std::u16string & name) const
367
    {
368
        for(name_index_t i : _globals)
369
            if (variable(i).name() == name)
370
                return i;
371

372
        return UNDEFINED_NAME_INDEX;
373
    }
374

375
}
376

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

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

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

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