1 /**
2 License:
3     Boost Software License - Version 1.0 - August 17th, 2003
4 
5     Permission is hereby granted, free of charge, to any person or organization
6     obtaining a copy of the software and accompanying documentation covered by
7     this license (the "Software") to use, reproduce, display, distribute,
8     execute, and transmit the Software, and to prepare derivative works of the
9     Software, and to permit third-parties to whom the Software is furnished to
10     do so, all subject to the following:
11 
12     The copyright notices in the Software and this entire statement, including
13     the above license grant, this restriction and the following disclaimer,
14     must be included in all copies of the Software, in whole or in part, and
15     all derivative works of the Software, unless such copies or derivative
16     works are solely in the form of machine-executable object code generated by
17     a source language processor.
18 
19     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21     FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22     SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23     FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24     ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25     DEALINGS IN THE SOFTWARE.
26 
27 Authors:
28     Alexandru Ermicioi
29 **/
30 module aermicioi.aedi_property_reader.sdlang.accessor;
31 
32 import sdlang.ast;
33 import aermicioi.aedi_property_reader.core.accessor;
34 import aermicioi.aedi.exception.not_found_exception : NotFoundException;
35 import taggedalgebraic : TaggedAlgebraic;
36 import std.exception;
37 import std.experimental.logger;
38 import aermicioi.aedi_property_reader.core.traits : n;
39 
40 union SdlangElementUnion {
41     Tag tag;
42     Attribute attribute;
43 };
44 
45 alias SdlangElement = TaggedAlgebraic!(SdlangElementUnion);
46 
47 /**
48 Accessor allowing to access child tags from a sdlang tag by their name.
49 **/
50 class SdlangTagPropertyAccessor : PropertyAccessor!(Tag, Tag) {
51 
52     /**
53      Get a property out of component
54 
55      Params:
56          component = a component which has some properties identified by property.
57      Throws:
58          NotFoundException in case when no requested property is available.
59          InvalidArgumentException in case when passed arguments are somehow invalid for use.
60      Returns:
61          FieldType accessed property.
62      **/
63     Tag access(Tag component, in string property) const {
64 
65         if (property in component.tags) {
66             return component.tags[property].front;
67         }
68 
69         throw new NotFoundException("Sdlang tag " ~ component.getFullName.toString ~ " doesn't have child " ~ property);
70     }
71 
72     /**
73      Check if requested property is present in component.
74 
75      Check if requested property is present in component.
76      The method could have allocation side effects due to the fact that
77      it is not restricted in calling access method of the accessor.
78 
79      Params:
80          component = component which is supposed to have property
81          property = speculated property that is to be tested if it is present in component
82      Returns:
83          true if property is in component
84      **/
85     bool has(in Tag component, in string property) const nothrow {
86 
87         try {
88 
89             return (component !is null) && property in (cast(Tag) component).tags;
90         } catch (Exception e) {
91 
92             debug(trace) error("Failed to check property ", property, " existence due to ", e).n;
93         }
94 
95         return false;
96     }
97 
98     /**
99      Identify the type of supported component.
100 
101      Identify the type of supported component. It returns type info of component
102      if it is supported by accessor, otherwise it will return typeid(void) denoting that
103      the type isn't supported by accessor. The accessor is not limited to returning the type
104      info of passed component, it can actually return type info of super type or any type
105      given the returned type is implicitly convertible or castable to ComponentType.
106 
107      Params:
108          component = the component for which accessor should identify the underlying type
109 
110      Returns:
111          TypeInfo type information about passed component, or typeid(void) if component is not supported.
112      **/
113     TypeInfo componentType(Tag component) const nothrow {
114         return typeid(Tag);
115     }
116 }
117 
118 /**
119 Accessor allowing access to child tags by their index.
120 **/
121 class SdlangIntegerIndexAccessor : PropertyAccessor!(Tag, Tag) {
122 
123     /**
124      Get a property out of component
125 
126      Params:
127          component = a component which has some properties identified by property.
128      Throws:
129          NotFoundException in case when no requested property is available.
130          InvalidArgumentException in case when passed arguments are somehow invalid for use.
131      Returns:
132          FieldType accessed property.
133      **/
134     Tag access(Tag component, in string property) const {
135 
136         if (this.has(component, property)) {
137             import std.conv : to;
138 
139             return component.tags[property.to!size_t];
140         }
141 
142         throw new NotFoundException("Sdlang tag " ~ component.getFullName.toString ~ " doesn't have child on index " ~ property);
143     }
144 
145     /**
146      Check if requested property is present in component.
147 
148      Check if requested property is present in component.
149      The method could have allocation side effects due to the fact that
150      it is not restricted in calling access method of the accessor.
151 
152      Params:
153          component = component which is supposed to have property
154          property = speculated property that is to be tested if it is present in component
155      Returns:
156          true if property is in component
157      **/
158     bool has(in Tag component, in string property) const nothrow {
159         try {
160             import std.string;
161             import std.conv;
162 
163             return (component !is null) && property.isNumeric && ((cast(Tag) component).tags.length > property.to!size_t);
164         } catch (Exception e) {
165 
166             debug(trace) error("Failed to check property ", property, " existence due to ", e).n;
167         }
168 
169         return false;
170     }
171 
172     /**
173      Identify the type of supported component.
174 
175      Identify the type of supported component. It returns type info of component
176      if it is supported by accessor, otherwise it will return typeid(void) denoting that
177      the type isn't supported by accessor. The accessor is not limited to returning the type
178      info of passed component, it can actually return type info of super type or any type
179      given the returned type is implicitly convertible or castable to ComponentType.
180 
181      Params:
182          component = the component for which accessor should identify the underlying type
183 
184      Returns:
185          TypeInfo type information about passed component, or typeid(void) if component is not supported.
186      **/
187     TypeInfo componentType(Tag component) const nothrow {
188         return typeid(Tag);
189     }
190 }
191 
192 /**
193 Accessor for sdlang tag attributes.
194 **/
195 class SdlangAttributePropertyAccessor : PropertyAccessor!(Tag, Attribute) {
196     /**
197      Get a property out of component
198 
199      Params:
200          component = a component which has some properties identified by property.
201      Throws:
202          NotFoundException in case when no requested property is available.
203          InvalidArgumentException in case when passed arguments are somehow invalid for use.
204      Returns:
205          FieldType accessed property.
206      **/
207     Attribute access(Tag component, in string property) const {
208 
209         if (property in component.attributes) {
210             return component.attributes[property].front;
211         }
212 
213         throw new NotFoundException("Sdlang tag " ~ component.getFullName.toString ~ " doesn't have attribute " ~ property);
214     }
215 
216     /**
217      Check if requested property is present in component.
218 
219      Check if requested property is present in component.
220      The method could have allocation side effects due to the fact that
221      it is not restricted in calling access method of the accessor.
222 
223      Params:
224          component = component which is supposed to have property
225          property = speculated property that is to be tested if it is present in component
226      Returns:
227          true if property is in component
228      **/
229     bool has(in Tag component, in string property) const nothrow {
230         try {
231 
232             return (component !is null) && property in (cast(Tag) component).attributes;
233         } catch (Exception e) {
234 
235             debug(trace) error("Failed to check property ", property, " existence due to ", e).n;
236         }
237 
238         return false;
239     }
240 
241     /**
242      Identify the type of supported component.
243 
244      Identify the type of supported component. It returns type info of component
245      if it is supported by accessor, otherwise it will return typeid(void) denoting that
246      the type isn't supported by accessor. The accessor is not limited to returning the type
247      info of passed component, it can actually return type info of super type or any type
248      given the returned type is implicitly convertible or castable to ComponentType.
249 
250      Params:
251          component = the component for which accessor should identify the underlying type
252 
253      Returns:
254          TypeInfo type information about passed component, or typeid(void) if component is not supported.
255      **/
256     TypeInfo componentType(Tag component) const nothrow {
257         return typeid(Tag);
258     }
259 }