1 /** 2 * Authors: Tomoya Tanjo 3 * Copyright: © 2021 Tomoya Tanjo 4 * License: Apache-2.0 5 */ 6 module salad.ast; 7 8 version(none): 9 import dyaml : Mark, Node; 10 11 import salad.type; 12 13 import std.typecons : Tuple; 14 15 alias ASTNodeType = Optional!(bool, 16 long, 17 real, 18 string, 19 AST[string], 20 AST[], 21 AST, 22 Node); 23 24 /// 25 class AST 26 { 27 Mark mark; 28 string vocabulary; 29 ASTNodeType value; 30 31 /// 32 this(T)(Node node, string vocab, T val) // validate T type 33 { 34 mark = node.startMark; 35 vocabulary = vocab; 36 value = ASTNodeType(val); 37 } 38 39 override string toString() @trusted 40 { 41 import std.conv : to; 42 import std.format : format; 43 return format!"AST(%s, %s)"(vocabulary, value.match!(v => v.to!string)); 44 } 45 } 46 47 /// dig 48 auto dig(T)(AST ast, string key, T default_) 49 { 50 return dig(ast, [key], default_); 51 } 52 53 /// ditto 54 AST dig(T)(AST ast, string[] keys, T default_) 55 { 56 import std.algorithm : canFind; 57 import std.range : empty; 58 59 if (auto a = ast.value.match!((AST a) => a, others => null)) 60 { 61 return a.dig(keys, default_); 62 } 63 else if (auto n = ast.value.match!((Node n) => &n, others => null)) 64 { 65 import salad.util : dig; 66 auto digged = n.dig(keys, default_); 67 return new AST(digged, "Any", digged); 68 } 69 else if (keys.empty) 70 { 71 return ast; 72 } 73 74 auto k = keys[0]; 75 76 auto rec = ast.value.tryMatch!((AST[string] rec) => rec); 77 if (auto a = k in rec) 78 { 79 return (*a).dig(keys[1..$], default_); 80 } 81 else 82 { 83 if (k.canFind("://")) 84 { 85 static if (is(T: void[])) 86 { 87 auto n = Node((Node[]).init); 88 } 89 else 90 { 91 auto n = Node(default_); 92 } 93 return new AST(Node.init, "Any", n); 94 } 95 else 96 { 97 static if (is(T : void[])) 98 { 99 auto def = (AST[]).init; 100 } 101 else 102 { 103 auto def = default_; 104 } 105 return new AST(Node.init, "Any", def); 106 } 107 } 108 } 109 110 /// edig 111 auto edig(Ex = Exception)(AST ast, string key) 112 { 113 return edig!Ex(ast, [key]); 114 } 115 116 /// ditto 117 AST edig(Ex = Exception)(AST ast, string[] keys) 118 { 119 import std.algorithm : canFind; 120 import std.range : empty; 121 122 if (auto a = ast.value.match!((AST a) => a, others => null)) 123 { 124 return a.edig!Ex(keys); 125 } 126 else if (auto n = ast.value.match!((return ref Node n) => &n, others => null)) 127 { 128 import salad.util : edig; 129 auto digged = (*n).edig!Ex(keys); 130 return new AST(digged, "Any", digged); 131 } 132 else if (keys.empty) 133 { 134 return ast; 135 } 136 137 auto k = keys[0]; 138 139 auto rec = ast.value.tryMatch!((AST[string] rec) => rec); 140 if (auto a = k in rec) 141 { 142 return (*a).edig!Ex(keys[1..$]); 143 } 144 else 145 { 146 import std.format : format; 147 throw new Ex(format!"No such field: %s"(k)); 148 } 149 }