1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
|
#pragma once
#include "Named.h"
#include "Template.h"
#include "Core/Array.h"
#include "Core/Map.h"
namespace storm {
STORM_PKG(core.lang);
class NameSet;
/**
* Interface receiving differences between two NameSets.
*
* Not intended to be used from Storm; only intended for reload internals.
*/
class NameDiff {
public:
// Called for each entity that was added.
virtual void added(Named *item) = 0;
virtual void added(Template *item) = 0;
// Called for each entity that was removed.
virtual void removed(Named *item) = 0;
virtual void removed(Template *item) = 0;
// Called for each entity that exists in both versions. Note: We can't diff templates, so
// they are never treated as being 'equal'.
virtual void changed(Named *old, Named *changed) = 0;
};
/**
* A set of named objects, all with the same name but with different parameters.
*/
class NameOverloads : public ObjectOn<Compiler> {
STORM_CLASS;
public:
// Create.
STORM_CTOR NameOverloads();
// Is this instance empty? (ie. not even any template?)
Bool STORM_FN empty() const;
// Get the number of items in here. Note: May return 0 even if 'empty' returns false.
Nat STORM_FN count() const;
// Get item #n in here.
Named *STORM_FN operator [](Nat id) const;
Named *at(Nat id) const;
// Check if an element is in here.
MAYBE(Named *) STORM_FN has(Named *item);
// Add an element.
void STORM_FN add(Named *item);
// Add a template.
void STORM_FN add(Template *item);
// Remove an element. Returns true on success.
Bool STORM_FN remove(Named *item);
// Remove a template. Returns true on success.
Bool STORM_FN remove(Template *item);
// Merge from another NameOverloads.
void STORM_FN merge(NameOverloads *from);
// Diff in various situations.
void diff(NameOverloads *with, NameDiff &callback, ReplaceContext *ctx);
void diffAdded(NameDiff &callback);
void diffRemoved(NameDiff &callback);
void diffTemplatesAdded(NameDiff &callback);
void diffTemplatesRemoved(NameDiff &callback);
// Does this object contain any templates?
Bool STORM_FN anyTemplates() const;
// Generate a matching template. Does *not* add it to this object.
// TODO: More care should be taking when dealing with templates and overload resolution!
MAYBE(Named *) STORM_FN createTemplate(NameSet *owner, SimplePart *from, Scope source);
// To string.
virtual void STORM_FN toS(StrBuf *to) const;
private:
// All named items.
Array<Named *> *items;
// Templates with this name. Might be null.
Array<Template *> *templates;
};
/**
* A named object containing other named objects. Used for building recursive trees inside the
* compiler.
*
* Implements support for lazy-loading. At creation, the NameSet assumes there is some amount of
* content that can be loaded on demand. When someone tries to access the content in the
* NameSet, it tries to load as little as possible while still determining if the content exists.
*
* Lazy-loading happens in two steps:
* 1: The NameSet asks the derived class to load a specific Name that does not yet exist.
* 2: The NameSet asks the derived class to load all content.
*
* The first step does not need to be implemented, while the second step is mandatory. As soon
* as #2 has been called, the NameSet assumes that all content is loaded, and will therefore
* never call #1 again. Pay attention if you implement both, that #2 may not load things that #1
* have previously loaded.
*
* Content can of course be added eagerly by calling 'add'. This does not affect the
* lazy-loading process in any way.
*/
class NameSet : public Named {
STORM_CLASS;
public:
// Create.
STORM_CTOR NameSet(Str *name);
STORM_CTOR NameSet(Str *name, Array<Value> *params);
STORM_CTOR NameSet(SrcPos pos, Str *name);
STORM_CTOR NameSet(SrcPos pos, Str *name, Array<Value> *params);
// Check if this name set has a Named with the exact parameters as the provided
// entity. I.e., would it be possible to store 'item' here without issues?
virtual MAYBE(Named *) STORM_FN has(Named *item) const;
// Add a named object.
virtual void STORM_FN add(Named *item);
// Add a template.
virtual void STORM_FN add(Template *item);
// Remove a named object from here.
virtual Bool STORM_FN remove(Named *item);
// Remove a template from here.
virtual Bool STORM_FN remove(Template *item);
// Get an anonymous name for this NameSet.
virtual Str *STORM_FN anonName();
// Get all members.
virtual Array<Named *> *STORM_FN content();
// Find all entities that might be generated by a template.
Array<NameOverloads *> *STORM_FN templateOverloads();
// Find all overloads for a particular name.
MAYBE(NameOverloads *) STORM_FN allOverloads(Str *name);
// Force loading this NameSet.
void STORM_FN forceLoad();
// Find a named entity in the name set. Overloads the `find` function in `NameLookup`.
virtual MAYBE(Named *) STORM_FN find(SimplePart *part, Scope source);
using Named::find;
// Watch this NameSet for new additions.
virtual void STORM_FN watchAdd(Named *notifyTo);
// Remove a previously added watch.
virtual void STORM_FN watchRemove(Named *notifyTo);
// Output.
virtual void STORM_FN toS(StrBuf *to) const;
// Late initialization.
virtual void lateInit();
// Force compilation.
virtual void STORM_FN compile();
// Discard source information.
virtual void STORM_FN discardSource();
// Iterator. TODO: How to do wrt threading?
class Iter {
STORM_VALUE;
friend class NameSet;
public:
// Create an iterator pointing to the end.
STORM_CTOR Iter();
// Compare.
Bool STORM_FN operator ==(const Iter &o) const;
Bool STORM_FN operator !=(const Iter &o) const;
// Get the value.
Named *STORM_FN v() const;
// Increment.
Iter &STORM_FN operator ++();
Iter STORM_FN operator ++(int d);
private:
// Create an iterator to the start.
Iter(Map<Str *, NameOverloads *> *c, NameSet *next);
// Current position in the map.
typedef Map<Str *, NameOverloads *>::Iter MapIter;
UNKNOWN(MapBase::Iter) MapIter name;
// Next NameSet to visit (if any).
MAYBE(NameSet *) nextSet;
// Current position in NameOverloads at 'pos'.
Nat pos;
// Advance 'name' until we find something!
void advance();
};
// Get iterators to the begin and end of the contents.
virtual Iter STORM_FN begin() const;
virtual Iter STORM_FN end() const;
// Get all overloads for a specific name.
Array<Named *> *STORM_FN findName(Str *name) const;
// Dump the internal contents of the NameSet for debugging.
void dbg_dump() const;
protected:
/**
* Lazy-loading callbacks.
*/
// Attempt to load a single missing name. Assumed to call `add()` on one or more candidates
// for `part`, and then return true. It is acceptable to add no candidates and return `true`,
// which is interpreted as `no matches can be lazy-loaded`. If there may be candidates, but
// none can be loaded from here, return `false`. This causes `loadAll` to be called instead.
virtual Bool STORM_FN loadName(SimplePart *part);
// Called when we need to load all content. Assumed to call `add()` on all entities. Returns
// false or throws an exception on failure. Failure will re-try loading at a later time.
virtual Bool STORM_FN loadAll();
// Check if this `NameSet` is loaded fully.
inline Bool STORM_FN allLoaded() const { return loaded; }
// Find a name part in this `NameSet`, but do not perform lazy-loading.
MAYBE(Named *) STORM_FN tryFind(SimplePart *part, Scope source);
// Find a named in the NameSet. Use the SimplePart to determine which one to choose, and how
// to respect visibility.
MAYBE(Named *) STORM_FN tryFind(SimplePart *part, Scope source, NameOverloads *from);
// Find a name in the NameSet. Use the SimplePart to determine which to choose. Only
// examines one level of NameParts.
MAYBE(Named *) STORM_FN tryFindSingle(SimplePart *part, Scope source, NameOverloads *from);
// Get an iterator that visits another name set after the current one.
Iter STORM_FN begin(NameSet *after) const;
// Import entities from another NameSet.
void STORM_FN merge(NameSet *from);
// Find differences between two NameSets. For terminology, assumes that 'with' is the "new" version.
// If 'ctx' is not null, it is used to resolve equivalences between new and old trees.
void diff(NameSet *with, NameDiff &callback, ReplaceContext *ctx);
// Stop auto-discarding source when items are added. This effectively undoes what
// `discardSource` does, but it only applies for newly added entities.
void STORM_FN stopDiscardSource();
private:
// Overloads.
typedef Map<Str *, NameOverloads *> Overloads;
Map<Str *, NameOverloads *> *overloads;
// Lazy-loading done?
Bool loaded;
// Lazy-loading in progress?
Bool loading;
// Asked to discard sources?
Bool sourceDiscarded;
// Identifier for the next anonymous thing.
Nat nextAnon;
// Initialize.
void init();
// Recursive helper to the public function.
void templateOverloads(Array<NameOverloads *> *result);
// All Named object who want notifications from us. May be null.
WeakSet<Named> *notify;
// Notify something has been added.
void notifyAdd(Named *what);
// Notify something has been removed.
void notifyRemove(Named *what);
};
}
|