1 module dud.sdlang.astaccess; 2 3 import dud.sdlang.ast; 4 import dud.sdlang.value; 5 import dud.sdlang.tokenmodule; 6 7 @safe pure: 8 9 struct AstAccessor(T,E) { 10 @safe pure: 11 T value; 12 this(T value) { 13 this.value = value; 14 } 15 16 @property bool empty() const { 17 return this.value is null; 18 } 19 20 @property ref E front() { 21 return this.value.cur; 22 } 23 24 void popFront() { 25 this.value = this.value.follow; 26 } 27 28 @property AstAccessor!(T,E) save() { 29 return this; 30 } 31 } 32 33 alias TagAccessor = AstAccessor!(Tags, Tag); 34 alias IDAccessor = AstAccessor!(IDFull, Token); 35 alias ValueAccessor = AstAccessor!(Values, Token); 36 alias AttributeAccessor = AstAccessor!(Attributes, Attribute); 37 38 TagAccessor tags(Root root) { 39 return root is null 40 ? TagAccessor(null) 41 : TagAccessor(root.tags); 42 } 43 44 TagAccessor tags(Tags t) { 45 return TagAccessor(t); 46 } 47 48 TagAccessor tags(OptChild child) { 49 return child is null 50 ? TagAccessor(null) 51 : TagAccessor(child.tags); 52 } 53 54 IDAccessor key(Tag tag) { 55 return tag is null 56 ? IDAccessor(null) 57 : IDAccessor(tag.id); 58 } 59 60 AttributeAccessor attributes(Tag tag) { 61 return AttributeAccessor(tag.attrs); 62 } 63 64 string identifier(Attribute attr) { 65 auto a = IDAccessor(attr.id); 66 return identifierImpl(a); 67 } 68 69 string fullIdentifier(Tag tag) { 70 import std.array : appender; 71 import std.algorithm.iteration : map, joiner; 72 import std.algorithm.mutation : copy; 73 74 auto app = appender!string; 75 auto a = IDAccessor(tag.id); 76 a 77 .map!(it => it.value.get!string()) 78 .joiner(":") 79 .copy(app); 80 return app.data; 81 82 } 83 84 string identifier(Tag tag) { 85 auto a = IDAccessor(tag.id); 86 return identifierImpl(a); 87 } 88 89 string identifierImpl(IDAccessor a) { 90 import std.exception : enforce; 91 enforce(!a.empty, "Can get an ID from an empty IDAccessor"); 92 string cur; 93 while(!a.empty) { 94 cur = a.front.value.get!string(); 95 a.popFront(); 96 } 97 return cur; 98 } 99 100 struct ValueRange { 101 @safe pure: 102 ValueAccessor range; 103 104 @property bool empty() const { 105 return this.range.empty; 106 } 107 108 @property ref Token front() { 109 return this.range.front; 110 } 111 112 void popFront() { 113 this.range.popFront(); 114 } 115 } 116 117 ValueRange values(Values vals) { 118 return ValueRange(ValueAccessor(vals)); 119 } 120 121 ValueRange values(Tag tag) { 122 return values(tag.vals); 123 }