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 }