!752 static class Thing { S name, type, file; } static S masterURL = "https://github.com/mcheese/cheesebase/archive/master.zip"; static File zipFile; static new MultiMap map; static new MultiMap definitions; p { zipFile = getProgramFile("master.zip"); if (!zipFile.exists()) loadMaster(); analyze(); makeBot("Cheesebase Bot."); } static void loadMaster() ctex { saveBinaryFile(zipFile, loadBinaryPage(masterURL)); print("master.zip loaded from github."); } static void analyze() { findStuff("namespace", "class", "using", "template", "struct", "union", "auto"); } synchronized answer { if (match("what is *", s, m)) { S name = m.unq(0); L things = lookupPossiblyIgnoreCase(map, name); L defs = lookupPossiblyIgnoreCase(definitions, name); if (!things.isEmpty() || !empty(defs)) { L types = list(getSortedSet(things, "type")); L files = list(getSortedSet(things, "file")); types = replace(types, "using", "alias"); types = replace(types, "auto", "variable"); S theTypes = isEmpty(types) ? "unknown something" : join("/", types); S a = (empty(things) ? name : things.get(0).name) + " is " + a(theTypes) + " in cheesebase. It is defined "; if (!empty(defs)) a += "as " + join("/", quoteAll(defs)) + " "; if (!empty(files)) { a += "in "; if (l(files) == 1) a += "file " + quote(files.get(0)); else if (l(files) == 2) a += "files " + quote(files.get(0)) + " and " + quote(files .get(1)); else a += quote(files.get(0)) + " and " + n(l(files)-1, " other file"); } ret a + "."; } } if (match("all things", s)) ret structure(map); if (match("cheesebase reload", s)) { loadMaster(); analyze(); ret "OK, reloaded from GitHub."; } } static void findStuff(S... keywords) { map.clear(); definitions.clear(); for (S file : listZip(zipFile)) { if (endsWithOneOf(file, ".h", ".cc")) pcall { S text = loadTextFileFromZip(zipFile, file); print("Scanning " + file); L tok = javaTok(text); for (S keyword : keywords) { int i = 0; while ((i = findCodeTokens(tok, i+1, keyword, "")) >= 0) { new Thing t; t.name = tok.get(i+2); t.type = keyword; t.file = dropPrefix("cheesebase-master/" , file); map.put(t.name, t); } } definitions.putAll(findInitializers(text)); } } } static L replace(L in, O a, O b) { new L l; for (O x: in) l.add(eq(x, a) ? b : x); ret l; } static S a(S s) { ret ("aeiou".contains(substr(s,0, 1)) ? "an " : "a ")+s; }