From eef5de613c75661e5d94baa086f6f2ddc26c7ed0 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 24 Mar 2016 23:16:07 -0400 Subject: Added verb frames In addition: - Added prepositions. - Rewrote a lot of the query interface. It now, for a lot of relationships, supports nested AND, OR, and NOT logic. - Rewrote the token class. It is now a union-like class instead of being polymorphic, which means smart pointers are no longer necessary. - Querying with regards to word derivation has been temporarily removed. - Sentinel values are now supported for all word types. - The VerbNet data retrieved from http://verbs.colorado.edu/~mpalmer/projects/verbnet/downloads.html was found to not be perfectly satisfactory in some regards, especially regarding adjective phrases. A patch file is now included in the repository describing the changes made to the VerbNet v3.2 download for the canonical verbly datafile. --- .gitmodules | 3 + CMakeLists.txt | 3 +- LICENSE | 48 ++ generator/CMakeLists.txt | 2 +- generator/generator.cpp | 545 ++++++++++++++++- generator/prepositions.txt | 49 ++ generator/schema.sql | 16 +- generator/vn.diff | 482 +++++++++++++++ lib/adjective.cpp | 655 ++------------------ lib/adjective.h | 94 +-- lib/adjective_query.cpp | 819 +++++++++++++++++++++++++ lib/adjective_query.h | 91 +++ lib/adverb.cpp | 443 +------------- lib/adverb.h | 62 +- lib/adverb_query.cpp | 514 ++++++++++++++++ lib/adverb_query.h | 65 ++ lib/c++14.h | 35 -- lib/data.cpp | 12 +- lib/data.h | 299 ++++++++- lib/frame.cpp | 320 ++++++++++ lib/frame.h | 118 ++++ lib/frame_query.cpp | 142 +++++ lib/frame_query.h | 21 + lib/noun.cpp | 1010 ++---------------------------- lib/noun.h | 150 +---- lib/noun_query.cpp | 1453 ++++++++++++++++++++++++++++++++++++++++++++ lib/noun_query.h | 139 +++++ lib/preposition.cpp | 83 +++ lib/preposition.h | 38 ++ lib/token.cpp | 617 ++++++++++++++++++- lib/token.h | 413 ++++--------- lib/util.h | 8 +- lib/verb.cpp | 169 +----- lib/verb.h | 45 +- lib/verb_query.cpp | 170 ++++++ lib/verb_query.h | 34 ++ lib/verbly.h | 25 +- lib/word.cpp | 11 +- lib/word.h | 13 +- vendor/json | 1 + 40 files changed, 6364 insertions(+), 2853 deletions(-) create mode 100644 .gitmodules create mode 100644 generator/prepositions.txt create mode 100644 generator/vn.diff create mode 100644 lib/adjective_query.cpp create mode 100644 lib/adjective_query.h create mode 100644 lib/adverb_query.cpp create mode 100644 lib/adverb_query.h delete mode 100644 lib/c++14.h create mode 100644 lib/frame.cpp create mode 100644 lib/frame.h create mode 100644 lib/frame_query.cpp create mode 100644 lib/frame_query.h create mode 100644 lib/noun_query.cpp create mode 100644 lib/noun_query.h create mode 100644 lib/preposition.cpp create mode 100644 lib/preposition.h create mode 100644 lib/verb_query.cpp create mode 100644 lib/verb_query.h create mode 160000 vendor/json diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..44fa617 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/json"] + path = vendor/json + url = https://github.com/nlohmann/json diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a3e526..c0b5dc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ project (verbly) find_package(PkgConfig) pkg_check_modules(sqlite3 sqlite3 REQUIRED) -add_library(verbly lib/data.cpp lib/adjective.cpp lib/noun.cpp lib/verb.cpp lib/adverb.cpp lib/token.cpp lib/word.cpp) +include_directories(vendor/json/src) +add_library(verbly lib/data.cpp lib/adjective.cpp lib/noun.cpp lib/verb.cpp lib/adverb.cpp lib/token.cpp lib/word.cpp lib/frame.cpp lib/preposition.cpp lib/adjective_query.cpp lib/adverb_query.cpp lib/noun_query.cpp lib/verb_query.cpp lib/frame_query.cpp) set_property(TARGET verbly PROPERTY CXX_STANDARD 11) set_property(TARGET verbly PROPERTY CXX_STANDARD_REQUIRED ON) diff --git a/LICENSE b/LICENSE index 68de0ce..ad40f03 100644 --- a/LICENSE +++ b/LICENSE @@ -72,3 +72,51 @@ purpose is completely unrestricted. If you make use of or redistribute this material we request that you acknowledge its origin in your descriptions, as per the license information included in the dictionary file (a Simplified BSD lincense). + +VerbNet v3.2 +============ + VerbNet 3.0 License (also applies to VerbNet 3.X versions) + +This software and database is being provided to you, the LICENSEE, by +the University of Colorado under the following license. By obtaining, using +and/or copying this software and database, you agree that you have +read, understood, and will comply with these terms and conditions.: + +Permission to use, copy, modify and distribute this software and +database and its documentation for any purpose and without fee or +royalty is hereby granted, provided that you agree to comply with +the following copyright notice and statements, including the disclaimer, +and that the same appear on ALL copies of the software, database and +documentation, including modifications that you make for internal +use or for distribution. + +VerbNet 3.0 (or 3.X) Copyright 2009 by University of Colorado. All rights reserved. + +THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND THE UNIVERSITY +OF COLORADO MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, UNIVERSITY +OF COLORADO MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCHANT- +ABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE +OF THE LICENSED SOFTWARE, DATABASE OR DOCUMENTATION WILL NOT +INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR +OTHER RIGHTS. + +The name of University of Colorado or CU may not be used in +advertising or publicity pertaining to distribution of the software +and/or database. Title to copyright in this software, database and +any associated documentation shall at all times remain with +University of Colorado and LICENSEE agrees to preserve same. + +Please reference the following document(s) in any description of +applications based on VerbNet 3.0 or 3.X: + +Karin Kipper, Anna Korhonen, Neville Ryant, Martha Palmer, +A Large-scale Classification of English Verbs, +Language Resources and Evaluation Journal, 42(1), pp. 21-40, +Springer Netherland, 2008. + +and/or + +Karin Kipper Schuler, Anna Korhonen, Susan W. Brown, VerbNet overview, +extensions, mappings and apps, Tutorial, NAACL-HLT 2009, Boulder, +Colorado. \ No newline at end of file diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index bbc3c4f..552526d 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -5,7 +5,7 @@ find_package(PkgConfig) pkg_check_modules(sqlite3 sqlite3 REQUIRED) find_package(libxml2 REQUIRED) -include_directories(${sqlite3_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) +include_directories(${sqlite3_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR} ../vendor/json/src) add_executable(generator generator.cpp) set_property(TARGET generator PROPERTY CXX_STANDARD 11) set_property(TARGET generator PROPERTY CXX_STANDARD_REQUIRED ON) diff --git a/generator/generator.cpp b/generator/generator.cpp index 7ec94df..aea750c 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp @@ -11,36 +11,75 @@ #include #include #include +#include #include "progress.h" +#include "../lib/util.h" -struct verb { +using json = nlohmann::json; + +struct verb_t { std::string infinitive; std::string past_tense; std::string past_participle; std::string ing_form; std::string s_form; + int id; }; -struct adjective { +struct adjective_t { std::string base; std::string comparative; std::string superlative; }; -struct noun { +struct noun_t { std::string singular; std::string plural; }; -struct group { +struct selrestr_t { + enum class type_t { + singleton, + andlogic, + orlogic, + empty + }; + type_t type; + std::string restriction; + bool pos; + std::list subordinates; +}; + +struct framepart_t { + enum class type_t { + np, + v, + pp, + adj, + adv, + lex + }; + type_t type; + std::string role; + selrestr_t selrestrs; + std::set preprestrs; + std::set synrestrs; + std::list choices; + std::string lexval; +}; + +struct group_t { std::string id; + std::string parent; std::set members; + std::map roles; + std::list> frames; }; -std::map groups; -std::map verbs; -std::map adjectives; -std::map nouns; +std::map groups; +std::map verbs; +std::map adjectives; +std::map nouns; std::map> wn; std::map> pronunciations; @@ -59,15 +98,97 @@ void print_usage() exit(1); } -void db_error(sqlite3* ppdb, std::string) +void db_error(sqlite3* ppdb, std::string query) { std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; + std::cout << query << std::endl; sqlite3_close_v2(ppdb); print_usage(); } -/* -void parse_group(xmlNodePtr top, std::string filename) +json export_selrestrs(selrestr_t r) +{ + if (r.type == selrestr_t::type_t::empty) + { + return {}; + } else if (r.type == selrestr_t::type_t::singleton) + { + json result; + result["type"] = r.restriction; + result["pos"] = r.pos; + return result; + } else { + json result; + if (r.type == selrestr_t::type_t::andlogic) + { + result["logic"] = "and"; + } else { + result["logic"] = "or"; + } + + std::list outlist; + std::transform(std::begin(r.subordinates), std::end(r.subordinates), std::back_inserter(outlist), &export_selrestrs); + result["children"] = outlist; + + return result; + } +} + +selrestr_t parse_selrestrs(xmlNodePtr top, std::string filename) +{ + selrestr_t r; + xmlChar* key; + + if (!xmlStrcmp(top->name, (const xmlChar*) "SELRESTRS")) + { + if (xmlChildElementCount(top) == 0) + { + r.type = selrestr_t::type_t::empty; + } else if (xmlChildElementCount(top) == 1) + { + r = parse_selrestrs(xmlFirstElementChild(top), filename); + } else { + r.type = selrestr_t::type_t::andlogic; + + if (xmlHasProp(top, (const xmlChar*) "logic")) + { + key = xmlGetProp(top, (const xmlChar*) "logic"); + if (!xmlStrcmp(key, (const xmlChar*) "or")) + { + r.type = selrestr_t::type_t::orlogic; + } + xmlFree(key); + } + + for (xmlNodePtr selrestr = top->xmlChildrenNode; selrestr != nullptr; selrestr = selrestr->next) + { + if (!xmlStrcmp(selrestr->name, (const xmlChar*) "SELRESTRS") || !xmlStrcmp(selrestr->name, (const xmlChar*) "SELRESTR")) + { + r.subordinates.push_back(parse_selrestrs(selrestr, filename)); + } + } + } + } else if (!xmlStrcmp(top->name, (const xmlChar*) "SELRESTR")) + { + r.type = selrestr_t::type_t::singleton; + + key = xmlGetProp(top, (xmlChar*) "Value"); + r.pos = (std::string((const char*)key) == "+"); + xmlFree(key); + + key = xmlGetProp(top, (xmlChar*) "type"); + r.restriction = (const char*) key; + xmlFree(key); + } else { + // Invalid + std::cout << "Bad VerbNet file format: " << filename << std::endl; + print_usage(); + } + + return r; +} + +group_t& parse_group(xmlNodePtr top, std::string filename) { xmlChar* key = xmlGetProp(top, (xmlChar*) "ID"); if (key == 0) @@ -75,41 +196,183 @@ void parse_group(xmlNodePtr top, std::string filename) std::cout << "Bad VerbNet file format: " << filename << std::endl; print_usage(); } - std::string vnid = key; + std::string vnid = (const char*)key; vnid = vnid.substr(vnid.find_first_of("-")+1); xmlFree(key); - group g; + group_t g; g.id = vnid; for (xmlNodePtr node = top->xmlChildrenNode; node != nullptr; node = node->next) { - if (!xmlStrcmp(node->name, (const xmlChar*) "MEMBERS")) + if (!xmlStrcmp(node->name, (const xmlChar*) "SUBCLASSES")) + { + for (xmlNodePtr subclass = node->xmlChildrenNode; subclass != nullptr; subclass = subclass->next) + { + if (!xmlStrcmp(subclass->name, (const xmlChar*) "VNSUBCLASS")) + { + auto& sg = parse_group(subclass, filename); + sg.parent = vnid; + + for (auto member : sg.members) + { + g.members.insert(member); + } + + // The schema requires that subclasses appear after role definitions, so we can do this now + for (auto role : g.roles) + { + if (sg.roles.count(role.first) == 0) + { + sg.roles[role.first] = role.second; + } + } + } + } + } else if (!xmlStrcmp(node->name, (const xmlChar*) "MEMBERS")) { for (xmlNodePtr member = node->xmlChildrenNode; member != nullptr; member = member->next) { if (!xmlStrcmp(member->name, (const xmlChar*) "MEMBER")) { key = xmlGetProp(member, (xmlChar*) "name"); - g.members.insert(key); + g.members.insert((const char*)key); xmlFree(key); } } + } else if (!xmlStrcmp(node->name, (const xmlChar*) "THEMROLES")) + { + for (xmlNodePtr role = node->xmlChildrenNode; role != nullptr; role = role->next) + { + if (!xmlStrcmp(role->name, (const xmlChar*) "THEMROLE")) + { + selrestr_t r; + r.type = selrestr_t::type_t::empty; + + key = xmlGetProp(role, (const xmlChar*) "type"); + std::string type = (const char*)key; + xmlFree(key); + + for (xmlNodePtr rolenode = role->xmlChildrenNode; rolenode != nullptr; rolenode = rolenode->next) + { + if (!xmlStrcmp(rolenode->name, (const xmlChar*) "SELRESTRS")) + { + r = parse_selrestrs(rolenode, filename); + } + } + + g.roles[type] = r; + } + } } else if (!xmlStrcmp(node->name, (const xmlChar*) "FRAMES")) { for (xmlNodePtr frame = node->xmlChildrenNode; frame != nullptr; frame = frame->next) { if (!xmlStrcmp(frame->name, (const xmlChar*) "FRAME")) { + std::list f; + for (xmlNodePtr framenode = frame->xmlChildrenNode; framenode != nullptr; framenode = framenode->next) { - + if (!xmlStrcmp(framenode->name, (const xmlChar*) "SYNTAX")) + { + for (xmlNodePtr syntaxnode = framenode->xmlChildrenNode; syntaxnode != nullptr; syntaxnode = syntaxnode->next) + { + framepart_t fp; + + if (!xmlStrcmp(syntaxnode->name, (const xmlChar*) "NP")) + { + fp.type = framepart_t::type_t::np; + + key = xmlGetProp(syntaxnode, (xmlChar*) "value"); + fp.role = (const char*)key; + xmlFree(key); + + fp.selrestrs.type = selrestr_t::type_t::empty; + + for (xmlNodePtr npnode = syntaxnode->xmlChildrenNode; npnode != nullptr; npnode = npnode->next) + { + if (!xmlStrcmp(npnode->name, (const xmlChar*) "SYNRESTRS")) + { + for (xmlNodePtr synrestr = npnode->xmlChildrenNode; synrestr != nullptr; synrestr = synrestr->next) + { + if (!xmlStrcmp(synrestr->name, (const xmlChar*) "SYNRESTR")) + { + key = xmlGetProp(synrestr, (xmlChar*) "type"); + fp.synrestrs.insert(std::string((const char*)key)); + xmlFree(key); + } + } + } + + if (!xmlStrcmp(npnode->name, (const xmlChar*) "SELRESTRS")) + { + fp.selrestrs = parse_selrestrs(npnode, filename); + } + } + } else if (!xmlStrcmp(syntaxnode->name, (xmlChar*) "VERB")) + { + fp.type = framepart_t::type_t::v; + } else if (!xmlStrcmp(syntaxnode->name, (xmlChar*) "PREP")) + { + fp.type = framepart_t::type_t::pp; + + if (xmlHasProp(syntaxnode, (xmlChar*) "value")) + { + key = xmlGetProp(syntaxnode, (xmlChar*) "value"); + std::string choices = (const char*)key; + xmlFree(key); + + fp.choices = verbly::split>(choices, " "); + } + + for (xmlNodePtr npnode = syntaxnode->xmlChildrenNode; npnode != nullptr; npnode = npnode->next) + { + if (!xmlStrcmp(npnode->name, (const xmlChar*) "SELRESTRS")) + { + for (xmlNodePtr synrestr = npnode->xmlChildrenNode; synrestr != nullptr; synrestr = synrestr->next) + { + if (!xmlStrcmp(synrestr->name, (const xmlChar*) "SELRESTR")) + { + key = xmlGetProp(synrestr, (xmlChar*) "type"); + fp.preprestrs.insert(std::string((const char*)key)); + xmlFree(key); + } + } + } + } + } else if (!xmlStrcmp(syntaxnode->name, (xmlChar*) "ADJ")) + { + fp.type = framepart_t::type_t::adj; + } else if (!xmlStrcmp(syntaxnode->name, (xmlChar*) "ADV")) + { + fp.type = framepart_t::type_t::adv; + } else if (!xmlStrcmp(syntaxnode->name, (xmlChar*) "LEX")) + { + fp.type = framepart_t::type_t::lex; + + key = xmlGetProp(syntaxnode, (xmlChar*) "value"); + fp.lexval = (const char*)key; + xmlFree(key); + } else { + continue; + } + + f.push_back(fp); + } + + g.frames.push_back(f); + } } } } } } -}*/ + + groups[vnid] = g; + + return groups[vnid]; +} int main(int argc, char** argv) { @@ -118,7 +381,10 @@ int main(int argc, char** argv) print_usage(); } - /*DIR* dir; + // VerbNet data + std::cout << "Reading verb frames..." << std::endl; + + DIR* dir; if ((dir = opendir(argv[1])) == nullptr) { std::cout << "Invalid VerbNet data directory." << std::endl; @@ -160,7 +426,7 @@ int main(int argc, char** argv) parse_group(top, filename); } - closedir(dir);*/ + closedir(dir); // Get verbs from AGID std::cout << "Reading inflections..." << std::endl; @@ -222,7 +488,7 @@ int main(int argc, char** argv) { case 'V': { - verb v; + verb_t v; v.infinitive = word; if (forms.size() == 4) { @@ -258,7 +524,7 @@ int main(int argc, char** argv) case 'A': { - adjective adj; + adjective_t adj; adj.base = word; if (forms.size() == 2) { @@ -276,7 +542,7 @@ int main(int argc, char** argv) case 'N': { - noun n; + noun_t n; n.singular = word; if (forms.size() == 1) { @@ -388,6 +654,85 @@ int main(int argc, char** argv) sqlite3_finalize(schmstmt); } + std::cout << "Writing prepositions..." << std::endl; + std::ifstream prepfile("prepositions.txt"); + if (!prepfile.is_open()) + { + std::cout << "Could not find prepositions file" << std::endl; + print_usage(); + } + + for (;;) + { + std::string line; + if (!getline(prepfile, line)) + { + break; + } + + if (line.back() == '\r') + { + line.pop_back(); + } + + std::regex relation("^([^:]+): (.+)"); + std::smatch relation_data; + std::regex_search(line, relation_data, relation); + std::string prep = relation_data[1]; + std::list groups = verbly::split>(relation_data[2], ", "); + + std::string query("INSERT INTO prepositions (form) VALUES (?)"); + sqlite3_stmt* ppstmt; + + if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + db_error(ppdb, query); + } + + sqlite3_bind_text(ppstmt, 1, prep.c_str(), prep.length(), SQLITE_STATIC); + + if (sqlite3_step(ppstmt) != SQLITE_DONE) + { + db_error(ppdb, query); + } + + sqlite3_finalize(ppstmt); + + query = "SELECT last_insert_rowid()"; + if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + db_error(ppdb, query); + } + + if (sqlite3_step(ppstmt) != SQLITE_ROW) + { + db_error(ppdb, query); + } + + int rowid = sqlite3_column_int(ppstmt, 0); + sqlite3_finalize(ppstmt); + + for (auto group : groups) + { + query = "INSERT INTO preposition_groups (preposition_id, groupname) VALUES (?, ?)"; + if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + db_error(ppdb, query); + } + + sqlite3_bind_int(ppstmt, 1, rowid); + sqlite3_bind_text(ppstmt, 2, group.c_str(), group.length(), SQLITE_STATIC); + + if (sqlite3_step(ppstmt) != SQLITE_DONE) + { + db_error(ppdb, query); + } + + sqlite3_finalize(ppstmt); + } + } + + { progress ppgs("Writing verbs...", verbs.size()); for (auto& mapping : verbs) @@ -431,6 +776,8 @@ int main(int argc, char** argv) sqlite3_finalize(ppstmt); + mapping.second.id = rowid; + for (auto pronunciation : pronunciations[canonical]) { query = "INSERT INTO verb_pronunciations (verb_id, pronunciation) VALUES (?, ?)"; @@ -455,6 +802,160 @@ int main(int argc, char** argv) } } + { + progress ppgs("Writing verb frames...", groups.size()); + for (auto& mapping : groups) + { + std::list roledatal; + std::transform(std::begin(mapping.second.roles), std::end(mapping.second.roles), std::back_inserter(roledatal), [] (std::pair r) { + json role; + role["type"] = r.first; + role["selrestrs"] = export_selrestrs(r.second); + + return role; + }); + + json roledata(roledatal); + std::string rdm = roledata.dump(); + + sqlite3_stmt* ppstmt; + std::string query("INSERT INTO groups (data) VALUES (?)"); + if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + db_error(ppdb, query); + } + + sqlite3_bind_blob(ppstmt, 1, rdm.c_str(), rdm.size(), SQLITE_STATIC); + + if (sqlite3_step(ppstmt) != SQLITE_DONE) + { + db_error(ppdb, query); + } + + sqlite3_finalize(ppstmt); + + query = "SELECT last_insert_rowid()"; + if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + db_error(ppdb, query); + } + + if (sqlite3_step(ppstmt) != SQLITE_ROW) + { + db_error(ppdb, query); + } + + int gid = sqlite3_column_int(ppstmt, 0); + sqlite3_finalize(ppstmt); + + for (auto frame : mapping.second.frames) + { + std::list fdatap; + std::transform(std::begin(frame), std::end(frame), std::back_inserter(fdatap), [] (framepart_t& fp) { + json part; + + switch (fp.type) + { + case framepart_t::type_t::np: + { + part["type"] = "np"; + part["role"] = fp.role; + part["selrestrs"] = export_selrestrs(fp.selrestrs); + part["synrestrs"] = fp.synrestrs; + + break; + } + + case framepart_t::type_t::pp: + { + part["type"] = "pp"; + part["values"] = fp.choices; + part["preprestrs"] = fp.preprestrs; + + break; + } + + case framepart_t::type_t::v: + { + part["type"] = "v"; + + break; + } + + case framepart_t::type_t::adj: + { + part["type"] = "adj"; + + break; + } + + case framepart_t::type_t::adv: + { + part["type"] = "adv"; + + break; + } + + case framepart_t::type_t::lex: + { + part["type"] = "lex"; + part["value"] = fp.lexval; + + break; + } + } + + return part; + }); + + json fdata(fdatap); + std::string marshall = fdata.dump(); + + query = "INSERT INTO frames (group_id, data) VALUES (?, ?)"; + if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + db_error(ppdb, query); + } + + sqlite3_bind_int(ppstmt, 1, gid); + sqlite3_bind_blob(ppstmt, 2, marshall.c_str(), marshall.length(), SQLITE_STATIC); + + if (sqlite3_step(ppstmt) != SQLITE_DONE) + { + db_error(ppdb, query); + } + + sqlite3_finalize(ppstmt); + } + + for (auto member : mapping.second.members) + { + if (verbs.count(member) == 1) + { + auto& v = verbs[member]; + + query = "INSERT INTO verb_groups (verb_id, group_id) VALUES (?, ?)"; + if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + db_error(ppdb, query); + } + + sqlite3_bind_int(ppstmt, 1, v.id); + sqlite3_bind_int(ppstmt, 2, gid); + + if (sqlite3_step(ppstmt) != SQLITE_DONE) + { + db_error(ppdb, query); + } + + sqlite3_finalize(ppstmt); + } + } + + ppgs.update(); + } + } + // Get nouns/adjectives/adverbs from WordNet // Useful relations: // - s: master list diff --git a/generator/prepositions.txt b/generator/prepositions.txt new file mode 100644 index 0000000..283e5c4 --- /dev/null +++ b/generator/prepositions.txt @@ -0,0 +1,49 @@ +from: src, path, spatial, loc +out: src, path, spatial +out of: src, path, spatial, loc +off: src, path, spatial, loc +off of: src, path, spatial +into: dest_conf, dest, path, spatial +onto: dest_conf, dest, path, spatial +for: dest_dir, dest, path, spatial +at: dest_dir, dest, path, spatial, loc +to: dest_dir, dest, path, spatial +towards: dest_dir, dest, path, spatial +along: dir, path, spatial, loc +across: dir, path, spatial +around: dir, path, spatial, loc +down: dir, path, spatial +over: dir, path, spatial, loc +past: dir, path, spatial +round: dir, path, spatial, loc +through: dir, path, spatial +towards: dir, path, spatial +up: dir, path, spatial +about: loc, spatial +above: loc, spatial +against: loc, spatial +alongside: loc, spatial +amid: loc, spatial +among: loc, spatial +amongst: loc, spatial +astride: loc, spatial +athwart: loc, spatial +before: loc, spatial +behind: loc, spatial +beside: loc, spatial +between: loc, spatial +beyond: loc, spatial +by: loc, spatial +in: loc, spatial +in front of: loc, spatial +inside: loc, spatial +near: loc, spatial +next to: loc, spatial +on: loc, spatial +opposite: loc, spatial +outside: loc, spatial +throughout: loc, spatial +under: loc, spatial +underneath: loc, spatial +upon: loc, spatial +within: loc, spatial \ No newline at end of file diff --git a/generator/schema.sql b/generator/schema.sql index 8e1e822..2295444 100644 --- a/generator/schema.sql +++ b/generator/schema.sql @@ -11,8 +11,7 @@ CREATE TABLE `verbs` ( DROP TABLE IF EXISTS `groups`; CREATE TABLE `groups` ( `group_id` INTEGER PRIMARY KEY, - `parent_id` INTEGER, - FOREIGN KEY (`parent_id`) REFERENCES `groups`(`group_id`) + `data` BLOB NOT NULL ); DROP TABLE IF EXISTS `frames`; @@ -251,3 +250,16 @@ CREATE TABLE `adverb_adverb_derivation` ( FOREIGN KEY (`adverb_1_id`) REFERENCES `adverbs`(`adverb_id`), FOREIGN KEY (`adverb_2_id`) REFERENCES `adverbs`(`adverb_id`) ); + +DROP TABLE IF EXISTS `prepositions`; +CREATE TABLE `prepositions` ( + `preposition_id` INTEGER PRIMARY KEY, + `form` VARCHAR(32) NOT NULL +); + +DROP TABLE IF EXISTS `preposition_groups`; +CREATE TABLE `preposition_groups` ( + `preposition_id` INTEGER NOT NULL, + `groupname` VARCHAR(32) NOT NULL, + FOREIGN KEY (`preposition_id`) REFERENCES `prepositions`(`preposition_id`) +); diff --git a/generator/vn.diff b/generator/vn.diff new file mode 100644 index 0000000..f636d28 --- /dev/null +++ b/generator/vn.diff @@ -0,0 +1,482 @@ +diff /Users/hatkirby/Downloads/new_vn 2/admit-65.xml datadir/vn/admit-65.xml +104c104 +< +--- +> +diff /Users/hatkirby/Downloads/new_vn 2/amuse-31.1.xml datadir/vn/amuse-31.1.xml +270a271,273 +> +> +> +368c371,373 +< +--- +> +> +> +404c409,411 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/animal_sounds-38.xml datadir/vn/animal_sounds-38.xml +186a187,191 +> +> +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/assessment-34.1.xml datadir/vn/assessment-34.1.xml +103d102 +< +diff /Users/hatkirby/Downloads/new_vn 2/battle-36.4.xml datadir/vn/battle-36.4.xml +96c96 +< +--- +> +diff /Users/hatkirby/Downloads/new_vn 2/become-109.1.xml datadir/vn/become-109.1.xml +34c34,36 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/beg-58.2.xml datadir/vn/beg-58.2.xml +41c41 +< +--- +> +diff /Users/hatkirby/Downloads/new_vn 2/bend-45.2.xml datadir/vn/bend-45.2.xml +47c47,49 +< +--- +> +> +> +230c232,234 +< +--- +> +> +> +280,282c284 +< +< +< +--- +> +332,334c334 +< +< +< +--- +> +diff /Users/hatkirby/Downloads/new_vn 2/break-45.1.xml datadir/vn/break-45.1.xml +255c255,257 +< +--- +> +> +> +307c309,311 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/characterize-29.2.xml datadir/vn/characterize-29.2.xml +107c107 +< +--- +> +109,111c109,111 +< +< +< +--- +> +> +> +386a387,391 +> +> +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/coloring-24.xml datadir/vn/coloring-24.xml +89c89,91 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/confess-37.10.xml datadir/vn/confess-37.10.xml +110a111,115 +> +> +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/consider-29.9.xml datadir/vn/consider-29.9.xml +191,193c191,193 +< +< +< +--- +> +> +> +334,336c334,336 +< +< +< +--- +> +> +> +468,470c468,470 +< +< +< +--- +> +> +> +554,556c554,556 +< +< +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/cut-21.1.xml datadir/vn/cut-21.1.xml +316c316,318 +< +--- +> +> +> +368c370,372 +< +--- +> +> +> +560c564,566 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/declare-29.4.xml datadir/vn/declare-29.4.xml +33,35c33,35 +< +< +< +--- +> +> +> +122,124c122,124 +< +< +< +--- +> +> +> +244,246c244,246 +< +< +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/estimate-34.2.xml datadir/vn/estimate-34.2.xml +123a124 +> +125,127c126,128 +< +< +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/get-13.5.1.xml datadir/vn/get-13.5.1.xml +55,56c55 +< +< +--- +> +diff /Users/hatkirby/Downloads/new_vn 2/hit-18.1.xml datadir/vn/hit-18.1.xml +234c234,236 +< +--- +> +> +> +294c296,298 +< +--- +> +> +> +619c623,625 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/instr_communication-37.4.xml datadir/vn/instr_communication-37.4.xml +195c195,197 +< +--- +> +> +> +233c235,237 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/judgment-33.xml datadir/vn/judgment-33.xml +187a188,190 +> +> +> +243a247 +> +245,247c249 +< +< +< +--- +> +diff /Users/hatkirby/Downloads/new_vn 2/manner_speaking-37.3.xml datadir/vn/manner_speaking-37.3.xml +264c264,266 +< +--- +> +> +> +603c605,607 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/other_cos-45.4.xml datadir/vn/other_cos-45.4.xml +534c534,536 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/pocket-9.10.xml datadir/vn/pocket-9.10.xml +256c256,258 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/poison-42.2.xml datadir/vn/poison-42.2.xml +93c93,95 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/pour-9.5.xml datadir/vn/pour-9.5.xml +59,61c59,62 +< +< +< +--- +> +> +> +> +157,160c158,162 +< +< +< +< +--- +> +> +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/push-12.xml datadir/vn/push-12.xml +90c90,92 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/roll-51.3.1.xml datadir/vn/roll-51.3.1.xml +190c190,192 +< +--- +> +> +> +256c258,260 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/see-30.1.xml datadir/vn/see-30.1.xml +16a17,19 +> +> +> +93a97,102 +> +> +> +> +> +> +231a241,243 +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/seem-109.xml datadir/vn/seem-109.xml +30,32c30,32 +< +< +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/slide-11.2.xml datadir/vn/slide-11.2.xml +69,72c69,73 +< +< +< +< +--- +> +> +> +> +> +218,221c219,223 +< +< +< +< +--- +> +> +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/spank-18.3.xml datadir/vn/spank-18.3.xml +69a70,72 +> +> +> +201c204,206 +< +--- +> +> +> +529,532c534,541 +< +< +< +< +--- +> +> +> +> +> +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/swat-18.2.xml datadir/vn/swat-18.2.xml +264c264,266 +< +--- +> +> +> +324c326,328 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/tape-22.4.xml datadir/vn/tape-22.4.xml +364c364,366 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/vehicle-51.4.1.xml datadir/vn/vehicle-51.4.1.xml +227c227,229 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/waltz-51.5.xml datadir/vn/waltz-51.5.xml +181c181,183 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/want-32.1.xml datadir/vn/want-32.1.xml +142a143 +> +194a196 +> +305a308 +> +307,309c310,312 +< +< +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/wipe_instr-10.4.2.xml datadir/vn/wipe_instr-10.4.2.xml +178c178,180 +< +--- +> +> +> +diff /Users/hatkirby/Downloads/new_vn 2/wipe_manner-10.4.1.xml datadir/vn/wipe_manner-10.4.1.xml +198c198,199 +< +--- +> +> +diff /Users/hatkirby/Downloads/new_vn 2/wish-62.xml datadir/vn/wish-62.xml +91a92 +> +93,95c94,96 +< +< +< +--- +> +> +> +122a124 +> diff --git a/lib/adjective.cpp b/lib/adjective.cpp index b2b53e4..ba8254a 100644 --- a/lib/adjective.cpp +++ b/lib/adjective.cpp @@ -2,6 +2,11 @@ namespace verbly { + adjective::adjective() + { + + } + adjective::adjective(const data& _data, int _id) : word(_data, _id) { @@ -9,682 +14,100 @@ namespace verbly { std::string adjective::base_form() const { + assert(_valid == true); + return _base_form; } std::string adjective::comparative_form() const { + assert(_valid == true); + return _comparative_form; } std::string adjective::superlative_form() const { + assert(_valid == true); + return _superlative_form; } adjective::positioning adjective::position() const { + assert(_valid == true); + return _position; } bool adjective::has_comparative_form() const { + assert(_valid == true); + return !_comparative_form.empty(); } bool adjective::has_superlative_form() const { + assert(_valid == true); + return !_superlative_form.empty(); } bool adjective::has_position() const { + assert(_valid == true); + return _position != adjective::positioning::undefined; } adjective_query adjective::antonyms() const { - return _data.adjectives().antonym_of(*this); - } - - adjective_query adjective::synonyms() const - { - return _data.adjectives().synonym_of(*this); - } - - adjective_query adjective::generalizations() const - { - return _data.adjectives().generalization_of(*this); - } - - adjective_query adjective::specifications() const - { - return _data.adjectives().specification_of(*this); - } - - noun_query adjective::anti_pertainyms() const - { - return _data.nouns().anti_pertainym_of(*this); - } - - adverb_query adjective::mannernyms() const - { - return _data.adverbs().mannernym_of(*this); - } - - noun_query adjective::attributes() const - { - return _data.nouns().attribute_of(*this); - } - - adjective_query::adjective_query(const data& _data) : _data(_data) - { - - } - - adjective_query& adjective_query::limit(int _limit) - { - if ((_limit > 0) || (_limit == unlimited)) - { - this->_limit = _limit; - } - - return *this; - } - - adjective_query& adjective_query::random(bool _random) - { - this->_random = _random; - - return *this; - } - - adjective_query& adjective_query::except(const adjective& _word) - { - _except.push_back(_word); - - return *this; - } - - adjective_query& adjective_query::rhymes_with(const word& _word) - { - for (auto rhyme : _word.rhyme_phonemes()) - { - _rhymes.push_back(rhyme); - } - - if (dynamic_cast(&_word) != nullptr) - { - _except.push_back(dynamic_cast(_word)); - } - - return *this; - } - - adjective_query& adjective_query::has_pronunciation(bool _has_prn) - { - this->_has_prn = _has_prn; - - return *this; - } - - adjective_query& adjective_query::is_variant(bool _is_variant) - { - this->_is_variant = _is_variant; - - return *this; - } - - adjective_query& adjective_query::variant_of(const noun& _noun) - { - _variant_of.push_back(_noun); - - return *this; - } - - adjective_query& adjective_query::not_variant_of(const noun& _noun) - { - _not_variant_of.push_back(_noun); - - return *this; - } - - adjective_query& adjective_query::has_antonyms(bool _is_antonymic) - { - this->_is_antonymic = _is_antonymic; - - return *this; - } - - adjective_query& adjective_query::antonym_of(const adjective& _adj) - { - _antonym_of.push_back(_adj); - - return *this; - } - - adjective_query& adjective_query::not_antonym_of(const adjective& _adj) - { - _not_antonym_of.push_back(_adj); - - return *this; - } - - adjective_query& adjective_query::has_synonyms(bool _is_synonymic) - { - this->_is_synonymic = _is_synonymic; - - return *this; - } - - adjective_query& adjective_query::synonym_of(const adjective& _adj) - { - _synonym_of.push_back(_adj); - - return *this; - } - - adjective_query& adjective_query::not_synonym_of(const adjective& _adj) - { - _not_synonym_of.push_back(_adj); - - return *this; - } - - adjective_query& adjective_query::is_generalization(bool _is_generalization) - { - this->_is_generalization = _is_generalization; - - return *this; - } - - adjective_query& adjective_query::generalization_of(const adjective& _adj) - { - _generalization_of.push_back(_adj); - - return *this; - } - - adjective_query& adjective_query::not_generalization_of(const adjective& _adj) - { - _not_generalization_of.push_back(_adj); - - return *this; - } - - adjective_query& adjective_query::is_specification(bool _is_specification) - { - this->_is_specification = _is_specification; - - return *this; - } - - adjective_query& adjective_query::specification_of(const adjective& _adj) - { - _specification_of.push_back(_adj); + assert(_valid == true); - return *this; + return _data->adjectives().antonym_of(*this); } - adjective_query& adjective_query::not_specification_of(const adjective& _adj) - { - _not_specification_of.push_back(_adj); - - return *this; - } - - adjective_query& adjective_query::is_pertainymic(bool _is_pertainymic) - { - this->_is_pertainymic = _is_pertainymic; - - return *this; - } - - adjective_query& adjective_query::pertainym_of(const noun& _noun) + adjective_query adjective::synonyms() const { - _pertainym_of.push_back(_noun); + assert(_valid == true); - return *this; + return _data->adjectives().synonym_of(*this); } - adjective_query& adjective_query::is_mannernymic(bool _is_mannernymic) + adjective_query adjective::generalizations() const { - this->_is_mannernymic = _is_mannernymic; + assert(_valid == true); - return *this; + return _data->adjectives().generalization_of(*this); } - adjective_query& adjective_query::anti_mannernym_of(const adverb& _adv) + adjective_query adjective::specifications() const { - _anti_mannernym_of.push_back(_adv); + assert(_valid == true); - return *this; + return _data->adjectives().specification_of(*this); } - adjective_query& adjective_query::derived_from(const word& _w) + noun_query adjective::anti_pertainyms() const { - if (dynamic_cast(&_w) != nullptr) - { - _derived_from_adjective.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _derived_from_adverb.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _derived_from_noun.push_back(dynamic_cast(_w)); - } + assert(_valid == true); - return *this; + return _data->nouns().anti_pertainym_of(*this); } - adjective_query& adjective_query::not_derived_from(const word& _w) + adverb_query adjective::mannernyms() const { - if (dynamic_cast(&_w) != nullptr) - { - _not_derived_from_adjective.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _not_derived_from_adverb.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _not_derived_from_noun.push_back(dynamic_cast(_w)); - } + assert(_valid == true); - return *this; + return _data->adverbs().mannernym_of(*this); } - std::list adjective_query::run() const + noun_query adjective::attributes() const { - std::stringstream construct; - construct << "SELECT adjective_id, base_form, comparative, superlative, position FROM adjectives"; - std::list conditions; - - if (_has_prn) - { - conditions.push_back("adjective_id IN (SELECT adjective_id FROM adjective_pronunciations)"); - } - - if (!_rhymes.empty()) - { - std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); - std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - for (auto except : _except) - { - conditions.push_back("adjective_id != @EXCID"); - } - - if (_requires_comparative_form) - { - conditions.push_back("comparative IS NOT NULL"); - } - - if (_requires_superlative_form) - { - conditions.push_back("superlative IS NOT NULL"); - } - - if (_position != adjective::positioning::undefined) - { - switch (_position) - { - case adjective::positioning::predicate: conditions.push_back("position = 'p'"); break; - case adjective::positioning::attributive: conditions.push_back("position = 'a'"); break; - case adjective::positioning::postnominal: conditions.push_back("position = 'i'"); break; - } - } - - if (_is_variant) - { - conditions.push_back("adjective_id IN (SELECT adjective_id FROM variation)"); - } - - if (!_variant_of.empty()) - { - std::list clauses(_variant_of.size(), "noun_id = @ATTRID"); - std::string cond = "adjective_id IN (SELECT adjective_id FROM variation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_variant_of.empty()) - { - std::list clauses(_not_variant_of.size(), "noun_id = @NATTRID"); - std::string cond = "adjective_id NOT IN (SELECT adjective_id FROM variation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_antonymic) - { - conditions.push_back("adjective_id IN (SELECT adjective_2_id FROM adjective_antonymy)"); - } - - if (!_antonym_of.empty()) - { - std::list clauses(_antonym_of.size(), "adjective_1_id = @ANTID"); - std::string cond = "adjective_id IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_antonym_of.empty()) - { - std::list clauses(_not_antonym_of.size(), "adjective_1_id = @NANTID"); - std::string cond = "adjective_id NOT IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } + assert(_valid == true); - if (_is_synonymic) - { - conditions.push_back("adjective_id IN (SELECT adjective_2_id FROM adjective_synonymy)"); - } - - if (!_synonym_of.empty()) - { - std::list clauses(_synonym_of.size(), "adjective_1_id = @SYNID"); - std::string cond = "adjective_id IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_synonym_of.empty()) - { - std::list clauses(_not_synonym_of.size(), "adjective_1_id = @NSYNID"); - std::string cond = "adjective_id NOT IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_generalization) - { - conditions.push_back("adjective_id IN (SELECT general_id FROM specification)"); - } - - if (!_generalization_of.empty()) - { - std::list clauses(_generalization_of.size(), "specific_id = @SPECID"); - std::string cond = "adjective_id IN (SELECT general_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_generalization_of.empty()) - { - std::list clauses(_not_generalization_of.size(), "specific_id = @NSPECID"); - std::string cond = "adjective_id NOT IN (SELECT general_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_specification) - { - conditions.push_back("adjective_id IN (SELECT specific_id FROM specification)"); - } - - if (!_specification_of.empty()) - { - std::list clauses(_specification_of.size(), "general_id = @GENID"); - std::string cond = "adjective_id IN (SELECT specific_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_specification_of.empty()) - { - std::list clauses(_not_specification_of.size(), "general_id = @NGENID"); - std::string cond = "adjective_id NOT IN (SELECT specific_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_pertainymic) - { - conditions.push_back("adjective_id IN (SELECT pertainym_id FROM pertainymy)"); - } - - if (!_pertainym_of.empty()) - { - std::list clauses(_pertainym_of.size(), "noun_id = @APERID"); - std::string cond = "adjective_id IN (SELECT pertainym_id FROM pertainymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_mannernymic) - { - conditions.push_back("adjective_id IN (SELECT adjective_id FROM mannernymy)"); - } - - if (!_anti_mannernym_of.empty()) - { - std::list clauses(_anti_mannernym_of.size(), "mannernym_id = @MANID"); - std::string cond = "adjective_id IN (SELECT adjective_id FROM mannernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_derived_from_adjective.empty()) - { - std::list clauses(_derived_from_adjective.size(), "adjective_2_id = @DERADJ"); - std::string cond = "adjective_id IN (SELECT adjective_1_id FROM adjective_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_derived_from_adjective.empty()) - { - std::list clauses(_not_derived_from_adjective.size(), "adjective_2_id = @NDERADJ"); - std::string cond = "adjective_id NOT IN (SELECT adjective_1_id FROM adjective_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_derived_from_adverb.empty()) - { - std::list clauses(_derived_from_adverb.size(), "adverb_id = @DERADV"); - std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_derived_from_adverb.empty()) - { - std::list clauses(_not_derived_from_adverb.size(), "adverb_id = @NDERADV"); - std::string cond = "adjective_id NOT IN (SELECT adjective_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_derived_from_noun.empty()) - { - std::list clauses(_derived_from_noun.size(), "noun_id = @DERN"); - std::string cond = "adjective_id IN (SELECT adjective_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_derived_from_noun.empty()) - { - std::list clauses(_not_derived_from_noun.size(), "noun_id = @NDERN"); - std::string cond = "adjective_id NOT IN (SELECT adjective_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!conditions.empty()) - { - construct << " WHERE "; - construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND "); - } - - if (_random) - { - construct << " ORDER BY RANDOM()"; - } - - if (_limit != unlimited) - { - construct << " LIMIT " << _limit; - } - - sqlite3_stmt* ppstmt; - std::string query = construct.str(); - if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) - { - throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); - } - - if (!_rhymes.empty()) - { - int i = 0; - for (auto rhyme : _rhymes) - { - std::string rhymer = "%" + rhyme; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); - - i++; - } - } - - for (auto except : _except) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); - } - - for (auto attribute : _variant_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ATTRID"), attribute._id); - } - - for (auto attribute : _not_variant_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NATTRID"), attribute._id); - } - - for (auto antonym : _antonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id); - } - - for (auto antonym : _not_antonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NANTID"), antonym._id); - } - - for (auto synonym : _synonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id); - } - - for (auto synonym : _not_synonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSYNID"), synonym._id); - } - - for (auto specific : _generalization_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SPECID"), specific._id); - } - - for (auto specific : _not_generalization_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSPECID"), specific._id); - } - - for (auto general : _specification_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@GENID"), general._id); - } - - for (auto general : _not_specification_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NGENID"), general._id); - } - - for (auto n : _pertainym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@APERID"), n._id); - } - - for (auto mannernym : _anti_mannernym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MANID"), mannernym._id); - } - - for (auto adj : _derived_from_adjective) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADJ"), adj._id); - } - - for (auto adj : _not_derived_from_adjective) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADJ"), adj._id); - } - - for (auto adv : _derived_from_adverb) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADV"), adv._id); - } - - for (auto adv : _not_derived_from_adverb) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADV"), adv._id); - } - - for (auto n : _derived_from_noun) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERN"), n._id); - } - - for (auto n : _not_derived_from_noun) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERN"), n._id); - } - - std::list output; - while (sqlite3_step(ppstmt) == SQLITE_ROW) - { - adjective tnc {_data, sqlite3_column_int(ppstmt, 0)}; - tnc._base_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); - - if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL) - { - tnc._comparative_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); - } - - if (sqlite3_column_type(ppstmt, 3) != SQLITE_NULL) - { - tnc._superlative_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 3))); - } - - if (sqlite3_column_type(ppstmt, 4) != SQLITE_NULL) - { - std::string adjpos(reinterpret_cast(sqlite3_column_text(ppstmt, 4))); - if (adjpos == "p") - { - tnc._position = adjective::positioning::predicate; - } else if (adjpos == "a") - { - tnc._position = adjective::positioning::attributive; - } else if (adjpos == "i") - { - tnc._position = adjective::positioning::postnominal; - } - } - - output.push_back(tnc); - } - - sqlite3_finalize(ppstmt); - - for (auto& adjective : output) - { - query = "SELECT pronunciation FROM adjective_pronunciations WHERE adjective_id = ?"; - if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) - { - throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); - } - - sqlite3_bind_int(ppstmt, 1, adjective._id); - - while (sqlite3_step(ppstmt) == SQLITE_ROW) - { - std::string pronunciation(reinterpret_cast(sqlite3_column_text(ppstmt, 0))); - auto phonemes = verbly::split>(pronunciation, " "); - - adjective.pronunciations.push_back(phonemes); - } - - sqlite3_finalize(ppstmt); - } - - return output; + return _data->nouns().attribute_of(*this); } }; diff --git a/lib/adjective.h b/lib/adjective.h index 3dcab9b..a6eb293 100644 --- a/lib/adjective.h +++ b/lib/adjective.h @@ -25,6 +25,7 @@ namespace verbly { friend class adjective_query; public: + adjective(); adjective(const data& _data, int _id); std::string base_form() const; @@ -45,99 +46,6 @@ namespace verbly { noun_query attributes() const; }; - class adjective_query { - public: - adjective_query(const data& _data); - - adjective_query& limit(int _limit); - adjective_query& random(bool _random); - adjective_query& except(const adjective& _word); - adjective_query& rhymes_with(const word& _word); - adjective_query& has_pronunciation(bool _has_prn); - - adjective_query& requires_comparative_form(bool req); - adjective_query& requires_superlative_form(bool req); - adjective_query& position(adjective::positioning pos); - - adjective_query& is_variant(bool _is_variant); - adjective_query& variant_of(const noun& _noun); - adjective_query& not_variant_of(const noun& _noun); - - adjective_query& has_antonyms(bool _is_antonymic); - adjective_query& antonym_of(const adjective& _adj); - adjective_query& not_antonym_of(const adjective& _adj); - - adjective_query& has_synonyms(bool _is_synonymic); - adjective_query& synonym_of(const adjective& _adj); - adjective_query& not_synonym_of(const adjective& _adj); - - adjective_query& is_generalization(bool _is_generalization); - adjective_query& generalization_of(const adjective& _adj); - adjective_query& not_generalization_of(const adjective& _adj); - - adjective_query& is_specification(bool _is_specification); - adjective_query& specification_of(const adjective& _adj); - adjective_query& not_specification_of(const adjective& _adj); - - adjective_query& is_pertainymic(bool _is_pertainymic); - adjective_query& pertainym_of(const noun& _noun); - - adjective_query& is_mannernymic(bool _is_mannernymic); - adjective_query& anti_mannernym_of(const adverb& _adv); - - adjective_query& derived_from(const word& _w); - adjective_query& not_derived_from(const word& _w); - - std::list run() const; - - const static int unlimited = -1; - - protected: - const data& _data; - int _limit = unlimited; - bool _random = false; - std::list _rhymes; - std::list _except; - bool _has_prn = false; - - bool _requires_comparative_form = false; - bool _requires_superlative_form = false; - adjective::positioning _position = adjective::positioning::undefined; - - bool _is_variant = false; - std::list _variant_of; - std::list _not_variant_of; - - bool _is_antonymic = false; - std::list _antonym_of; - std::list _not_antonym_of; - - bool _is_synonymic = false; - std::list _synonym_of; - std::list _not_synonym_of; - - bool _is_generalization = false; - std::list _generalization_of; - std::list _not_generalization_of; - - bool _is_specification = false; - std::list _specification_of; - std::list _not_specification_of; - - bool _is_pertainymic = false; - std::list _pertainym_of; - - bool _is_mannernymic = false; - std::list _anti_mannernym_of; - - std::list _derived_from_adjective; - std::list _not_derived_from_adjective; - std::list _derived_from_adverb; - std::list _not_derived_from_adverb; - std::list _derived_from_noun; - std::list _not_derived_from_noun; - }; - }; #endif /* end of include guard: ADJECTIVE_H_87B3FB75 */ diff --git a/lib/adjective_query.cpp b/lib/adjective_query.cpp new file mode 100644 index 0000000..ec100e3 --- /dev/null +++ b/lib/adjective_query.cpp @@ -0,0 +1,819 @@ +#include "verbly.h" + +namespace verbly { + + adjective_query::adjective_query(const data& _data) : _data(_data) + { + + } + + adjective_query& adjective_query::limit(int _limit) + { + if ((_limit > 0) || (_limit == unlimited)) + { + this->_limit = _limit; + } + + return *this; + } + + adjective_query& adjective_query::random() + { + this->_random = true; + + return *this; + } + + adjective_query& adjective_query::except(const adjective& _word) + { + _except.push_back(_word); + + return *this; + } + + adjective_query& adjective_query::rhymes_with(const word& _word) + { + for (auto rhyme : _word.rhyme_phonemes()) + { + _rhymes.push_back(rhyme); + } + + if (dynamic_cast(&_word) != nullptr) + { + _except.push_back(dynamic_cast(_word)); + } + + return *this; + } + + adjective_query& adjective_query::has_pronunciation() + { + this->_has_prn = true; + + return *this; + } + + adjective_query& adjective_query::is_variant() + { + this->_is_variant = true; + + return *this; + } + + adjective_query& adjective_query::variant_of(filter _f) + { + _f.clean(); + _variant_of = _f; + + return *this; + } + + adjective_query& adjective_query::has_antonyms() + { + this->_is_antonymic = true; + + return *this; + } + + adjective_query& adjective_query::antonym_of(filter _f) + { + _f.clean(); + _antonym_of = _f; + + return *this; + } + + adjective_query& adjective_query::has_synonyms() + { + this->_is_synonymic = true; + + return *this; + } + + adjective_query& adjective_query::synonym_of(filter _f) + { + _f.clean(); + _synonym_of = _f; + + return *this; + } + + adjective_query& adjective_query::is_generalization() + { + this->_is_generalization = true; + + return *this; + } + + adjective_query& adjective_query::generalization_of(filter _f) + { + _f.clean(); + _generalization_of = _f; + + return *this; + } + + adjective_query& adjective_query::is_specification() + { + this->_is_specification = true; + + return *this; + } + + adjective_query& adjective_query::specification_of(filter _f) + { + _f.clean(); + _specification_of = _f; + + return *this; + } + + adjective_query& adjective_query::is_pertainymic() + { + this->_is_pertainymic = true; + + return *this; + } + + adjective_query& adjective_query::pertainym_of(filter _f) + { + _f.clean(); + _pertainym_of = _f; + + return *this; + } + + adjective_query& adjective_query::is_mannernymic() + { + this->_is_mannernymic = true; + + return *this; + } + + adjective_query& adjective_query::anti_mannernym_of(filter _f) + { + _f.clean(); + _anti_mannernym_of = _f; + + return *this; + } + /* + adjective_query& adjective_query::derived_from(const word& _w) + { + if (dynamic_cast(&_w) != nullptr) + { + _derived_from_adjective.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _derived_from_adverb.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _derived_from_noun.push_back(dynamic_cast(_w)); + } + + return *this; + } + + adjective_query& adjective_query::not_derived_from(const word& _w) + { + if (dynamic_cast(&_w) != nullptr) + { + _not_derived_from_adjective.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _not_derived_from_adverb.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _not_derived_from_noun.push_back(dynamic_cast(_w)); + } + + return *this; + } + */ + std::list adjective_query::run() const + { + std::stringstream construct; + construct << "SELECT adjective_id, base_form, comparative, superlative, position FROM adjectives"; + std::list conditions; + + if (_has_prn) + { + conditions.push_back("adjective_id IN (SELECT adjective_id FROM adjective_pronunciations)"); + } + + if (!_rhymes.empty()) + { + std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); + std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + for (auto except : _except) + { + conditions.push_back("adjective_id != @EXCID"); + } + + if (_requires_comparative_form) + { + conditions.push_back("comparative IS NOT NULL"); + } + + if (_requires_superlative_form) + { + conditions.push_back("superlative IS NOT NULL"); + } + + switch (_position) + { + case adjective::positioning::predicate: conditions.push_back("position = 'p'"); break; + case adjective::positioning::attributive: conditions.push_back("position = 'a'"); break; + case adjective::positioning::postnominal: conditions.push_back("position = 'i'"); break; + case adjective::positioning::undefined: break; + } + + if (_is_variant) + { + conditions.push_back("adjective_id IN (SELECT adjective_id FROM variation)"); + } + + if (!_variant_of.empty()) + { + std::stringstream cond; + if (_variant_of.get_notlogic()) + { + cond << "adjective_id NOT IN"; + } else { + cond << "adjective_id IN"; + } + + cond << "(SELECT adjective_id FROM variation WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "noun_id = @ATTRID"; + } else { + return "noun_id != @ATTRID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_variant_of, _variant_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_antonymic) + { + conditions.push_back("adjective_id IN (SELECT adjective_2_id FROM adjective_antonymy)"); + } + + if (!_antonym_of.empty()) + { + std::stringstream cond; + if (_antonym_of.get_notlogic()) + { + cond << "adjective_id NOT IN"; + } else { + cond << "adjective_id IN"; + } + + cond << "(SELECT adjective_2_id FROM adjective_antonymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "adjective_1_id = @ANTID"; + } else { + return "adjective_1_id != @ANTID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_antonym_of, _antonym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_synonymic) + { + conditions.push_back("adjective_id IN (SELECT adjective_2_id FROM adjective_synonymy)"); + } + + if (!_synonym_of.empty()) + { + std::stringstream cond; + if (_synonym_of.get_notlogic()) + { + cond << "adjective_id NOT IN"; + } else { + cond << "adjective_id IN"; + } + + cond << "(SELECT adjective_2_id FROM adjective_synonymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "adjective_1_id = @SYNID"; + } else { + return "adjective_1_id != @SYNID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_synonym_of, _synonym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_generalization) + { + conditions.push_back("adjective_id IN (SELECT general_id FROM specification)"); + } + + if (!_generalization_of.empty()) + { + std::stringstream cond; + if (_generalization_of.get_notlogic()) + { + cond << "adjective_id NOT IN"; + } else { + cond << "adjective_id IN"; + } + + cond << "(SELECT general_id FROM specification WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "specific_id = @SPECID"; + } else { + return "specific_id != @SPECID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_generalization_of, _generalization_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_specification) + { + conditions.push_back("adjective_id IN (SELECT specific_id FROM specification)"); + } + + if (!_specification_of.empty()) + { + std::stringstream cond; + if (_specification_of.get_notlogic()) + { + cond << "adjective_id NOT IN"; + } else { + cond << "adjective_id IN"; + } + + cond << "(SELECT specific_id FROM specification WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "general_id = @GENID"; + } else { + return "general_id != @GENID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_specification_of, _specification_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_pertainymic) + { + conditions.push_back("adjective_id IN (SELECT pertainym_id FROM pertainymy)"); + } + + if (!_pertainym_of.empty()) + { + std::stringstream cond; + if (_pertainym_of.get_notlogic()) + { + cond << "adjective_id NOT IN"; + } else { + cond << "adjective_id IN"; + } + + cond << "(SELECT pertainym_id FROM pertainymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "noun_id = @APERID"; + } else { + return "noun_id != @APERID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_pertainym_of, _pertainym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_mannernymic) + { + conditions.push_back("adjective_id IN (SELECT adjective_id FROM mannernymy)"); + } + + if (!_anti_mannernym_of.empty()) + { + std::stringstream cond; + if (_anti_mannernym_of.get_notlogic()) + { + cond << "adjective_id NOT IN"; + } else { + cond << "adjective_id IN"; + } + + cond << "(SELECT adjective_id FROM mannernymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "mannernym_id = @MANID"; + } else { + return "mannernym_id != @MANID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_anti_mannernym_of, _anti_mannernym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } +/* + if (!_derived_from_adjective.empty()) + { + std::list clauses(_derived_from_adjective.size(), "adjective_2_id = @DERADJ"); + std::string cond = "adjective_id IN (SELECT adjective_1_id FROM adjective_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_not_derived_from_adjective.empty()) + { + std::list clauses(_not_derived_from_adjective.size(), "adjective_2_id = @NDERADJ"); + std::string cond = "adjective_id NOT IN (SELECT adjective_1_id FROM adjective_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_derived_from_adverb.empty()) + { + std::list clauses(_derived_from_adverb.size(), "adverb_id = @DERADV"); + std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_not_derived_from_adverb.empty()) + { + std::list clauses(_not_derived_from_adverb.size(), "adverb_id = @NDERADV"); + std::string cond = "adjective_id NOT IN (SELECT adjective_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_derived_from_noun.empty()) + { + std::list clauses(_derived_from_noun.size(), "noun_id = @DERN"); + std::string cond = "adjective_id IN (SELECT adjective_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_not_derived_from_noun.empty()) + { + std::list clauses(_not_derived_from_noun.size(), "noun_id = @NDERN"); + std::string cond = "adjective_id NOT IN (SELECT adjective_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + }*/ + + if (!conditions.empty()) + { + construct << " WHERE "; + construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND "); + } + + if (_random) + { + construct << " ORDER BY RANDOM()"; + } + + if (_limit != unlimited) + { + construct << " LIMIT " << _limit; + } + + sqlite3_stmt* ppstmt; + std::string query = construct.str(); + if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); + } + + if (!_rhymes.empty()) + { + int i = 0; + for (auto rhyme : _rhymes) + { + std::string rhymer = "%" + rhyme; + sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); + + i++; + } + } + + for (auto except : _except) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); + } + + for (auto attribute : _variant_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ATTRID"), attribute._id); + } + + for (auto antonym : _antonym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id); + } + + for (auto synonym : _synonym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id); + } + + for (auto specific : _generalization_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SPECID"), specific._id); + } + + for (auto general : _specification_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@GENID"), general._id); + } + + for (auto n : _pertainym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@APERID"), n._id); + } + + for (auto mannernym : _anti_mannernym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MANID"), mannernym._id); + } + /* + for (auto adj : _derived_from_adjective) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADJ"), adj._id); + } + + for (auto adj : _not_derived_from_adjective) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADJ"), adj._id); + } + + for (auto adv : _derived_from_adverb) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADV"), adv._id); + } + + for (auto adv : _not_derived_from_adverb) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADV"), adv._id); + } + + for (auto n : _derived_from_noun) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERN"), n._id); + } + + for (auto n : _not_derived_from_noun) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERN"), n._id); + } +*/ + std::list output; + while (sqlite3_step(ppstmt) == SQLITE_ROW) + { + adjective tnc {_data, sqlite3_column_int(ppstmt, 0)}; + tnc._base_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); + + if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL) + { + tnc._comparative_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); + } + + if (sqlite3_column_type(ppstmt, 3) != SQLITE_NULL) + { + tnc._superlative_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 3))); + } + + if (sqlite3_column_type(ppstmt, 4) != SQLITE_NULL) + { + std::string adjpos(reinterpret_cast(sqlite3_column_text(ppstmt, 4))); + if (adjpos == "p") + { + tnc._position = adjective::positioning::predicate; + } else if (adjpos == "a") + { + tnc._position = adjective::positioning::attributive; + } else if (adjpos == "i") + { + tnc._position = adjective::positioning::postnominal; + } + } + + output.push_back(tnc); + } + + sqlite3_finalize(ppstmt); + + for (auto& adjective : output) + { + query = "SELECT pronunciation FROM adjective_pronunciations WHERE adjective_id = ?"; + if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); + } + + sqlite3_bind_int(ppstmt, 1, adjective._id); + + while (sqlite3_step(ppstmt) == SQLITE_ROW) + { + std::string pronunciation(reinterpret_cast(sqlite3_column_text(ppstmt, 0))); + auto phonemes = verbly::split>(pronunciation, " "); + + adjective.pronunciations.push_back(phonemes); + } + + sqlite3_finalize(ppstmt); + } + + return output; + } + +}; diff --git a/lib/adjective_query.h b/lib/adjective_query.h new file mode 100644 index 0000000..e7755cb --- /dev/null +++ b/lib/adjective_query.h @@ -0,0 +1,91 @@ +#ifndef ADJECTIVE_QUERY_H_05E590FD +#define ADJECTIVE_QUERY_H_05E590FD + +namespace verbly { + + class adjective_query { + public: + adjective_query(const data& _data); + + adjective_query& limit(int _limit); + adjective_query& random(); + adjective_query& except(const adjective& _word); + adjective_query& rhymes_with(const word& _word); + adjective_query& has_pronunciation(); + + adjective_query& requires_comparative_form(); + adjective_query& requires_superlative_form(); + adjective_query& position(adjective::positioning pos); + + adjective_query& is_variant(); + adjective_query& variant_of(filter _f); + + adjective_query& has_antonyms(); + adjective_query& antonym_of(filter _f); + + adjective_query& has_synonyms(); + adjective_query& synonym_of(filter _f); + + adjective_query& is_generalization(); + adjective_query& generalization_of(filter _f); + + adjective_query& is_specification(); + adjective_query& specification_of(filter _f); + + adjective_query& is_pertainymic(); + adjective_query& pertainym_of(filter _f); + + adjective_query& is_mannernymic(); + adjective_query& anti_mannernym_of(filter _f); + +/* adjective_query& derived_from(const word& _w); + adjective_query& not_derived_from(const word& _w);*/ + + std::list run() const; + + const static int unlimited = -1; + + protected: + const data& _data; + int _limit = unlimited; + bool _random = false; + std::list _rhymes; + std::list _except; + bool _has_prn = false; + + bool _requires_comparative_form = false; + bool _requires_superlative_form = false; + adjective::positioning _position = adjective::positioning::undefined; + + bool _is_variant = false; + filter _variant_of; + + bool _is_antonymic = false; + filter _antonym_of; + + bool _is_synonymic = false; + filter _synonym_of; + + bool _is_generalization = false; + filter _generalization_of; + + bool _is_specification = false; + filter _specification_of; + + bool _is_pertainymic = false; + filter _pertainym_of; + + bool _is_mannernymic = false; + filter _anti_mannernym_of; + +/* std::list _derived_from_adjective; + std::list _not_derived_from_adjective; + std::list _derived_from_adverb; + std::list _not_derived_from_adverb; + std::list _derived_from_noun; + std::list _not_derived_from_noun;*/ + }; + +}; + +#endif /* end of include guard: ADJECTIVE_QUERY_H_05E590FD */ diff --git a/lib/adverb.cpp b/lib/adverb.cpp index 8fcddad..442574e 100644 --- a/lib/adverb.cpp +++ b/lib/adverb.cpp @@ -2,6 +2,11 @@ namespace verbly { + adverb::adverb() + { + + } + adverb::adverb(const data& _data, int _id) : word(_data, _id) { @@ -9,460 +14,58 @@ namespace verbly { std::string adverb::base_form() const { + assert(_valid == true); + return _base_form; } std::string adverb::comparative_form() const { + assert(_valid == true); + return _comparative_form; } std::string adverb::superlative_form() const { + assert(_valid == true); + return _superlative_form; } bool adverb::has_comparative_form() const { + assert(_valid == true); + return !_comparative_form.empty(); } bool adverb::has_superlative_form() const { + assert(_valid == true); + return !_superlative_form.empty(); } adverb_query adverb::antonyms() const { - return _data.adverbs().antonym_of(*this); - } - - adverb_query adverb::synonyms() const - { - return _data.adverbs().synonym_of(*this); - } - - adjective_query adverb::anti_mannernyms() const - { - return _data.adjectives().anti_mannernym_of(*this); - } - - adverb_query::adverb_query(const data& _data) : _data(_data) - { - - } - - adverb_query& adverb_query::limit(int _limit) - { - if ((_limit > 0) || (_limit == unlimited)) - { - this->_limit = _limit; - } - - return *this; - } - - adverb_query& adverb_query::random(bool _random) - { - this->_random = _random; - - return *this; - } - - adverb_query& adverb_query::except(const adverb& _word) - { - _except.push_back(_word); + assert(_valid == true); - return *this; + return _data->adverbs().antonym_of(*this); } - adverb_query& adverb_query::rhymes_with(const word& _word) - { - for (auto rhyme : _word.rhyme_phonemes()) - { - _rhymes.push_back(rhyme); - } - - if (dynamic_cast(&_word) != nullptr) - { - _except.push_back(dynamic_cast(_word)); - } - - return *this; - } - - adverb_query& adverb_query::has_pronunciation(bool _has_prn) - { - this->_has_prn = _has_prn; - - return *this; - } - - adverb_query& adverb_query::requires_comparative_form(bool _arg) - { - _requires_comparative_form = _arg; - - return *this; - } - - adverb_query& adverb_query::requires_superlative_form(bool _arg) - { - _requires_superlative_form = _arg; - - return *this; - } - - adverb_query& adverb_query::has_antonyms(bool _arg) - { - _has_antonyms = _arg; - - return *this; - } - - adverb_query& adverb_query::antonym_of(const adverb& _adv) - { - _antonym_of.push_back(_adv); - - return *this; - } - - adverb_query& adverb_query::not_antonym_of(const adverb& _adv) - { - _not_antonym_of.push_back(_adv); - - return *this; - } - - adverb_query& adverb_query::has_synonyms(bool _arg) - { - _has_synonyms = _arg; - - return *this; - } - - adverb_query& adverb_query::synonym_of(const adverb& _adv) - { - _synonym_of.push_back(_adv); - - return *this; - } - - adverb_query& adverb_query::not_synonym_of(const adverb& _adv) - { - _not_synonym_of.push_back(_adv); - - return *this; - } - - adverb_query& adverb_query::is_mannernymic(bool _arg) - { - _is_mannernymic = _arg; - - return *this; - } - - adverb_query& adverb_query::mannernym_of(const adjective& _adj) - { - _mannernym_of.push_back(_adj); - - return *this; - } - - adverb_query& adverb_query::derived_from(const word& _w) - { - if (dynamic_cast(&_w) != nullptr) - { - _derived_from_adjective.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _derived_from_adverb.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _derived_from_noun.push_back(dynamic_cast(_w)); - } - - return *this; - } - - adverb_query& adverb_query::not_derived_from(const word& _w) + adverb_query adverb::synonyms() const { - if (dynamic_cast(&_w) != nullptr) - { - _not_derived_from_adjective.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _not_derived_from_adverb.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _not_derived_from_noun.push_back(dynamic_cast(_w)); - } + assert(_valid == true); - return *this; + return _data->adverbs().synonym_of(*this); } - std::list adverb_query::run() const + adjective_query adverb::anti_mannernyms() const { - std::stringstream construct; - construct << "SELECT adverb_id, base_form, comparative, superlative FROM adverbs"; - std::list conditions; - - if (_has_prn) - { - conditions.push_back("adverb_id IN (SELECT adverb_id FROM adverb_pronunciations)"); - } - - if (!_rhymes.empty()) - { - std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); - std::string cond = "adverb_id IN (SELECT adverb_id FROM adverb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - for (auto except : _except) - { - conditions.push_back("adverb_id != @EXCID"); - } - - if (_requires_comparative_form) - { - conditions.push_back("comparative IS NOT NULL"); - } - - if (_requires_superlative_form) - { - conditions.push_back("superlative IS NOT NULL"); - } - - if (_has_antonyms) - { - conditions.push_back("adverb_id IN (SELECT adverb_2_id FROM adverb_antonymy)"); - } - - if (!_antonym_of.empty()) - { - std::list clauses(_antonym_of.size(), "adverb_1_id = @ANTID"); - std::string cond = "adverb_id IN (SELECT adverb_2_id FROM adverb_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_antonym_of.empty()) - { - std::list clauses(_not_antonym_of.size(), "adverb_1_id = @NANTID"); - std::string cond = "adverb_id NOT IN (SELECT adverb_2_id FROM adverb_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_has_synonyms) - { - conditions.push_back("adverb_id IN (SELECT adverb_2_id FROM adverb_synonymy)"); - } + assert(_valid == true); - if (!_synonym_of.empty()) - { - std::list clauses(_synonym_of.size(), "adverb_1_id = @SYNID"); - std::string cond = "adverb_id IN (SELECT adverb_2_id FROM adverb_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_synonym_of.empty()) - { - std::list clauses(_not_synonym_of.size(), "adverb_1_id = @NSYNID"); - std::string cond = "adverb_id NOT IN (SELECT adverb_2_id FROM adverb_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_mannernymic) - { - conditions.push_back("adverb_id IN (SELECT mannernym_id FROM mannernymy)"); - } - - if (!_mannernym_of.empty()) - { - std::list clauses(_mannernym_of.size(), "adjective_id = @AMANID"); - std::string cond = "adverb_id IN (SELECT mannernym_id FROM mannernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_derived_from_adjective.empty()) - { - std::list clauses(_derived_from_adjective.size(), "adjective_id = @DERADJ"); - std::string cond = "adverb_id IN (SELECT adverb_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_derived_from_adjective.empty()) - { - std::list clauses(_not_derived_from_adjective.size(), "adjective_id = @NDERADJ"); - std::string cond = "adverb_id NOT IN (SELECT adverb_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_derived_from_adverb.empty()) - { - std::list clauses(_derived_from_adverb.size(), "adverb_2_id = @DERADV"); - std::string cond = "adverb_id IN (SELECT adverb_1_id FROM adverb_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_derived_from_adverb.empty()) - { - std::list clauses(_not_derived_from_adverb.size(), "adverb_2_id = @NDERADV"); - std::string cond = "adverb_id NOT IN (SELECT adverb_1_id FROM adverb_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_derived_from_noun.empty()) - { - std::list clauses(_derived_from_noun.size(), "noun_id = @DERN"); - std::string cond = "adverb_id IN (SELECT adverb_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_derived_from_noun.empty()) - { - std::list clauses(_not_derived_from_noun.size(), "noun_id = @NDERN"); - std::string cond = "adverb_id NOT IN (SELECT adverb_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!conditions.empty()) - { - construct << " WHERE "; - construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND "); - } - - if (_random) - { - construct << " ORDER BY RANDOM()"; - } - - if (_limit != unlimited) - { - construct << " LIMIT " << _limit; - } - - sqlite3_stmt* ppstmt; - std::string query = construct.str(); - if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) - { - throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); - } - - if (!_rhymes.empty()) - { - int i = 0; - for (auto rhyme : _rhymes) - { - std::string rhymer = "%" + rhyme; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); - - i++; - } - } - - for (auto except : _except) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); - } - - for (auto antonym : _antonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id); - } - - for (auto antonym : _not_antonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NANTID"), antonym._id); - } - - for (auto synonym : _synonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id); - } - - for (auto synonym : _not_synonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSYNID"), synonym._id); - } - - for (auto adj : _mannernym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@AMANID"), adj._id); - } - - for (auto adj : _derived_from_adjective) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADJ"), adj._id); - } - - for (auto adj : _not_derived_from_adjective) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADJ"), adj._id); - } - - for (auto adv : _derived_from_adverb) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADV"), adv._id); - } - - for (auto adv : _not_derived_from_adverb) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADV"), adv._id); - } - - for (auto n : _derived_from_noun) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERN"), n._id); - } - - for (auto n : _not_derived_from_noun) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERN"), n._id); - } - - std::list output; - while (sqlite3_step(ppstmt) == SQLITE_ROW) - { - adverb tnc {_data, sqlite3_column_int(ppstmt, 0)}; - tnc._base_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); - - if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL) - { - tnc._comparative_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); - } - - if (sqlite3_column_type(ppstmt, 3) != SQLITE_NULL) - { - tnc._superlative_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 3))); - } - - output.push_back(tnc); - } - - sqlite3_finalize(ppstmt); - - for (auto& adverb : output) - { - query = "SELECT pronunciation FROM adverb_pronunciations WHERE adverb_id = ?"; - if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) - { - throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); - } - - sqlite3_bind_int(ppstmt, 1, adverb._id); - - while (sqlite3_step(ppstmt) == SQLITE_ROW) - { - std::string pronunciation(reinterpret_cast(sqlite3_column_text(ppstmt, 0))); - auto phonemes = verbly::split>(pronunciation, " "); - - adverb.pronunciations.push_back(phonemes); - } - - sqlite3_finalize(ppstmt); - } - - return output; + return _data->adjectives().anti_mannernym_of(*this); } }; diff --git a/lib/adverb.h b/lib/adverb.h index 65e3c5c..56d4e28 100644 --- a/lib/adverb.h +++ b/lib/adverb.h @@ -12,6 +12,7 @@ namespace verbly { friend class adverb_query; public: + adverb(); adverb(const data& _data, int _id); std::string base_form() const; @@ -29,67 +30,6 @@ namespace verbly { adverb_query& not_derived_from(const word& _w); }; - class adverb_query { - public: - adverb_query(const data& _data); - - adverb_query& limit(int _limit); - adverb_query& random(bool _random); - adverb_query& except(const adverb& _word); - adverb_query& rhymes_with(const word& _word); - adverb_query& has_pronunciation(bool _has_prn); - - adverb_query& requires_comparative_form(bool _arg); - adverb_query& requires_superlative_form(bool _arg); - - adverb_query& has_antonyms(bool _arg); - adverb_query& antonym_of(const adverb& _adv); - adverb_query& not_antonym_of(const adverb& _adv); - - adverb_query& has_synonyms(bool _arg); - adverb_query& synonym_of(const adverb& _adv); - adverb_query& not_synonym_of(const adverb& _adv); - - adverb_query& is_mannernymic(bool _arg); - adverb_query& mannernym_of(const adjective& _adj); - - adverb_query& derived_from(const word& _w); - adverb_query& not_derived_from(const word& _w); - - std::list run() const; - - const static int unlimited = -1; - - private: - const data& _data; - int _limit = unlimited; - bool _random = false; - std::list _rhymes; - std::list _except; - bool _has_prn = false; - - bool _requires_comparative_form = false; - bool _requires_superlative_form = false; - - bool _has_antonyms = false; - std::list _antonym_of; - std::list _not_antonym_of; - - bool _has_synonyms = false; - std::list _synonym_of; - std::list _not_synonym_of; - - bool _is_mannernymic = false; - std::list _mannernym_of; - - std::list _derived_from_adjective; - std::list _not_derived_from_adjective; - std::list _derived_from_adverb; - std::list _not_derived_from_adverb; - std::list _derived_from_noun; - std::list _not_derived_from_noun; - }; - }; #endif /* end of include guard: ADVERB_H_86F8302F */ diff --git a/lib/adverb_query.cpp b/lib/adverb_query.cpp new file mode 100644 index 0000000..639f16f --- /dev/null +++ b/lib/adverb_query.cpp @@ -0,0 +1,514 @@ +#include "verbly.h" + +namespace verbly { + + adverb_query::adverb_query(const data& _data) : _data(_data) + { + + } + + adverb_query& adverb_query::limit(int _limit) + { + if ((_limit > 0) || (_limit == unlimited)) + { + this->_limit = _limit; + } + + return *this; + } + + adverb_query& adverb_query::random() + { + this->_random = true; + + return *this; + } + + adverb_query& adverb_query::except(const adverb& _word) + { + _except.push_back(_word); + + return *this; + } + + adverb_query& adverb_query::rhymes_with(const word& _word) + { + for (auto rhyme : _word.rhyme_phonemes()) + { + _rhymes.push_back(rhyme); + } + + if (dynamic_cast(&_word) != nullptr) + { + _except.push_back(dynamic_cast(_word)); + } + + return *this; + } + + adverb_query& adverb_query::has_pronunciation() + { + this->_has_prn = true; + + return *this; + } + + adverb_query& adverb_query::requires_comparative_form() + { + _requires_comparative_form = true; + + return *this; + } + + adverb_query& adverb_query::requires_superlative_form() + { + _requires_superlative_form = true; + + return *this; + } + + adverb_query& adverb_query::has_antonyms() + { + _has_antonyms = true; + + return *this; + } + + adverb_query& adverb_query::antonym_of(filter _f) + { + _f.clean(); + _antonym_of = _f; + + return *this; + } + + adverb_query& adverb_query::has_synonyms() + { + _has_synonyms = true; + + return *this; + } + + adverb_query& adverb_query::synonym_of(filter _f) + { + _f.clean(); + _synonym_of = _f; + + return *this; + } + + adverb_query& adverb_query::is_mannernymic() + { + _is_mannernymic = true; + + return *this; + } + + adverb_query& adverb_query::mannernym_of(filter _f) + { + _f.clean(); + _mannernym_of = _f; + + return *this; + } + /* + adverb_query& adverb_query::derived_from(const word& _w) + { + if (dynamic_cast(&_w) != nullptr) + { + _derived_from_adjective.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _derived_from_adverb.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _derived_from_noun.push_back(dynamic_cast(_w)); + } + + return *this; + } + + adverb_query& adverb_query::not_derived_from(const word& _w) + { + if (dynamic_cast(&_w) != nullptr) + { + _not_derived_from_adjective.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _not_derived_from_adverb.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _not_derived_from_noun.push_back(dynamic_cast(_w)); + } + + return *this; + } + */ + std::list adverb_query::run() const + { + std::stringstream construct; + construct << "SELECT adverb_id, base_form, comparative, superlative FROM adverbs"; + std::list conditions; + + if (_has_prn) + { + conditions.push_back("adverb_id IN (SELECT adverb_id FROM adverb_pronunciations)"); + } + + if (!_rhymes.empty()) + { + std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); + std::string cond = "adverb_id IN (SELECT adverb_id FROM adverb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + for (auto except : _except) + { + conditions.push_back("adverb_id != @EXCID"); + } + + if (_requires_comparative_form) + { + conditions.push_back("comparative IS NOT NULL"); + } + + if (_requires_superlative_form) + { + conditions.push_back("superlative IS NOT NULL"); + } + + if (_has_antonyms) + { + conditions.push_back("adverb_id IN (SELECT adverb_2_id FROM adverb_antonymy)"); + } + + if (!_antonym_of.empty()) + { + std::stringstream cond; + if (_antonym_of.get_notlogic()) + { + cond << "adverb_id NOT IN"; + } else { + cond << "adverb_id IN"; + } + + cond << "(SELECT adverb_2_id FROM adverb_antonymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "adverb_1_id = @ANTID"; + } else { + return "adverb_1_id != @ANTID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_antonym_of, _antonym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_has_synonyms) + { + conditions.push_back("adverb_id IN (SELECT adverb_2_id FROM adverb_synonymy)"); + } + + if (!_synonym_of.empty()) + { + std::stringstream cond; + if (_antonym_of.get_notlogic()) + { + cond << "adverb_id NOT IN"; + } else { + cond << "adverb_id IN"; + } + + cond << "(SELECT adverb_2_id FROM adverb_synonymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "adverb_1_id = @SYNID"; + } else { + return "adverb_1_id != @SYNID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_synonym_of, _synonym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_mannernymic) + { + conditions.push_back("adverb_id IN (SELECT mannernym_id FROM mannernymy)"); + } + + if (!_mannernym_of.empty()) + { + std::stringstream cond; + if (_antonym_of.get_notlogic()) + { + cond << "adverb_id NOT IN"; + } else { + cond << "adverb_id IN"; + } + + cond << "(SELECT mannernym_id FROM mannernymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "adjective_id = @AMANID"; + } else { + return "adjective_id != @AMANID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_mannernym_of, _mannernym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + +/* if (!_derived_from_adjective.empty()) + { + std::list clauses(_derived_from_adjective.size(), "adjective_id = @DERADJ"); + std::string cond = "adverb_id IN (SELECT adverb_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_not_derived_from_adjective.empty()) + { + std::list clauses(_not_derived_from_adjective.size(), "adjective_id = @NDERADJ"); + std::string cond = "adverb_id NOT IN (SELECT adverb_id FROM adjective_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_derived_from_adverb.empty()) + { + std::list clauses(_derived_from_adverb.size(), "adverb_2_id = @DERADV"); + std::string cond = "adverb_id IN (SELECT adverb_1_id FROM adverb_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_not_derived_from_adverb.empty()) + { + std::list clauses(_not_derived_from_adverb.size(), "adverb_2_id = @NDERADV"); + std::string cond = "adverb_id NOT IN (SELECT adverb_1_id FROM adverb_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_derived_from_noun.empty()) + { + std::list clauses(_derived_from_noun.size(), "noun_id = @DERN"); + std::string cond = "adverb_id IN (SELECT adverb_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_not_derived_from_noun.empty()) + { + std::list clauses(_not_derived_from_noun.size(), "noun_id = @NDERN"); + std::string cond = "adverb_id NOT IN (SELECT adverb_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + }*/ + + if (!conditions.empty()) + { + construct << " WHERE "; + construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND "); + } + + if (_random) + { + construct << " ORDER BY RANDOM()"; + } + + if (_limit != unlimited) + { + construct << " LIMIT " << _limit; + } + + sqlite3_stmt* ppstmt; + std::string query = construct.str(); + if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); + } + + if (!_rhymes.empty()) + { + int i = 0; + for (auto rhyme : _rhymes) + { + std::string rhymer = "%" + rhyme; + sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); + + i++; + } + } + + for (auto except : _except) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); + } + + for (auto antonym : _antonym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id); + } + + for (auto synonym : _synonym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id); + } + + for (auto adj : _mannernym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@AMANID"), adj._id); + } + /* + for (auto adj : _derived_from_adjective) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADJ"), adj._id); + } + + for (auto adj : _not_derived_from_adjective) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADJ"), adj._id); + } + + for (auto adv : _derived_from_adverb) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADV"), adv._id); + } + + for (auto adv : _not_derived_from_adverb) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADV"), adv._id); + } + + for (auto n : _derived_from_noun) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERN"), n._id); + } + + for (auto n : _not_derived_from_noun) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERN"), n._id); + }*/ + + std::list output; + while (sqlite3_step(ppstmt) == SQLITE_ROW) + { + adverb tnc {_data, sqlite3_column_int(ppstmt, 0)}; + tnc._base_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); + + if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL) + { + tnc._comparative_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); + } + + if (sqlite3_column_type(ppstmt, 3) != SQLITE_NULL) + { + tnc._superlative_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 3))); + } + + output.push_back(tnc); + } + + sqlite3_finalize(ppstmt); + + for (auto& adverb : output) + { + query = "SELECT pronunciation FROM adverb_pronunciations WHERE adverb_id = ?"; + if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); + } + + sqlite3_bind_int(ppstmt, 1, adverb._id); + + while (sqlite3_step(ppstmt) == SQLITE_ROW) + { + std::string pronunciation(reinterpret_cast(sqlite3_column_text(ppstmt, 0))); + auto phonemes = verbly::split>(pronunciation, " "); + + adverb.pronunciations.push_back(phonemes); + } + + sqlite3_finalize(ppstmt); + } + + return output; + } + +}; diff --git a/lib/adverb_query.h b/lib/adverb_query.h new file mode 100644 index 0000000..20f9ce5 --- /dev/null +++ b/lib/adverb_query.h @@ -0,0 +1,65 @@ +#ifndef ADVERB_QUERY_H_CA13CCDD +#define ADVERB_QUERY_H_CA13CCDD + +namespace verbly { + + class adverb_query { + public: + adverb_query(const data& _data); + + adverb_query& limit(int _limit); + adverb_query& random(); + adverb_query& except(const adverb& _word); + adverb_query& rhymes_with(const word& _word); + adverb_query& has_pronunciation(); + + adverb_query& requires_comparative_form(); + adverb_query& requires_superlative_form(); + + adverb_query& has_antonyms(); + adverb_query& antonym_of(filter _f); + + adverb_query& has_synonyms(); + adverb_query& synonym_of(filter _f); + + adverb_query& is_mannernymic(); + adverb_query& mannernym_of(filter _f); + +/* adverb_query& derived_from(const word& _w); + adverb_query& not_derived_from(const word& _w);*/ + + std::list run() const; + + const static int unlimited = -1; + + private: + const data& _data; + int _limit = unlimited; + bool _random = false; + std::list _rhymes; + std::list _except; + bool _has_prn = false; + + bool _requires_comparative_form = false; + bool _requires_superlative_form = false; + + bool _has_antonyms = false; + filter _antonym_of; + + bool _has_synonyms = false; + filter _synonym_of; + + bool _is_mannernymic = false; + filter _mannernym_of; + +/* std::list _derived_from_adjective; + std::list _not_derived_from_adjective; + std::list _derived_from_adverb; + std::list _not_derived_from_adverb; + std::list _derived_from_noun; + std::list _not_derived_from_noun;*/ + }; + +}; + +#endif /* end of include guard: ADVERB_QUERY_H_CA13CCDD */ diff --git a/lib/c++14.h b/lib/c++14.h deleted file mode 100644 index b3efbe2..0000000 --- a/lib/c++14.h +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include -#include - -namespace std { - template struct _Unique_if { - typedef unique_ptr _Single_object; - }; - - template struct _Unique_if { - typedef unique_ptr _Unknown_bound; - }; - - template struct _Unique_if { - typedef void _Known_bound; - }; - - template - typename _Unique_if::_Single_object - make_unique(Args&&... args) { - return unique_ptr(new T(std::forward(args)...)); - } - - template - typename _Unique_if::_Unknown_bound - make_unique(size_t n) { - typedef typename remove_extent::type U; - return unique_ptr(new U[n]()); - } - - template - typename _Unique_if::_Known_bound - make_unique(Args&&...) = delete; -} diff --git a/lib/data.cpp b/lib/data.cpp index 57a8850..5a9397b 100644 --- a/lib/data.cpp +++ b/lib/data.cpp @@ -46,5 +46,15 @@ namespace verbly { { return noun_query(*this); } - + + frame_query data::frames() const + { + return frame_query(*this); + } + + preposition_query data::prepositions() const + { + return preposition_query(*this); + } + }; diff --git a/lib/data.h b/lib/data.h index 37092d7..6c2d580 100644 --- a/lib/data.h +++ b/lib/data.h @@ -2,7 +2,6 @@ #define DATA_H_C4AEC3DD #include -#include namespace verbly { @@ -12,10 +11,13 @@ namespace verbly { class noun; class verb; class adverb; + class frame; class adjective_query; class adverb_query; class noun_query; class verb_query; + class frame_query; + class preposition_query; class data { private: @@ -25,6 +27,8 @@ namespace verbly { friend class noun_query; friend class verb_query; friend class adverb_query; + friend class frame_query; + friend class preposition_query; public: data(std::string datafile); @@ -41,9 +45,302 @@ namespace verbly { adjective_query adjectives() const; adverb_query adverbs() const; noun_query nouns() const; + frame_query frames() const; + preposition_query prepositions() const; }; + template + class filter { + public: + enum class type { + singleton, + group + }; + + typedef filter value_type; + + type get_type() const + { + return _type; + } + + filter(const filter& other) + { + _type = other._type; + _notlogic = other._notlogic; + + switch (_type) + { + case type::singleton: + { + new(&_singleton.elem) T(other._singleton.elem); + + break; + } + + case type::group: + { + new(&_group.elems) std::list>(other._group.elems); + _group.orlogic = other._group.orlogic; + + break; + } + } + } + + filter& operator=(const filter& other) + { + this->~filter(); + + _type = other._type; + _notlogic = other._notlogic; + + switch (_type) + { + case type::singleton: + { + new(&_singleton.elem) T(other._singleton.elem); + + break; + } + + case type::group: + { + new(&_group.elems) std::list>(other._group.elems); + _group.orlogic = other._group.orlogic; + + break; + } + } + + return *this; + } + + ~filter() + { + switch (_type) + { + case type::singleton: + { + _singleton.elem.~T(); + + break; + } + + case type::group: + { + using list_type = std::list>; + _group.elems.~list_type(); + + break; + } + } + } + + bool get_notlogic() const + { + return _notlogic; + } + + void set_notlogic(bool _nl) + { + _notlogic = _nl; + } + + std::list inorder_flatten() const + { + std::list result; + + if (_type == type::singleton) + { + result.push_back(_singleton.elem); + } else if (_type == type::group) + { + for (auto elem : _group.elems) + { + auto l = elem.inorder_flatten(); + result.insert(std::end(result), std::begin(l), std::end(l)); + } + } + + return result; + } + + std::set uniq_flatten() const + { + std::set result; + + if (_type == type::singleton) + { + result.insert(_singleton.elem); + } else if (_type == type::group) + { + for (auto elem : _group.elems) + { + auto l = elem.uniq_flatten(); + result.insert(std::begin(l), std::end(l)); + } + } + + return result; + } + + void clean() + { + if (_type == type::group) + { + std::list>::iterator> toremove; + for (auto it = _group.elems.begin(); it != _group.elems.end(); it++) + { + it->clean(); + + if (it->get_type() == type::group) + { + if (it->_group.elems.size() == 0) + { + toremove.push_back(it); + } else if (it->_group.elems.size() == 1) + { + bool truelogic = it->_notlogic != it->_group.elems.front()._notlogic; + *it = it->_group.elems.front(); + it->_notlogic = truelogic; + } + } + } + + for (auto rem : toremove) + { + _group.elems.erase(rem); + } + + if (_group.elems.size() == 1) + { + bool truelogic = _notlogic != _group.elems.front()._notlogic; + *this = _group.elems.front(); + _notlogic = truelogic; + } + } + } + + // Singleton + filter(T _elem, bool _notlogic = false) : _type(type::singleton) + { + new(&_singleton.elem) T(_elem); + this->_notlogic = _notlogic; + } + + filter& operator=(T _elem) + { + *this = filter{_elem}; + + return *this; + } + + T get_elem() const + { + assert(_type == type::singleton); + + return _singleton.elem; + } + + void set_elem(T _elem) + { + assert(_type == type::singleton); + + _singleton.elem = _elem; + } + + // Group + typedef typename std::list>::iterator iterator; + + filter() : _type(type::group) + { + new(&_group.elems) std::list>(); + _group.orlogic = false; + } + + filter(std::initializer_list> _init) : _type(type::group) + { + new(&_group.elems) std::list>(_init); + _group.orlogic = false; + } + + iterator begin() + { + assert(_type == type::group); + + return _group.elems.begin(); + } + + iterator end() + { + assert(_type == type::group); + + return _group.elems.end(); + } + + filter& operator<<(filter _elem) + { + assert(_type == type::group); + + _group.elems.push_back(_elem); + + return *this; + } + + void push_back(filter _elem) + { + assert(_type == type::group); + + _group.elems.push_back(_elem); + } + + bool get_orlogic() const + { + assert(_type == type::group); + + return _group.orlogic; + } + + void set_orlogic(bool _ol) + { + assert(_type == type::group); + + _group.orlogic = _ol; + } + + bool empty() const + { + if (_type == type::group) + { + return _group.elems.empty(); + } else { + return false; + } + } + + int size() const + { + assert(_type == type::group); + + return _group.elems.size(); + } + + private: + type _type; + bool _notlogic = false; + union { + struct { + T elem; + } _singleton; + struct { + std::list> elems; + bool orlogic; + } _group; + }; + }; + }; #endif /* end of include guard: DATA_H_C4AEC3DD */ diff --git a/lib/frame.cpp b/lib/frame.cpp new file mode 100644 index 0000000..ccec81b --- /dev/null +++ b/lib/frame.cpp @@ -0,0 +1,320 @@ +#include "verbly.h" + +namespace verbly { + + frame::selrestr::type frame::selrestr::get_type() const + { + return _type; + } + + frame::selrestr::selrestr(const selrestr& other) + { + _type = other._type; + + switch (_type) + { + case frame::selrestr::type::singleton: + { + _singleton.pos = other._singleton.pos; + new(&_singleton.restriction) std::string(other._singleton.restriction); + + break; + } + + case frame::selrestr::type::group: + { + new(&_group.children) std::list(other._group.children); + _group.orlogic = other._group.orlogic; + + break; + } + + case frame::selrestr::type::empty: + { + // Nothing! + + break; + } + } + } + + frame::selrestr::~selrestr() + { + switch (_type) + { + case frame::selrestr::type::singleton: + { + using string_type = std::string; + _singleton.restriction.~string_type(); + + break; + } + + case frame::selrestr::type::group: + { + using list_type = std::list; + _group.children.~list_type(); + + break; + } + + case frame::selrestr::type::empty: + { + // Nothing! + + break; + } + } + } + + frame::selrestr& frame::selrestr::operator=(const selrestr& other) + { + this->~selrestr(); + + _type = other._type; + + switch (_type) + { + case frame::selrestr::type::singleton: + { + _singleton.pos = other._singleton.pos; + new(&_singleton.restriction) std::string(other._singleton.restriction); + + break; + } + + case frame::selrestr::type::group: + { + new(&_group.children) std::list(other._group.children); + _group.orlogic = other._group.orlogic; + + break; + } + + case frame::selrestr::type::empty: + { + // Nothing! + + break; + } + } + + return *this; + } + + frame::selrestr::selrestr() : _type(frame::selrestr::type::empty) + { + + } + + frame::selrestr::selrestr(std::string restriction, bool pos) : _type(frame::selrestr::type::singleton) + { + new(&_singleton.restriction) std::string(restriction); + _singleton.pos = pos; + } + + std::string frame::selrestr::get_restriction() const + { + assert(_type == frame::selrestr::type::singleton); + + return _singleton.restriction; + } + + bool frame::selrestr::get_pos() const + { + assert(_type == frame::selrestr::type::singleton); + + return _singleton.pos; + } + + frame::selrestr::selrestr(std::list children, bool orlogic) : _type(frame::selrestr::type::group) + { + new(&_group.children) std::list(children); + _group.orlogic = orlogic; + } + + std::list frame::selrestr::get_children() const + { + assert(_type == frame::selrestr::type::group); + + return _group.children; + } + + std::list::const_iterator frame::selrestr::begin() const + { + assert(_type == frame::selrestr::type::group); + + return _group.children.begin(); + } + + std::list::const_iterator frame::selrestr::end() const + { + assert(_type == frame::selrestr::type::group); + + return _group.children.end(); + } + + bool frame::selrestr::get_orlogic() const + { + assert(_type == frame::selrestr::type::group); + + return _group.orlogic; + } + + frame::part::type frame::part::get_type() const + { + return _type; + } + + frame::part::part() + { + + } + + frame::part::part(const part& other) + { + _type = other._type; + + switch (_type) + { + case frame::part::type::noun_phrase: + { + new(&_noun_phrase.role) std::string(other._noun_phrase.role); + new(&_noun_phrase.selrestrs) selrestr(other._noun_phrase.selrestrs); + new(&_noun_phrase.synrestrs) std::set(other._noun_phrase.synrestrs); + + break; + } + + case frame::part::type::literal_preposition: + { + new(&_literal_preposition.choices) std::vector(other._literal_preposition.choices); + + break; + } + + case frame::part::type::selection_preposition: + { + new(&_selection_preposition.preprestrs) std::vector(other._selection_preposition.preprestrs); + + break; + } + + case frame::part::type::literal: + { + new(&_literal.lexval) std::string(other._literal.lexval); + + break; + } + + default: + { + // Nothing! + + break; + } + } + } + + frame::part::~part() + { + switch (_type) + { + case frame::part::type::noun_phrase: + { + using string_type = std::string; + using set_type = std::set; + + _noun_phrase.role.~string_type(); + _noun_phrase.selrestrs.~selrestr(); + _noun_phrase.synrestrs.~set_type(); + + break; + } + + case frame::part::type::literal_preposition: + { + using vector_type = std::vector; + _literal_preposition.choices.~vector_type(); + + break; + } + + case frame::part::type::selection_preposition: + { + using vector_type = std::vector; + _selection_preposition.preprestrs.~vector_type(); + + break; + } + + case frame::part::type::literal: + { + using string_type = std::string; + _literal.lexval.~string_type(); + + break; + } + + default: + { + // Nothing! + + break; + } + } + } + + std::string frame::part::get_role() const + { + assert(_type == frame::part::type::noun_phrase); + + return _noun_phrase.role; + } + + frame::selrestr frame::part::get_selrestrs() const + { + assert(_type == frame::part::type::noun_phrase); + + return _noun_phrase.selrestrs; + } + + std::set frame::part::get_synrestrs() const + { + assert(_type == frame::part::type::noun_phrase); + + return _noun_phrase.synrestrs; + } + + std::vector frame::part::get_choices() const + { + assert(_type == frame::part::type::literal_preposition); + + return _literal_preposition.choices; + } + + std::vector frame::part::get_preprestrs() const + { + assert(_type == frame::part::type::selection_preposition); + + return _selection_preposition.preprestrs; + } + + std::string frame::part::get_literal() const + { + assert(_type == frame::part::type::literal); + + return _literal.lexval; + } + + std::vector frame::parts() const + { + return _parts; + } + + std::map frame::roles() const + { + return _roles; + } + +}; diff --git a/lib/frame.h b/lib/frame.h new file mode 100644 index 0000000..fa57e1b --- /dev/null +++ b/lib/frame.h @@ -0,0 +1,118 @@ +#ifndef FRAME_H_9A5D90FE +#define FRAME_H_9A5D90FE + +namespace verbly { + + class frame_query; + + class frame { + public: + class selrestr { + public: + enum class type { + empty, + singleton, + group + }; + + type get_type() const; + selrestr(const selrestr& other); + ~selrestr(); + selrestr& operator=(const selrestr& other); + + // Empty + selrestr(); + + // Singleton + selrestr(std::string restriction, bool pos); + std::string get_restriction() const; + bool get_pos() const; + + // Group + selrestr(std::list children, bool orlogic); + std::list get_children() const; + std::list::const_iterator begin() const; + std::list::const_iterator end() const; + bool get_orlogic() const; + + private: + union { + struct { + bool pos; + std::string restriction; + } _singleton; + struct { + std::list children; + bool orlogic; + } _group; + }; + type _type; + }; + + class part { + public: + enum class type { + noun_phrase, + verb, + literal_preposition, + selection_preposition, + adjective, + adverb, + literal + }; + + type get_type() const; + part(const part& other); + ~part(); + + // Noun phrase + std::string get_role() const; + selrestr get_selrestrs() const; + std::set get_synrestrs() const; + + // Literal preposition + std::vector get_choices() const; + + // Selection preposition + std::vector get_preprestrs() const; + + // Literal + std::string get_literal() const; + + private: + friend class frame_query; + + part(); + + union { + struct { + std::string role; + selrestr selrestrs; + std::set synrestrs; + } _noun_phrase; + struct { + std::vector choices; + } _literal_preposition; + struct { + std::vector preprestrs; + } _selection_preposition; + struct { + std::string lexval; + } _literal; + }; + type _type; + }; + + std::vector parts() const; + std::map roles() const; + + private: + friend class frame_query; + + std::vector _parts; + std::map _roles; + }; + +}; + +#endif /* end of include guard: FRAME_H_9A5D90FE */ diff --git a/lib/frame_query.cpp b/lib/frame_query.cpp new file mode 100644 index 0000000..6583da4 --- /dev/null +++ b/lib/frame_query.cpp @@ -0,0 +1,142 @@ +#include "verbly.h" +#include + +using json = nlohmann::json; + +namespace verbly { + + frame_query::frame_query(const data& _data) : _data(_data) + { + + } + + frame_query& frame_query::for_verb(const verb& _v) + { + _for_verb.push_back(_v); + + return *this; + } + + frame::selrestr parse_selrestr(const json data) + { + if (data.find("children") != data.end()) + { + std::list children; + std::transform(std::begin(data["children"]), std::end(data["children"]), std::back_inserter(children), &parse_selrestr); + + return frame::selrestr{children, data["logic"] == "or"}; + } else if (data.find("type") != data.end()) + { + return frame::selrestr{data["type"].get(), data["pos"].get()}; + } else { + return frame::selrestr{}; + } + } + + std::list frame_query::run() const + { + std::stringstream construct; + construct << "SELECT frames.data, groups.data FROM frames INNER JOIN groups ON frames.group_id = groups.group_id"; + + if (!_for_verb.empty()) + { + std::list clauses(_for_verb.size(), "verb_id = @VERID"); + construct << " WHERE frames.group_id IN (SELECT group_id FROM verb_groups WHERE "; + construct << verbly::implode(std::begin(clauses), std::end(clauses), " OR "); + construct << ")"; + } + + sqlite3_stmt* ppstmt; + std::string query = construct.str(); + if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); + } + + for (auto verb : _for_verb) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@VERID"), verb._id); + } + + std::list output; + while (sqlite3_step(ppstmt) == SQLITE_ROW) + { + frame f; + + std::string fdatat(reinterpret_cast(sqlite3_column_blob(ppstmt, 0))); + const json fdata = json::parse(fdatat); + for (const auto& part : fdata) + { + frame::part p; + + if (part["type"] == "np") + { + p._type = frame::part::type::noun_phrase; + new(&p._noun_phrase.role) std::string(part["role"].get()); + new(&p._noun_phrase.selrestrs) frame::selrestr(parse_selrestr(part["selrestrs"])); + new(&p._noun_phrase.synrestrs) std::set(); + for (auto synrestr : part["synrestrs"]) + { + p._noun_phrase.synrestrs.insert(synrestr.get()); + } + } else if (part["type"] == "pp") + { + if (!part["values"].empty()) + { + p._type = frame::part::type::literal_preposition; + new(&p._literal_preposition.choices) std::vector(); + for (auto choice : part["values"]) + { + p._literal_preposition.choices.push_back(choice.get()); + } + } else if (!part["preprestrs"].empty()) + { + p._type = frame::part::type::selection_preposition; + new(&p._selection_preposition.preprestrs) std::vector(); + for (auto preprestr : part["preprestrs"]) + { + p._selection_preposition.preprestrs.push_back(preprestr.get()); + } + } + } else if (part["type"] == "v") + { + p._type = frame::part::type::verb; + } else if (part["type"] == "adj") + { + p._type = frame::part::type::adjective; + } else if (part["type"] == "adv") + { + p._type = frame::part::type::adverb; + } else if (part["type"] == "lex") + { + p._type = frame::part::type::literal; + new(&p._literal.lexval) std::string(part["value"].get()); + } + + f._parts.push_back(p); + } + + std::string rdatat(reinterpret_cast(sqlite3_column_blob(ppstmt, 1))); + const json rdata = json::parse(rdatat); + for (const auto& role : rdata) + { + std::string rt = role["type"]; + frame::selrestr rs; + + if (role.find("selrestrs") != role.end()) + { + rs = parse_selrestr(role["selrestrs"]); + } + + f._roles[rt] = rs; + } + + output.push_back(f); + } + + sqlite3_finalize(ppstmt); + + return output; + } + +}; diff --git a/lib/frame_query.h b/lib/frame_query.h new file mode 100644 index 0000000..dd11d16 --- /dev/null +++ b/lib/frame_query.h @@ -0,0 +1,21 @@ +#ifndef FRAME_QUERY_H_334B9D47 +#define FRAME_QUERY_H_334B9D47 + +namespace verbly { + + class frame_query { + public: + frame_query(const data& _data); + + frame_query& for_verb(const verb& _v); + + std::list run() const; + + private: + const data& _data; + std::list _for_verb; + }; + +}; + +#endif /* end of include guard: FRAME_QUERY_H_334B9D47 */ diff --git a/lib/noun.cpp b/lib/noun.cpp index 81e6613..f575117 100644 --- a/lib/noun.cpp +++ b/lib/noun.cpp @@ -1,7 +1,14 @@ #include "verbly.h" +#include +#include namespace verbly { + noun::noun() + { + + } + noun::noun(const data& _data, int _id) : word(_data, _id) { @@ -9,1036 +16,147 @@ namespace verbly { std::string noun::base_form() const { + assert(_valid == true); + return _singular; } std::string noun::singular_form() const { + assert(_valid == true); + return _singular; } std::string noun::plural_form() const { + assert(_valid == true); + return _plural; } bool noun::has_plural_form() const { + assert(_valid == true); + return !_plural.empty(); } noun_query noun::hypernyms() const { - return _data.nouns().hypernym_of(*this); - } - - noun_query noun::hyponyms() const - { - return _data.nouns().hyponym_of(*this); - } - - noun_query noun::part_meronyms() const - { - return _data.nouns().part_meronym_of(*this); - } - - noun_query noun::part_holonyms() const - { - return _data.nouns().part_holonym_of(*this); - } - - noun_query noun::substance_meronyms() const - { - return _data.nouns().substance_meronym_of(*this); - } - - noun_query noun::substance_holonyms() const - { - return _data.nouns().substance_holonym_of(*this); - } - - noun_query noun::member_meronyms() const - { - return _data.nouns().member_meronym_of(*this); - } - - noun_query noun::member_holonyms() const - { - return _data.nouns().member_holonym_of(*this); - } - - noun_query noun::classes() const - { - return _data.nouns().class_of(*this); - } - - noun_query noun::instances() const - { - return _data.nouns().instance_of(*this); - } - - noun_query noun::synonyms() const - { - return _data.nouns().synonym_of(*this); - } - - noun_query noun::antonyms() const - { - return _data.nouns().antonym_of(*this); - } - - adjective_query noun::pertainyms() const - { - return _data.adjectives().pertainym_of(*this); - } - - adjective_query noun::variations() const - { - return _data.adjectives().variant_of(*this); - } - - noun_query::noun_query(const data& _data) : _data(_data) - { - - } - - noun_query& noun_query::limit(int _limit) - { - if ((_limit > 0) || (_limit == unlimited)) - { - this->_limit = _limit; - } - - return *this; - } - - noun_query& noun_query::random(bool _random) - { - this->_random = _random; - - return *this; - } - - noun_query& noun_query::except(const noun& _word) - { - _except.push_back(_word); - - return *this; - } - - noun_query& noun_query::rhymes_with(const word& _word) - { - for (auto rhyme : _word.rhyme_phonemes()) - { - _rhymes.push_back(rhyme); - } - - if (dynamic_cast(&_word) != nullptr) - { - _except.push_back(dynamic_cast(_word)); - } - - return *this; - } - - noun_query& noun_query::has_pronunciation(bool _has_prn) - { - this->_has_prn = _has_prn; - - return *this; - } - - noun_query& noun_query::is_hypernym(bool _arg) - { - _is_hypernym = _arg; - - return *this; - } - - noun_query& noun_query::hypernym_of(const noun& _noun) - { - _hypernym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::not_hypernym_of(const noun& _noun) - { - _not_hypernym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::is_hyponym(bool _arg) - { - _is_hyponym = _arg; - - return *this; - } - - noun_query& noun_query::hyponym_of(const noun& _noun) - { - _hyponym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::not_hyponym_of(const noun& _noun) - { - _not_hyponym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::is_part_meronym(bool _arg) - { - _is_part_meronym = _arg; - - return *this; - } - - noun_query& noun_query::part_meronym_of(const noun& _noun) - { - _part_meronym_of.push_back(_noun); + assert(_valid == true); - return *this; + return _data->nouns().hypernym_of(*this); } - noun_query& noun_query::not_part_meronym_of(const noun& _noun) + noun_query noun::full_hypernyms() const { - _not_part_meronym_of.push_back(_noun); + assert(_valid == true); - return *this; + return _data->nouns().full_hypernym_of(*this); } - noun_query& noun_query::is_part_holonym(bool _arg) - { - _is_part_holonym = _arg; - - return *this; - } - - noun_query& noun_query::part_holonym_of(const noun& _noun) - { - _part_holonym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::not_part_holonym_of(const noun& _noun) - { - _not_part_holonym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::is_substance_meronym(bool _arg) - { - _is_substance_meronym = _arg; - - return *this; - } - - noun_query& noun_query::substance_meronym_of(const noun& _noun) - { - _substance_meronym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::not_substance_meronym_of(const noun& _noun) - { - _not_substance_meronym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::is_substance_holonym(bool _arg) - { - _is_substance_holonym = _arg; - - return *this; - } - - noun_query& noun_query::substance_holonym_of(const noun& _noun) - { - _substance_holonym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::not_substance_holonym_of(const noun& _noun) - { - _not_substance_holonym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::is_member_meronym(bool _arg) - { - _is_member_meronym = _arg; - - return *this; - } - - noun_query& noun_query::member_meronym_of(const noun& _noun) - { - _member_meronym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::not_member_meronym_of(const noun& _noun) - { - _not_member_meronym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::is_member_holonym(bool _arg) - { - _is_member_holonym = _arg; - - return *this; - } - - noun_query& noun_query::member_holonym_of(const noun& _noun) - { - _member_holonym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::not_member_holonym_of(const noun& _noun) - { - _not_member_holonym_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::is_proper(bool _arg) - { - _is_proper = _arg; - - return *this; - } - - noun_query& noun_query::is_not_proper(bool _arg) - { - _is_not_proper = _arg; - - return *this; - } - - noun_query& noun_query::is_instance(bool _arg) - { - _is_instance = _arg; - - return *this; - } - - noun_query& noun_query::instance_of(const noun& _noun) - { - _instance_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::not_instance_of(const noun& _noun) - { - _not_instance_of.push_back(_noun); - - return *this; - } - - noun_query& noun_query::is_class(bool _arg) - { - _is_class = _arg; - - return *this; - } - - noun_query& noun_query::class_of(const noun& _noun) + noun_query noun::hyponyms() const { - _class_of.push_back(_noun); + assert(_valid == true); - return *this; + return _data->nouns().hyponym_of(*this); } - noun_query& noun_query::not_class_of(const noun& _noun) + noun_query noun::full_hyponyms() const { - _not_class_of.push_back(_noun); + assert(_valid == true); - return *this; + return _data->nouns().full_hyponym_of(*this); } - noun_query& noun_query::has_synonyms(bool _arg) + noun_query noun::part_meronyms() const { - _has_synonyms = _arg; + assert(_valid == true); - return *this; + return _data->nouns().part_meronym_of(*this); } - noun_query& noun_query::synonym_of(const noun& _noun) + noun_query noun::part_holonyms() const { - _synonym_of.push_back(_noun); + assert(_valid == true); - return *this; + return _data->nouns().part_holonym_of(*this); } - noun_query& noun_query::not_synonym_of(const noun& _noun) + noun_query noun::substance_meronyms() const { - _not_synonym_of.push_back(_noun); + assert(_valid == true); - return *this; + return _data->nouns().substance_meronym_of(*this); } - noun_query& noun_query::has_antonyms(bool _arg) + noun_query noun::substance_holonyms() const { - _has_antonyms = _arg; + assert(_valid == true); - return *this; + return _data->nouns().substance_holonym_of(*this); } - noun_query& noun_query::antonym_of(const noun& _noun) + noun_query noun::member_meronyms() const { - _antonym_of.push_back(_noun); + assert(_valid == true); - return *this; + return _data->nouns().member_meronym_of(*this); } - noun_query& noun_query::not_antonym_of(const noun& _noun) + noun_query noun::member_holonyms() const { - _not_antonym_of.push_back(_noun); + assert(_valid == true); - return *this; + return _data->nouns().member_holonym_of(*this); } - noun_query& noun_query::has_pertainym(bool _arg) + noun_query noun::classes() const { - _has_pertainym = _arg; + assert(_valid == true); - return *this; + return _data->nouns().class_of(*this); } - noun_query& noun_query::anti_pertainym_of(const adjective& _adj) + noun_query noun::instances() const { - _anti_pertainym_of.push_back(_adj); + assert(_valid == true); - return *this; + return _data->nouns().instance_of(*this); } - noun_query& noun_query::is_attribute(bool _arg) + noun_query noun::synonyms() const { - _is_attribute = _arg; + assert(_valid == true); - return *this; + return _data->nouns().synonym_of(*this); } - noun_query& noun_query::attribute_of(const adjective& _adj) + noun_query noun::antonyms() const { - _attribute_of.push_back(_adj); + assert(_valid == true); - return *this; + return _data->nouns().antonym_of(*this); } - noun_query& noun_query::derived_from(const word& _w) + adjective_query noun::pertainyms() const { - if (dynamic_cast(&_w) != nullptr) - { - _derived_from_adjective.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _derived_from_adverb.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _derived_from_noun.push_back(dynamic_cast(_w)); - } + assert(_valid == true); - return *this; + return _data->adjectives().pertainym_of(*this); } - noun_query& noun_query::not_derived_from(const word& _w) + adjective_query noun::variations() const { - if (dynamic_cast(&_w) != nullptr) - { - _not_derived_from_adjective.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _not_derived_from_adverb.push_back(dynamic_cast(_w)); - } else if (dynamic_cast(&_w) != nullptr) - { - _not_derived_from_noun.push_back(dynamic_cast(_w)); - } + assert(_valid == true); - return *this; + return _data->adjectives().variant_of(*this); } - std::list noun_query::run() const + bool noun::operator<(const noun& other) const { - std::stringstream construct; - construct << "SELECT noun_id, singular, plural FROM nouns"; - std::list conditions; - - if (_has_prn) - { - conditions.push_back("noun_id IN (SELECT noun_id FROM noun_pronunciations)"); - } - - if (!_rhymes.empty()) - { - std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); - std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - for (auto except : _except) - { - conditions.push_back("noun_id != @EXCID"); - } - - if (_is_hypernym) - { - conditions.push_back("noun_id IN (SELECT hypernym_id FROM hypernymy)"); - } - - if (!_hypernym_of.empty()) - { - std::list clauses(_hypernym_of.size(), "hyponym_id = @HYPO"); - std::string cond = "noun_id IN (SELECT hypernym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_hypernym_of.empty()) - { - std::list clauses(_not_hypernym_of.size(), "hyponym_id = @NHYPO"); - std::string cond = "noun_id NOT IN (SELECT hypernym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_hyponym) - { - conditions.push_back("noun_id IN (SELECT hyponym_id FROM hypernymy)"); - } - - if (!_hyponym_of.empty()) - { - std::list clauses(_hyponym_of.size(), "hypernym_id = @HYPER"); - std::string cond = "noun_id IN (SELECT hyponym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_hyponym_of.empty()) - { - std::list clauses(_not_hyponym_of.size(), "hypernym_id = @NHYPER"); - std::string cond = "noun_id NOT IN (SELECT hyponym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_part_meronym) - { - conditions.push_back("noun_id IN (SELECT meronym_id FROM part_meronymy)"); - } - - if (!_part_meronym_of.empty()) - { - std::list clauses(_part_meronym_of.size(), "holonym_id = @PHOLO"); - std::string cond = "noun_id IN (SELECT meronym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_part_meronym_of.empty()) - { - std::list clauses(_not_part_meronym_of.size(), "holonym_id = @NPHOLO"); - std::string cond = "noun_id NOT IN (SELECT meronym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_part_holonym) - { - conditions.push_back("noun_id IN (SELECT holonym_id FROM part_meronymy)"); - } - - if (!_part_holonym_of.empty()) - { - std::list clauses(_part_holonym_of.size(), "meronym_id = @PMERO"); - std::string cond = "noun_id IN (SELECT holonym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_part_holonym_of.empty()) - { - std::list clauses(_not_part_holonym_of.size(), "meronym_id = @NPMERO"); - std::string cond = "noun_id NOT IN (SELECT holonym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_substance_meronym) - { - conditions.push_back("noun_id IN (SELECT meronym_id FROM substance_meronymy)"); - } - - if (!_substance_meronym_of.empty()) - { - std::list clauses(_substance_meronym_of.size(), "holonym_id = @SHOLO"); - std::string cond = "noun_id IN (SELECT meronym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_substance_meronym_of.empty()) - { - std::list clauses(_not_substance_meronym_of.size(), "holonym_id = @NSHOLO"); - std::string cond = "noun_id NOT IN (SELECT meronym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_substance_holonym) - { - conditions.push_back("noun_id IN (SELECT holonym_id FROM substance_meronymy)"); - } - - if (!_substance_holonym_of.empty()) - { - std::list clauses(_substance_holonym_of.size(), "meronym_id = @SMERO"); - std::string cond = "noun_id IN (SELECT holonym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_substance_holonym_of.empty()) - { - std::list clauses(_not_substance_holonym_of.size(), "meronym_id = @NSMERO"); - std::string cond = "noun_id NOT IN (SELECT holonym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_member_meronym) - { - conditions.push_back("noun_id IN (SELECT meronym_id FROM member_meronymy)"); - } - - if (!_member_meronym_of.empty()) - { - std::list clauses(_member_meronym_of.size(), "holonym_id = @MHOLO"); - std::string cond = "noun_id IN (SELECT meronym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_member_meronym_of.empty()) - { - std::list clauses(_not_member_meronym_of.size(), "holonym_id = @NMHOLO"); - std::string cond = "noun_id NOT IN (SELECT meronym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_member_holonym) - { - conditions.push_back("noun_id IN (SELECT holonym_id FROM member_meronym)"); - } - - if (!_member_holonym_of.empty()) - { - std::list clauses(_member_holonym_of.size(), "meronym_id = @MMERO"); - std::string cond = "noun_id IN (SELECT holonym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_member_holonym_of.empty()) - { - std::list clauses(_not_member_holonym_of.size(), "meronym_id = @NMMERO"); - std::string cond = "noun_id NOT IN (SELECT holonym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_proper) - { - conditions.push_back("proper = 1"); - } - - if (_is_not_proper) - { - conditions.push_back("proper = 0"); - } - - if (_is_instance) - { - conditions.push_back("noun_id IN (SELECT instance_id FROM instantiation)"); - } - - if (!_instance_of.empty()) - { - std::list clauses(_instance_of.size(), "class_id = @CLSID"); - std::string cond = "noun_id IN (SELECT instance_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_instance_of.empty()) - { - std::list clauses(_not_instance_of.size(), "class_id = @NCLSID"); - std::string cond = "noun_id NOT IN (SELECT instance_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_class) - { - conditions.push_back("noun_id IN (SELECT class_id FROM instantiation)"); - } - - if (!_class_of.empty()) - { - std::list clauses(_class_of.size(), "instance_id = @INSID"); - std::string cond = "noun_id IN (SELECT class_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_class_of.empty()) - { - std::list clauses(_not_class_of.size(), "instance_id = @NINSID"); - std::string cond = "noun_id NOT IN (SELECT class_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_has_synonyms) - { - conditions.push_back("noun_id IN (SELECT adjective_2_id FROM adjective_synonymy)"); - } - - if (!_synonym_of.empty()) - { - std::list clauses(_synonym_of.size(), "adjective_1_id = @SYNID"); - std::string cond = "noun_id IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_synonym_of.empty()) - { - std::list clauses(_not_synonym_of.size(), "adjective_1_id = @NSYNID"); - std::string cond = "noun_id NOT IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_has_antonyms) - { - conditions.push_back("noun_id IN (SELECT adjective_2_id FROM adjective_antonymy)"); - } - - if (!_antonym_of.empty()) - { - std::list clauses(_antonym_of.size(), "adjective_1_id = @ANTID"); - std::string cond = "noun_id IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_antonym_of.empty()) - { - std::list clauses(_not_antonym_of.size(), "adjective_1_id = @NANTID"); - std::string cond = "noun_id NOT IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_has_pertainym) - { - conditions.push_back("noun_id IN (SELECT noun_id FROM pertainymy)"); - } - - if (!_anti_pertainym_of.empty()) - { - std::list clauses(_anti_pertainym_of.size(), "pertainym_id = @PERID"); - std::string cond = "noun_id IN (SELECT noun_id FROM pertainymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (_is_attribute) - { - conditions.push_back("noun_id IN (SELECT noun_id FROM variation)"); - } - - if (!_attribute_of.empty()) - { - std::list clauses(_attribute_of.size(), "adjective_id = @VALID"); - std::string cond = "noun_id IN (SELECT noun_id FROM variation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_derived_from_adjective.empty()) - { - std::list clauses(_derived_from_adjective.size(), "adjective_id = @DERADJ"); - std::string cond = "noun_id IN (SELECT noun_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_derived_from_adjective.empty()) - { - std::list clauses(_not_derived_from_adjective.size(), "adjective_id = @NDERADJ"); - std::string cond = "noun_id NOT IN (SELECT noun_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_derived_from_adverb.empty()) - { - std::list clauses(_derived_from_adverb.size(), "adverb_id = @DERADV"); - std::string cond = "noun_id IN (SELECT noun_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_derived_from_adverb.empty()) - { - std::list clauses(_not_derived_from_adverb.size(), "adverb_id = @NDERADV"); - std::string cond = "noun_id NOT IN (SELECT noun_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_derived_from_noun.empty()) - { - std::list clauses(_derived_from_noun.size(), "noun_2_id = @DERN"); - std::string cond = "noun_id IN (SELECT noun_1_id FROM noun_noun_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!_not_derived_from_noun.empty()) - { - std::list clauses(_not_derived_from_noun.size(), "noun_2_id = @NDERN"); - std::string cond = "noun_id NOT IN (SELECT noun_1_id FROM noun_noun_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - if (!conditions.empty()) - { - construct << " WHERE "; - construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND "); - } - - if (_random) - { - construct << " ORDER BY RANDOM()"; - } - - if (_limit != unlimited) - { - construct << " LIMIT " << _limit; - } - - sqlite3_stmt* ppstmt; - std::string query = construct.str(); - if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) - { - throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); - } - - if (!_rhymes.empty()) - { - int i = 0; - for (auto rhyme : _rhymes) - { - std::string rhymer = "%" + rhyme; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); - - i++; - } - } - - for (auto except : _except) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); - } - - for (auto hyponym : _hypernym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPO"), hyponym._id); - } - - for (auto hyponym : _not_hypernym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NHYPO"), hyponym._id); - } - - for (auto hypernym : _hyponym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPER"), hypernym._id); - } - - for (auto hypernym : _not_hyponym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NHYPER"), hypernym._id); - } - - for (auto holonym : _part_meronym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PHOLO"), holonym._id); - } - - for (auto holonym : _not_part_meronym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NPHOLO"), holonym._id); - } - - for (auto meronym : _part_holonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PMERO"), meronym._id); - } - - for (auto meronym : _not_part_holonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NPMERO"), meronym._id); - } - - for (auto holonym : _substance_meronym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SHOLO"), holonym._id); - } - - for (auto holonym : _not_substance_meronym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSHOLO"), holonym._id); - } - - for (auto meronym : _substance_holonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SMERO"), meronym._id); - } - - for (auto meronym : _not_substance_holonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSMERO"), meronym._id); - } - - for (auto holonym : _member_meronym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MHOLO"), holonym._id); - } - - for (auto holonym : _not_member_meronym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NMHOLO"), holonym._id); - } - - for (auto meronym : _member_holonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MMERO"), meronym._id); - } - - for (auto meronym : _not_member_holonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NMMERO"), meronym._id); - } - - for (auto cls : _instance_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@CLSID"), cls._id); - } - - for (auto cls : _not_instance_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NCLSID"), cls._id); - } - - for (auto inst : _class_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@INSID"), inst._id); - } - - for (auto inst : _not_class_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NINSID"), inst._id); - } - - for (auto synonym : _synonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id); - } - - for (auto synonym : _not_synonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSYNID"), synonym._id); - } - - for (auto antonym : _antonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id); - } - - for (auto antonym : _not_antonym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NANTID"), antonym._id); - } - - for (auto pertainym : _anti_pertainym_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PERID"), pertainym._id); - } - - for (auto value : _attribute_of) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@VALID"), value._id); - } - - for (auto adj : _derived_from_adjective) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADJ"), adj._id); - } - - for (auto adj : _not_derived_from_adjective) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADJ"), adj._id); - } - - for (auto adv : _derived_from_adverb) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADV"), adv._id); - } - - for (auto adv : _not_derived_from_adverb) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADV"), adv._id); - } - - for (auto n : _derived_from_noun) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERN"), n._id); - } - - for (auto n : _not_derived_from_noun) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERN"), n._id); - } - - std::list output; - while (sqlite3_step(ppstmt) == SQLITE_ROW) - { - noun tnc {_data, sqlite3_column_int(ppstmt, 0)}; - tnc._singular = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); - - if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL) - { - tnc._plural = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); - } - - output.push_back(tnc); - } - - sqlite3_finalize(ppstmt); - - for (auto& noun : output) - { - query = "SELECT pronunciation FROM noun_pronunciations WHERE noun_id = ?"; - if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) - { - throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); - } - - sqlite3_bind_int(ppstmt, 1, noun._id); - - while (sqlite3_step(ppstmt) == SQLITE_ROW) - { - std::string pronunciation(reinterpret_cast(sqlite3_column_text(ppstmt, 0))); - auto phonemes = verbly::split>(pronunciation, " "); - - noun.pronunciations.push_back(phonemes); - } - - sqlite3_finalize(ppstmt); - } - - return output; + return _id < other._id; } }; diff --git a/lib/noun.h b/lib/noun.h index fbc2f9e..77601d0 100644 --- a/lib/noun.h +++ b/lib/noun.h @@ -11,6 +11,7 @@ namespace verbly { friend class noun_query; public: + noun(); noun(const data& _data, int _id); std::string base_form() const; @@ -20,7 +21,9 @@ namespace verbly { bool has_plural_form() const; noun_query hypernyms() const; + noun_query full_hypernyms() const; noun_query hyponyms() const; + noun_query full_hyponyms() const; noun_query part_meronyms() const; noun_query part_holonyms() const; noun_query substance_meronyms() const; @@ -33,153 +36,8 @@ namespace verbly { noun_query antonyms() const; adjective_query pertainyms() const; adjective_query variations() const; - }; - - class noun_query { - public: - noun_query(const data& _data); - - noun_query& limit(int _limit); - noun_query& random(bool _random); - noun_query& except(const noun& _word); - noun_query& rhymes_with(const word& _word); - noun_query& has_pronunciation(bool _has_prn); - - noun_query& is_hypernym(bool _arg); - noun_query& hypernym_of(const noun& _noun); - noun_query& not_hypernym_of(const noun& _noun); - - noun_query& is_hyponym(bool _arg); - noun_query& hyponym_of(const noun& _noun); - noun_query& not_hyponym_of(const noun& _noun); - - noun_query& is_part_meronym(bool _arg); - noun_query& part_meronym_of(const noun& _noun); - noun_query& not_part_meronym_of(const noun& _noun); - - noun_query& is_part_holonym(bool _arg); - noun_query& part_holonym_of(const noun& _noun); - noun_query& not_part_holonym_of(const noun& _noun); - - noun_query& is_substance_meronym(bool _arg); - noun_query& substance_meronym_of(const noun& _noun); - noun_query& not_substance_meronym_of(const noun& _noun); - - noun_query& is_substance_holonym(bool _arg); - noun_query& substance_holonym_of(const noun& _noun); - noun_query& not_substance_holonym_of(const noun& _noun); - - noun_query& is_member_meronym(bool _arg); - noun_query& member_meronym_of(const noun& _noun); - noun_query& not_member_meronym_of(const noun& _noun); - - noun_query& is_member_holonym(bool _arg); - noun_query& member_holonym_of(const noun& _noun); - noun_query& not_member_holonym_of(const noun& _noun); - - noun_query& is_proper(bool _arg); - noun_query& is_not_proper(bool _arg); - - noun_query& is_instance(bool _arg); - noun_query& instance_of(const noun& _noun); - noun_query& not_instance_of(const noun& _noun); - - noun_query& is_class(bool _arg); - noun_query& class_of(const noun& _noun); - noun_query& not_class_of(const noun& _noun); - - noun_query& has_synonyms(bool _arg); - noun_query& synonym_of(const noun& _noun); - noun_query& not_synonym_of(const noun& _noun); - - noun_query& has_antonyms(bool _arg); - noun_query& antonym_of(const noun& _noun); - noun_query& not_antonym_of(const noun& _noun); - - noun_query& has_pertainym(bool _arg); - noun_query& anti_pertainym_of(const adjective& _adj); - - noun_query& is_attribute(bool _arg); - noun_query& attribute_of(const adjective& _adj); - - noun_query& derived_from(const word& _w); - noun_query& not_derived_from(const word& _w); - - std::list run() const; - - const static int unlimited = -1; - - private: - const data& _data; - int _limit = unlimited; - bool _random = false; - std::list _rhymes; - std::list _except; - bool _has_prn = false; - - bool _is_hypernym = false; - std::list _hypernym_of; - std::list _not_hypernym_of; - - bool _is_hyponym = false; - std::list _hyponym_of; - std::list _not_hyponym_of; - - bool _is_part_meronym = false; - std::list _part_meronym_of; - std::list _not_part_meronym_of; - - bool _is_substance_meronym = false; - std::list _substance_meronym_of; - std::list _not_substance_meronym_of; - - bool _is_member_meronym = false; - std::list _member_meronym_of; - std::list _not_member_meronym_of; - - bool _is_part_holonym = false; - std::list _part_holonym_of; - std::list _not_part_holonym_of; - - bool _is_substance_holonym = false; - std::list _substance_holonym_of; - std::list _not_substance_holonym_of; - - bool _is_member_holonym = false; - std::list _member_holonym_of; - std::list _not_member_holonym_of; - - bool _is_proper = false; - bool _is_not_proper = false; - - bool _is_instance = false; - std::list _instance_of; - std::list _not_instance_of; - - bool _is_class = false; - std::list _class_of; - std::list _not_class_of; - - bool _has_synonyms = false; - std::list _synonym_of; - std::list _not_synonym_of; - - bool _has_antonyms = false; - std::list _antonym_of; - std::list _not_antonym_of; - - bool _has_pertainym = false; - std::list _anti_pertainym_of; - - bool _is_attribute = false; - std::list _attribute_of; - std::list _derived_from_adjective; - std::list _not_derived_from_adjective; - std::list _derived_from_adverb; - std::list _not_derived_from_adverb; - std::list _derived_from_noun; - std::list _not_derived_from_noun; + bool operator<(const noun& other) const; }; }; diff --git a/lib/noun_query.cpp b/lib/noun_query.cpp new file mode 100644 index 0000000..cb11577 --- /dev/null +++ b/lib/noun_query.cpp @@ -0,0 +1,1453 @@ +#include "verbly.h" + +namespace verbly { + + noun_query::noun_query(const data& _data) : _data(_data) + { + + } + + noun_query& noun_query::limit(int _limit) + { + if ((_limit > 0) || (_limit == unlimited)) + { + this->_limit = _limit; + } + + return *this; + } + + noun_query& noun_query::random() + { + this->_random = true; + + return *this; + } + + noun_query& noun_query::except(const noun& _word) + { + _except.push_back(_word); + + return *this; + } + + noun_query& noun_query::rhymes_with(const word& _word) + { + for (auto rhyme : _word.rhyme_phonemes()) + { + _rhymes.push_back(rhyme); + } + + if (dynamic_cast(&_word) != nullptr) + { + _except.push_back(dynamic_cast(_word)); + } + + return *this; + } + + noun_query& noun_query::has_pronunciation() + { + this->_has_prn = true; + + return *this; + } + + noun_query& noun_query::with_singular_form(std::string _arg) + { + _with_singular_form.push_back(_arg); + + return *this; + } + + noun_query& noun_query::is_hypernym() + { + _is_hypernym = true; + + return *this; + } + + noun_query& noun_query::hypernym_of(filter _f) + { + _f.clean(); + _hypernym_of = _f; + + return *this; + } + + noun_query& noun_query::full_hypernym_of(filter _f) + { + _f.clean(); + _full_hypernym_of = _f; + + return *this; + } + + noun_query& noun_query::is_hyponym() + { + _is_hyponym = true; + + return *this; + } + + noun_query& noun_query::hyponym_of(filter _f) + { + _f.clean(); + _hyponym_of = _f; + + return *this; + } + + noun_query& noun_query::full_hyponym_of(filter _f) + { + _f.clean(); + _full_hyponym_of = _f; + + return *this; + } + + noun_query& noun_query::is_part_meronym() + { + _is_part_meronym = true; + + return *this; + } + + noun_query& noun_query::part_meronym_of(filter _f) + { + _f.clean(); + _part_meronym_of = _f; + + return *this; + } + + noun_query& noun_query::is_part_holonym() + { + _is_part_holonym = true; + + return *this; + } + + noun_query& noun_query::part_holonym_of(filter _f) + { + _f.clean(); + _part_holonym_of = _f; + + return *this; + } + + noun_query& noun_query::is_substance_meronym() + { + _is_substance_meronym = true; + + return *this; + } + + noun_query& noun_query::substance_meronym_of(filter _f) + { + _f.clean(); + _substance_meronym_of = _f; + + return *this; + } + + noun_query& noun_query::is_substance_holonym() + { + _is_substance_holonym = true; + + return *this; + } + + noun_query& noun_query::substance_holonym_of(filter _f) + { + _f.clean(); + _substance_holonym_of = _f; + + return *this; + } + + noun_query& noun_query::is_member_meronym() + { + _is_member_meronym = true; + + return *this; + } + + noun_query& noun_query::member_meronym_of(filter _f) + { + _f.clean(); + _member_meronym_of = _f; + + return *this; + } + + noun_query& noun_query::is_member_holonym() + { + _is_member_holonym = true; + + return *this; + } + + noun_query& noun_query::member_holonym_of(filter _f) + { + _f.clean(); + _member_holonym_of = _f; + + return *this; + } + + noun_query& noun_query::is_proper() + { + _is_proper = true; + + return *this; + } + + noun_query& noun_query::is_not_proper() + { + _is_not_proper = true; + + return *this; + } + + noun_query& noun_query::is_instance() + { + _is_instance = true; + + return *this; + } + + noun_query& noun_query::instance_of(filter _f) + { + _f.clean(); + _instance_of = _f; + + return *this; + } + + noun_query& noun_query::is_class() + { + _is_class = true; + + return *this; + } + + noun_query& noun_query::class_of(filter _f) + { + _f.clean(); + _class_of = _f; + + return *this; + } + + noun_query& noun_query::has_synonyms() + { + _has_synonyms = true; + + return *this; + } + + noun_query& noun_query::synonym_of(filter _f) + { + _f.clean(); + _synonym_of = _f; + + return *this; + } + + noun_query& noun_query::has_antonyms() + { + _has_antonyms = true; + + return *this; + } + + noun_query& noun_query::antonym_of(filter _f) + { + _f.clean(); + _antonym_of = _f; + + return *this; + } + + noun_query& noun_query::has_pertainym() + { + _has_pertainym = true; + + return *this; + } + + noun_query& noun_query::anti_pertainym_of(filter _f) + { + _f.clean(); + _anti_pertainym_of = _f; + + return *this; + } + + noun_query& noun_query::is_attribute() + { + _is_attribute = true; + + return *this; + } + + noun_query& noun_query::attribute_of(filter _f) + { + _f.clean(); + _attribute_of = _f; + + return *this; + } + /* + noun_query& noun_query::derived_from(const word& _w) + { + if (dynamic_cast(&_w) != nullptr) + { + _derived_from_adjective.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _derived_from_adverb.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _derived_from_noun.push_back(dynamic_cast(_w)); + } + + return *this; + } + + noun_query& noun_query::not_derived_from(const word& _w) + { + if (dynamic_cast(&_w) != nullptr) + { + _not_derived_from_adjective.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _not_derived_from_adverb.push_back(dynamic_cast(_w)); + } else if (dynamic_cast(&_w) != nullptr) + { + _not_derived_from_noun.push_back(dynamic_cast(_w)); + } + + return *this; + }*/ + + std::list noun_query::run() const + { + std::stringstream construct; + + if (!_full_hypernym_of.empty() || !_full_hyponym_of.empty()) + { + construct << "WITH RECURSIVE "; + + std::list ctes; + + for (auto hyponym : _full_hypernym_of.uniq_flatten()) + { + ctes.push_back("hypernym_tree_" + std::to_string(hyponym._id) + " AS (SELECT hypernym_id FROM hypernymy WHERE hyponym_id = " + std::to_string(hyponym._id) + " UNION SELECT h.hypernym_id FROM hypernym_tree_" + std::to_string(hyponym._id) + " AS t INNER JOIN hypernymy AS h ON t.hypernym_id = h.hyponym_id)"); + } + + for (auto hypernym : _full_hyponym_of.uniq_flatten()) + { + ctes.push_back("hyponym_tree_" + std::to_string(hypernym._id) + " AS (SELECT hyponym_id FROM hypernymy WHERE hypernym_id = " + std::to_string(hypernym._id) + " UNION SELECT h.hyponym_id FROM hyponym_tree_" + std::to_string(hypernym._id) + " AS t INNER JOIN hypernymy AS h ON t.hyponym_id = h.hypernym_id)"); + } + + construct << verbly::implode(std::begin(ctes), std::end(ctes), ", "); + construct << " "; + } + + construct << "SELECT noun_id, singular, plural FROM nouns"; + std::list conditions; + + if (_has_prn) + { + conditions.push_back("noun_id IN (SELECT noun_id FROM noun_pronunciations)"); + } + + if (!_rhymes.empty()) + { + std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); + std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + for (auto except : _except) + { + conditions.push_back("noun_id != @EXCID"); + } + + if (!_with_singular_form.empty()) + { + std::list clauses(_with_singular_form.size(), "singular = @SFORM"); + std::string cond = "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (_is_hypernym) + { + conditions.push_back("noun_id IN (SELECT hypernym_id FROM hypernymy)"); + } + + if (!_hypernym_of.empty()) + { + std::stringstream cond; + if (_hypernym_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT hypernym_id FROM hypernymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "hyponym_id = @HYPO"; + } else { + return "hyponym_id != @HYPO"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_hypernym_of, _hypernym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (!_full_hypernym_of.empty()) + { + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "noun_id IN (SELECT hypernym_id FROM hypernym_tree_" + std::to_string(f.get_elem()._id) + ")"; + } else { + return "noun_id NOT IN (SELECT hypernym_id FROM hypernym_tree_" + std::to_string(f.get_elem()._id) + ")"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + conditions.push_back(recur(_full_hypernym_of, false)); + } + + if (!_full_hyponym_of.empty()) + { + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "noun_id IN (SELECT hyponym_id FROM hyponym_tree_" + std::to_string(f.get_elem()._id) + ")"; + } else { + return "noun_id NOT IN (SELECT hyponym_id FROM hyponym_tree_" + std::to_string(f.get_elem()._id) + ")"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + conditions.push_back(recur(_full_hyponym_of, false)); + } + + if (_is_hyponym) + { + conditions.push_back("noun_id IN (SELECT hyponym_id FROM hypernymy)"); + } + + if (!_hyponym_of.empty()) + { + std::stringstream cond; + if (_hyponym_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT hyponym_id FROM hypernymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "hypernym_id = @HYPER"; + } else { + return "hypernym_id != @HYPER"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_hyponym_of, _hyponym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_part_meronym) + { + conditions.push_back("noun_id IN (SELECT meronym_id FROM part_meronymy)"); + } + + if (!_part_meronym_of.empty()) + { + std::stringstream cond; + if (_part_meronym_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT meronym_id FROM part_meronymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "holonym_id = @PHOLO"; + } else { + return "holonym_id != @PHOLO"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_part_meronym_of, _part_meronym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_part_holonym) + { + conditions.push_back("noun_id IN (SELECT holonym_id FROM part_meronymy)"); + } + + if (!_part_holonym_of.empty()) + { + std::stringstream cond; + if (_part_holonym_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT holonym_id FROM part_meronymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "meronym_id = @PMERO"; + } else { + return "meronym_id != @PMERO"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_part_holonym_of, _part_holonym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_substance_meronym) + { + conditions.push_back("noun_id IN (SELECT meronym_id FROM substance_meronymy)"); + } + + if (!_substance_meronym_of.empty()) + { + std::stringstream cond; + if (_substance_meronym_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT meronym_id FROM substance_meronymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "holonym_id = @SHOLO"; + } else { + return "holonym_id != @SHOLO"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_substance_meronym_of, _substance_meronym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_substance_holonym) + { + conditions.push_back("noun_id IN (SELECT holonym_id FROM substance_meronymy)"); + } + + if (!_substance_holonym_of.empty()) + { + std::stringstream cond; + if (_substance_holonym_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT holonym_id FROM substance_meronymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "meronym_id = @SMERO"; + } else { + return "meronym_id != @SMERO"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_substance_holonym_of, _substance_holonym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_member_meronym) + { + conditions.push_back("noun_id IN (SELECT meronym_id FROM member_meronymy)"); + } + + if (!_member_meronym_of.empty()) + { + std::stringstream cond; + if (_member_meronym_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT meronym_id FROM member_meronymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "holonym_id = @MHOLO"; + } else { + return "holonym_id != @MHOLO"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_member_meronym_of, _member_meronym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_member_holonym) + { + conditions.push_back("noun_id IN (SELECT holonym_id FROM member_meronym)"); + } + + if (!_member_holonym_of.empty()) + { + std::stringstream cond; + if (_member_holonym_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT holonym_id FROM member_meronymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "meronym_id = @MMERO"; + } else { + return "meronym_id != @MMERO"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_member_holonym_of, _member_holonym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_proper) + { + conditions.push_back("proper = 1"); + } + + if (_is_not_proper) + { + conditions.push_back("proper = 0"); + } + + if (_is_instance) + { + conditions.push_back("noun_id IN (SELECT instance_id FROM instantiation)"); + } + + if (!_instance_of.empty()) + { + std::stringstream cond; + if (_instance_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT instance_id FROM instantiation WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "class_id = @CLSID"; + } else { + return "class_id != @CLSID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_instance_of, _instance_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_class) + { + conditions.push_back("noun_id IN (SELECT class_id FROM instantiation)"); + } + + if (!_class_of.empty()) + { + std::stringstream cond; + if (_class_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT class_id FROM instantiation WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "instance_id = @INSID"; + } else { + return "instance_id != @INSID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_class_of, _class_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_has_synonyms) + { + conditions.push_back("noun_id IN (SELECT noun_2_id FROM noun_synonymy)"); + } + + if (!_synonym_of.empty()) + { + std::stringstream cond; + if (_synonym_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT noun_2_id FROM noun_synonymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "noun_1_id = @SYNID"; + } else { + return "noun_1_id != @SYNID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_synonym_of, _synonym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_has_antonyms) + { + conditions.push_back("noun_id IN (SELECT noun_2_id FROM noun_antonymy)"); + } + + if (!_antonym_of.empty()) + { + std::stringstream cond; + if (_antonym_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT noun_2_id FROM noun_antonymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "noun_1_id = @ANTID"; + } else { + return "noun_1_id != @ANTID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_antonym_of, _antonym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_has_pertainym) + { + conditions.push_back("noun_id IN (SELECT noun_id FROM pertainymy)"); + } + + if (!_anti_pertainym_of.empty()) + { + std::stringstream cond; + if (_anti_pertainym_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT noun_id FROM pertainymy WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "pertainym_id = @PERID"; + } else { + return "pertainym_id != @PERID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_anti_pertainym_of, _anti_pertainym_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + + if (_is_attribute) + { + conditions.push_back("noun_id IN (SELECT noun_id FROM variation)"); + } + + if (!_attribute_of.empty()) + { + std::stringstream cond; + if (_attribute_of.get_notlogic()) + { + cond << "noun_id NOT IN"; + } else { + cond << "noun_id IN"; + } + + cond << "(SELECT noun_id FROM variation WHERE "; + + std::function, bool)> recur = [&] (filter f, bool notlogic) -> std::string { + switch (f.get_type()) + { + case filter::type::singleton: + { + if (notlogic == f.get_notlogic()) + { + return "adjective_id = @VALID"; + } else { + return "adjective_id != @VALID"; + } + } + + case filter::type::group: + { + bool truelogic = notlogic != f.get_notlogic(); + + std::list clauses; + std::transform(std::begin(f), std::end(f), std::back_inserter(clauses), [&] (filter f2) { + return recur(f2, truelogic); + }); + + if (truelogic == f.get_orlogic()) + { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " AND ") + ")"; + } else { + return "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + } + } + } + }; + + cond << recur(_attribute_of, _attribute_of.get_notlogic()); + cond << ")"; + conditions.push_back(cond.str()); + } + /* + if (!_derived_from_adjective.empty()) + { + std::list clauses(_derived_from_adjective.size(), "adjective_id = @DERADJ"); + std::string cond = "noun_id IN (SELECT noun_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_not_derived_from_adjective.empty()) + { + std::list clauses(_not_derived_from_adjective.size(), "adjective_id = @NDERADJ"); + std::string cond = "noun_id NOT IN (SELECT noun_id FROM noun_adjective_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_derived_from_adverb.empty()) + { + std::list clauses(_derived_from_adverb.size(), "adverb_id = @DERADV"); + std::string cond = "noun_id IN (SELECT noun_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_not_derived_from_adverb.empty()) + { + std::list clauses(_not_derived_from_adverb.size(), "adverb_id = @NDERADV"); + std::string cond = "noun_id NOT IN (SELECT noun_id FROM noun_adverb_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_derived_from_noun.empty()) + { + std::list clauses(_derived_from_noun.size(), "noun_2_id = @DERN"); + std::string cond = "noun_id IN (SELECT noun_1_id FROM noun_noun_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + if (!_not_derived_from_noun.empty()) + { + std::list clauses(_not_derived_from_noun.size(), "noun_2_id = @NDERN"); + std::string cond = "noun_id NOT IN (SELECT noun_1_id FROM noun_noun_derivation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + */ + if (!conditions.empty()) + { + construct << " WHERE "; + construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND "); + } + + if (_random) + { + construct << " ORDER BY RANDOM()"; + } + + if (_limit != unlimited) + { + construct << " LIMIT " << _limit; + } + + sqlite3_stmt* ppstmt; + std::string query = construct.str(); + if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); + } + + if (!_rhymes.empty()) + { + int i = 0; + for (auto rhyme : _rhymes) + { + std::string rhymer = "%" + rhyme; + sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); + + i++; + } + } + + for (auto except : _except) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); + } + + for (auto sform : _with_singular_form) + { + sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SFORM"), sform.c_str(), sform.size(), SQLITE_STATIC); + } + + for (auto hyponym : _hypernym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPO"), hyponym._id); + } + + for (auto hypernym : _hyponym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPER"), hypernym._id); + } + + for (auto holonym : _part_meronym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PHOLO"), holonym._id); + } + + for (auto meronym : _part_holonym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PMERO"), meronym._id); + } + + for (auto holonym : _substance_meronym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SHOLO"), holonym._id); + } + + for (auto meronym : _substance_holonym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SMERO"), meronym._id); + } + + for (auto holonym : _member_meronym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MHOLO"), holonym._id); + } + + for (auto meronym : _member_holonym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MMERO"), meronym._id); + } + + for (auto cls : _instance_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@CLSID"), cls._id); + } + + for (auto inst : _class_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@INSID"), inst._id); + } + + for (auto synonym : _synonym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id); + } + + for (auto antonym : _antonym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id); + } + + for (auto pertainym : _anti_pertainym_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PERID"), pertainym._id); + } + + for (auto value : _attribute_of.inorder_flatten()) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@VALID"), value._id); + } + /* + for (auto adj : _derived_from_adjective) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADJ"), adj._id); + } + + for (auto adj : _not_derived_from_adjective) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADJ"), adj._id); + } + + for (auto adv : _derived_from_adverb) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERADV"), adv._id); + } + + for (auto adv : _not_derived_from_adverb) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERADV"), adv._id); + } + + for (auto n : _derived_from_noun) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@DERN"), n._id); + } + + for (auto n : _not_derived_from_noun) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NDERN"), n._id); + } +*/ + std::list output; + while (sqlite3_step(ppstmt) == SQLITE_ROW) + { + noun tnc {_data, sqlite3_column_int(ppstmt, 0)}; + tnc._singular = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); + + if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL) + { + tnc._plural = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); + } + + output.push_back(tnc); + } + + sqlite3_finalize(ppstmt); + + for (auto& noun : output) + { + query = "SELECT pronunciation FROM noun_pronunciations WHERE noun_id = ?"; + if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); + } + + sqlite3_bind_int(ppstmt, 1, noun._id); + + while (sqlite3_step(ppstmt) == SQLITE_ROW) + { + std::string pronunciation(reinterpret_cast(sqlite3_column_text(ppstmt, 0))); + auto phonemes = verbly::split>(pronunciation, " "); + + noun.pronunciations.push_back(phonemes); + } + + sqlite3_finalize(ppstmt); + } + + return output; + } + +}; diff --git a/lib/noun_query.h b/lib/noun_query.h new file mode 100644 index 0000000..0c41a68 --- /dev/null +++ b/lib/noun_query.h @@ -0,0 +1,139 @@ +#ifndef NOUN_QUERY_H_5DE51DD7 +#define NOUN_QUERY_H_5DE51DD7 + +namespace verbly { + + class noun_query { + public: + noun_query(const data& _data); + + noun_query& limit(int _limit); + noun_query& random(); + noun_query& except(const noun& _word); + noun_query& rhymes_with(const word& _word); + noun_query& has_pronunciation(); + + noun_query& with_singular_form(std::string _arg); + + noun_query& is_hypernym(); + noun_query& hypernym_of(filter _f); + noun_query& full_hypernym_of(filter _f); + + noun_query& is_hyponym(); + noun_query& hyponym_of(filter _f); + noun_query& full_hyponym_of(filter _f); + + noun_query& is_part_meronym(); + noun_query& part_meronym_of(filter _f); + + noun_query& is_part_holonym(); + noun_query& part_holonym_of(filter _f); + + noun_query& is_substance_meronym(); + noun_query& substance_meronym_of(filter _f); + + noun_query& is_substance_holonym(); + noun_query& substance_holonym_of(filter _f); + + noun_query& is_member_meronym(); + noun_query& member_meronym_of(filter _f); + + noun_query& is_member_holonym(); + noun_query& member_holonym_of(filter _f); + + noun_query& is_proper(); + noun_query& is_not_proper(); + + noun_query& is_instance(); + noun_query& instance_of(filter _f); + + noun_query& is_class(); + noun_query& class_of(filter _f); + + noun_query& has_synonyms(); + noun_query& synonym_of(filter _f); + + noun_query& has_antonyms(); + noun_query& antonym_of(filter _f); + + noun_query& has_pertainym(); + noun_query& anti_pertainym_of(filter _f); + + noun_query& is_attribute(); + noun_query& attribute_of(filter _f); + +/* noun_query& derived_from(const word& _w); + noun_query& not_derived_from(const word& _w);*/ + + std::list run() const; + + const static int unlimited = -1; + + private: + const data& _data; + int _limit = unlimited; + bool _random = false; + std::list _rhymes; + std::list _except; + bool _has_prn = false; + + std::list _with_singular_form; + + bool _is_hypernym = false; + filter _hypernym_of; + filter _full_hypernym_of; + + bool _is_hyponym = false; + filter _hyponym_of; + filter _full_hyponym_of; + + bool _is_part_meronym = false; + filter _part_meronym_of; + + bool _is_substance_meronym = false; + filter _substance_meronym_of; + + bool _is_member_meronym = false; + filter _member_meronym_of; + + bool _is_part_holonym = false; + filter _part_holonym_of; + + bool _is_substance_holonym = false; + filter _substance_holonym_of; + + bool _is_member_holonym = false; + filter _member_holonym_of; + + bool _is_proper = false; + bool _is_not_proper = false; + + bool _is_instance = false; + filter _instance_of; + + bool _is_class = false; + filter _class_of; + + bool _has_synonyms = false; + filter _synonym_of; + + bool _has_antonyms = false; + filter _antonym_of; + + bool _has_pertainym = false; + filter _anti_pertainym_of; + + bool _is_attribute = false; + filter _attribute_of; + +/* std::list _derived_from_adjective; + std::list _not_derived_from_adjective; + std::list _derived_from_adverb; + std::list _not_derived_from_adverb; + std::list _derived_from_noun; + std::list _not_derived_from_noun;*/ + }; + +}; + +#endif /* end of include guard: NOUN_QUERY_H_5DE51DD7 */ diff --git a/lib/preposition.cpp b/lib/preposition.cpp new file mode 100644 index 0000000..c619bbf --- /dev/null +++ b/lib/preposition.cpp @@ -0,0 +1,83 @@ +#include "verbly.h" + +namespace verbly { + + std::string preposition::get_form() const + { + return form; + } + + preposition_query::preposition_query(const data& _data) : _data(_data) + { + + } + + preposition_query& preposition_query::limit(int _limit) + { + this->_limit = _limit; + + return *this; + } + + preposition_query& preposition_query::random() + { + _random = true; + + return *this; + } + + preposition_query& preposition_query::in_group(std::string _arg) + { + _in_group.push_back(_arg); + + return *this; + } + + std::list preposition_query::run() const + { + std::stringstream construct; + construct << "SELECT form FROM prepositions"; + + if (!_in_group.empty()) + { + std::list clauses(_in_group.size(), "groupname = @GNAME"); + construct << " WHERE preposition_id IN (SELECT preposition_id FROM preposition_groups WHERE "; + construct << verbly::implode(std::begin(clauses), std::end(clauses), " OR "); + construct << ")"; + } + + if (_random) + { + construct << " ORDER BY RANDOM()"; + } + + if (_limit != unlimited) + { + construct << " LIMIT " << _limit; + } + + sqlite3_stmt* ppstmt; + std::string query = construct.str(); + if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); + } + + for (auto& group : _in_group) + { + sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@GNAME"), group.c_str(), group.length(), SQLITE_STATIC); + } + + std::list output; + while (sqlite3_step(ppstmt) == SQLITE_ROW) + { + preposition pp; + pp.form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 0))); + + output.push_back(pp); + } + + return output; + } + +}; diff --git a/lib/preposition.h b/lib/preposition.h new file mode 100644 index 0000000..89f24fa --- /dev/null +++ b/lib/preposition.h @@ -0,0 +1,38 @@ +#ifndef PREPOSITION_H_FF908021 +#define PREPOSITION_H_FF908021 + +namespace verbly { + + class preposition_query; + + class preposition { + public: + std::string get_form() const; + + private: + friend class preposition_query; + + std::string form; + }; + + class preposition_query { + public: + preposition_query(const data& _data); + + preposition_query& limit(int _limit); + preposition_query& random(); + preposition_query& in_group(std::string _arg); + + std::list run() const; + + const static int unlimited = -1; + private: + const data& _data; + int _limit = unlimited; + bool _random = false; + std::list _in_group; + }; + +}; + +#endif /* end of include guard: PREPOSITION_H_FF908021 */ diff --git a/lib/token.cpp b/lib/token.cpp index facab8a..1e25acb 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -2,52 +2,627 @@ namespace verbly { - token::token(token::type _type) : _type(_type) + token::type token::get_type() const { - + return _type; } - token::type token::token_type() const + int token::get_extra() const { - return _type; + return _extra; } - verb_token::verb_token(const verb& _verb) : token(token::type::verb), _verb(&_verb) + void token::set_extra(int _arg) { - + _extra = _arg; } - const verb& verb_token::get_verb() const + token::token(const token& other) { - return *_verb; + _type = other._type; + + switch (_type) + { + case token::type::verb: + { + new(&_verb._verb) verb(other._verb._verb); + _verb._infl = other._verb._infl; + + break; + } + + case token::type::noun: + { + new(&_noun._noun) noun(other._noun._noun); + _noun._infl = other._noun._infl; + + break; + } + + case token::type::adjective: + { + new(&_adjective._adjective) adjective(other._adjective._adjective); + _adjective._infl = other._adjective._infl; + + break; + } + + case token::type::adverb: + { + new(&_adverb._adverb) adverb(other._adverb._adverb); + _adverb._infl = other._adverb._infl; + + break; + } + + case token::type::preposition: + { + new(&_preposition._preposition) preposition(other._preposition._preposition); + + break; + } + + case token::type::fillin: + { + _fillin._type = other._fillin._type; + + break; + } + + case token::type::string: + { + new(&_string._str) std::string(other._string._str); + + break; + } + + case token::type::utterance: + { + new(&_utterance._utterance) std::list(other._utterance._utterance); + + break; + } + } } - verb_token& verb_token::inflect(verb_token::inflection infl) + token& token::operator=(const token& other) { - _inflection = infl; + this->~token(); + + _type = other._type; + + switch (_type) + { + case token::type::verb: + { + new(&_verb._verb) verb(other._verb._verb); + _verb._infl = other._verb._infl; + + break; + } + + case token::type::noun: + { + new(&_noun._noun) noun(other._noun._noun); + _noun._infl = other._noun._infl; + + break; + } + + case token::type::adjective: + { + new(&_adjective._adjective) adjective(other._adjective._adjective); + _adjective._infl = other._adjective._infl; + + break; + } + + case token::type::adverb: + { + new(&_adverb._adverb) adverb(other._adverb._adverb); + _adverb._infl = other._adverb._infl; + + break; + } + + case token::type::preposition: + { + new(&_preposition._preposition) preposition(other._preposition._preposition); + + break; + } + + case token::type::fillin: + { + _fillin._type = other._fillin._type; + + break; + } + + case token::type::string: + { + new(&_string._str) std::string(other._string._str); + + break; + } + + case token::type::utterance: + { + new(&_utterance._utterance) std::list(other._utterance._utterance); + + break; + } + } + return *this; } - bool verb_token::complete() const + token::~token() { - return true; + switch (_type) + { + case token::type::verb: + { + _verb._verb.~verb(); + + break; + } + + case token::type::noun: + { + _noun._noun.~noun(); + + break; + } + + case token::type::adjective: + { + _adjective._adjective.~adjective(); + + break; + } + + case token::type::adverb: + { + _adverb._adverb.~adverb(); + + break; + } + + case token::type::preposition: + { + _preposition._preposition.~preposition(); + + break; + } + + case token::type::fillin: + { + // Nothing! + + break; + } + + case token::type::string: + { + using string_type = std::string; + _string._str.~string_type(); + + break; + } + + case token::type::utterance: + { + using list_type = std::list; + _utterance._utterance.~list_type(); + + break; + } + } } - std::string verb_token::compile() const + bool token::is_complete() const { - switch (_inflection) + if (_type == token::type::utterance) { - case inflection::infinitive: return _verb->infinitive_form(); - case inflection::past_tense: return _verb->past_tense_form(); - case inflection::past_participle: return _verb->past_participle_form(); - case inflection::ing_form: return _verb->ing_form(); - case inflection::s_form: return _verb->s_form(); + return std::all_of(std::begin(_utterance._utterance), std::end(_utterance._utterance), [] (const token& tkn) { + return tkn.is_complete(); + }); + } else if (_type == token::type::fillin) + { + return false; + } else { + return true; } } - token* verb_token::copy() const + std::string token::compile() const + { + switch (_type) + { + case token::type::verb: + { + switch (_verb._infl) + { + case token::verb_inflection::infinitive: return _verb._verb.infinitive_form(); + case token::verb_inflection::past_tense: return _verb._verb.past_tense_form(); + case token::verb_inflection::past_participle: return _verb._verb.past_participle_form(); + case token::verb_inflection::ing_form: return _verb._verb.ing_form(); + case token::verb_inflection::s_form: return _verb._verb.s_form(); + } + } + + case token::type::noun: + { + switch (_noun._infl) + { + case token::noun_inflection::singular: return _noun._noun.singular_form(); + case token::noun_inflection::plural: return _noun._noun.plural_form(); + } + } + + case token::type::adjective: + { + switch (_adjective._infl) + { + case token::adjective_inflection::base: return _adjective._adjective.base_form(); + case token::adjective_inflection::comparative: return _adjective._adjective.comparative_form(); + case token::adjective_inflection::superlative: return _adjective._adjective.superlative_form(); + } + } + + case token::type::adverb: + { + switch (_adverb._infl) + { + case token::adverb_inflection::base: return _adverb._adverb.base_form(); + case token::adverb_inflection::comparative: return _adverb._adverb.comparative_form(); + case token::adverb_inflection::superlative: return _adverb._adverb.superlative_form(); + } + } + + case token::type::preposition: return _preposition._preposition.get_form(); + case token::type::string: return _string._str; + + case token::type::fillin: + { + throw std::runtime_error("Cannot compile a fillin token."); + } + + case token::type::utterance: + { + std::list compiled; + std::transform(std::begin(_utterance._utterance), std::end(_utterance._utterance), std::back_inserter(compiled), [] (token tkn) { + return tkn.compile(); + }); + + return verbly::implode(std::begin(compiled), std::end(compiled), " "); + } + } + } + + token::token(verb _verb) : _type(type::verb) + { + new(&this->_verb._verb) verb(_verb); + this->_verb._infl = verb_inflection::infinitive; + } + + token::token(verb _verb, verb_inflection _infl) : token(_verb) + { + this->_verb._infl = _infl; + } + + token& token::operator=(verb _verb) + { + *this = token{_verb}; + + return *this; + } + + verb token::get_verb() const + { + assert(_type == type::verb); + + return _verb._verb; + } + + void token::set_verb(verb _verb) + { + assert(_type == type::verb); + + this->_verb._verb = _verb; + } + + token::verb_inflection token::get_verb_inflection() const + { + assert(_type == type::verb); + + return _verb._infl; + } + + void token::set_verb_inflection(verb_inflection _infl) + { + assert(_type == type::verb); + + _verb._infl = _infl; + } + + token::token(noun _noun) : _type(type::noun) + { + new(&this->_noun._noun) noun(_noun); + this->_noun._infl = noun_inflection::singular; + } + + token::token(noun _noun, noun_inflection _infl) : token(_noun) + { + this->_noun._infl = _infl; + } + + token& token::operator=(noun _noun) { - return new verb_token(*this); + *this = token{_noun}; + + return *this; + } + + noun token::get_noun() const + { + assert(_type == type::noun); + + return _noun._noun; + } + + void token::set_noun(noun _noun) + { + assert(_type == type::noun); + + this->_noun._noun = _noun; + } + + token::noun_inflection token::get_noun_inflection() const + { + assert(_type == type::noun); + + return _noun._infl; + } + + void token::set_noun_inflection(noun_inflection _infl) + { + assert(_type == type::noun); + + _noun._infl = _infl; + } + + token::token(adjective _adjective) : _type(type::adjective) + { + new(&this->_adjective._adjective) adjective(_adjective); + this->_adjective._infl = adjective_inflection::base; + } + + token::token(adjective _adjective, adjective_inflection _infl) : token(_adjective) + { + this->_adjective._infl = _infl; + } + + token& token::operator=(adjective _adjective) + { + *this = token{_adjective}; + + return *this; + } + + adjective token::get_adjective() const + { + assert(_type == type::adjective); + + return _adjective._adjective; + } + + void token::set_adjective(adjective _adjective) + { + assert(_type == type::adjective); + + this->_adjective._adjective = _adjective; + } + + token::adjective_inflection token::get_adjective_inflection() const + { + assert(_type == type::adjective); + + return _adjective._infl; + } + + void token::set_adjective_inflection(adjective_inflection _infl) + { + assert(_type == type::adjective); + + _adjective._infl = _infl; + } + + token::token(adverb _adverb) : _type(type::adverb) + { + new(&this->_adverb._adverb) adverb(_adverb); + this->_adverb._infl = adverb_inflection::base; + } + + token::token(adverb _adverb, adverb_inflection _infl) : token(_adverb) + { + this->_adverb._infl = _infl; + } + + token& token::operator=(adverb _adverb) + { + *this = token{_adverb}; + + return *this; + } + + adverb token::get_adverb() const + { + assert(_type == type::adverb); + + return _adverb._adverb; + } + + void token::set_adverb(adverb _adverb) + { + assert(_type == type::adverb); + + this->_adverb._adverb = _adverb; + } + + token::adverb_inflection token::get_adverb_inflection() const + { + assert(_type == type::adverb); + + return _adverb._infl; + } + + void token::set_adverb_inflection(adverb_inflection _infl) + { + assert(_type == type::adverb); + + _adverb._infl = _infl; + } + + token::token(preposition _preposition) : _type(type::preposition) + { + new(&this->_preposition._preposition) preposition(_preposition); + } + + token& token::operator=(preposition _preposition) + { + *this = token{_preposition}; + + return *this; + } + + preposition token::get_preposition() const + { + assert(_type == type::preposition); + + return _preposition._preposition; + } + + void token::set_preposition(preposition _preposition) + { + assert(_type == type::preposition); + + this->_preposition._preposition = _preposition; + } + + token::token(fillin_type _ft) : _type(type::fillin) + { + _fillin._type = _ft; + } + + token& token::operator=(fillin_type _ft) + { + *this = token{_ft}; + + return *this; + } + + token::fillin_type token::get_fillin_type() const + { + assert(_type == type::fillin); + + return _fillin._type; + } + + void token::set_fillin_type(fillin_type _ft) + { + assert(_type == type::fillin); + + _fillin._type = _ft; + } + + token::token() : _type(type::utterance) + { + new(&_utterance._utterance) std::list(); + } + + token::token(std::initializer_list _init) : _type(type::utterance) + { + new(&_utterance._utterance) std::list(_init); + } + + token::iterator token::begin() + { + assert(_type == type::utterance); + + return _utterance._utterance.begin(); + } + + token::iterator token::end() + { + assert(_type == type::utterance); + + return _utterance._utterance.end(); + } + + token& token::operator<<(token _tkn) + { + assert(_type == type::utterance); + + _utterance._utterance.push_back(_tkn); + + return *this; + } + + void token::push_back(token _tkn) + { + assert(_type == type::utterance); + + _utterance._utterance.push_back(_tkn); + } + + void token::insert(iterator before, token _tkn) + { + assert(_type == type::utterance); + + _utterance._utterance.insert(before, _tkn); + } + + void token::replace(iterator torepl, token _tkn) + { + assert(_type == type::utterance); + + _utterance._utterance.insert(torepl, _tkn); + _utterance._utterance.erase(torepl); + } + + void token::erase(iterator toer) + { + assert(_type == type::utterance); + + _utterance._utterance.erase(toer); + } + + token::token(std::string _str) : _type(type::string) + { + new(&_string._str) std::string(_str); + } + + token& token::operator=(std::string _str) + { + *this = token{_str}; + + return *this; + } + + std::string token::get_string() const + { + assert(_type == type::string); + + return _string._str; + } + + void token::set_string(std::string _str) + { + assert(_type == type::string); + + _string._str = _str; } }; diff --git a/lib/token.h b/lib/token.h index b22032b..788a106 100644 --- a/lib/token.h +++ b/lib/token.h @@ -1,314 +1,169 @@ #ifndef TOKEN_H_AD62C505 #define TOKEN_H_AD62C505 -#include -#include -#include -#include - namespace verbly { - class verb; - - class selrestr { - }; - - class synrestr { - }; - - enum class fillin_type { - noun_phrase, - participle_phrase, - adjective, - adverb - }; - class token { public: enum class type { verb, + noun, + adjective, + adverb, + preposition, fillin, - string, - utterance + utterance, + string }; - protected: - // General - type _type; - - token(type _type); - - public: - enum type token_type() const; - - virtual bool complete() const = 0; - virtual std::string compile() const = 0; - virtual token* copy() const = 0; - }; - - class verb_token : public token { - public: - enum class inflection { + enum class verb_inflection { infinitive, past_tense, past_participle, - ing_form, - s_form + s_form, + ing_form }; - private: - // Verb - const verb* _verb; - inflection _inflection = inflection::infinitive; - - public: - verb_token(const verb& _verb); - - const verb& get_verb() const; - - verb_token& inflect(inflection infl); - - bool complete() const; - - std::string compile() const; - - token* copy() const; - }; - - class utterance_token : public token { - private: - // Utterance - std::list> utterance; - - public: - typedef std::list>::iterator iterator; - /*class iterator { - private: - friend class utterance_token; - - std::list>::iterator it; - - public: - iterator(std::list>::iterator it) : it(it) - { - - } - - iterator& operator++() - { - ++it; - return *this; - } - - iterator& operator--() - { - --it; - return *this; - } - - bool operator==(const iterator& other) const - { - return it == other.it; - } - - bool operator!=(const iterator& other) const - { - return it != other.it; - } - - token& operator*() - { - return **it; - } - - token& operator->() - { - return **it; - } - };*/ - - utterance_token(std::initializer_list tkns) : token(token::type::utterance) - { - for (auto tkn : tkns) - { - utterance.push_back(std::unique_ptr(tkn)); - } - } - - utterance_token(const utterance_token& other) : token(token::type::utterance) - { - for (auto& tkn : other.utterance) - { - utterance.push_back(std::unique_ptr(tkn->copy())); - } - } + enum class noun_inflection { + singular, + plural + }; - utterance_token(utterance_token&& other) : token(token::type::utterance), utterance(std::move(other.utterance)) - { - - } + enum class adjective_inflection { + base, + comparative, + superlative + }; - utterance_token& operator=(const utterance_token& other) - { - utterance.clear(); - - for (auto& tkn : other.utterance) - { - utterance.push_back(std::unique_ptr(tkn->copy())); - } - - return *this; - } + enum class adverb_inflection { + base, + comparative, + superlative + }; - utterance_token& operator=(utterance_token&& other) - { - utterance = std::move(other.utterance); - - return *this; - } + enum class fillin_type { + generic, + noun_phrase, + adjective_phrase, + adverb_phrase, + participle_phrase, + infinitive_phrase + }; - iterator begin() - { - return std::begin(utterance); - } + type get_type() const; - iterator end() - { - return std::end(utterance); - } + int get_extra() const; + void set_extra(int _arg); - void erase(iterator it) - { - utterance.erase(it); - } + token(const token& other); + token& operator=(const token& other); + ~token(); - bool complete() const - { - return std::all_of(std::begin(utterance), std::end(utterance), [] (const std::unique_ptr& tkn) { - return tkn->complete(); - }); - } + bool is_complete() const; + std::string compile() const; - std::string compile() const - { - std::stringstream result; - for (auto& t : utterance) - { - if (t->complete()) - { - result << t->compile() << " "; - } else { - return "Could not compile!"; - } - } - - std::string output = result.str(); - if (output != "") - { - output.pop_back(); - } - - return output; - } + // Verb + token(verb _verb); + token(verb _verb, verb_inflection _infl); + token& operator=(verb _verb); + verb get_verb() const; + void set_verb(verb _verb); + verb_inflection get_verb_inflection() const; + void set_verb_inflection(verb_inflection _infl); + + // Noun + token(noun _noun); + token(noun _noun, noun_inflection _infl); + token& operator=(noun _noun); + noun get_noun() const; + void set_noun(noun _noun); + noun_inflection get_noun_inflection() const; + void set_noun_inflection(noun_inflection _infl); + + // Adjective + token(adjective _adjective); + token(adjective _adjective, adjective_inflection _infl); + token& operator=(adjective _adjective); + adjective get_adjective() const; + void set_adjective(adjective _adjective); + adjective_inflection get_adjective_inflection() const; + void set_adjective_inflection(adjective_inflection _infl); + + // Adverb + token(adverb _adverb); + token(adverb _adverb, adverb_inflection _infl); + token& operator=(adverb _adverb); + adverb get_adverb() const; + void set_adverb(adverb _adverb); + adverb_inflection get_adverb_inflection() const; + void set_adverb_inflection(adverb_inflection _infl); + + // Preposition + token(preposition _preposition); + token& operator=(preposition _preposition); + preposition get_preposition() const; + void set_preposition(preposition _preposition); - token* copy() const - { - return new utterance_token(*this); - } - }; - - class fillin_token : public token { - private: // Fillin - std::string m_theme; - fillin_type m_fillin_type; - - public: - fillin_token(fillin_type ft) : token(token::type::fillin), m_fillin_type(ft) - { - - } - -/* void synrestrs(std::initializer_list ins) - { - m_synrestrs = std::set(ins); - } - - std::set& synrestrs() - { - return m_synrestrs; - } - - void selrestrs(std::initializer_list ins) - { - m_selrestrs = std::set(ins); - } - - std::set& selrestrs() - { - return m_selrestrs; - }*/ - - fillin_token theme(std::string theme) - { - m_theme = theme; - - return *this; - } + token(fillin_type _ft); + token& operator=(fillin_type _ft); + fillin_type get_fillin_type() const; + void set_fillin_type(fillin_type _ft); - std::string& theme() - { - return m_theme; - } - - fillin_type get_fillin_type() const - { - return m_fillin_type; - } - - bool complete() const - { - return false; - } - - std::string compile() const - { - return ""; - } + // Utterance + typedef std::list::iterator iterator; + + token(); + token(std::initializer_list _init); + iterator begin(); + iterator end(); + token& operator<<(token _tkn); + void push_back(token _tkn); + void insert(iterator before, token _tkn); + void replace(iterator torepl, token _tkn); + void erase(iterator toer); - token* copy() const - { - return new fillin_token(*this); - } - }; - - class string_token : public token { - private: // String - std::string str; - - public: - string_token(std::string str) : token(token::type::string), str(str) - { - - } - - bool complete() const - { - return true; - } + token(std::string _str); + token& operator=(std::string _str); + std::string get_string() const; + void set_string(std::string _str); - std::string compile() const - { - return str; - } - - token* copy() const - { - return new string_token(*this); - } + private: + type _type; + int _extra = 0; + union { + struct { + verb _verb; + verb_inflection _infl; + } _verb; + struct { + noun _noun; + noun_inflection _infl; + } _noun; + struct { + adjective _adjective; + adjective_inflection _infl; + } _adjective; + struct { + adverb _adverb; + adverb_inflection _infl; + } _adverb; + struct { + preposition _preposition; + } _preposition; + struct { + fillin_type _type; + } _fillin; + struct { + std::string _str; + } _string; + struct { + std::list _utterance; + } _utterance; + }; }; - + }; #endif /* end of include guard: TOKEN_H_AD62C505 */ diff --git a/lib/util.h b/lib/util.h index 815b47c..fb5fe67 100644 --- a/lib/util.h +++ b/lib/util.h @@ -1,10 +1,6 @@ #ifndef UTIL_H_15DDCA2D #define UTIL_H_15DDCA2D -#include -#include -#include - namespace verbly { template @@ -32,7 +28,7 @@ namespace verbly { while (!input.empty()) { - int divider = input.find(" "); + int divider = input.find(delimiter); if (divider == std::string::npos) { result.push_back(input); @@ -41,7 +37,7 @@ namespace verbly { } else { result.push_back(input.substr(0, divider)); - input = input.substr(divider+1); + input = input.substr(divider+delimiter.length()); } } diff --git a/lib/verb.cpp b/lib/verb.cpp index 23f7c92..1f45d53 100644 --- a/lib/verb.cpp +++ b/lib/verb.cpp @@ -2,6 +2,11 @@ namespace verbly { + verb::verb() + { + + } + verb::verb(const data& _data, int _id) : word(_data, _id) { @@ -9,185 +14,51 @@ namespace verbly { std::string verb::base_form() const { + assert(_valid == true); + return _infinitive; } std::string verb::infinitive_form() const { + assert(_valid == true); + return _infinitive; } std::string verb::past_tense_form() const { + assert(_valid == true); + return _past_tense; } std::string verb::past_participle_form() const { + assert(_valid == true); + return _past_participle; } std::string verb::ing_form() const { + assert(_valid == true); + return _ing_form; } std::string verb::s_form() const { - return _s_form; - } - - verb_query::verb_query(const data& _data) : _data(_data) - { - - } - - verb_query& verb_query::limit(int _limit) - { - if ((_limit > 0) || (_limit == unlimited)) - { - this->_limit = _limit; - } - - return *this; - } - - verb_query& verb_query::random(bool _random) - { - this->_random = _random; - - return *this; - } - - verb_query& verb_query::except(const verb& _word) - { - _except.push_back(_word); - - return *this; - } - - verb_query& verb_query::rhymes_with(const word& _word) - { - for (auto rhyme : _word.rhyme_phonemes()) - { - _rhymes.push_back(rhyme); - } - - if (dynamic_cast(&_word) != nullptr) - { - _except.push_back(dynamic_cast(_word)); - } + assert(_valid == true); - return *this; + return _s_form; } - verb_query& verb_query::has_pronunciation(bool _has_prn) + frame_query verb::frames() const { - this->_has_prn = _has_prn; + assert(_valid == true); - return *this; + return _data->frames().for_verb(*this); } - - std::list verb_query::run() const - { - std::stringstream construct; - construct << "SELECT verb_id, infinitive, past_tense, past_participle, ing_form, s_form FROM verbs"; - std::list conditions; - - if (_has_prn) - { - conditions.push_back("verb_id IN (SELECT verb_id FROM verb_pronunciations)"); - } - - if (!_rhymes.empty()) - { - std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); - std::string cond = "verb_id IN (SELECT verb_id FROM verb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; - conditions.push_back(cond); - } - - for (auto except : _except) - { - conditions.push_back("verb_id != @EXCID"); - } - if (!conditions.empty()) - { - construct << " WHERE "; - construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND "); - } - - if (_random) - { - construct << " ORDER BY RANDOM()"; - } - - if (_limit != unlimited) - { - construct << " LIMIT " << _limit; - } - - sqlite3_stmt* ppstmt; - std::string query = construct.str(); - if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) - { - throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); - } - - if (!_rhymes.empty()) - { - int i = 0; - for (auto rhyme : _rhymes) - { - std::string rhymer = "%" + rhyme; - sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); - - i++; - } - } - - for (auto except : _except) - { - sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); - } - - std::list output; - while (sqlite3_step(ppstmt) == SQLITE_ROW) - { - verb tnc {_data, sqlite3_column_int(ppstmt, 0)}; - tnc._infinitive = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); - tnc._past_tense = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); - tnc._past_participle = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 3))); - tnc._ing_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 4))); - tnc._s_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 5))); - - output.push_back(tnc); - } - - sqlite3_finalize(ppstmt); - - for (auto& verb : output) - { - query = "SELECT pronunciation FROM verb_pronunciations WHERE verb_id = ?"; - if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) - { - throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); - } - - sqlite3_bind_int(ppstmt, 1, verb._id); - - while (sqlite3_step(ppstmt) == SQLITE_ROW) - { - std::string pronunciation(reinterpret_cast(sqlite3_column_text(ppstmt, 0))); - auto phonemes = verbly::split>(pronunciation, " "); - - verb.pronunciations.push_back(phonemes); - } - - sqlite3_finalize(ppstmt); - } - - return output; - } - }; diff --git a/lib/verb.h b/lib/verb.h index 7cc87e2..7a2486e 100644 --- a/lib/verb.h +++ b/lib/verb.h @@ -3,26 +3,7 @@ namespace verbly { - /*class frame_part { - - }; - - class frame { - private: - std::list content; - std::map::iterator>> predicates; - - public: - frame(std::list content) : content(content) - { - - } - - std::unique_ptr make_utterance() const - { - - } - };*/ + class frame_query; class verb : public word { private: @@ -35,6 +16,7 @@ namespace verbly { friend class verb_query; public: + verb(); verb(const data& _data, int _id); std::string base_form() const; @@ -43,29 +25,8 @@ namespace verbly { std::string past_participle_form() const; std::string ing_form() const; std::string s_form() const; - }; - - class verb_query { - public: - verb_query(const data& _data); - - verb_query& limit(int _limit); - verb_query& random(bool _random); - verb_query& except(const verb& _word); - verb_query& rhymes_with(const word& _word); - verb_query& has_pronunciation(bool _has_prn); - std::list run() const; - - const static int unlimited = -1; - - private: - const data& _data; - int _limit = unlimited; - bool _random = false; - std::list _rhymes; - std::list _except; - bool _has_prn = false; + frame_query frames() const; }; }; diff --git a/lib/verb_query.cpp b/lib/verb_query.cpp new file mode 100644 index 0000000..173a04e --- /dev/null +++ b/lib/verb_query.cpp @@ -0,0 +1,170 @@ +#include "verbly.h" + +namespace verbly { + + verb_query::verb_query(const data& _data) : _data(_data) + { + + } + + verb_query& verb_query::limit(int _limit) + { + if ((_limit > 0) || (_limit == unlimited)) + { + this->_limit = _limit; + } + + return *this; + } + + verb_query& verb_query::random() + { + this->_random = true; + + return *this; + } + + verb_query& verb_query::except(const verb& _word) + { + _except.push_back(_word); + + return *this; + } + + verb_query& verb_query::rhymes_with(const word& _word) + { + for (auto rhyme : _word.rhyme_phonemes()) + { + _rhymes.push_back(rhyme); + } + + if (dynamic_cast(&_word) != nullptr) + { + _except.push_back(dynamic_cast(_word)); + } + + return *this; + } + + verb_query& verb_query::has_pronunciation() + { + this->_has_prn = true; + + return *this; + } + + verb_query& verb_query::has_frames() + { + this->_has_frames = true; + + return *this; + } + + std::list verb_query::run() const + { + std::stringstream construct; + construct << "SELECT verb_id, infinitive, past_tense, past_participle, ing_form, s_form FROM verbs"; + std::list conditions; + + if (_has_prn) + { + conditions.push_back("verb_id IN (SELECT verb_id FROM verb_pronunciations)"); + } + + if (!_rhymes.empty()) + { + std::list clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); + std::string cond = "verb_id IN (SELECT verb_id FROM verb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; + conditions.push_back(cond); + } + + for (auto except : _except) + { + conditions.push_back("verb_id != @EXCID"); + } + + if (!_has_frames) + { + conditions.push_back("verb_id IN (SELECT verb_id FROM verb_groups)"); + } + + if (!conditions.empty()) + { + construct << " WHERE "; + construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND "); + } + + if (_random) + { + construct << " ORDER BY RANDOM()"; + } + + if (_limit != unlimited) + { + construct << " LIMIT " << _limit; + } + + sqlite3_stmt* ppstmt; + std::string query = construct.str(); + if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); + } + + if (!_rhymes.empty()) + { + int i = 0; + for (auto rhyme : _rhymes) + { + std::string rhymer = "%" + rhyme; + sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); + + i++; + } + } + + for (auto except : _except) + { + sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id); + } + + std::list output; + while (sqlite3_step(ppstmt) == SQLITE_ROW) + { + verb tnc {_data, sqlite3_column_int(ppstmt, 0)}; + tnc._infinitive = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 1))); + tnc._past_tense = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 2))); + tnc._past_participle = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 3))); + tnc._ing_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 4))); + tnc._s_form = std::string(reinterpret_cast(sqlite3_column_text(ppstmt, 5))); + + output.push_back(tnc); + } + + sqlite3_finalize(ppstmt); + + for (auto& verb : output) + { + query = "SELECT pronunciation FROM verb_pronunciations WHERE verb_id = ?"; + if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) + { + throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); + } + + sqlite3_bind_int(ppstmt, 1, verb._id); + + while (sqlite3_step(ppstmt) == SQLITE_ROW) + { + std::string pronunciation(reinterpret_cast(sqlite3_column_text(ppstmt, 0))); + auto phonemes = verbly::split>(pronunciation, " "); + + verb.pronunciations.push_back(phonemes); + } + + sqlite3_finalize(ppstmt); + } + + return output; + } + +}; diff --git a/lib/verb_query.h b/lib/verb_query.h new file mode 100644 index 0000000..24f5732 --- /dev/null +++ b/lib/verb_query.h @@ -0,0 +1,34 @@ +#ifndef VERB_QUERY_H_34E5A679 +#define VERB_QUERY_H_34E5A679 + +namespace verbly { + + class verb_query { + public: + verb_query(const data& _data); + + verb_query& limit(int _limit); + verb_query& random(); + verb_query& except(const verb& _word); + verb_query& rhymes_with(const word& _word); + verb_query& has_pronunciation(); + + verb_query& has_frames(); + + std::list run() const; + + const static int unlimited = -1; + + private: + const data& _data; + int _limit = unlimited; + bool _random = false; + std::list _rhymes; + std::list _except; + bool _has_prn = false; + bool _has_frames = false; + }; + +}; + +#endif /* end of include guard: VERB_QUERY_H_34E5A679 */ diff --git a/lib/verbly.h b/lib/verbly.h index b9f5367..cfaf5bc 100644 --- a/lib/verbly.h +++ b/lib/verbly.h @@ -1,14 +1,35 @@ #ifndef VERBLY_H_5B39CE50 #define VERBLY_H_5B39CE50 -#include "c++14.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "util.h" -#include "token.h" #include "data.h" #include "word.h" #include "verb.h" #include "adverb.h" #include "adjective.h" #include "noun.h" +#include "frame.h" +#include "preposition.h" +#include "token.h" +#include "noun_query.h" +#include "adverb_query.h" +#include "adjective_query.h" +#include "verb_query.h" +#include "frame_query.h" #endif /* end of include guard: VERBLY_H_5B39CE50 */ diff --git a/lib/word.cpp b/lib/word.cpp index 15af150..13c611f 100644 --- a/lib/word.cpp +++ b/lib/word.cpp @@ -3,13 +3,20 @@ namespace verbly { - word::word(const data& _data, int _id) : _data(_data), _id(_id) + word::word() + { + + } + + word::word(const data& _data, int _id) : _data(&_data), _id(_id), _valid(true) { } std::list word::rhyme_phonemes() const { + assert(_valid == true); + std::list result; for (auto pronunciation : pronunciations) @@ -32,6 +39,8 @@ namespace verbly { bool word::starts_with_vowel_sound() const { + assert(_valid == true); + if (pronunciations.size() > 0) { return std::any_of(std::begin(pronunciations), std::end(pronunciations), [] (std::list phonemes) { diff --git a/lib/word.h b/lib/word.h index db3242a..dc6fac8 100644 --- a/lib/word.h +++ b/lib/word.h @@ -3,26 +3,23 @@ namespace verbly { - class adjective_query; - class verb_query; - class adverb_query; - - template - class query; - class word { protected: - const data& _data; + const data* _data; int _id; + bool _valid = false; std::list> pronunciations; + word(); word(const data& _data, int _id); friend class adjective_query; friend class verb_query; friend class noun_query; friend class adverb_query; + friend class frame_query; + friend class preposition_query; public: virtual std::string base_form() const = 0; diff --git a/vendor/json b/vendor/json new file mode 160000 index 0000000..2b13711 --- /dev/null +++ b/vendor/json @@ -0,0 +1 @@ +Subproject commit 2b137110095c2b2046cde5af4ac8892b8a3f3809 -- cgit 1.4.1