GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — tree-query/tree-query.d at main · CrazyPython/tree-query Expand file tree/ Copy pathtree-query.dMore file actions 203 lines (199 loc) · 6.09 KB / Copy pathtree-query.dFile metadata and controls203 lines (199 loc) · 6.09 KB 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 module tree_query; import std.stdio; import std.variant; import std.string; import query; import interp; /++ + Extract the query from the input. + These forms are supported, where QUERY represents the query itself. + - QUERY + - {{query: QUERY }} + - {{query:QUERY}} + - {{[[query]]: QUERY }} + + Leading and trailing whitespace are allowed before the start and end of the query. + + Note that Roam does not accept {{ query: nor {{ query : + +/ string extractQuery(string query) { import std.string; query = strip(query); // Allow leading and trailing whitespace if (query.startsWith("{{")) { if (query.endsWith("}}")) { // "1"th index is 2 auto withoutWhitespace = stripLeft(query[2..$]); enum command = "query:"; if (withoutWhitespace.startsWith(command)) { auto result = query[2+command.length..$-2].strip; return result; } else { throw new Error("Unrecognized command, command must be 'query:'"); } } else { throw new Exception("Malformed query. Must end with '}}'"); } } else { return query; } } unittest { const nakedQueries = [ "{and: [[foo]] [[bar]] }", "{or: [[foo]] [[bar]] }", "{and: [[foo]] [[bar]]}", "{and: [[foo]] {and: [[bar]] [[spam]]}}" ]; foreach (nakedQuery; nakedQueries) { assert(extractQuery(nakedQuery) == nakedQuery); assert(extractQuery("{{query:" ~ nakedQuery ~ "}}") == nakedQuery); assert(extractQuery(" {{query: " ~ nakedQuery ~ " }} ") == nakedQuery); } } struct ParsedQuery { string[] terms; Form form; } ParsedQuery parseQuery(string query) { ParsedQuery q; return q; } // TODO: Implement atom dedup // TODO: Implement support for arbitrary atoms // TODO: Allocate Form from an array for efficiency ParsedQuery booleanQuery(string query, ref ubyte bitshift) { import std.array; ParsedQuery q; debug writeln("subquery", query); query = query.strip(); auto start = query.split(" ")[0]; if (start == "{and:") { q.form.op = Op.AND; } else if (start == "{or:") { q.form.op = Op.OR; } else if (start == "{not:") { q.form.op = Op.NOT; } else { throw new Exception("Unrecognized keyword" ~ start); } // (\[\[.+\]\])|(".+") // recursive call // using the rest of the words, build a form int[] indexes; int ntoskip = 0; foreach (i, token; query[start.length..$].split("]]")) { debug writeln("Parse token", token); if (ntoskip > 0) { ntoskip--; continue; } if (token.startsWith("[[") || token.startsWith(" [[")) { auto text = token.strip() ~ "]]"; q.terms ~= text; Form inner = { Op.ATOM, bitshift: bitshift++ }; debug bitshift.writeln; q.form.operands ~= inner; } else if (token.strip().startsWith("}")) { return q; } else { auto subquery = booleanQuery( query[start.length..$].split("]]")[i..$].join("]]"), bitshift ); q.terms ~= subquery.terms; q.form.operands ~= subquery.form; ntoskip = cast(int)subquery.terms.length + 1; } } return q; } unittest { ubyte bitshift = 0; auto pq = booleanQuery("{and: [[Hi]] {or: [[Blue]] [[White]] } }", bitshift); assert(pq.terms == ["[[Hi]]", "[[Blue]]", "[[White]]"]); assert(pq.form.operands[1].op == Op.OR); assert(pq.form.operands[1].operands[0].bitshift == 1); assert(pq.form.operands[1].operands[1].bitshift == 2); } string escape(string text) { return text.replace(`\`, `\\`) .replace(`"`, `\"`) .replace(`\\n`, `\n`) .replace(`\\t`, `\t`); } unittest { import std.stdio; ubyte n = 0; auto parsed = booleanQuery("{and: [[Hi]] [[Hello]] }", n); assert(parsed.terms == ["[[Hi]]", "[[Hello]]"]); } private struct WithConstructor { string[] member; this(string[] arg, Form a) { member = arg; } void start(string text) { } void end() { } } unittest { import parser; Form form; parse!(WithConstructor) ("Test", 4, "Title", ["arg"], form); } int main(string[] args) { import std.getopt, std.file, std.stdio; // Parse arguments string query; if (args.length >= 2 && args[1].strip.startsWith("{")) { query = args[1]; args = args[2..$]; } else { throw new Exception("Query must be first parameter"); } // Read query immediately. If the user has written an invalid query, show // an error before we read in all files. ubyte n = 0; ParsedQuery qu = booleanQuery(extractQuery(query), n); string[] inputs; string[] inputnames; if (args.length == 0) { // stdin string input; string line; while ((line = readln()) !is null) input ~= line; inputnames ~= "stdin"; inputs ~= input; } foreach (filename; args) { if (filename.isDir) { import std.algorithm.iteration; filename.dirEntries(SpanMode.depth).filter!isFile.each!((string filename) { // TODO: Proper mechanism to detect and avoid binary files import std.utf; try { inputnames ~= filename; // TODO: Stream input from files for cache locality, instead of reading everything in at once inputs ~= filename.readText; } catch (UTFException) { inputnames.length--; } }); } else { assert(filename.exists); inputnames ~= filename; inputs ~= filename.readText; } } for (int i = 0; i < inputs.length; ++i) { import parser; import std.meta; parse!(QueryHandler, doNothing, doNothing, true)(inputs[i], 4, inputnames[i], qu.terms, qu.form); // Write each on a separate lines } return 0; } |
| You are visitor 01402520 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |