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 }