loom

Форк
0
/
ScriptSemantics_contract.cpp 
160 строк · 9.1 Кб
1
/*
2
MIT License
3

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

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

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

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

15
#include <cassert>
16

17
namespace simodo::interpret
18
{
19
    namespace
20
    {
21
        // static const variable::Variable error = variable::error_variable();
22
    }
23

24
    void ScriptSemantics_abstract::appendContractProperties(const variable::Variable & from, variable::Variable & to)
25
    {
26
        /// \note Спецификация (Variable::spec) передаётся переменной только слева направо, т.е. не через
27
        /// инициализацию и не через присвоение.
28
        /// Информация о типе хранится только в спецификации (Variable::spec), а значит, если она была задана 
29
        /// в структуре, то её нужно перенести в спеку контракта.
30

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;
37

38
        const std::shared_ptr<variable::Object> spec_source = spec_in_body 
39
                                                    ? from_origin.value().getObject()
40
                                                    : from_spec;
41

42
        if (!spec_in_body) {
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"));
49

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"));
56

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();
63

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())
67
                            to_object->add(p);
68
                        else
69
                            existing_contract.setValue(p.value());
70
                    }
71
                }
72
            }
73
            else if (from_origin.value().isArray())
74
                to.setValue(from_origin.value());
75
        }
76

77
        // Наполняем структуру спецификации
78
        for(const variable::Variable & spec : spec_source->variables()) {
79
            if (spec.name() == variable::SPEC_ORIGIN) {
80
                // Происхождение спецификации не имеет значения
81
                continue;
82
            }
83

84
            // Очевидные проверки
85
            inout::TokenLocation err_loc = spec_in_body ? spec.location() : from.location();
86

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"));
93

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"));
99
            }
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"));
108
            }
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'")
115
                                            .arg(spec.name()));
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"));
121
            }
122

123
            // Копируем спецификацию (std::shared_ptr для объектов и массивов сохраняются)
124
            to.spec().set(spec.name(),spec.value());
125
        }
126
    }
127

128
    variable::Variable ScriptSemantics_abstract::createVariable( const variable::Variable & contract, 
129
                                                const inout::Token & token, 
130
                                                const std::u16string & origin)
131
    {
132
        variable::Variable var { token.lexeme(), {}, token.location(), contract.spec().copy() }; 
133

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());
138
        else {
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();
143
                if (index < 0)
144
                    var.setValue({}); // error || empty
145
                else
146
                    var.setValue({variable::ValueType(index)});
147
            }
148
            else
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()));
153
        }
154

155
        var.spec().set(variable::SPEC_ORIGIN, origin);
156

157
        return var;
158
    }
159

160
}

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

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

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

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