1 /**** Primary node type and associated types. 2 * 3 * Author: ARaspiK 4 * License: MIT 5 */ 6 module sdlangp.node; 7 8 import std.bigint; 9 import std.datetime; 10 import std.algorithm; 11 import sumtype; 12 import std.conv; 13 import std.exception; 14 import std.format; 15 import std.range; 16 17 /// The node type. 18 struct Node { 19 20 Node* parent; 21 22 string namespace, name; 23 24 Value[] values; 25 Value[string] attrs; 26 27 Node*[] children; 28 29 @safe this(Node* parent, string namespace = "", string name = "", 30 Value[] values = [], Value[string] attrs = null, Node*[] children = [], 31 ) nothrow pure { 32 this.parent = parent; 33 this.namespace = namespace; 34 this.name = name; 35 this.values = values; 36 this.attrs = attrs; 37 this.children = children; 38 if (parent !is null) 39 parent.children ~= &this; 40 } 41 42 @trusted string toString() const nothrow { 43 import std.array; 44 import std.string; 45 46 auto res = appender!string; 47 bool noname = false; 48 49 if (namespace.length > 0) 50 res.put(format!"%s:%s: "(namespace, name.length > 0 ? name : `""`) 51 .assumeWontThrow); 52 else if (name.length > 0) 53 res.put(name.format!"%s: ".assumeWontThrow); 54 else 55 noname = true; 56 57 res.put( 58 choose(values.length + attrs.length > 0, 59 values.map!(v => v.toString) 60 .chain(attrs.byKeyValue 61 .map!(a => format!"%s=%s"(a.key, a.value.toString).assumeWontThrow)) 62 .array 63 .format!"%-(%s%|, %)\n".assumeWontThrow 64 .only, 65 choose(noname, "".only.takeNone, "\n".only)) 66 .chain(choose(noname, 67 children.map!(c => c.toString), 68 children.map!(c => c.toString 69 .lineSplitter 70 .map!(l => l.format!" %s\n".assumeWontThrow).join) 71 )) 72 .join); 73 return res.data; 74 } 75 76 @property @safe Value opIndex(size_t i) const nothrow pure { 77 return values[i]; 78 } 79 80 @property @safe Value opIndexAssign(Value v, size_t i) nothrow pure { 81 return values[i] = v; 82 } 83 84 @property @safe Value opIndex(string name) const nothrow pure { 85 return attrs[name]; 86 } 87 88 @property @safe Value opIndexAssign(Value v, string name) nothrow pure { 89 return attrs[name] = v; 90 } 91 } 92 93 /// The value type. 94 alias Value = SumType!( 95 int, long, BigInt, // Number 96 float, double, // Float 97 bool, typeof(null), // Boolean and Null 98 Duration, SysTime, // Time 99 string, // Text 100 ubyte[], // Miscellaneous 101 ); 102 103 /// Converts the value to a string. 104 @trusted string toString(Value v) nothrow { 105 return v.match!(t => t.to!string.assumeWontThrow); 106 }