1 /++ 2 Wrapper for SDLite. 3 4 Noticable differences between SDLang and SDLite parser: 5 - Line breaking is not allowed ("title \", newline, " 'value'"), i.e: 6 --- 7 title \ 8 "Some title" 9 --- 10 +/ 11 module sily.sdlang; 12 13 import sdl = sdlite; 14 import std.range; 15 16 import taggedalgebraic.taggedunion; 17 18 /++ 19 Representation of single sdlang node 20 Example: 21 --- 22 // Create SDLNode. SDLNode("name", SDLValue[] values, SDLAttribute[] attributes, SDLNode[] children) 23 SDLNode node = SDLNode("name", [SDLValue.text("values")], [], []); 24 // Get name 25 node.name; 26 // Get namespace 27 node.namespace; 28 // Get/Set qualified name (eq to namespace:name) 29 node.qualifiedName; 30 node.qualifiedName = "namespace:name"; 31 // Get array of values (aka 'node 1 "b" v=2' -> returns 1 "b") 32 node.values; 33 // Get array of attributes (aka 'node 1 "b" v=2' -> returns v=2) 34 node.attributes; 35 // Get array of children 36 node.children; 37 // Gets attribute by qualified name 38 node.getAttribute("email") 39 // Gets attribute by qualified name with default value 40 node.getAttribute("email", SDLValue.text("mail@mail.com")) 41 --- 42 +/ 43 alias SDLNode = sdl.SDLNode; 44 45 /++ 46 Value of sdlang node 47 Example: 48 --- 49 // Create new value 50 SDLValue val = SDLValue.double_(22.5); 51 // Get value casted to int 52 val.value!int; 53 // Check type 54 val.kind == SDLType.text; 55 --- 56 +/ 57 alias SDLValue = sdl.SDLValue; 58 59 /++ 60 Attribute of sdlang node (attr="val") 61 Example: 62 --- 63 // Create new attribute 64 SDLAttribute attr = SDLAttribute("qualifiedName", SDLValue.text("value")); 65 // Get name 66 attr.name; 67 // Get namepsace 68 attr.namespace; 69 // Get/Set qualified name (namespace:name) 70 attr.qualifiedName; 71 attr.qualifiedName = "namespace:name"; 72 // Get/Set value 73 attr.value; 74 attr.value = SDLValue.text("new value") 75 --- 76 +/ 77 alias SDLAttribute = sdl.SDLAttribute; 78 79 /++ 80 Alias to SDLValue.Kind. Represents type of SDLValue (might conflict with SDL library). 81 Example: 82 --- 83 node.values[0].kind == SDLType.float_; 84 node.values[0].kind == SDLFloat; 85 --- 86 Defined types (have aliases in form `SDLTypeName`, i.e SDLBinary or SDLDateTime): 87 --- 88 Void null_; 89 string text; 90 immutable(ubyte)[] binary; 91 int int_; 92 long long_; 93 long[2] decimal; 94 float float_; 95 double double_; 96 bool bool_; 97 SysTime dateTime; 98 Date date; 99 Duration duration; 100 --- 101 +/ 102 alias SDLType = sdl.SDLValue.Kind; 103 /// Ditto 104 alias SDLNull = SDLType.null_; 105 /// Ditto 106 alias SDLString = SDLType.text; 107 /// Ditto 108 alias SDLBinary = SDLType.binary; 109 /// Ditto 110 alias SDLInt = SDLType.int_; 111 /// Ditto 112 alias SDLLong = SDLType.long_; 113 /// Ditto 114 alias SDLDecimal = SDLType.decimal; 115 /// Ditto 116 alias SDLFloat = SDLType.float_; 117 /// Ditto 118 alias SDLDouble = SDLType.double_; 119 /// Ditto 120 alias SDLBool = SDLType.bool_; 121 /// Ditto 122 alias SDLDateTime = SDLType.dateTime; 123 /// Ditto 124 alias SDLDate = SDLType.date; 125 /// Ditto 126 alias SDLDuration = SDLType.duration; 127 128 /++ 129 Parses SDL string into SDLNode[] 130 Example: 131 --- 132 import sily.sdlang; 133 import std.file; 134 SDLNode[] arr1 = parseSDL(readText("file.sdl")); 135 SDLNode[] arr2 = parseSDL("name \"Direct SDLang parsing\" cool=true"); 136 SDLNode[] arr3 = parseSDL("name will print parsing error", true); 137 --- 138 +/ 139 SDLNode[] parseSDL(string input, bool printOnError = false) { 140 SDLNode[] result; 141 try { 142 sdl.parseSDLDocument!((n) { result ~= n; })(input, ""); 143 } catch (Exception e) { 144 if (printOnError) { 145 import std.stdio: writeln; 146 writeln("EXCEPTION: ", e.message); 147 } 148 } 149 return result; 150 } 151 152 private alias generateSDLang = sdl.generateSDLang; 153 154 /++ 155 Writes SDL data into string 156 Example: 157 --- 158 import sily.sdlang; 159 import std.file; 160 SDLNode[] arr1 = parseSDL(readText("file.sdl")); 161 string out = arr1.generateSDL(); 162 --- 163 +/ 164 string generateSDL(SDLNode[] input) { 165 auto app = appender!string; 166 app.generateSDLang(input); 167 return app.data; 168 } 169 170 /// Ditto 171 string generateSDL(SDLNode input) { 172 auto app = appender!string; 173 app.generateSDLang(input); 174 return app.data; 175 } 176 177 /// Ditto 178 string generateSDL(SDLValue input) { 179 auto app = appender!string; 180 app.generateSDLang(input); 181 return app.data; 182 } 183 184 /// Returns true is value `val` is type `T` 185 bool isType(SDLType T)(SDLValue val) { 186 return val.kind == T; 187 } 188 189 /// Returns true if `node` has child with qualified name `qualifiedName` 190 bool hasNode(SDLNode node, string qualifiedName) { 191 foreach(child; node.children) { 192 if (child.qualifiedName == qualifiedName) return true; 193 } 194 return false; 195 } 196 197 /// Returns child of `node` with qualified name `qualifiedName` 198 SDLNode getNode(SDLNode node, string qualifiedName) { 199 foreach(child; node.children) { 200 if (child.qualifiedName == qualifiedName) return child; 201 } 202 return SDLNode.init; 203 } 204 /// Ditto 205 alias node = getNode; 206 207 /// Returns children of `node` with qualified name `qualifiedName` 208 SDLNode[] getNodes(SDLNode node, string qualifiedName) { 209 SDLNode[] arr = []; 210 foreach(child; node.children) { 211 if (child.qualifiedName == qualifiedName) arr ~= child; 212 } 213 return arr; 214 } 215 216 /// Returns nodes from `nodes` array with qualified name `qualifiedName` 217 SDLNode[] getNodes(SDLNode[] nodes, string qualifiedName) { 218 SDLNode[] arr = []; 219 foreach(child; nodes) { 220 if (child.qualifiedName == qualifiedName) arr ~= child; 221 } 222 return arr; 223 } 224 225 /// Alias to `getNodes(SDLNode, string)` and `getNodes(SDLNode[], string)` 226 alias nodes = getNodes; 227 228 /// Returns true if `node` has attribute with qualified name `qualifiedName` 229 bool hasAttribute(SDLNode node, string qualifiedName) { 230 foreach(attrib; node.attributes) { 231 if (attrib.qualifiedName == qualifiedName) return true; 232 } 233 return false; 234 } 235 236 /// Returns true if `node` has attribute with qualified name `qualifiedName` of type `T` 237 bool hasAttribute(SDLType T)(SDLNode node, string qualifiedName) { 238 foreach(attrib; node.attributes) { 239 if (attrib.qualifiedName == qualifiedName && attrib.value.kind == T) return true; 240 } 241 return false; 242 } 243 244 /// Returns all values of type `S` as type `T` from node. 245 T[] getValues(T)(SDLNode node, SDLType type) { 246 T[] arr = []; 247 foreach (val; node.values) { 248 if (val.kind == type) arr ~= val.value!T; 249 } 250 return arr; 251 } 252 253 /// Returns all values of type `S` as type `T` from nodes. Useful when dealing with matrices 254 T[] getValues(T)(SDLNode[] node, SDLType type) { 255 T[] arr = []; 256 foreach (n; node) { 257 foreach (val; n.values) { 258 if (val.kind == type) arr ~= val.value!T; 259 } 260 } 261 return arr; 262 } 263 264 /// Alias to `getValues(T)(SDLNode, SDLType)` and `getValues(T)(SDLNode[], SDLType)` 265 alias values = getValues; 266 267 /// Returns count of values of type `T` 268 size_t hasValues(SDLType T)(SDLNode node) { 269 size_t size = 0; 270 foreach (val; node.values) { 271 if (val.kind == type) ++size; 272 } 273 return size; 274 } 275 /// Ditto 276 size_t hasValues(SDLType T)(SDLNode[] node) { 277 size_t size = 0; 278 foreach (n; node) { 279 foreach (val; n.values) { 280 if (val.kind == type) ++size; 281 } 282 } 283 return size; 284 } 285 /// Ditto 286 alias value = hasValues; 287 288 /// Returns attribute value with qualified name `qualifiedName` and type as `T` 289 T getAttribute(T)(SDLNode node, string qualifiedName) { 290 if (node.hasAttribute(qualifiedName)) { 291 return node.getAttribute(qualifiedName).value!T; 292 } 293 return T.init; 294 } 295 296 /// Returns attribute value with qualified name `qualifiedName` and type as `T` 297 T[] getAttributes(T)(SDLNode[] node, string qualifiedName) { 298 T[] arr = []; 299 foreach (n; node) { 300 if (n.hasAttribute(qualifiedName)) { 301 arr ~= n.getAttribute(qualifiedName).value!T; 302 } 303 } 304 return arr; 305 } 306 307 /// Alias to `getAttribute(T)(SDLNode, string)` 308 alias attribute = getAttribute; 309 310 /// Alias to `getAttributes(T)(SDLNode[], string)` 311 alias attributes = getAttributes; 312 313 /// Returns SDLang attribute value as T 314 T getValue(T)(SDLAttribute attr) { 315 return attr.value.value!T; 316 } 317 /// Ditto 318 alias value = getValue;