1 /** Types for holding SDLang document data. 2 */ 3 module sdlite.ast; 4 5 import taggedalgebraic.taggedunion; 6 import std.datetime; 7 import std.string : indexOf; 8 9 @safe pure: 10 11 void validateQualifiedIdentiifier(string qualified_ident) 12 { 13 auto idx = qualified_ident.indexOf(':'); 14 if (idx >= 0) { 15 if (qualified_ident[idx+1 .. $].indexOf(':') >= 0) 16 throw new Exception("Multiple namespace separators in identifier: "~qualified_ident); 17 validateIdentifier(qualified_ident[0 .. idx]); 18 validateIdentifier(qualified_ident[idx+1 .. $]); 19 } else validateIdentifier(qualified_ident); 20 } 21 22 void validateIdentifier(string ident) 23 { 24 // TODO 25 } 26 27 28 /** Represents a single SDL node. 29 */ 30 struct SDLNode { 31 private string m_qualifiedName; 32 SDLValue[] values; 33 SDLAttribute[] attributes; 34 SDLNode[] children; 35 36 this(string qualified_name, SDLValue[] values = null, 37 SDLAttribute[] attributes = null, SDLNode[] children = null) 38 { 39 this.qualifiedName = qualified_name; 40 this.values = values; 41 this.attributes = attributes; 42 this.children = children; 43 } 44 45 @safe pure: 46 /** Qualified name of the tag 47 48 The form of this value is either "namespace:name" or just "name". 49 */ 50 @property string qualifiedName() const nothrow { return m_qualifiedName; } 51 /// ditto 52 @property void qualifiedName(string qualified_ident) 53 { 54 validateQualifiedIdentiifier(qualified_ident); 55 m_qualifiedName = qualified_ident; 56 } 57 58 59 /// Namespace (if any) of the tag 60 @property string namespace() 61 const nothrow { 62 auto idx = m_qualifiedName.indexOf(':'); 63 if (idx >= 0) return m_qualifiedName[0 .. idx]; 64 return null; 65 } 66 67 /// Unqualified name of the tag (use `namespace` to disambiguate) 68 @property string name() 69 const nothrow { 70 auto idx = m_qualifiedName.indexOf(':'); 71 if (idx >= 0) return m_qualifiedName[idx+1 .. $]; 72 return m_qualifiedName; 73 } 74 75 /// Looks up an attribute by qualified name 76 SDLValue getAttribute(string qualified_name, SDLValue default_ = SDLValue.null_) 77 nothrow { 78 foreach (ref a; attributes) 79 if (a.qualifiedName == qualified_name) 80 return a.value; 81 return default_; 82 } 83 } 84 85 86 /** Attribute of a node 87 */ 88 struct SDLAttribute { 89 private string m_qualifiedName; 90 91 SDLValue value; 92 93 @safe pure: 94 this(string qualified_ident, SDLValue value) 95 { 96 this.qualifiedName = qualified_ident; 97 this.value = value; 98 } 99 100 /** Qualified name of the attribute 101 102 The form of this value is either "namespace:name" or just "name". 103 */ 104 @property string qualifiedName() const nothrow { return m_qualifiedName; } 105 /// ditto 106 @property void qualifiedName(string qualified_ident) 107 { 108 validateQualifiedIdentiifier(qualified_ident); 109 m_qualifiedName = qualified_ident; 110 } 111 112 /// Namespace (if any) of the attribute 113 @property string namespace() 114 const nothrow { 115 auto idx = m_qualifiedName.indexOf(':'); 116 if (idx >= 0) return m_qualifiedName[0 .. idx]; 117 return null; 118 } 119 120 /// Unqualified name of the attribute (use `namespace` to disambiguate) 121 @property string name() 122 const nothrow { 123 auto idx = m_qualifiedName.indexOf(':'); 124 if (idx >= 0) return m_qualifiedName[idx+1 .. $]; 125 return m_qualifiedName; 126 } 127 } 128 129 130 /** A single SDLang value 131 */ 132 alias SDLValue = TaggedUnion!SDLValueFields; 133 134 struct SDLValueFields { 135 Void null_; 136 string text; 137 immutable(ubyte)[] binary; 138 int int_; 139 long long_; 140 long[2] decimal; 141 float float_; 142 double double_; 143 bool bool_; 144 SysTime dateTime; 145 Date date; 146 Duration duration; 147 }