context.cpp (4540B)
1 #include "context.hpp" 2 3 #include "item.hpp" 4 #include "../utils.hpp" 5 6 #include <libshit/except.hpp> 7 #include <libshit/string_utils.hpp> 8 9 #include <iomanip> 10 #include <fstream> 11 #include <sstream> 12 13 namespace Neptools 14 { 15 16 Context::Context() 17 : ItemWithChildren{Key{}, *this} 18 {} 19 20 Context::~Context() 21 { 22 Context::Dispose(); 23 } 24 25 void Context::SetupParseFrom(Item& item) 26 { 27 pmap[0] = &item; 28 GetChildren().push_back(item); // noexcept 29 } 30 31 void Context::Fixup() 32 { 33 pmap.clear(); 34 35 FilePosition pos = 0; 36 for (auto& c : GetChildren()) 37 { 38 c.UpdatePosition(pos); 39 pos += c.GetSize(); 40 } 41 // todo? size = pos; 42 } 43 44 45 Libshit::NotNull<LabelPtr> Context::GetLabel(const std::string& name) const 46 { 47 auto it = labels.find(name); 48 if (it == labels.end()) 49 LIBSHIT_THROW(std::out_of_range, "Context::GetLabel", 50 "Affected label", name); 51 return MakeNotNull(const_cast<Label*>(&*it)); 52 } 53 54 Libshit::NotNull<LabelPtr> Context::CreateLabel( 55 std::string name, ItemPointer ptr) 56 { 57 auto lbl = new Label{std::move(name), ptr}; 58 auto pair = labels.insert(*lbl); 59 if (!pair.second) 60 { 61 name = std::move(lbl->name); 62 delete lbl; 63 LIBSHIT_THROW(std::out_of_range, "label already exists", 64 "Affected label", std::move(name)); 65 } 66 67 ptr->labels.insert(*pair.first); 68 return MakeNotNull(&*pair.first); 69 } 70 71 Libshit::NotNull<LabelPtr> Context::CreateLabelFallback( 72 const std::string& name, ItemPointer ptr) 73 { 74 LabelsMap::insert_commit_data commit; 75 std::string str = name; 76 77 auto pair = labels.insert_check(str, commit); 78 for (int i = 1; !pair.second; ++i) 79 { 80 std::stringstream ss; 81 ss << name << '_' << i; 82 str = ss.str(); 83 pair = labels.insert_check(str, commit); 84 } 85 86 auto it = labels.insert_commit(*new Label{std::move(str), ptr}, commit); 87 88 ptr->labels.insert(*it); 89 return MakeNotNull(&*it); 90 } 91 92 Libshit::NotNull<LabelPtr> Context::CreateOrSetLabel( 93 std::string name, ItemPointer ptr) 94 { 95 LabelsMap::insert_commit_data commit; 96 auto [it, insertable] = labels.insert_check(name, commit); 97 98 if (insertable) 99 { 100 auto it = labels.insert_commit(*new Label{std::move(name), ptr}, commit); 101 ptr->labels.insert(*it); 102 return MakeNotNull(&*it); 103 } 104 else 105 { 106 if (it->ptr != nullptr) it->ptr->labels.remove_node(*it); 107 it->ptr = ptr; 108 ptr->labels.insert(*it); 109 return MakeNotNull(&*it); 110 } 111 } 112 113 Libshit::NotNull<LabelPtr> Context::GetOrCreateDummyLabel(std::string name) 114 { 115 LabelsMap::insert_commit_data commit; 116 auto [it, insertable] = labels.insert_check(name, commit); 117 118 if (insertable) 119 it = labels.insert_commit( 120 *new Label{std::move(name), {nullptr,0}}, commit); 121 return MakeNotNull(const_cast<Label*>(&*it)); 122 } 123 124 Libshit::NotNull<LabelPtr> Context::GetLabelTo(ItemPointer ptr) 125 { 126 auto& lctr = ptr.item->labels; 127 auto it = lctr.find(ptr.offset); 128 if (it != lctr.end()) return MakeNotNull(&*it); 129 130 std::stringstream ss; 131 ss << "loc_" << std::setw(8) << std::setfill('0') << std::hex 132 << ptr.item->GetPosition() + ptr.offset; 133 return CreateLabelFallback(ss.str(), ptr); 134 } 135 136 Libshit::NotNull<LabelPtr> Context::GetLabelTo( 137 FilePosition pos, const std::string& name) 138 { 139 auto ptr = GetPointer(pos); 140 auto& lctr = ptr.item->labels; 141 auto it = lctr.find(ptr.offset); 142 if (it != lctr.end()) return MakeNotNull(&*it); 143 144 return CreateLabelFallback(name, ptr); 145 } 146 147 ItemPointer Context::GetPointer(FilePosition pos) const noexcept 148 { 149 auto it = pmap.upper_bound(pos); 150 LIBSHIT_ASSERT_MSG(it != pmap.begin(), "file position out of range"); 151 --it; 152 LIBSHIT_ASSERT(it->first == it->second->GetPosition()); 153 return {it->second, pos - it->first}; 154 } 155 156 void Context::Dispose() noexcept 157 { 158 pmap.clear(); 159 struct Disposer 160 { 161 void operator()(Label* l) 162 { 163 auto& item = l->ptr.item; 164 if (item) 165 { 166 item->labels.erase(item->labels.iterator_to(*l)); 167 item = nullptr; 168 } 169 l->RemoveRef(); 170 } 171 }; 172 labels.clear_and_dispose(Disposer{}); 173 GetChildren().clear(); 174 175 ItemWithChildren::Dispose(); 176 } 177 178 std::ostream& operator<<(std::ostream& os, PrintLabelStruct l) 179 { 180 if (l.label == nullptr) 181 return os << "nil"; 182 return os << "l(" << Libshit::Quoted(l.label->GetName()) << ')'; 183 } 184 185 } 186 187 #include "context.binding.hpp"