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 }