about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2016-03-16 11:27:16 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2016-03-16 11:27:16 -0400
commit3aceae8ab1eb5992110ea57a9479bbc3177feb21 (patch)
tree13167a266805344efb7bb1d900486f782c23285e
parente1be2716746e75cf6ed37e86461a7f580a964564 (diff)
downloadfurries-3aceae8ab1eb5992110ea57a9479bbc3177feb21.tar.gz
furries-3aceae8ab1eb5992110ea57a9479bbc3177feb21.tar.bz2
furries-3aceae8ab1eb5992110ea57a9479bbc3177feb21.zip
Added more inflections, word relationships, and pronunciations
Nouns, adjectives, and adverbs now have inflected forms. A large number of WordNet word relationships (all noun-noun relationships, plus synonymy and antonymy for all word types except verbs) have been added. Additionally, CMUDICT is now being used to store word pronunciations for rhyming purposes. Verbly is now also a compiled library rather than being header-only due to the complexity of the query interface.
-rw-r--r--CMakeLists.txt6
-rw-r--r--furries.cpp16
-rw-r--r--generator.cpp1303
-rw-r--r--progress.h50
-rw-r--r--schema.sql59
-rw-r--r--verbly/adjective.cpp586
-rw-r--r--verbly/adjective.h126
-rw-r--r--verbly/adverb.cpp364
-rw-r--r--verbly/adverb.h75
-rw-r--r--verbly/data.cpp50
-rw-r--r--verbly/data.h275
-rw-r--r--verbly/noun.cpp916
-rw-r--r--verbly/noun.h171
-rw-r--r--verbly/token.cpp53
-rw-r--r--verbly/token.h82
-rw-r--r--verbly/util.h53
-rw-r--r--verbly/verb.cpp193
-rw-r--r--verbly/verb.h68
-rw-r--r--verbly/verbly.h7
-rw-r--r--verbly/word.cpp32
-rw-r--r--verbly/word.h35
21 files changed, 4043 insertions, 477 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b6d991..3a884b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -8,11 +8,15 @@ pkg_check_modules(YamlCpp yaml-cpp REQUIRED)
8pkg_check_modules(sqlite3 sqlite3 REQUIRED) 8pkg_check_modules(sqlite3 sqlite3 REQUIRED)
9find_package(libxml2 REQUIRED) 9find_package(libxml2 REQUIRED)
10 10
11add_library(verbly verbly/data.cpp verbly/adjective.cpp verbly/noun.cpp verbly/verb.cpp verbly/adverb.cpp verbly/token.cpp verbly/word.cpp)
12set_property(TARGET verbly PROPERTY CXX_STANDARD 11)
13set_property(TARGET verbly PROPERTY CXX_STANDARD_REQUIRED ON)
14
11include_directories(vendor/twitcurl/libtwitcurl ${LIBXML2_INCLUDE_DIR} ${sqlite3_INCLUDE_DIR}) 15include_directories(vendor/twitcurl/libtwitcurl ${LIBXML2_INCLUDE_DIR} ${sqlite3_INCLUDE_DIR})
12add_executable(furries furries.cpp) 16add_executable(furries furries.cpp)
13set_property(TARGET furries PROPERTY CXX_STANDARD 11) 17set_property(TARGET furries PROPERTY CXX_STANDARD 11)
14set_property(TARGET furries PROPERTY CXX_STANDARD_REQUIRED ON) 18set_property(TARGET furries PROPERTY CXX_STANDARD_REQUIRED ON)
15target_link_libraries(furries ${sqlite3_LIBRARIES} ${YamlCpp_LIBRARIES} twitcurl curl) 19target_link_libraries(furries ${sqlite3_LIBRARIES} ${YamlCpp_LIBRARIES} twitcurl curl verbly)
16 20
17add_executable(generator generator.cpp) 21add_executable(generator generator.cpp)
18set_property(TARGET generator PROPERTY CXX_STANDARD 11) 22set_property(TARGET generator PROPERTY CXX_STANDARD 11)
diff --git a/furries.cpp b/furries.cpp index 0cce8bd..55dfb7b 100644 --- a/furries.cpp +++ b/furries.cpp
@@ -20,7 +20,7 @@ class fill_blanks {
20 { 20 {
21 switch (it->token_type()) 21 switch (it->token_type())
22 { 22 {
23 case verbly::type::utterance: 23 case verbly::token::type::utterance:
24 { 24 {
25 auto& action = *dynamic_cast<verbly::utterance_token*>(it.get()); 25 auto& action = *dynamic_cast<verbly::utterance_token*>(it.get());
26 for (auto& tkn : action) 26 for (auto& tkn : action)
@@ -36,14 +36,14 @@ class fill_blanks {
36 break; 36 break;
37 } 37 }
38 38
39 case verbly::type::fillin: 39 case verbly::token::type::fillin:
40 { 40 {
41 auto& tkn = *dynamic_cast<verbly::fillin_token*>(it.get()); 41 auto& tkn = *dynamic_cast<verbly::fillin_token*>(it.get());
42 switch (tkn.fillin_type()) 42 switch (tkn.fillin_type())
43 { 43 {
44 case verbly::fillin_type::participle_phrase: 44 case verbly::fillin_type::participle_phrase:
45 { 45 {
46 const verbly::verb& v = database.verbs().random(true).limit(1).run().front(); 46 verbly::verb v = database.verbs().random(true).limit(1).run().front();
47 /*verbly::utterance_token phrase = verbly::random(v.frames).make_utterance(); 47 /*verbly::utterance_token phrase = verbly::random(v.frames).make_utterance();
48 while (std::begin(phrase)->token_type() != verbly::type::verb) 48 while (std::begin(phrase)->token_type() != verbly::type::verb)
49 { 49 {
@@ -53,7 +53,7 @@ class fill_blanks {
53 *std::begin(phrase) = verbly::verb_token(v).conjugate(verbly::conjugation::present_participle); 53 *std::begin(phrase) = verbly::verb_token(v).conjugate(verbly::conjugation::present_participle);
54 *it = phrase;*/ 54 *it = phrase;*/
55 auto avt = std::make_unique<verbly::verb_token>(v); 55 auto avt = std::make_unique<verbly::verb_token>(v);
56 avt->conjugate(verbly::conjugation::present_participle); 56 avt->inflect(verbly::verb_token::inflection::ing_form);
57 it = std::move(avt); 57 it = std::move(avt);
58 58
59 break; 59 break;
@@ -61,16 +61,16 @@ class fill_blanks {
61 61
62 case verbly::fillin_type::adjective: 62 case verbly::fillin_type::adjective:
63 { 63 {
64 const verbly::adjective& adj = database.adjectives().random(true).limit(1).run().front(); 64 verbly::adjective adj = database.adjectives().random(true).limit(1).run().front();
65 it = std::make_unique<verbly::string_token>(adj.form); 65 it = std::make_unique<verbly::string_token>(adj.base_form());
66 66
67 break; 67 break;
68 } 68 }
69 69
70 case verbly::fillin_type::adverb: 70 case verbly::fillin_type::adverb:
71 { 71 {
72 const verbly::adverb& adv = database.adverbs().random(true).limit(1).run().front(); 72 verbly::adverb adv = database.adverbs().random(true).limit(1).run().front();
73 it = std::make_unique<verbly::string_token>(adv.form); 73 it = std::make_unique<verbly::string_token>(adv.base_form());
74 74
75 break; 75 break;
76 } 76 }
diff --git a/generator.cpp b/generator.cpp index c389963..305d121 100644 --- a/generator.cpp +++ b/generator.cpp
@@ -9,6 +9,8 @@
9#include <sqlite3.h> 9#include <sqlite3.h>
10#include <sstream> 10#include <sstream>
11#include <regex> 11#include <regex>
12#include <list>
13#include "progress.h"
12 14
13struct verb { 15struct verb {
14 std::string infinitive; 16 std::string infinitive;
@@ -18,6 +20,17 @@ struct verb {
18 std::string s_form; 20 std::string s_form;
19}; 21};
20 22
23struct adjective {
24 std::string base;
25 std::string comparative;
26 std::string superlative;
27};
28
29struct noun {
30 std::string singular;
31 std::string plural;
32};
33
21struct group { 34struct group {
22 std::string id; 35 std::string id;
23 std::set<std::string> members; 36 std::set<std::string> members;
@@ -25,21 +38,33 @@ struct group {
25 38
26std::map<std::string, group> groups; 39std::map<std::string, group> groups;
27std::map<std::string, verb> verbs; 40std::map<std::string, verb> verbs;
41std::map<std::string, adjective> adjectives;
42std::map<std::string, noun> nouns;
28std::map<int, std::map<int, int>> wn; 43std::map<int, std::map<int, int>> wn;
44std::map<std::string, std::set<std::string>> pronunciations;
29 45
30void print_usage() 46void print_usage()
31{ 47{
32 std::cout << "Verbly Datafile Generator" << std::endl; 48 std::cout << "Verbly Datafile Generator" << std::endl;
33 std::cout << "-------------------------" << std::endl; 49 std::cout << "-------------------------" << std::endl;
34 std::cout << "Requires exactly four arguments." << std::endl; 50 std::cout << "Requires exactly six arguments." << std::endl;
35 std::cout << "1. The path to a VerbNet data directory." << std::endl; 51 std::cout << "1. The path to a VerbNet data directory." << std::endl;
36 std::cout << "2. The path to a SemLink vnpbMappings file." << std::endl; 52 std::cout << "2. The path to a SemLink vnpbMappings file." << std::endl;
37 std::cout << "3. The path to an AGID infl.txt file." << std::endl; 53 std::cout << "3. The path to an AGID infl.txt file." << std::endl;
38 std::cout << "4. The path to a WordNet prolog data directory." << std::endl; 54 std::cout << "4. The path to a WordNet prolog data directory." << std::endl;
39 std::cout << "5. Datafile output path." << std::endl; 55 std::cout << "5. The path to a CMUDICT pronunciation file." << std::endl;
56 std::cout << "6. Datafile output path." << std::endl;
40 57
41 exit(1); 58 exit(1);
42} 59}
60
61void db_error(sqlite3* ppdb, std::string)
62{
63 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl;
64 sqlite3_close_v2(ppdb);
65 print_usage();
66}
67
43/* 68/*
44void parse_group(xmlNodePtr top, std::string filename) 69void parse_group(xmlNodePtr top, std::string filename)
45{ 70{
@@ -87,7 +112,7 @@ void parse_group(xmlNodePtr top, std::string filename)
87 112
88int main(int argc, char** argv) 113int main(int argc, char** argv)
89{ 114{
90 if (argc != 6) 115 if (argc != 7)
91 { 116 {
92 print_usage(); 117 print_usage();
93 } 118 }
@@ -137,7 +162,7 @@ int main(int argc, char** argv)
137 closedir(dir);*/ 162 closedir(dir);*/
138 163
139 // Get verbs from AGID 164 // Get verbs from AGID
140 std::cout << "Reading verb inflection..." << std::endl; 165 std::cout << "Reading inflections..." << std::endl;
141 166
142 std::ifstream agidfile(argv[3]); 167 std::ifstream agidfile(argv[3]);
143 if (!agidfile.is_open()) 168 if (!agidfile.is_open())
@@ -162,11 +187,7 @@ int main(int argc, char** argv)
162 int divider = line.find_first_of(" "); 187 int divider = line.find_first_of(" ");
163 std::string word = line.substr(0, divider); 188 std::string word = line.substr(0, divider);
164 line = line.substr(divider+1); 189 line = line.substr(divider+1);
165 190 char type = line[0];
166 if (line[0] != 'V')
167 {
168 continue;
169 }
170 191
171 if (line[1] == '?') 192 if (line[1] == '?')
172 { 193 {
@@ -174,7 +195,7 @@ int main(int argc, char** argv)
174 } else { 195 } else {
175 line.erase(0, 3); 196 line.erase(0, 3);
176 } 197 }
177 198
178 std::vector<std::string> forms; 199 std::vector<std::string> forms;
179 while (!line.empty()) 200 while (!line.empty())
180 { 201 {
@@ -187,52 +208,129 @@ int main(int argc, char** argv)
187 inflection = line; 208 inflection = line;
188 line = ""; 209 line = "";
189 } 210 }
190 211
191 if ((divider = inflection.find_first_of(",?")) != std::string::npos) 212 if ((divider = inflection.find_first_of(",?")) != std::string::npos)
192 { 213 {
193 inflection = inflection.substr(0, divider); 214 inflection = inflection.substr(0, divider);
194 } 215 }
195 216
196 forms.push_back(inflection); 217 forms.push_back(inflection);
197 } 218 }
198 219
199 verb v; 220 switch (type)
200 v.infinitive = word;
201 if (forms.size() == 4)
202 { 221 {
203 v.past_tense = forms[0]; 222 case 'V':
204 v.past_participle = forms[1]; 223 {
205 v.ing_form = forms[2]; 224 verb v;
206 v.s_form = forms[3]; 225 v.infinitive = word;
207 } else if (forms.size() == 3) 226 if (forms.size() == 4)
227 {
228 v.past_tense = forms[0];
229 v.past_participle = forms[1];
230 v.ing_form = forms[2];
231 v.s_form = forms[3];
232 } else if (forms.size() == 3)
233 {
234 v.past_tense = forms[0];
235 v.past_participle = forms[0];
236 v.ing_form = forms[1];
237 v.s_form = forms[2];
238 } else if (forms.size() == 8)
239 {
240 // As of AGID 2014.08.11, this is only "to be"
241 v.past_tense = forms[0];
242 v.past_participle = forms[2];
243 v.ing_form = forms[3];
244 v.s_form = forms[4];
245 } else {
246 // Words that don't fit the cases above as of AGID 2014.08.11:
247 // - may and shall do not conjugate the way we want them to
248 // - methinks only has a past tense and is an outlier
249 // - wit has five forms, and is archaic/obscure enough that we can ignore it for now
250 std::cout << "Ignoring verb \"" << word << "\" due to non-standard number of forms." << std::endl;
251 }
252
253 verbs[word] = v;
254
255 break;
256 }
257
258 case 'A':
259 {
260 adjective adj;
261 adj.base = word;
262 if (forms.size() == 2)
263 {
264 adj.comparative = forms[0];
265 adj.superlative = forms[1];
266 } else {
267 // As of AGID 2014.08.11, this is only "only", which has only the form "onliest"
268 std::cout << "Ignoring adjective/adverb \"" << word << "\" due to non-standard number of forms." << std::endl;
269 }
270
271 adjectives[word] = adj;
272
273 break;
274 }
275
276 case 'N':
277 {
278 noun n;
279 n.singular = word;
280 if (forms.size() == 1)
281 {
282 n.plural = forms[0];
283 } else {
284 // As of AGID 2014.08.11, this is non-existent.
285 std::cout << "Ignoring noun \"" << word << "\" due to non-standard number of forms." << std::endl;
286 }
287
288 nouns[word] = n;
289
290 break;
291 }
292 }
293 }
294
295 // Pronounciations
296 std::cout << "Reading pronunciations..." << std::endl;
297
298 std::ifstream pronfile(argv[5]);
299 if (!pronfile.is_open())
300 {
301 std::cout << "Could not open CMUDICT file: " << argv[5] << std::endl;
302 print_usage();
303 }
304
305 for (;;)
306 {
307 std::string line;
308 if (!getline(pronfile, line))
208 { 309 {
209 v.past_tense = forms[0]; 310 break;
210 v.past_participle = forms[0]; 311 }
211 v.ing_form = forms[1]; 312
212 v.s_form = forms[2]; 313 if (line.back() == '\r')
213 } else if (forms.size() == 8)
214 { 314 {
215 // As of AGID 2014.08.11, this is only "to be" 315 line.pop_back();
216 v.past_tense = forms[0];
217 v.past_participle = forms[2];
218 v.ing_form = forms[3];
219 v.s_form = forms[4];
220 } else {
221 // Words that don't fit the cases above as of AGID 2014.08.11:
222 // - may and shall do not conjugate the way we want them to
223 // - methinks only has a past tense and is an outlier
224 // - wit has five forms, and is archaic/obscure enough that we can ignore it for now
225 std::cout << "Ignoring verb \"" << word << "\" due to non-standard number of forms." << std::endl;
226 } 316 }
227 317
228 verbs[word] = v; 318 std::regex phoneme("([A-Z][^ \\(]*)(?:\\(\\d+\\))? ([A-Z 0-9]+)");
319 std::smatch phoneme_data;
320 if (std::regex_search(line, phoneme_data, phoneme))
321 {
322 std::string canonical(phoneme_data[1]);
323 std::transform(std::begin(canonical), std::end(canonical), std::begin(canonical), ::tolower);
324
325 pronunciations[canonical].insert(phoneme_data[2]);
326 }
229 } 327 }
230 328
231 // Start writing output 329 // Start writing output
232 std::cout << "Writing output..." << std::endl; 330 std::cout << "Writing schema..." << std::endl;
233 331
234 sqlite3* ppdb; 332 sqlite3* ppdb;
235 if (sqlite3_open_v2(argv[5], &ppdb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) 333 if (sqlite3_open_v2(argv[6], &ppdb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK)
236 { 334 {
237 std::cout << "Error opening output datafile: " << sqlite3_errmsg(ppdb) << std::endl; 335 std::cout << "Error opening output datafile: " << sqlite3_errmsg(ppdb) << std::endl;
238 print_usage(); 336 print_usage();
@@ -278,47 +376,82 @@ int main(int argc, char** argv)
278 sqlite3_stmt* schmstmt; 376 sqlite3_stmt* schmstmt;
279 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &schmstmt, NULL) != SQLITE_OK) 377 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &schmstmt, NULL) != SQLITE_OK)
280 { 378 {
281 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 379 db_error(ppdb, query);
282 sqlite3_close_v2(ppdb);
283 print_usage();
284 } 380 }
285 381
286 if (sqlite3_step(schmstmt) != SQLITE_DONE) 382 if (sqlite3_step(schmstmt) != SQLITE_DONE)
287 { 383 {
288 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 384 db_error(ppdb, query);
289 sqlite3_close_v2(ppdb);
290 print_usage();
291 } 385 }
292 386
293 sqlite3_finalize(schmstmt); 387 sqlite3_finalize(schmstmt);
294 } 388 }
295 389
296 std::cout << "Writing verbs..." << std::endl;
297 for (auto& mapping : verbs)
298 { 390 {
299 sqlite3_stmt* ppstmt; 391 progress ppgs("Writing verbs...", verbs.size());
300 std::string query("INSERT INTO verbs (infinitive, past_tense, past_participle, ing_form, s_form) VALUES (?, ?, ?, ?, ?)"); 392 for (auto& mapping : verbs)
301 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
302 { 393 {
303 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 394 sqlite3_stmt* ppstmt;
304 sqlite3_close_v2(ppdb); 395 std::string query("INSERT INTO verbs (infinitive, past_tense, past_participle, ing_form, s_form) VALUES (?, ?, ?, ?, ?)");
305 print_usage(); 396 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
306 } 397 {
398 db_error(ppdb, query);
399 }
307 400
308 sqlite3_bind_text(ppstmt, 1, mapping.second.infinitive.c_str(), mapping.second.infinitive.length(), SQLITE_STATIC); 401 sqlite3_bind_text(ppstmt, 1, mapping.second.infinitive.c_str(), mapping.second.infinitive.length(), SQLITE_STATIC);
309 sqlite3_bind_text(ppstmt, 2, mapping.second.past_tense.c_str(), mapping.second.past_tense.length(), SQLITE_STATIC); 402 sqlite3_bind_text(ppstmt, 2, mapping.second.past_tense.c_str(), mapping.second.past_tense.length(), SQLITE_STATIC);
310 sqlite3_bind_text(ppstmt, 3, mapping.second.past_participle.c_str(), mapping.second.past_participle.length(), SQLITE_STATIC); 403 sqlite3_bind_text(ppstmt, 3, mapping.second.past_participle.c_str(), mapping.second.past_participle.length(), SQLITE_STATIC);
311 sqlite3_bind_text(ppstmt, 4, mapping.second.ing_form.c_str(), mapping.second.ing_form.length(), SQLITE_STATIC); 404 sqlite3_bind_text(ppstmt, 4, mapping.second.ing_form.c_str(), mapping.second.ing_form.length(), SQLITE_STATIC);
312 sqlite3_bind_text(ppstmt, 5, mapping.second.s_form.c_str(), mapping.second.s_form.length(), SQLITE_STATIC); 405 sqlite3_bind_text(ppstmt, 5, mapping.second.s_form.c_str(), mapping.second.s_form.length(), SQLITE_STATIC);
313 406
314 if (sqlite3_step(ppstmt) != SQLITE_DONE) 407 if (sqlite3_step(ppstmt) != SQLITE_DONE)
315 { 408 {
316 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 409 db_error(ppdb, query);
317 sqlite3_close_v2(ppdb); 410 }
318 print_usage();
319 }
320 411
321 sqlite3_finalize(ppstmt); 412 sqlite3_finalize(ppstmt);
413
414 std::string canonical(mapping.second.infinitive);
415 std::transform(std::begin(canonical), std::end(canonical), std::begin(canonical), ::tolower);
416 if (pronunciations.count(canonical) == 1)
417 {
418 query = "SELECT last_insert_rowid()";
419 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
420 {
421 db_error(ppdb, query);
422 }
423
424 if (sqlite3_step(ppstmt) != SQLITE_ROW)
425 {
426 db_error(ppdb, query);
427 }
428
429 int rowid = sqlite3_column_int(ppstmt, 0);
430
431 sqlite3_finalize(ppstmt);
432
433 for (auto pronunciation : pronunciations[canonical])
434 {
435 query = "INSERT INTO verb_pronunciations (verb_id, pronunciation) VALUES (?, ?)";
436 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
437 {
438 db_error(ppdb, query);
439 }
440
441 sqlite3_bind_int(ppstmt, 1, rowid);
442 sqlite3_bind_text(ppstmt, 2, pronunciation.c_str(), pronunciation.length(), SQLITE_STATIC);
443
444 if (sqlite3_step(ppstmt) != SQLITE_DONE)
445 {
446 db_error(ppdb, query);
447 }
448
449 sqlite3_finalize(ppstmt);
450 }
451 }
452
453 ppgs.update();
454 }
322 } 455 }
323 456
324 // Get nouns/adjectives/adverbs from WordNet 457 // Get nouns/adjectives/adverbs from WordNet
@@ -342,110 +475,1046 @@ int main(int argc, char** argv)
342 wnpref += '/'; 475 wnpref += '/';
343 } 476 }
344 477
345 std::cout << "Reading words from WordNet..." << std::endl; 478 // s table
346 std::ifstream wnsfile(wnpref + "wn_s.pl");
347 if (!wnsfile.is_open())
348 { 479 {
349 std::cout << "Invalid WordNet data directory." << std::endl; 480 std::ifstream wnsfile(wnpref + "wn_s.pl");
350 print_usage(); 481 if (!wnsfile.is_open())
482 {
483 std::cout << "Invalid WordNet data directory." << std::endl;
484 print_usage();
485 }
486
487 std::list<std::string> lines;
488 for (;;)
489 {
490 std::string line;
491 if (!getline(wnsfile, line))
492 {
493 break;
494 }
495
496 if (line.back() == '\r')
497 {
498 line.pop_back();
499 }
500
501 lines.push_back(line);
502 }
503
504 progress ppgs("Writing nouns, adjectives, and adverbs...", lines.size());
505 for (auto line : lines)
506 {
507 ppgs.update();
508
509 std::regex relation("^s\\(([134]\\d{8}),(\\d+),'([\\w ]+)',");
510 std::smatch relation_data;
511 if (!std::regex_search(line, relation_data, relation))
512 {
513 continue;
514 }
515
516 int synset_id = stoi(relation_data[1]);
517 int wnum = stoi(relation_data[2]);
518 std::string word = relation_data[3];
519
520 std::string query;
521 switch (synset_id / 100000000)
522 {
523 case 1: // Noun
524 {
525 if (nouns.count(word) == 1)
526 {
527 query = "INSERT INTO nouns (singular, plural) VALUES (?, ?)";
528 } else {
529 query = "INSERT INTO nouns (singular) VALUES (?)";
530 }
531
532 break;
533 }
534
535 case 2: // Verb
536 {
537 // Ignore
538
539 break;
540 }
541
542 case 3: // Adjective
543 {
544 if (adjectives.count(word) == 1)
545 {
546 query = "INSERT INTO adjectives (base_form, comparative, superlative) VALUES (?, ?, ?)";
547 } else {
548 query = "INSERT INTO adjectives (base_form) VALUES (?)";
549 }
550
551 break;
552 }
553
554 case 4: // Adverb
555 {
556 if (adjectives.count(word) == 1)
557 {
558 query = "INSERT INTO adverbs (base_form, comparative, superlative) VALUES (?, ?, ?)";
559 } else {
560 query = "INSERT INTO adverbs (base_form) VALUES (?)";
561 }
562
563 break;
564 }
565 }
566
567 sqlite3_stmt* ppstmt;
568 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
569 {
570 db_error(ppdb, query);
571 }
572
573 sqlite3_bind_text(ppstmt, 1, word.c_str(), word.length(), SQLITE_STATIC);
574 switch (synset_id / 100000000)
575 {
576 case 1: // Noun
577 {
578 if (nouns.count(word) == 1)
579 {
580 sqlite3_bind_text(ppstmt, 2, nouns[word].plural.c_str(), nouns[word].plural.length(), SQLITE_STATIC);
581 }
582
583 break;
584 }
585
586 case 3: // Adjective
587 case 4: // Adverb
588 {
589 if (adjectives.count(word) == 1)
590 {
591 sqlite3_bind_text(ppstmt, 2, adjectives[word].comparative.c_str(), adjectives[word].comparative.length(), SQLITE_STATIC);
592 sqlite3_bind_text(ppstmt, 3, adjectives[word].superlative.c_str(), adjectives[word].superlative.length(), SQLITE_STATIC);
593 }
594
595 break;
596 }
597 }
598
599 if (sqlite3_step(ppstmt) != SQLITE_DONE)
600 {
601 db_error(ppdb, query);
602 }
603
604 sqlite3_finalize(ppstmt);
605
606 query = "SELECT last_insert_rowid()";
607 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
608 {
609 db_error(ppdb, query);
610 }
611
612 if (sqlite3_step(ppstmt) != SQLITE_ROW)
613 {
614 db_error(ppdb, query);
615 }
616
617 int rowid = sqlite3_column_int(ppstmt, 0);
618 wn[synset_id][wnum] = rowid;
619
620 sqlite3_finalize(ppstmt);
621
622 std::string canonical(word);
623 std::transform(std::begin(canonical), std::end(canonical), std::begin(canonical), ::tolower);
624 if (pronunciations.count(canonical) == 1)
625 {
626 for (auto pronunciation : pronunciations[canonical])
627 {
628 switch (synset_id / 100000000)
629 {
630 case 1: // Noun
631 {
632 query = "INSERT INTO noun_pronunciations (noun_id, pronunciation) VALUES (?, ?)";
633
634 break;
635 }
636
637 case 3: // Adjective
638 {
639 query = "INSERT INTO adjective_pronunciations (adjective_id, pronunciation) VALUES (?, ?)";
640
641 break;
642 }
643
644 case 4: // Adverb
645 {
646 query = "INSERT INTO adverb_pronunciations (adverb_id, pronunciation) VALUES (?, ?)";
647
648 break;
649 }
650 }
651
652 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
653 {
654 db_error(ppdb, query);
655 }
656
657 sqlite3_bind_int(ppstmt, 1, rowid);
658 sqlite3_bind_text(ppstmt, 2, pronunciation.c_str(), pronunciation.length(), SQLITE_STATIC);
659
660 if (sqlite3_step(ppstmt) != SQLITE_DONE)
661 {
662 db_error(ppdb, query);
663 }
664
665 sqlite3_finalize(ppstmt);
666 }
667 }
668 }
351 } 669 }
352 670
353 for (;;) 671 // While we're working on s
354 { 672 {
355 std::string line; 673 progress ppgs("Writing word synonyms...", wn.size());
356 if (!getline(wnsfile, line)) 674 for (auto sense : wn)
357 { 675 {
358 break; 676 ppgs.update();
677
678 for (auto word1 : sense.second)
679 {
680 for (auto word2 : sense.second)
681 {
682 if (word1 != word2)
683 {
684 std::string query;
685 switch (sense.first / 100000000)
686 {
687 case 1: // Noun
688 {
689 query = "INSERT INTO noun_synonymy (noun_1_id, noun_2_id) VALUES (?, ?)";
690
691 break;
692 }
693
694 case 2: // Verb
695 {
696 // Ignore
697
698 break;
699 }
700
701 case 3: // Adjective
702 {
703 query = "INSERT INTO adjective_synonymy (adjective_1_id, adjective_2_id) VALUES (?, ?)";
704
705 break;
706 }
707
708 case 4: // Adverb
709 {
710 query = "INSERT INTO adverb_synonymy (adverb_1_id, adverb_2_id) VALUES (?, ?)";
711
712 break;
713 }
714 }
715
716 sqlite3_stmt* ppstmt;
717 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
718 {
719 db_error(ppdb, query);
720 }
721
722 sqlite3_bind_int(ppstmt, 1, word1.second);
723 sqlite3_bind_int(ppstmt, 2, word2.second);
724
725 if (sqlite3_step(ppstmt) != SQLITE_DONE)
726 {
727 db_error(ppdb, query);
728 }
729
730 sqlite3_finalize(ppstmt);
731 }
732 }
733 }
734 }
735 }
736
737 // ant table
738 {
739 std::ifstream wnantfile(wnpref + "wn_ant.pl");
740 if (!wnantfile.is_open())
741 {
742 std::cout << "Invalid WordNet data directory." << std::endl;
743 print_usage();
359 } 744 }
745
746 std::list<std::string> lines;
747 for (;;)
748 {
749 std::string line;
750 if (!getline(wnantfile, line))
751 {
752 break;
753 }
360 754
361 if (line.back() == '\r') 755 if (line.back() == '\r')
756 {
757 line.pop_back();
758 }
759
760 lines.push_back(line);
761 }
762
763 progress ppgs("Writing antonyms...", lines.size());
764 for (auto line : lines)
362 { 765 {
363 line.pop_back(); 766 ppgs.update();
767
768 std::regex relation("^ant\\(([134]\\d{8}),(\\d+),([134]\\d{8}),(\\d+)\\)\\.");
769 std::smatch relation_data;
770 if (!std::regex_search(line, relation_data, relation))
771 {
772 continue;
773 }
774
775 int synset_id_1 = stoi(relation_data[1]);
776 int wnum_1 = stoi(relation_data[2]);
777 int synset_id_2 = stoi(relation_data[3]);
778 int wnum_2 = stoi(relation_data[4]);
779
780 std::string query;
781 switch (synset_id_1 / 100000000)
782 {
783 case 1: // Noun
784 {
785 query = "INSERT INTO noun_antonymy (noun_1_id, noun_2_id) VALUES (?, ?)";
786
787 break;
788 }
789
790 case 2: // Verb
791 {
792 // Ignore
793
794 break;
795 }
796
797 case 3: // Adjective
798 {
799 query = "INSERT INTO adjective_antonymy (adjective_1_id, adjective_2_id) VALUES (?, ?)";
800
801 break;
802 }
803
804 case 4: // Adverb
805 {
806 query = "INSERT INTO adverb_antonymy (adverb_1_id, adverb_2_id) VALUES (?, ?)";
807
808 break;
809 }
810 }
811
812 sqlite3_stmt* ppstmt;
813 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
814 {
815 db_error(ppdb, query);
816 }
817
818 sqlite3_bind_int(ppstmt, 1, wn[synset_id_1][wnum_1]);
819 sqlite3_bind_int(ppstmt, 2, wn[synset_id_2][wnum_2]);
820
821 if (sqlite3_step(ppstmt) != SQLITE_DONE)
822 {
823 db_error(ppdb, query);
824 }
825
826 sqlite3_finalize(ppstmt);
827 }
828 }
829
830 // at table
831 {
832 std::ifstream wnatfile(wnpref + "wn_at.pl");
833 if (!wnatfile.is_open())
834 {
835 std::cout << "Invalid WordNet data directory." << std::endl;
836 print_usage();
364 } 837 }
838
839 std::list<std::string> lines;
840 for (;;)
841 {
842 std::string line;
843 if (!getline(wnatfile, line))
844 {
845 break;
846 }
365 847
366 std::regex relation("^s\\(([134]\\d{8}),(\\d+),'([\\w ]+)',"); 848 if (line.back() == '\r')
367 std::smatch relation_data; 849 {
368 if (!std::regex_search(line, relation_data, relation)) 850 line.pop_back();
851 }
852
853 lines.push_back(line);
854 }
855
856 progress ppgs("Writing variations...", lines.size());
857 for (auto line : lines)
369 { 858 {
370 continue; 859 ppgs.update();
860
861 std::regex relation("^at\\((1\\d{8}),(3\\d{8})\\)\\.");
862 std::smatch relation_data;
863 if (!std::regex_search(line, relation_data, relation))
864 {
865 continue;
866 }
867
868 int synset_id_1 = stoi(relation_data[1]);
869 int synset_id_2 = stoi(relation_data[2]);
870 std::string query("INSERT INTO variation (noun_id, adjective_id) VALUES (?, ?)");
871
872 for (auto mapping1 : wn[synset_id_1])
873 {
874 for (auto mapping2 : wn[synset_id_2])
875 {
876 sqlite3_stmt* ppstmt;
877 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
878 {
879 db_error(ppdb, query);
880 }
881
882 sqlite3_bind_int(ppstmt, 1, mapping1.second);
883 sqlite3_bind_int(ppstmt, 2, mapping2.second);
884
885 if (sqlite3_step(ppstmt) != SQLITE_DONE)
886 {
887 db_error(ppdb, query);
888 }
889
890 sqlite3_finalize(ppstmt);
891 }
892 }
371 } 893 }
894 }
895
896 // hyp table
897 {
898 std::ifstream wnhypfile(wnpref + "wn_hyp.pl");
899 if (!wnhypfile.is_open())
900 {
901 std::cout << "Invalid WordNet data directory." << std::endl;
902 print_usage();
903 }
904
905 std::list<std::string> lines;
906 for (;;)
907 {
908 std::string line;
909 if (!getline(wnhypfile, line))
910 {
911 break;
912 }
372 913
373 int synset_id = stoi(relation_data[1]); 914 if (line.back() == '\r')
374 int wnum = stoi(relation_data[2]); 915 {
375 std::string word = relation_data[3]; 916 line.pop_back();
917 }
918
919 lines.push_back(line);
920 }
376 921
377 std::string query; 922 progress ppgs("Writing hypernyms...", lines.size());
378 switch (synset_id / 100000000) 923 for (auto line : lines)
379 { 924 {
380 case 1: // Noun 925 ppgs.update();
926
927 std::regex relation("^hyp\\((1\\d{8}),(1\\d{8})\\)\\.");
928 std::smatch relation_data;
929 if (!std::regex_search(line, relation_data, relation))
930 {
931 continue;
932 }
933
934 int synset_id_1 = stoi(relation_data[1]);
935 int synset_id_2 = stoi(relation_data[2]);
936 std::string query("INSERT INTO hypernymy (hyponym_id, hypernym_id) VALUES (?, ?)");
937
938 for (auto mapping1 : wn[synset_id_1])
939 {
940 for (auto mapping2 : wn[synset_id_2])
941 {
942 sqlite3_stmt* ppstmt;
943 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
944 {
945 db_error(ppdb, query);
946 }
947
948 sqlite3_bind_int(ppstmt, 1, mapping1.second);
949 sqlite3_bind_int(ppstmt, 2, mapping2.second);
950
951 if (sqlite3_step(ppstmt) != SQLITE_DONE)
952 {
953 db_error(ppdb, query);
954 }
955
956 sqlite3_finalize(ppstmt);
957 }
958 }
959 }
960 }
961
962 // ins table
963 {
964 std::ifstream wninsfile(wnpref + "wn_ins.pl");
965 if (!wninsfile.is_open())
966 {
967 std::cout << "Invalid WordNet data directory." << std::endl;
968 print_usage();
969 }
970
971 std::list<std::string> lines;
972 for (;;)
973 {
974 std::string line;
975 if (!getline(wninsfile, line))
381 { 976 {
382 query = "INSERT INTO nouns (form) VALUES (?)";
383
384 break; 977 break;
385 } 978 }
979
980 if (line.back() == '\r')
981 {
982 line.pop_back();
983 }
386 984
387 case 2: // Verb 985 lines.push_back(line);
986 }
987
988 progress ppgs("Writing instantiations...", lines.size());
989 for (auto line : lines)
990 {
991 ppgs.update();
992
993 std::regex relation("^ins\\((1\\d{8}),(1\\d{8})\\)\\.");
994 std::smatch relation_data;
995 if (!std::regex_search(line, relation_data, relation))
996 {
997 continue;
998 }
999
1000 int synset_id_1 = stoi(relation_data[1]);
1001 int synset_id_2 = stoi(relation_data[2]);
1002 std::string query("INSERT INTO instantiation (instance_id, class_id) VALUES (?, ?)");
1003
1004 for (auto mapping1 : wn[synset_id_1])
1005 {
1006 for (auto mapping2 : wn[synset_id_2])
1007 {
1008 sqlite3_stmt* ppstmt;
1009 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1010 {
1011 db_error(ppdb, query);
1012 }
1013
1014 sqlite3_bind_int(ppstmt, 1, mapping1.second);
1015 sqlite3_bind_int(ppstmt, 2, mapping2.second);
1016
1017 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1018 {
1019 db_error(ppdb, query);
1020 }
1021
1022 sqlite3_finalize(ppstmt);
1023 }
1024 }
1025 }
1026 }
1027
1028 // mm table
1029 {
1030 std::ifstream wnmmfile(wnpref + "wn_mm.pl");
1031 if (!wnmmfile.is_open())
1032 {
1033 std::cout << "Invalid WordNet data directory." << std::endl;
1034 print_usage();
1035 }
1036
1037 std::list<std::string> lines;
1038 for (;;)
1039 {
1040 std::string line;
1041 if (!getline(wnmmfile, line))
388 { 1042 {
389 // Ignore
390
391 break; 1043 break;
392 } 1044 }
1045
1046 if (line.back() == '\r')
1047 {
1048 line.pop_back();
1049 }
1050
1051 lines.push_back(line);
1052 }
1053
1054 progress ppgs("Writing member meronyms...", lines.size());
1055 for (auto line : lines)
1056 {
1057 ppgs.update();
393 1058
394 case 3: // Adjective 1059 std::regex relation("^mm\\((1\\d{8}),(1\\d{8})\\)\\.");
1060 std::smatch relation_data;
1061 if (!std::regex_search(line, relation_data, relation))
1062 {
1063 continue;
1064 }
1065
1066 int synset_id_1 = stoi(relation_data[1]);
1067 int synset_id_2 = stoi(relation_data[2]);
1068 std::string query("INSERT INTO member_meronymy (holonym_id, meronym_id) VALUES (?, ?)");
1069
1070 for (auto mapping1 : wn[synset_id_1])
1071 {
1072 for (auto mapping2 : wn[synset_id_2])
1073 {
1074 sqlite3_stmt* ppstmt;
1075 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1076 {
1077 db_error(ppdb, query);
1078 }
1079
1080 sqlite3_bind_int(ppstmt, 1, mapping1.second);
1081 sqlite3_bind_int(ppstmt, 2, mapping2.second);
1082
1083 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1084 {
1085 db_error(ppdb, query);
1086 }
1087
1088 sqlite3_finalize(ppstmt);
1089 }
1090 }
1091 }
1092 }
1093
1094 // ms table
1095 {
1096 std::ifstream wnmsfile(wnpref + "wn_ms.pl");
1097 if (!wnmsfile.is_open())
1098 {
1099 std::cout << "Invalid WordNet data directory." << std::endl;
1100 print_usage();
1101 }
1102
1103 std::list<std::string> lines;
1104 for (;;)
1105 {
1106 std::string line;
1107 if (!getline(wnmsfile, line))
395 { 1108 {
396 query = "INSERT INTO adjectives (form) VALUES (?)";
397
398 break; 1109 break;
399 } 1110 }
1111
1112 if (line.back() == '\r')
1113 {
1114 line.pop_back();
1115 }
400 1116
401 case 4: // Adverb 1117 lines.push_back(line);
1118 }
1119
1120 progress ppgs("Writing substance meronyms...", lines.size());
1121 for (auto line : lines)
1122 {
1123 ppgs.update();
1124
1125 std::regex relation("^ms\\((1\\d{8}),(1\\d{8})\\)\\.");
1126 std::smatch relation_data;
1127 if (!std::regex_search(line, relation_data, relation))
1128 {
1129 continue;
1130 }
1131
1132 int synset_id_1 = stoi(relation_data[1]);
1133 int synset_id_2 = stoi(relation_data[2]);
1134 std::string query("INSERT INTO substance_meronymy (holonym_id, meronym_id) VALUES (?, ?)");
1135
1136 for (auto mapping1 : wn[synset_id_1])
1137 {
1138 for (auto mapping2 : wn[synset_id_2])
1139 {
1140 sqlite3_stmt* ppstmt;
1141 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1142 {
1143 db_error(ppdb, query);
1144 }
1145
1146 sqlite3_bind_int(ppstmt, 1, mapping1.second);
1147 sqlite3_bind_int(ppstmt, 2, mapping2.second);
1148
1149 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1150 {
1151 db_error(ppdb, query);
1152 }
1153
1154 sqlite3_finalize(ppstmt);
1155 }
1156 }
1157 }
1158 }
1159
1160 // mm table
1161 {
1162 std::ifstream wnmpfile(wnpref + "wn_mp.pl");
1163 if (!wnmpfile.is_open())
1164 {
1165 std::cout << "Invalid WordNet data directory." << std::endl;
1166 print_usage();
1167 }
1168
1169 std::list<std::string> lines;
1170 for (;;)
1171 {
1172 std::string line;
1173 if (!getline(wnmpfile, line))
402 { 1174 {
403 query = "INSERT INTO adverbs (form) VALUES (?)";
404
405 break; 1175 break;
406 } 1176 }
1177
1178 if (line.back() == '\r')
1179 {
1180 line.pop_back();
1181 }
1182
1183 lines.push_back(line);
407 } 1184 }
408 1185
409 sqlite3_stmt* ppstmt; 1186 progress ppgs("Writing part meronyms...", lines.size());
410 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 1187 for (auto line : lines)
1188 {
1189 ppgs.update();
1190
1191 std::regex relation("^mp\\((1\\d{8}),(1\\d{8})\\)\\.");
1192 std::smatch relation_data;
1193 if (!std::regex_search(line, relation_data, relation))
1194 {
1195 continue;
1196 }
1197
1198 int synset_id_1 = stoi(relation_data[1]);
1199 int synset_id_2 = stoi(relation_data[2]);
1200 std::string query("INSERT INTO part_meronymy (holonym_id, meronym_id) VALUES (?, ?)");
1201
1202 for (auto mapping1 : wn[synset_id_1])
1203 {
1204 for (auto mapping2 : wn[synset_id_2])
1205 {
1206 sqlite3_stmt* ppstmt;
1207 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1208 {
1209 db_error(ppdb, query);
1210 }
1211
1212 sqlite3_bind_int(ppstmt, 1, mapping1.second);
1213 sqlite3_bind_int(ppstmt, 2, mapping2.second);
1214
1215 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1216 {
1217 db_error(ppdb, query);
1218 }
1219
1220 sqlite3_finalize(ppstmt);
1221 }
1222 }
1223 }
1224 }
1225
1226 // per table
1227 {
1228 std::ifstream wnperfile(wnpref + "wn_per.pl");
1229 if (!wnperfile.is_open())
411 { 1230 {
412 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 1231 std::cout << "Invalid WordNet data directory." << std::endl;
413 sqlite3_close_v2(ppdb);
414 print_usage(); 1232 print_usage();
415 } 1233 }
1234
1235 std::list<std::string> lines;
1236 for (;;)
1237 {
1238 std::string line;
1239 if (!getline(wnperfile, line))
1240 {
1241 break;
1242 }
1243
1244 if (line.back() == '\r')
1245 {
1246 line.pop_back();
1247 }
1248
1249 lines.push_back(line);
1250 }
1251
1252 progress ppgs("Writing pertainyms and mannernyms...", lines.size());
1253 for (auto line : lines)
1254 {
1255 ppgs.update();
1256
1257 std::regex relation("^per\\(([34]\\d{8}),(\\d+),([13]\\d{8}),(\\d+)\\)\\.");
1258 std::smatch relation_data;
1259 if (!std::regex_search(line, relation_data, relation))
1260 {
1261 continue;
1262 }
1263
1264 int synset_id_1 = stoi(relation_data[1]);
1265 int wnum_1 = stoi(relation_data[2]);
1266 int synset_id_2 = stoi(relation_data[3]);
1267 int wnum_2 = stoi(relation_data[4]);
1268 std::string query;
1269 switch (synset_id_1 / 100000000)
1270 {
1271 case 3: // Adjective
1272 {
1273 // This is a pertainym, the second word should be a noun
1274 // Technically it can be an adjective but we're ignoring that
1275 if (synset_id_2 / 100000000 != 1)
1276 {
1277 continue;
1278 }
1279
1280 query = "INSERT INTO pertainymy (pertainym_id, noun_id) VALUES (?, ?)";
1281
1282 break;
1283 }
1284
1285 case 4: // Adverb
1286 {
1287 // This is a mannernym, the second word should be an adjective
1288 if (synset_id_2 / 100000000 != 3)
1289 {
1290 continue;
1291 }
1292
1293 query = "INSERT INTO mannernymy (mannernym_id, adjective_id) VALUES (?, ?)";
1294
1295 break;
1296 }
1297 }
1298
1299 sqlite3_stmt* ppstmt;
1300 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
1301 {
1302 db_error(ppdb, query);
1303 }
416 1304
417 sqlite3_bind_text(ppstmt, 1, word.c_str(), word.length(), SQLITE_STATIC); 1305 sqlite3_bind_int(ppstmt, 1, wn[synset_id_1][wnum_1]);
1306 sqlite3_bind_int(ppstmt, 2, wn[synset_id_2][wnum_2]);
418 1307
419 if (sqlite3_step(ppstmt) != SQLITE_DONE) 1308 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1309 {
1310 db_error(ppdb, query);
1311 }
1312
1313 sqlite3_finalize(ppstmt);
1314 }
1315 }
1316
1317 // sa table
1318 {
1319 std::ifstream wnsafile(wnpref + "wn_sa.pl");
1320 if (!wnsafile.is_open())
420 { 1321 {
421 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 1322 std::cout << "Invalid WordNet data directory." << std::endl;
422 sqlite3_close_v2(ppdb);
423 print_usage(); 1323 print_usage();
424 } 1324 }
1325
1326 std::list<std::string> lines;
1327 for (;;)
1328 {
1329 std::string line;
1330 if (!getline(wnsafile, line))
1331 {
1332 break;
1333 }
1334
1335 if (line.back() == '\r')
1336 {
1337 line.pop_back();
1338 }
1339
1340 lines.push_back(line);
1341 }
425 1342
426 sqlite3_finalize(ppstmt); 1343 progress ppgs("Writing specifications...", lines.size());
1344 for (auto line : lines)
1345 {
1346 ppgs.update();
1347
1348 std::regex relation("^per\\((3\\d{8}),(\\d+),(3\\d{8}),(\\d+)\\)\\.");
1349 std::smatch relation_data;
1350 if (!std::regex_search(line, relation_data, relation))
1351 {
1352 continue;
1353 }
1354
1355 int synset_id_1 = stoi(relation_data[1]);
1356 int wnum_1 = stoi(relation_data[2]);
1357 int synset_id_2 = stoi(relation_data[3]);
1358 int wnum_2 = stoi(relation_data[4]);
1359 std::string query("INSERT INTO specification (general_id, specific_id) VALUES (?, ?)");
1360
1361 sqlite3_stmt* ppstmt;
1362 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
1363 {
1364 db_error(ppdb, query);
1365 }
1366
1367 sqlite3_bind_int(ppstmt, 1, wn[synset_id_1][wnum_1]);
1368 sqlite3_bind_int(ppstmt, 2, wn[synset_id_2][wnum_2]);
427 1369
428 query = "SELECT last_insert_rowid()"; 1370 if (sqlite3_step(ppstmt) != SQLITE_DONE)
429 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 1371 {
1372 db_error(ppdb, query);
1373 }
1374
1375 sqlite3_finalize(ppstmt);
1376 }
1377 }
1378 /*
1379 // sim table
1380 {
1381 std::ifstream wnsimfile(wnpref + "wn_sim.pl");
1382 if (!wnsimfile.is_open())
430 { 1383 {
431 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 1384 std::cout << "Invalid WordNet data directory." << std::endl;
432 sqlite3_close_v2(ppdb);
433 print_usage(); 1385 print_usage();
434 } 1386 }
1387
1388 std::list<std::string> lines;
1389 for (;;)
1390 {
1391 std::string line;
1392 if (!getline(wnsimfile, line))
1393 {
1394 break;
1395 }
1396
1397 if (line.back() == '\r')
1398 {
1399 line.pop_back();
1400 }
1401
1402 lines.push_back(line);
1403 }
435 1404
436 if (sqlite3_step(ppstmt) != SQLITE_ROW) 1405 progress ppgs("Writing sense synonyms...", lines.size());
1406 for (auto line : lines)
1407 {
1408 ppgs.update();
1409
1410 std::regex relation("^sim\\((3\\d{8}),(3\\d{8})\\)\\.");
1411 std::smatch relation_data;
1412 if (!std::regex_search(line, relation_data, relation))
1413 {
1414 continue;
1415 }
1416
1417 int synset_id_1 = stoi(relation_data[1]);
1418 int synset_id_2 = stoi(relation_data[2]);
1419 std::string query("INSERT INTO adjective_synonymy (adjective_1_id, adjective_2_id) VALUES (?, ?)");
1420
1421 for (auto mapping1 : wn[synset_id_1])
1422 {
1423 for (auto mapping2 : wn[synset_id_2])
1424 {
1425 sqlite3_stmt* ppstmt;
1426 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1427 {
1428 db_error(ppdb, query);
1429 }
1430
1431 sqlite3_bind_int(ppstmt, 1, mapping1.second);
1432 sqlite3_bind_int(ppstmt, 2, mapping2.second);
1433
1434 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1435 {
1436 db_error(ppdb, query);
1437 }
1438
1439 sqlite3_reset(ppstmt);
1440 sqlite3_clear_bindings(ppstmt);
1441
1442 sqlite3_bind_int(ppstmt, 1, mapping2.second);
1443 sqlite3_bind_int(ppstmt, 2, mapping1.second);
1444
1445 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1446 {
1447 db_error(ppdb, query);
1448 }
1449
1450 sqlite3_finalize(ppstmt);
1451 }
1452 }
1453 }
1454 }
1455 */
1456 // syntax table
1457 {
1458 std::ifstream wnsyntaxfile(wnpref + "wn_syntax.pl");
1459 if (!wnsyntaxfile.is_open())
437 { 1460 {
438 std::cout << "Error writing to output database: " << sqlite3_errmsg(ppdb) << std::endl; 1461 std::cout << "Invalid WordNet data directory." << std::endl;
439 sqlite3_close_v2(ppdb);
440 print_usage(); 1462 print_usage();
441 } 1463 }
1464
1465 std::list<std::string> lines;
1466 for (;;)
1467 {
1468 std::string line;
1469 if (!getline(wnsyntaxfile, line))
1470 {
1471 break;
1472 }
442 1473
443 wn[synset_id][wnum] = sqlite3_column_int(ppstmt, 0); 1474 if (line.back() == '\r')
1475 {
1476 line.pop_back();
1477 }
1478
1479 lines.push_back(line);
1480 }
444 1481
445 sqlite3_finalize(ppstmt); 1482 progress ppgs("Writing adjective syntax markers...", lines.size());
1483 for (auto line : lines)
1484 {
1485 ppgs.update();
1486
1487 std::regex relation("^syntax\\((3\\d{8}),(\\d+),([ipa])p?\\)\\.");
1488 std::smatch relation_data;
1489 if (!std::regex_search(line, relation_data, relation))
1490 {
1491 continue;
1492 }
1493
1494 int synset_id = stoi(relation_data[1]);
1495 int wnum = stoi(relation_data[2]);
1496 std::string syn = relation_data[3];
1497 std::string query("UPDATE adjectives SET position = ? WHERE adjective_id = ?");
1498
1499 sqlite3_stmt* ppstmt;
1500 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.size(), &ppstmt, NULL) != SQLITE_OK)
1501 {
1502 db_error(ppdb, query);
1503 }
1504
1505 sqlite3_bind_text(ppstmt, 1, syn.c_str(), 1, SQLITE_STATIC);
1506 sqlite3_bind_int(ppstmt, 2, wn[synset_id][wnum]);
1507
1508 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1509 {
1510 db_error(ppdb, query);
1511 }
1512
1513 sqlite3_finalize(ppstmt);
1514 }
446 } 1515 }
447 1516
448 sqlite3_close_v2(ppdb); 1517 sqlite3_close_v2(ppdb);
449 1518
450 std::cout << "Done." << std::endl; 1519 std::cout << "Done." << std::endl;
451} \ No newline at end of file 1520}
diff --git a/progress.h b/progress.h new file mode 100644 index 0000000..81f07a3 --- /dev/null +++ b/progress.h
@@ -0,0 +1,50 @@
1#ifndef PROGRESS_H_A34EF856
2#define PROGRESS_H_A34EF856
3
4#include <string>
5
6class progress {
7 private:
8 std::string message;
9 int total;
10 int cur = 0;
11 int lprint = 0;
12
13 public:
14 progress(std::string message, int total) : message(message), total(total)
15 {
16 std::cout << message << " 0%" << std::flush;
17 }
18
19 void update(int val)
20 {
21 if (val <= total)
22 {
23 cur = val;
24 } else {
25 cur = total;
26 }
27
28 int pp = cur * 100 / total;
29 if (pp != lprint)
30 {
31 lprint = pp;
32
33 std::cout << "\b\b\b\b" << std::right;
34 std::cout.width(3);
35 std::cout << pp << "%" << std::flush;
36 }
37 }
38
39 void update()
40 {
41 update(cur+1);
42 }
43
44 ~progress()
45 {
46 std::cout << "\b\b\b\b100%" << std::endl;
47 }
48};
49
50#endif /* end of include guard: PROGRESS_H_A34EF856 */
diff --git a/schema.sql b/schema.sql index 62dd780..fd55734 100644 --- a/schema.sql +++ b/schema.sql
@@ -34,20 +34,25 @@ CREATE TABLE `verb_groups` (
34DROP TABLE IF EXISTS `adjectives`; 34DROP TABLE IF EXISTS `adjectives`;
35CREATE TABLE `adjectives` ( 35CREATE TABLE `adjectives` (
36 `adjective_id` INTEGER PRIMARY KEY, 36 `adjective_id` INTEGER PRIMARY KEY,
37 `form` VARCHAR(32) NOT NULL, 37 `base_form` VARCHAR(32) NOT NULL,
38 `comparative` VARCHAR(32),
39 `superlative` VARCHAR(32),
38 `position` CHAR(1) 40 `position` CHAR(1)
39); 41);
40 42
41DROP TABLE IF EXISTS `adverbs`; 43DROP TABLE IF EXISTS `adverbs`;
42CREATE TABLE `adverbs` ( 44CREATE TABLE `adverbs` (
43 `adverb_id` INTEGER PRIMARY KEY, 45 `adverb_id` INTEGER PRIMARY KEY,
44 `form` VARCHAR(32) NOT NULL 46 `base_form` VARCHAR(32) NOT NULL,
47 `comparative` VARCHAR(32),
48 `superlative` VARCHAR(32)
45); 49);
46 50
47DROP TABLE IF EXISTS `nouns`; 51DROP TABLE IF EXISTS `nouns`;
48CREATE TABLE `nouns` ( 52CREATE TABLE `nouns` (
49 `noun_id` INTEGER PRIMARY KEY, 53 `noun_id` INTEGER PRIMARY KEY,
50 `form` VARCHAR(32) NOT NULL 54 `singular` VARCHAR(32) NOT NULL,
55 `plural` VARCHAR(32)
51); 56);
52 57
53DROP TABLE IF EXISTS `hypernymy`; 58DROP TABLE IF EXISTS `hypernymy`;
@@ -146,10 +151,54 @@ CREATE TABLE `mannernymy` (
146 FOREIGN KEY (`mannernym_id`) REFERENCES `adverbs`(`adverb_id`) 151 FOREIGN KEY (`mannernym_id`) REFERENCES `adverbs`(`adverb_id`)
147); 152);
148 153
149DROP TABLE IF EXISTS `synonymy`; 154DROP TABLE IF EXISTS `noun_synonymy`;
150CREATE TABLE `synonymy` ( 155CREATE TABLE `noun_synonymy` (
156 `noun_1_id` INTEGER NOT NULL,
157 `noun_2_id` INTEGER NOT NULL,
158 FOREIGN KEY (`noun_1_id`) REFERENCES `nouns`(`nouns_id`),
159 FOREIGN KEY (`noun_2_id`) REFERENCES `nouns`(`nouns_id`)
160);
161
162DROP TABLE IF EXISTS `adjective_synonymy`;
163CREATE TABLE `adjective_synonymy` (
151 `adjective_1_id` INTEGER NOT NULL, 164 `adjective_1_id` INTEGER NOT NULL,
152 `adjective_2_id` INTEGER NOT NULL, 165 `adjective_2_id` INTEGER NOT NULL,
153 FOREIGN KEY (`adjective_1_id`) REFERENCES `adjectives`(`adjective_id`), 166 FOREIGN KEY (`adjective_1_id`) REFERENCES `adjectives`(`adjective_id`),
154 FOREIGN KEY (`adjective_2_id`) REFERENCES `adjectives`(`adjective_id`) 167 FOREIGN KEY (`adjective_2_id`) REFERENCES `adjectives`(`adjective_id`)
155); 168);
169
170DROP TABLE IF EXISTS `adverb_synonymy`;
171CREATE TABLE `adverb_synonymy` (
172 `adverb_1_id` INTEGER NOT NULL,
173 `adverb_2_id` INTEGER NOT NULL,
174 FOREIGN KEY (`adverb_1_id`) REFERENCES `adverbs`(`adverb_id`),
175 FOREIGN KEY (`adverb_2_id`) REFERENCES `adverbs`(`adverb_id`)
176);
177
178DROP TABLE IF EXISTS `noun_pronunciations`;
179CREATE TABLE `noun_pronunciations` (
180 `noun_id` INTEGER NOT NULL,
181 `pronunciation` VARCHAR(64) NOT NULL,
182 FOREIGN KEY (`noun_id`) REFERENCES `nouns`(`noun_id`)
183);
184
185DROP TABLE IF EXISTS `verb_pronunciations`;
186CREATE TABLE `verb_pronunciations` (
187 `verb_id` INTEGER NOT NULL,
188 `pronunciation` VARCHAR(64) NOT NULL,
189 FOREIGN KEY (`verb_id`) REFERENCES `verbs`(`verb_id`)
190);
191
192DROP TABLE IF EXISTS `adjective_pronunciations`;
193CREATE TABLE `adjective_pronunciations` (
194 `adjective_id` INTEGER NOT NULL,
195 `pronunciation` VARCHAR(64) NOT NULL,
196 FOREIGN KEY (`adjective_id`) REFERENCES `adjectives`(`adjective_id`)
197);
198
199DROP TABLE IF EXISTS `adverb_pronunciations`;
200CREATE TABLE `adverb_pronunciations` (
201 `adverb_id` INTEGER NOT NULL,
202 `pronunciation` VARCHAR(64) NOT NULL,
203 FOREIGN KEY (`adverb_id`) REFERENCES `adverbs`(`adverb_id`)
204);
diff --git a/verbly/adjective.cpp b/verbly/adjective.cpp new file mode 100644 index 0000000..0f4087f --- /dev/null +++ b/verbly/adjective.cpp
@@ -0,0 +1,586 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 adjective::adjective(const data& _data, int _id) : word(_data, _id)
6 {
7
8 }
9
10 std::string adjective::base_form() const
11 {
12 return _base_form;
13 }
14
15 std::string adjective::comparative_form() const
16 {
17 return _comparative_form;
18 }
19
20 std::string adjective::superlative_form() const
21 {
22 return _superlative_form;
23 }
24
25 adjective::positioning adjective::position() const
26 {
27 return _position;
28 }
29
30 bool adjective::has_comparative_form() const
31 {
32 return !_comparative_form.empty();
33 }
34
35 bool adjective::has_superlative_form() const
36 {
37 return !_superlative_form.empty();
38 }
39
40 bool adjective::has_position() const
41 {
42 return _position != adjective::positioning::undefined;
43 }
44
45 adjective_query adjective::antonyms() const
46 {
47 return _data.adjectives().antonym_of(*this);
48 }
49
50 adjective_query adjective::synonyms() const
51 {
52 return _data.adjectives().synonym_of(*this);
53 }
54
55 adjective_query adjective::generalizations() const
56 {
57 return _data.adjectives().generalization_of(*this);
58 }
59
60 adjective_query adjective::specifications() const
61 {
62 return _data.adjectives().specification_of(*this);
63 }
64
65 noun_query adjective::anti_pertainyms() const
66 {
67 return _data.nouns().anti_pertainym_of(*this);
68 }
69
70 adverb_query adjective::mannernyms() const
71 {
72 return _data.adverbs().mannernym_of(*this);
73 }
74
75 noun_query adjective::attributes() const
76 {
77 return _data.nouns().attribute_of(*this);
78 }
79
80 adjective_query::adjective_query(const data& _data) : _data(_data)
81 {
82
83 }
84
85 adjective_query& adjective_query::limit(int _limit)
86 {
87 if ((_limit > 0) || (_limit == unlimited))
88 {
89 this->_limit = _limit;
90 }
91
92 return *this;
93 }
94
95 adjective_query& adjective_query::random(bool _random)
96 {
97 this->_random = _random;
98
99 return *this;
100 }
101
102 adjective_query& adjective_query::except(const adjective& _word)
103 {
104 _except.push_back(_word);
105
106 return *this;
107 }
108
109 adjective_query& adjective_query::rhymes_with(const word& _word)
110 {
111 for (auto rhyme : _word.rhyme_phonemes())
112 {
113 _rhymes.push_back(rhyme);
114 }
115
116 if (dynamic_cast<const adjective*>(&_word) != nullptr)
117 {
118 _except.push_back(dynamic_cast<const adjective&>(_word));
119 }
120
121 return *this;
122 }
123
124 adjective_query& adjective_query::has_pronunciation(bool _has_prn)
125 {
126 this->_has_prn = _has_prn;
127
128 return *this;
129 }
130
131 adjective_query& adjective_query::is_variant(bool _is_variant)
132 {
133 this->_is_variant = _is_variant;
134
135 return *this;
136 }
137
138 adjective_query& adjective_query::variant_of(const noun& _noun)
139 {
140 _variant_of.push_back(_noun);
141
142 return *this;
143 }
144
145 adjective_query& adjective_query::not_variant_of(const noun& _noun)
146 {
147 _not_variant_of.push_back(_noun);
148
149 return *this;
150 }
151
152 adjective_query& adjective_query::has_antonyms(bool _is_antonymic)
153 {
154 this->_is_antonymic = _is_antonymic;
155
156 return *this;
157 }
158
159 adjective_query& adjective_query::antonym_of(const adjective& _adj)
160 {
161 _antonym_of.push_back(_adj);
162
163 return *this;
164 }
165
166 adjective_query& adjective_query::not_antonym_of(const adjective& _adj)
167 {
168 _not_antonym_of.push_back(_adj);
169
170 return *this;
171 }
172
173 adjective_query& adjective_query::has_synonyms(bool _is_synonymic)
174 {
175 this->_is_synonymic = _is_synonymic;
176
177 return *this;
178 }
179
180 adjective_query& adjective_query::synonym_of(const adjective& _adj)
181 {
182 _synonym_of.push_back(_adj);
183
184 return *this;
185 }
186
187 adjective_query& adjective_query::not_synonym_of(const adjective& _adj)
188 {
189 _not_synonym_of.push_back(_adj);
190
191 return *this;
192 }
193
194 adjective_query& adjective_query::is_generalization(bool _is_generalization)
195 {
196 this->_is_generalization = _is_generalization;
197
198 return *this;
199 }
200
201 adjective_query& adjective_query::generalization_of(const adjective& _adj)
202 {
203 _generalization_of.push_back(_adj);
204
205 return *this;
206 }
207
208 adjective_query& adjective_query::not_generalization_of(const adjective& _adj)
209 {
210 _not_generalization_of.push_back(_adj);
211
212 return *this;
213 }
214
215 adjective_query& adjective_query::is_specification(bool _is_specification)
216 {
217 this->_is_specification = _is_specification;
218
219 return *this;
220 }
221
222 adjective_query& adjective_query::specification_of(const adjective& _adj)
223 {
224 _specification_of.push_back(_adj);
225
226 return *this;
227 }
228
229 adjective_query& adjective_query::not_specification_of(const adjective& _adj)
230 {
231 _not_specification_of.push_back(_adj);
232
233 return *this;
234 }
235
236 adjective_query& adjective_query::is_pertainymic(bool _is_pertainymic)
237 {
238 this->_is_pertainymic = _is_pertainymic;
239
240 return *this;
241 }
242
243 adjective_query& adjective_query::pertainym_of(const noun& _noun)
244 {
245 _pertainym_of.push_back(_noun);
246
247 return *this;
248 }
249
250 adjective_query& adjective_query::is_mannernymic(bool _is_mannernymic)
251 {
252 this->_is_mannernymic = _is_mannernymic;
253
254 return *this;
255 }
256
257 adjective_query& adjective_query::anti_mannernym_of(const adverb& _adv)
258 {
259 _anti_mannernym_of.push_back(_adv);
260
261 return *this;
262 }
263
264 std::list<adjective> adjective_query::run() const
265 {
266 std::stringstream construct;
267 construct << "SELECT adjective_id, base_form, comparative, superlative, position FROM adjectives";
268 std::list<std::string> conditions;
269
270 if (_has_prn)
271 {
272 conditions.push_back("adjective_id IN (SELECT adjective_id FROM adjective_pronunciations)");
273 }
274
275 if (!_rhymes.empty())
276 {
277 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN");
278 std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
279 conditions.push_back(cond);
280 }
281
282 for (auto except : _except)
283 {
284 conditions.push_back("adjective_id != @EXCID");
285 }
286
287 if (_requires_comparative_form)
288 {
289 conditions.push_back("comparative IS NOT NULL");
290 }
291
292 if (_requires_superlative_form)
293 {
294 conditions.push_back("superlative IS NOT NULL");
295 }
296
297 if (_position != adjective::positioning::undefined)
298 {
299 switch (_position)
300 {
301 case adjective::positioning::predicate: conditions.push_back("position = 'p'"); break;
302 case adjective::positioning::attributive: conditions.push_back("position = 'a'"); break;
303 case adjective::positioning::postnominal: conditions.push_back("position = 'i'"); break;
304 }
305 }
306
307 if (_is_variant)
308 {
309 conditions.push_back("adjective_id IN (SELECT adjective_id FROM variation)");
310 }
311
312 if (!_variant_of.empty())
313 {
314 std::list<std::string> clauses(_variant_of.size(), "noun_id = @ATTRID");
315 std::string cond = "adjective_id IN (SELECT adjective_id FROM variation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
316 conditions.push_back(cond);
317 }
318
319 if (!_not_variant_of.empty())
320 {
321 std::list<std::string> clauses(_not_variant_of.size(), "noun_id = @NATTRID");
322 std::string cond = "adjective_id NOT IN (SELECT adjective_id FROM variation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
323 conditions.push_back(cond);
324 }
325
326 if (_is_antonymic)
327 {
328 conditions.push_back("adjective_id IN (SELECT adjective_2_id FROM adjective_antonymy)");
329 }
330
331 if (!_antonym_of.empty())
332 {
333 std::list<std::string> clauses(_antonym_of.size(), "adjective_1_id = @ANTID");
334 std::string cond = "adjective_id IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
335 conditions.push_back(cond);
336 }
337
338 if (!_not_antonym_of.empty())
339 {
340 std::list<std::string> clauses(_not_antonym_of.size(), "adjective_1_id = @NANTID");
341 std::string cond = "adjective_id NOT IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
342 conditions.push_back(cond);
343 }
344
345 if (_is_synonymic)
346 {
347 conditions.push_back("adjective_id IN (SELECT adjective_2_id FROM adjective_synonymy)");
348 }
349
350 if (!_synonym_of.empty())
351 {
352 std::list<std::string> clauses(_synonym_of.size(), "adjective_1_id = @SYNID");
353 std::string cond = "adjective_id IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
354 conditions.push_back(cond);
355 }
356
357 if (!_not_synonym_of.empty())
358 {
359 std::list<std::string> clauses(_not_synonym_of.size(), "adjective_1_id = @NSYNID");
360 std::string cond = "adjective_id NOT IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
361 conditions.push_back(cond);
362 }
363
364 if (_is_generalization)
365 {
366 conditions.push_back("adjective_id IN (SELECT general_id FROM specification)");
367 }
368
369 if (!_generalization_of.empty())
370 {
371 std::list<std::string> clauses(_generalization_of.size(), "specific_id = @SPECID");
372 std::string cond = "adjective_id IN (SELECT general_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
373 conditions.push_back(cond);
374 }
375
376 if (!_not_generalization_of.empty())
377 {
378 std::list<std::string> clauses(_not_generalization_of.size(), "specific_id = @NSPECID");
379 std::string cond = "adjective_id NOT IN (SELECT general_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
380 conditions.push_back(cond);
381 }
382
383 if (_is_specification)
384 {
385 conditions.push_back("adjective_id IN (SELECT specific_id FROM specification)");
386 }
387
388 if (!_specification_of.empty())
389 {
390 std::list<std::string> clauses(_specification_of.size(), "general_id = @GENID");
391 std::string cond = "adjective_id IN (SELECT specific_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
392 conditions.push_back(cond);
393 }
394
395 if (!_not_specification_of.empty())
396 {
397 std::list<std::string> clauses(_not_specification_of.size(), "general_id = @NGENID");
398 std::string cond = "adjective_id NOT IN (SELECT specific_id FROM specification WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
399 conditions.push_back(cond);
400 }
401
402 if (_is_pertainymic)
403 {
404 conditions.push_back("adjective_id IN (SELECT pertainym_id FROM pertainymy)");
405 }
406
407 if (!_pertainym_of.empty())
408 {
409 std::list<std::string> clauses(_pertainym_of.size(), "noun_id = @APERID");
410 std::string cond = "adjective_id IN (SELECT pertainym_id FROM pertainymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
411 conditions.push_back(cond);
412 }
413
414 if (_is_mannernymic)
415 {
416 conditions.push_back("adjective_id IN (SELECT adjective_id FROM mannernymy)");
417 }
418
419 if (!_anti_mannernym_of.empty())
420 {
421 std::list<std::string> clauses(_anti_mannernym_of.size(), "mannernym_id = @MANID");
422 std::string cond = "adjective_id IN (SELECT adjective_id FROM mannernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
423 conditions.push_back(cond);
424 }
425
426 if (!conditions.empty())
427 {
428 construct << " WHERE ";
429 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
430 }
431
432 if (_random)
433 {
434 construct << " ORDER BY RANDOM()";
435 }
436
437 if (_limit != unlimited)
438 {
439 construct << " LIMIT " << _limit;
440 }
441
442 sqlite3_stmt* ppstmt;
443 std::string query = construct.str();
444 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
445 {
446 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
447 }
448
449 if (!_rhymes.empty())
450 {
451 int i = 0;
452 for (auto rhyme : _rhymes)
453 {
454 std::string rhymer = "%" + rhyme;
455 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC);
456
457 i++;
458 }
459 }
460
461 for (auto except : _except)
462 {
463 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
464 }
465
466 for (auto attribute : _variant_of)
467 {
468 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ATTRID"), attribute._id);
469 }
470
471 for (auto attribute : _not_variant_of)
472 {
473 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NATTRID"), attribute._id);
474 }
475
476 for (auto antonym : _antonym_of)
477 {
478 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id);
479 }
480
481 for (auto antonym : _not_antonym_of)
482 {
483 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NANTID"), antonym._id);
484 }
485
486 for (auto synonym : _synonym_of)
487 {
488 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id);
489 }
490
491 for (auto synonym : _not_synonym_of)
492 {
493 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSYNID"), synonym._id);
494 }
495
496 for (auto specific : _generalization_of)
497 {
498 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SPECID"), specific._id);
499 }
500
501 for (auto specific : _not_generalization_of)
502 {
503 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSPECID"), specific._id);
504 }
505
506 for (auto general : _specification_of)
507 {
508 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@GENID"), general._id);
509 }
510
511 for (auto general : _not_specification_of)
512 {
513 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NGENID"), general._id);
514 }
515
516 for (auto n : _pertainym_of)
517 {
518 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@APERID"), n._id);
519 }
520
521 for (auto mannernym : _anti_mannernym_of)
522 {
523 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MANID"), mannernym._id);
524 }
525
526 std::list<adjective> output;
527 while (sqlite3_step(ppstmt) == SQLITE_ROW)
528 {
529 adjective tnc {_data, sqlite3_column_int(ppstmt, 0)};
530 tnc._base_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
531
532 if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)
533 {
534 tnc._comparative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
535 }
536
537 if (sqlite3_column_type(ppstmt, 3) != SQLITE_NULL)
538 {
539 tnc._superlative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3)));
540 }
541
542 if (sqlite3_column_type(ppstmt, 4) != SQLITE_NULL)
543 {
544 std::string adjpos(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 4)));
545 if (adjpos == "p")
546 {
547 tnc._position = adjective::positioning::predicate;
548 } else if (adjpos == "a")
549 {
550 tnc._position = adjective::positioning::attributive;
551 } else if (adjpos == "i")
552 {
553 tnc._position = adjective::positioning::postnominal;
554 }
555 }
556
557 output.push_back(tnc);
558 }
559
560 sqlite3_finalize(ppstmt);
561
562 for (auto& adjective : output)
563 {
564 query = "SELECT pronunciation FROM adjective_pronunciations WHERE adjective_id = ?";
565 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
566 {
567 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
568 }
569
570 sqlite3_bind_int(ppstmt, 1, adjective._id);
571
572 while (sqlite3_step(ppstmt) == SQLITE_ROW)
573 {
574 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
575 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
576
577 adjective.pronunciations.push_back(phonemes);
578 }
579
580 sqlite3_finalize(ppstmt);
581 }
582
583 return output;
584 }
585
586};
diff --git a/verbly/adjective.h b/verbly/adjective.h index 9d7883f..4927d59 100644 --- a/verbly/adjective.h +++ b/verbly/adjective.h
@@ -3,17 +3,129 @@
3 3
4namespace verbly { 4namespace verbly {
5 5
6 class adjective { 6 class adjective_query;
7 class adverb_query;
8 class noun_query;
9
10 class adjective : public word {
11 public:
12 enum class positioning {
13 undefined,
14 predicate,
15 attributive,
16 postnominal
17 };
18
7 private: 19 private:
8 int id; 20 std::string _base_form;
21 std::string _comparative_form;
22 std::string _superlative_form;
23 positioning _position = positioning::undefined;
24
25 friend class adjective_query;
26
27 public:
28 adjective(const data& _data, int _id);
29
30 std::string base_form() const;
31 std::string comparative_form() const;
32 std::string superlative_form() const;
33 positioning position() const;
34
35 bool has_comparative_form() const;
36 bool has_superlative_form() const;
37 bool has_position() const;
9 38
39 adjective_query antonyms() const;
40 adjective_query synonyms() const;
41 adjective_query generalizations() const;
42 adjective_query specifications() const;
43 noun_query anti_pertainyms() const;
44 adverb_query mannernyms() const;
45 noun_query attributes() const;
46 };
47
48 class adjective_query {
10 public: 49 public:
11 std::string form; 50 adjective_query(const data& _data);
51
52 adjective_query& limit(int _limit);
53 adjective_query& random(bool _random);
54 adjective_query& except(const adjective& _word);
55 adjective_query& rhymes_with(const word& _word);
56 adjective_query& has_pronunciation(bool _has_prn);
57
58 adjective_query& requires_comparative_form(bool req);
59 adjective_query& requires_superlative_form(bool req);
60 adjective_query& position(adjective::positioning pos);
61
62 adjective_query& is_variant(bool _is_variant);
63 adjective_query& variant_of(const noun& _noun);
64 adjective_query& not_variant_of(const noun& _noun);
65
66 adjective_query& has_antonyms(bool _is_antonymic);
67 adjective_query& antonym_of(const adjective& _adj);
68 adjective_query& not_antonym_of(const adjective& _adj);
69
70 adjective_query& has_synonyms(bool _is_synonymic);
71 adjective_query& synonym_of(const adjective& _adj);
72 adjective_query& not_synonym_of(const adjective& _adj);
73
74 adjective_query& is_generalization(bool _is_generalization);
75 adjective_query& generalization_of(const adjective& _adj);
76 adjective_query& not_generalization_of(const adjective& _adj);
77
78 adjective_query& is_specification(bool _is_specification);
79 adjective_query& specification_of(const adjective& _adj);
80 adjective_query& not_specification_of(const adjective& _adj);
81
82 adjective_query& is_pertainymic(bool _is_pertainymic);
83 adjective_query& pertainym_of(const noun& _noun);
84
85 adjective_query& is_mannernymic(bool _is_mannernymic);
86 adjective_query& anti_mannernym_of(const adverb& _adv);
87
88 std::list<adjective> run() const;
89
90 const static int unlimited = -1;
91
92 protected:
93 const data& _data;
94 int _limit = unlimited;
95 bool _random = false;
96 std::list<std::string> _rhymes;
97 std::list<adjective> _except;
98 bool _has_prn = false;
99
100 bool _requires_comparative_form = false;
101 bool _requires_superlative_form = false;
102 adjective::positioning _position = adjective::positioning::undefined;
103
104 bool _is_variant = false;
105 std::list<noun> _variant_of;
106 std::list<noun> _not_variant_of;
107
108 bool _is_antonymic = false;
109 std::list<adjective> _antonym_of;
110 std::list<adjective> _not_antonym_of;
111
112 bool _is_synonymic = false;
113 std::list<adjective> _synonym_of;
114 std::list<adjective> _not_synonym_of;
115
116 bool _is_generalization = false;
117 std::list<adjective> _generalization_of;
118 std::list<adjective> _not_generalization_of;
119
120 bool _is_specification = false;
121 std::list<adjective> _specification_of;
122 std::list<adjective> _not_specification_of;
123
124 bool _is_pertainymic = false;
125 std::list<noun> _pertainym_of;
12 126
13 adjective(int id) : id(id) 127 bool _is_mannernymic = false;
14 { 128 std::list<adverb> _anti_mannernym_of;
15
16 }
17 }; 129 };
18 130
19}; 131};
diff --git a/verbly/adverb.cpp b/verbly/adverb.cpp new file mode 100644 index 0000000..9bb5a0d --- /dev/null +++ b/verbly/adverb.cpp
@@ -0,0 +1,364 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 adverb::adverb(const data& _data, int _id) : word(_data, _id)
6 {
7
8 }
9
10 std::string adverb::base_form() const
11 {
12 return _base_form;
13 }
14
15 std::string adverb::comparative_form() const
16 {
17 return _comparative_form;
18 }
19
20 std::string adverb::superlative_form() const
21 {
22 return _superlative_form;
23 }
24
25 bool adverb::has_comparative_form() const
26 {
27 return !_comparative_form.empty();
28 }
29
30 bool adverb::has_superlative_form() const
31 {
32 return !_superlative_form.empty();
33 }
34
35 adverb_query adverb::antonyms() const
36 {
37 return _data.adverbs().antonym_of(*this);
38 }
39
40 adverb_query adverb::synonyms() const
41 {
42 return _data.adverbs().synonym_of(*this);
43 }
44
45 adjective_query adverb::anti_mannernyms() const
46 {
47 return _data.adjectives().anti_mannernym_of(*this);
48 }
49
50 adverb_query::adverb_query(const data& _data) : _data(_data)
51 {
52
53 }
54
55 adverb_query& adverb_query::limit(int _limit)
56 {
57 if ((_limit > 0) || (_limit == unlimited))
58 {
59 this->_limit = _limit;
60 }
61
62 return *this;
63 }
64
65 adverb_query& adverb_query::random(bool _random)
66 {
67 this->_random = _random;
68
69 return *this;
70 }
71
72 adverb_query& adverb_query::except(const adverb& _word)
73 {
74 _except.push_back(_word);
75
76 return *this;
77 }
78
79 adverb_query& adverb_query::rhymes_with(const word& _word)
80 {
81 for (auto rhyme : _word.rhyme_phonemes())
82 {
83 _rhymes.push_back(rhyme);
84 }
85
86 if (dynamic_cast<const adverb*>(&_word) != nullptr)
87 {
88 _except.push_back(dynamic_cast<const adverb&>(_word));
89 }
90
91 return *this;
92 }
93
94 adverb_query& adverb_query::has_pronunciation(bool _has_prn)
95 {
96 this->_has_prn = _has_prn;
97
98 return *this;
99 }
100
101 adverb_query& adverb_query::requires_comparative_form(bool _arg)
102 {
103 _requires_comparative_form = _arg;
104
105 return *this;
106 }
107
108 adverb_query& adverb_query::requires_superlative_form(bool _arg)
109 {
110 _requires_superlative_form = _arg;
111
112 return *this;
113 }
114
115 adverb_query& adverb_query::has_antonyms(bool _arg)
116 {
117 _has_antonyms = _arg;
118
119 return *this;
120 }
121
122 adverb_query& adverb_query::antonym_of(const adverb& _adv)
123 {
124 _antonym_of.push_back(_adv);
125
126 return *this;
127 }
128
129 adverb_query& adverb_query::not_antonym_of(const adverb& _adv)
130 {
131 _not_antonym_of.push_back(_adv);
132
133 return *this;
134 }
135
136 adverb_query& adverb_query::has_synonyms(bool _arg)
137 {
138 _has_synonyms = _arg;
139
140 return *this;
141 }
142
143 adverb_query& adverb_query::synonym_of(const adverb& _adv)
144 {
145 _synonym_of.push_back(_adv);
146
147 return *this;
148 }
149
150 adverb_query& adverb_query::not_synonym_of(const adverb& _adv)
151 {
152 _not_synonym_of.push_back(_adv);
153
154 return *this;
155 }
156
157 adverb_query& adverb_query::is_mannernymic(bool _arg)
158 {
159 _is_mannernymic = _arg;
160
161 return *this;
162 }
163
164 adverb_query& adverb_query::mannernym_of(const adjective& _adj)
165 {
166 _mannernym_of.push_back(_adj);
167
168 return *this;
169 }
170
171 std::list<adverb> adverb_query::run() const
172 {
173 std::stringstream construct;
174 construct << "SELECT adverb_id, base_form, comparative, superlative FROM adverbs";
175 std::list<std::string> conditions;
176
177 if (_has_prn)
178 {
179 conditions.push_back("adverb_id IN (SELECT adverb_id FROM adverb_pronunciations)");
180 }
181
182 if (!_rhymes.empty())
183 {
184 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN");
185 std::string cond = "adverb_id IN (SELECT adverb_id FROM adverb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
186 conditions.push_back(cond);
187 }
188
189 for (auto except : _except)
190 {
191 conditions.push_back("adverb_id != @EXCID");
192 }
193
194 if (_requires_comparative_form)
195 {
196 conditions.push_back("comparative IS NOT NULL");
197 }
198
199 if (_requires_superlative_form)
200 {
201 conditions.push_back("superlative IS NOT NULL");
202 }
203
204 if (_has_antonyms)
205 {
206 conditions.push_back("adverb_id IN (SELECT adverb_2_id FROM adverb_antonymy)");
207 }
208
209 if (!_antonym_of.empty())
210 {
211 std::list<std::string> clauses(_antonym_of.size(), "adverb_1_id = @ANTID");
212 std::string cond = "adverb_id IN (SELECT adverb_2_id FROM adverb_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
213 conditions.push_back(cond);
214 }
215
216 if (!_not_antonym_of.empty())
217 {
218 std::list<std::string> clauses(_not_antonym_of.size(), "adverb_1_id = @NANTID");
219 std::string cond = "adverb_id NOT IN (SELECT adverb_2_id FROM adverb_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
220 conditions.push_back(cond);
221 }
222
223 if (_has_synonyms)
224 {
225 conditions.push_back("adverb_id IN (SELECT adverb_2_id FROM adverb_synonymy)");
226 }
227
228 if (!_synonym_of.empty())
229 {
230 std::list<std::string> clauses(_synonym_of.size(), "adverb_1_id = @SYNID");
231 std::string cond = "adverb_id IN (SELECT adverb_2_id FROM adverb_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
232 conditions.push_back(cond);
233 }
234
235 if (!_not_synonym_of.empty())
236 {
237 std::list<std::string> clauses(_not_synonym_of.size(), "adverb_1_id = @NSYNID");
238 std::string cond = "adverb_id NOT IN (SELECT adverb_2_id FROM adverb_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
239 conditions.push_back(cond);
240 }
241
242 if (_is_mannernymic)
243 {
244 conditions.push_back("adverb_id IN (SELECT mannernym_id FROM mannernymy)");
245 }
246
247 if (!_mannernym_of.empty())
248 {
249 std::list<std::string> clauses(_mannernym_of.size(), "adjective_id = @AMANID");
250 std::string cond = "adverb_id IN (SELECT mannernym_id FROM mannernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
251 conditions.push_back(cond);
252 }
253
254 if (!conditions.empty())
255 {
256 construct << " WHERE ";
257 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
258 }
259
260 if (_random)
261 {
262 construct << " ORDER BY RANDOM()";
263 }
264
265 if (_limit != unlimited)
266 {
267 construct << " LIMIT " << _limit;
268 }
269
270 sqlite3_stmt* ppstmt;
271 std::string query = construct.str();
272 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
273 {
274 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
275 }
276
277 if (!_rhymes.empty())
278 {
279 int i = 0;
280 for (auto rhyme : _rhymes)
281 {
282 std::string rhymer = "%" + rhyme;
283 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC);
284
285 i++;
286 }
287 }
288
289 for (auto except : _except)
290 {
291 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
292 }
293
294 for (auto antonym : _antonym_of)
295 {
296 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id);
297 }
298
299 for (auto antonym : _not_antonym_of)
300 {
301 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NANTID"), antonym._id);
302 }
303
304 for (auto synonym : _synonym_of)
305 {
306 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id);
307 }
308
309 for (auto synonym : _not_synonym_of)
310 {
311 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSYNID"), synonym._id);
312 }
313
314 for (auto adj : _mannernym_of)
315 {
316 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@AMANID"), adj._id);
317 }
318
319 std::list<adverb> output;
320 while (sqlite3_step(ppstmt) == SQLITE_ROW)
321 {
322 adverb tnc {_data, sqlite3_column_int(ppstmt, 0)};
323 tnc._base_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
324
325 if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)
326 {
327 tnc._comparative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
328 }
329
330 if (sqlite3_column_type(ppstmt, 3) != SQLITE_NULL)
331 {
332 tnc._superlative_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3)));
333 }
334
335 output.push_back(tnc);
336 }
337
338 sqlite3_finalize(ppstmt);
339
340 for (auto& adverb : output)
341 {
342 query = "SELECT pronunciation FROM adverb_pronunciations WHERE adverb_id = ?";
343 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
344 {
345 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
346 }
347
348 sqlite3_bind_int(ppstmt, 1, adverb._id);
349
350 while (sqlite3_step(ppstmt) == SQLITE_ROW)
351 {
352 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
353 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
354
355 adverb.pronunciations.push_back(phonemes);
356 }
357
358 sqlite3_finalize(ppstmt);
359 }
360
361 return output;
362 }
363
364};
diff --git a/verbly/adverb.h b/verbly/adverb.h index 6d2466e..42c3492 100644 --- a/verbly/adverb.h +++ b/verbly/adverb.h
@@ -3,17 +3,78 @@
3 3
4namespace verbly { 4namespace verbly {
5 5
6 class adverb { 6 class adverb : public word {
7 private: 7 private:
8 int id; 8 std::string _base_form;
9 std::string _comparative_form;
10 std::string _superlative_form;
9 11
12 friend class adverb_query;
13
14 public:
15 adverb(const data& _data, int _id);
16
17 std::string base_form() const;
18 std::string comparative_form() const;
19 std::string superlative_form() const;
20
21 bool has_comparative_form() const;
22 bool has_superlative_form() const;
23
24 adverb_query antonyms() const;
25 adverb_query synonyms() const;
26 adjective_query anti_mannernyms() const;
27 };
28
29 class adverb_query {
10 public: 30 public:
11 std::string form; 31 adverb_query(const data& _data);
32
33 adverb_query& limit(int _limit);
34 adverb_query& random(bool _random);
35 adverb_query& except(const adverb& _word);
36 adverb_query& rhymes_with(const word& _word);
37 adverb_query& has_pronunciation(bool _has_prn);
38
39 adverb_query& requires_comparative_form(bool _arg);
40 adverb_query& requires_superlative_form(bool _arg);
41
42 adverb_query& has_antonyms(bool _arg);
43 adverb_query& antonym_of(const adverb& _adv);
44 adverb_query& not_antonym_of(const adverb& _adv);
45
46 adverb_query& has_synonyms(bool _arg);
47 adverb_query& synonym_of(const adverb& _adv);
48 adverb_query& not_synonym_of(const adverb& _adv);
49
50 adverb_query& is_mannernymic(bool _arg);
51 adverb_query& mannernym_of(const adjective& _adj);
52
53 std::list<adverb> run() const;
54
55 const static int unlimited = -1;
56
57 private:
58 const data& _data;
59 int _limit = unlimited;
60 bool _random = false;
61 std::list<std::string> _rhymes;
62 std::list<adverb> _except;
63 bool _has_prn = false;
64
65 bool _requires_comparative_form = false;
66 bool _requires_superlative_form = false;
67
68 bool _has_antonyms = false;
69 std::list<adverb> _antonym_of;
70 std::list<adverb> _not_antonym_of;
71
72 bool _has_synonyms = false;
73 std::list<adverb> _synonym_of;
74 std::list<adverb> _not_synonym_of;
12 75
13 adverb(int id) : id(id) 76 bool _is_mannernymic = false;
14 { 77 std::list<adjective> _mannernym_of;
15
16 }
17 }; 78 };
18 79
19}; 80};
diff --git a/verbly/data.cpp b/verbly/data.cpp new file mode 100644 index 0000000..57a8850 --- /dev/null +++ b/verbly/data.cpp
@@ -0,0 +1,50 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 data::data(std::string datafile)
6 {
7 if (sqlite3_open_v2(datafile.c_str(), &ppdb, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK)
8 {
9 throw std::invalid_argument(sqlite3_errmsg(ppdb));
10 }
11 }
12
13 data::data(data&& other)
14 {
15 ppdb = other.ppdb;
16 }
17
18 data& data::operator=(data&& other)
19 {
20 ppdb = other.ppdb;
21
22 return *this;
23 }
24
25 data::~data()
26 {
27 sqlite3_close_v2(ppdb);
28 }
29
30 verb_query data::verbs() const
31 {
32 return verb_query(*this);
33 }
34
35 adjective_query data::adjectives() const
36 {
37 return adjective_query(*this);
38 }
39
40 adverb_query data::adverbs() const
41 {
42 return adverb_query(*this);
43 }
44
45 noun_query data::nouns() const
46 {
47 return noun_query(*this);
48 }
49
50};
diff --git a/verbly/data.h b/verbly/data.h index e901cba..37092d7 100644 --- a/verbly/data.h +++ b/verbly/data.h
@@ -1,273 +1,46 @@
1#ifndef DATA_H_C4AEC3DD 1#ifndef DATA_H_C4AEC3DD
2#define DATA_H_C4AEC3DD 2#define DATA_H_C4AEC3DD
3 3
4#include "verb.h"
5#include <sqlite3.h> 4#include <sqlite3.h>
6#include <stdexcept> 5#include <stdexcept>
7 6
8namespace verbly { 7namespace verbly {
9 8
9 class data;
10 class word;
11 class adjective;
12 class noun;
13 class verb;
14 class adverb;
15 class adjective_query;
16 class adverb_query;
17 class noun_query;
18 class verb_query;
19
10 class data { 20 class data {
11 private: 21 private:
12 sqlite3* ppdb; 22 sqlite3* ppdb;
13 23
14 public: 24 friend class adjective_query;
15 class verb_query { 25 friend class noun_query;
16 public: 26 friend class verb_query;
17 const static int unlimited = -1; 27 friend class adverb_query;
18
19 private:
20 const data& database;
21 int m_limit = unlimited;
22 bool m_random = false;
23
24 public:
25 verb_query(const data& database) : database(database)
26 {
27
28 }
29
30 verb_query& limit(int m_limit)
31 {
32 if ((m_limit > 0) || (m_limit == unlimited))
33 {
34 this->m_limit = m_limit;
35 }
36
37 return *this;
38 }
39
40 verb_query& random(bool m_random)
41 {
42 this->m_random = m_random;
43
44 return *this;
45 }
46
47 std::list<verb> run() const
48 {
49 std::stringstream construct;
50 construct << "SELECT verb_id, infinitive, past_tense, past_participle, ing_form, s_form FROM verbs";
51
52 if (m_random)
53 {
54 construct << " ORDER BY RANDOM()";
55 }
56
57 if (m_limit != unlimited)
58 {
59 construct << " LIMIT " << m_limit;
60 }
61
62 sqlite3_stmt* ppstmt;
63 std::string query = construct.str();
64 if (sqlite3_prepare_v2(database.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
65 {
66 throw std::runtime_error(sqlite3_errmsg(database.ppdb));
67 }
68
69 std::list<verb> output;
70 while (sqlite3_step(ppstmt) == SQLITE_ROW)
71 {
72 verb tnc {sqlite3_column_int(ppstmt, 0)};
73 tnc.infinitive = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
74 tnc.past_tense = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
75 tnc.past_participle = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3)));
76 tnc.ing_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 4)));
77 tnc.s_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 5)));
78
79 output.push_back(tnc);
80 }
81
82 sqlite3_finalize(ppstmt);
83
84 return output;
85 }
86
87 };
88
89 class adjective_query {
90 public:
91 const static int unlimited = -1;
92
93 private:
94 const data& database;
95 int m_limit = unlimited;
96 bool m_random = false;
97
98 public:
99 adjective_query(const data& database) : database(database)
100 {
101
102 }
103
104 adjective_query& limit(int m_limit)
105 {
106 if ((m_limit > 0) || (m_limit == unlimited))
107 {
108 this->m_limit = m_limit;
109 }
110
111 return *this;
112 }
113
114 adjective_query& random(bool m_random)
115 {
116 this->m_random = m_random;
117
118 return *this;
119 }
120
121 std::list<adjective> run() const
122 {
123 std::stringstream construct;
124 construct << "SELECT adjective_id, form FROM adjectives";
125
126 if (m_random)
127 {
128 construct << " ORDER BY RANDOM()";
129 }
130
131 if (m_limit != unlimited)
132 {
133 construct << " LIMIT " << m_limit;
134 }
135
136 sqlite3_stmt* ppstmt;
137 std::string query = construct.str();
138 if (sqlite3_prepare_v2(database.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
139 {
140 throw std::runtime_error(sqlite3_errmsg(database.ppdb));
141 }
142
143 std::list<adjective> output;
144 while (sqlite3_step(ppstmt) == SQLITE_ROW)
145 {
146 adjective tnc {sqlite3_column_int(ppstmt, 0)};
147 tnc.form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
148
149 output.push_back(tnc);
150 }
151
152 sqlite3_finalize(ppstmt);
153
154 return output;
155 }
156
157 };
158
159 class adverb_query {
160 public:
161 const static int unlimited = -1;
162
163 private:
164 const data& database;
165 int m_limit = unlimited;
166 bool m_random = false;
167
168 public:
169 adverb_query(const data& database) : database(database)
170 {
171
172 }
173
174 adverb_query& limit(int m_limit)
175 {
176 if ((m_limit > 0) || (m_limit == unlimited))
177 {
178 this->m_limit = m_limit;
179 }
180
181 return *this;
182 }
183
184 adverb_query& random(bool m_random)
185 {
186 this->m_random = m_random;
187
188 return *this;
189 }
190
191 std::list<adverb> run() const
192 {
193 std::stringstream construct;
194 construct << "SELECT adverb_id, form FROM adverbs";
195
196 if (m_random)
197 {
198 construct << " ORDER BY RANDOM()";
199 }
200
201 if (m_limit != unlimited)
202 {
203 construct << " LIMIT " << m_limit;
204 }
205
206 sqlite3_stmt* ppstmt;
207 std::string query = construct.str();
208 if (sqlite3_prepare_v2(database.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
209 {
210 throw std::runtime_error(sqlite3_errmsg(database.ppdb));
211 }
212
213 std::list<adverb> output;
214 while (sqlite3_step(ppstmt) == SQLITE_ROW)
215 {
216 adverb tnc {sqlite3_column_int(ppstmt, 0)};
217 tnc.form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
218
219 output.push_back(tnc);
220 }
221
222 sqlite3_finalize(ppstmt);
223
224 return output;
225 }
226
227 };
228 28
229 data(std::string datafile) 29 public:
230 { 30 data(std::string datafile);
231 if (sqlite3_open_v2(datafile.c_str(), &ppdb, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK)
232 {
233 throw std::invalid_argument(sqlite3_errmsg(ppdb));
234 }
235 }
236 31
237 data(const data& other) = delete; 32 data(const data& other) = delete;
238 data& operator=(const data& other) = delete; 33 data& operator=(const data& other) = delete;
239 34
240 data(data&& other) 35 data(data&& other);
241 { 36 data& operator=(data&& other);
242 ppdb = other.ppdb;
243 }
244
245 data& operator=(data&& other)
246 {
247 ppdb = other.ppdb;
248
249 return *this;
250 }
251
252 ~data()
253 {
254 sqlite3_close_v2(ppdb);
255 }
256
257 verb_query verbs() const
258 {
259 return verb_query(*this);
260 }
261 37
262 adjective_query adjectives() const 38 ~data();
263 {
264 return adjective_query(*this);
265 }
266 39
267 adverb_query adverbs() const 40 verb_query verbs() const;
268 { 41 adjective_query adjectives() const;
269 return adverb_query(*this); 42 adverb_query adverbs() const;
270 } 43 noun_query nouns() const;
271 44
272 }; 45 };
273 46
diff --git a/verbly/noun.cpp b/verbly/noun.cpp new file mode 100644 index 0000000..9336a1c --- /dev/null +++ b/verbly/noun.cpp
@@ -0,0 +1,916 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 noun::noun(const data& _data, int _id) : word(_data, _id)
6 {
7
8 }
9
10 std::string noun::base_form() const
11 {
12 return _singular;
13 }
14
15 std::string noun::singular_form() const
16 {
17 return _singular;
18 }
19
20 std::string noun::plural_form() const
21 {
22 return _plural;
23 }
24
25 bool noun::has_plural_form() const
26 {
27 return !_plural.empty();
28 }
29
30 noun_query noun::hypernyms() const
31 {
32 return _data.nouns().hypernym_of(*this);
33 }
34
35 noun_query noun::hyponyms() const
36 {
37 return _data.nouns().hyponym_of(*this);
38 }
39
40 noun_query noun::part_meronyms() const
41 {
42 return _data.nouns().part_meronym_of(*this);
43 }
44
45 noun_query noun::part_holonyms() const
46 {
47 return _data.nouns().part_holonym_of(*this);
48 }
49
50 noun_query noun::substance_meronyms() const
51 {
52 return _data.nouns().substance_meronym_of(*this);
53 }
54
55 noun_query noun::substance_holonyms() const
56 {
57 return _data.nouns().substance_holonym_of(*this);
58 }
59
60 noun_query noun::member_meronyms() const
61 {
62 return _data.nouns().member_meronym_of(*this);
63 }
64
65 noun_query noun::member_holonyms() const
66 {
67 return _data.nouns().member_holonym_of(*this);
68 }
69
70 noun_query noun::classes() const
71 {
72 return _data.nouns().class_of(*this);
73 }
74
75 noun_query noun::instances() const
76 {
77 return _data.nouns().instance_of(*this);
78 }
79
80 noun_query noun::synonyms() const
81 {
82 return _data.nouns().synonym_of(*this);
83 }
84
85 noun_query noun::antonyms() const
86 {
87 return _data.nouns().antonym_of(*this);
88 }
89
90 adjective_query noun::pertainyms() const
91 {
92 return _data.adjectives().pertainym_of(*this);
93 }
94
95 adjective_query noun::variations() const
96 {
97 return _data.adjectives().variant_of(*this);
98 }
99
100 noun_query::noun_query(const data& _data) : _data(_data)
101 {
102
103 }
104
105 noun_query& noun_query::limit(int _limit)
106 {
107 if ((_limit > 0) || (_limit == unlimited))
108 {
109 this->_limit = _limit;
110 }
111
112 return *this;
113 }
114
115 noun_query& noun_query::random(bool _random)
116 {
117 this->_random = _random;
118
119 return *this;
120 }
121
122 noun_query& noun_query::except(const noun& _word)
123 {
124 _except.push_back(_word);
125
126 return *this;
127 }
128
129 noun_query& noun_query::rhymes_with(const word& _word)
130 {
131 for (auto rhyme : _word.rhyme_phonemes())
132 {
133 _rhymes.push_back(rhyme);
134 }
135
136 if (dynamic_cast<const noun*>(&_word) != nullptr)
137 {
138 _except.push_back(dynamic_cast<const noun&>(_word));
139 }
140
141 return *this;
142 }
143
144 noun_query& noun_query::has_pronunciation(bool _has_prn)
145 {
146 this->_has_prn = _has_prn;
147
148 return *this;
149 }
150
151 noun_query& noun_query::is_hypernym(bool _arg)
152 {
153 _is_hypernym = _arg;
154
155 return *this;
156 }
157
158 noun_query& noun_query::hypernym_of(const noun& _noun)
159 {
160 _hypernym_of.push_back(_noun);
161
162 return *this;
163 }
164
165 noun_query& noun_query::not_hypernym_of(const noun& _noun)
166 {
167 _not_hypernym_of.push_back(_noun);
168
169 return *this;
170 }
171
172 noun_query& noun_query::is_hyponym(bool _arg)
173 {
174 _is_hyponym = _arg;
175
176 return *this;
177 }
178
179 noun_query& noun_query::hyponym_of(const noun& _noun)
180 {
181 _hyponym_of.push_back(_noun);
182
183 return *this;
184 }
185
186 noun_query& noun_query::not_hyponym_of(const noun& _noun)
187 {
188 _not_hyponym_of.push_back(_noun);
189
190 return *this;
191 }
192
193 noun_query& noun_query::is_part_meronym(bool _arg)
194 {
195 _is_part_meronym = _arg;
196
197 return *this;
198 }
199
200 noun_query& noun_query::part_meronym_of(const noun& _noun)
201 {
202 _part_meronym_of.push_back(_noun);
203
204 return *this;
205 }
206
207 noun_query& noun_query::not_part_meronym_of(const noun& _noun)
208 {
209 _not_part_meronym_of.push_back(_noun);
210
211 return *this;
212 }
213
214 noun_query& noun_query::is_part_holonym(bool _arg)
215 {
216 _is_part_holonym = _arg;
217
218 return *this;
219 }
220
221 noun_query& noun_query::part_holonym_of(const noun& _noun)
222 {
223 _part_holonym_of.push_back(_noun);
224
225 return *this;
226 }
227
228 noun_query& noun_query::not_part_holonym_of(const noun& _noun)
229 {
230 _not_part_holonym_of.push_back(_noun);
231
232 return *this;
233 }
234
235 noun_query& noun_query::is_substance_meronym(bool _arg)
236 {
237 _is_substance_meronym = _arg;
238
239 return *this;
240 }
241
242 noun_query& noun_query::substance_meronym_of(const noun& _noun)
243 {
244 _substance_meronym_of.push_back(_noun);
245
246 return *this;
247 }
248
249 noun_query& noun_query::not_substance_meronym_of(const noun& _noun)
250 {
251 _not_substance_meronym_of.push_back(_noun);
252
253 return *this;
254 }
255
256 noun_query& noun_query::is_substance_holonym(bool _arg)
257 {
258 _is_substance_holonym = _arg;
259
260 return *this;
261 }
262
263 noun_query& noun_query::substance_holonym_of(const noun& _noun)
264 {
265 _substance_holonym_of.push_back(_noun);
266
267 return *this;
268 }
269
270 noun_query& noun_query::not_substance_holonym_of(const noun& _noun)
271 {
272 _not_substance_holonym_of.push_back(_noun);
273
274 return *this;
275 }
276
277 noun_query& noun_query::is_member_meronym(bool _arg)
278 {
279 _is_member_meronym = _arg;
280
281 return *this;
282 }
283
284 noun_query& noun_query::member_meronym_of(const noun& _noun)
285 {
286 _member_meronym_of.push_back(_noun);
287
288 return *this;
289 }
290
291 noun_query& noun_query::not_member_meronym_of(const noun& _noun)
292 {
293 _not_member_meronym_of.push_back(_noun);
294
295 return *this;
296 }
297
298 noun_query& noun_query::is_member_holonym(bool _arg)
299 {
300 _is_member_holonym = _arg;
301
302 return *this;
303 }
304
305 noun_query& noun_query::member_holonym_of(const noun& _noun)
306 {
307 _member_holonym_of.push_back(_noun);
308
309 return *this;
310 }
311
312 noun_query& noun_query::not_member_holonym_of(const noun& _noun)
313 {
314 _not_member_holonym_of.push_back(_noun);
315
316 return *this;
317 }
318
319 noun_query& noun_query::is_proper(bool _arg)
320 {
321 _is_proper = _arg;
322
323 return *this;
324 }
325
326 noun_query& noun_query::instance_of(const noun& _noun)
327 {
328 _instance_of.push_back(_noun);
329
330 return *this;
331 }
332
333 noun_query& noun_query::not_instance_of(const noun& _noun)
334 {
335 _not_instance_of.push_back(_noun);
336
337 return *this;
338 }
339
340 noun_query& noun_query::is_class(bool _arg)
341 {
342 _is_class = _arg;
343
344 return *this;
345 }
346
347 noun_query& noun_query::class_of(const noun& _noun)
348 {
349 _class_of.push_back(_noun);
350
351 return *this;
352 }
353
354 noun_query& noun_query::not_class_of(const noun& _noun)
355 {
356 _not_class_of.push_back(_noun);
357
358 return *this;
359 }
360
361 noun_query& noun_query::has_synonyms(bool _arg)
362 {
363 _has_synonyms = _arg;
364
365 return *this;
366 }
367
368 noun_query& noun_query::synonym_of(const noun& _noun)
369 {
370 _synonym_of.push_back(_noun);
371
372 return *this;
373 }
374
375 noun_query& noun_query::not_synonym_of(const noun& _noun)
376 {
377 _not_synonym_of.push_back(_noun);
378
379 return *this;
380 }
381
382 noun_query& noun_query::has_antonyms(bool _arg)
383 {
384 _has_antonyms = _arg;
385
386 return *this;
387 }
388
389 noun_query& noun_query::antonym_of(const noun& _noun)
390 {
391 _antonym_of.push_back(_noun);
392
393 return *this;
394 }
395
396 noun_query& noun_query::not_antonym_of(const noun& _noun)
397 {
398 _not_antonym_of.push_back(_noun);
399
400 return *this;
401 }
402
403 noun_query& noun_query::has_pertainym(bool _arg)
404 {
405 _has_pertainym = _arg;
406
407 return *this;
408 }
409
410 noun_query& noun_query::anti_pertainym_of(const adjective& _adj)
411 {
412 _anti_pertainym_of.push_back(_adj);
413
414 return *this;
415 }
416
417 noun_query& noun_query::is_attribute(bool _arg)
418 {
419 _is_attribute = _arg;
420
421 return *this;
422 }
423
424 noun_query& noun_query::attribute_of(const adjective& _adj)
425 {
426 _attribute_of.push_back(_adj);
427
428 return *this;
429 }
430
431 std::list<noun> noun_query::run() const
432 {
433 std::stringstream construct;
434 construct << "SELECT noun_id, singular, plural FROM nouns";
435 std::list<std::string> conditions;
436
437 if (_has_prn)
438 {
439 conditions.push_back("noun_id IN (SELECT noun_id FROM noun_pronunciations)");
440 }
441
442 if (!_rhymes.empty())
443 {
444 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN");
445 std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
446 conditions.push_back(cond);
447 }
448
449 for (auto except : _except)
450 {
451 conditions.push_back("noun_id != @EXCID");
452 }
453
454 if (_is_hypernym)
455 {
456 conditions.push_back("noun_id IN (SELECT hypernym_id FROM hypernymy)");
457 }
458
459 if (!_hypernym_of.empty())
460 {
461 std::list<std::string> clauses(_hypernym_of.size(), "hyponym_id = @HYPO");
462 std::string cond = "noun_id IN (SELECT hypernym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
463 conditions.push_back(cond);
464 }
465
466 if (!_not_hypernym_of.empty())
467 {
468 std::list<std::string> clauses(_not_hypernym_of.size(), "hyponym_id = @NHYPO");
469 std::string cond = "noun_id NOT IN (SELECT hypernym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
470 conditions.push_back(cond);
471 }
472
473 if (_is_hyponym)
474 {
475 conditions.push_back("noun_id IN (SELECT hyponym_id FROM hypernymy)");
476 }
477
478 if (!_hyponym_of.empty())
479 {
480 std::list<std::string> clauses(_hyponym_of.size(), "hypernym_id = @HYPER");
481 std::string cond = "noun_id IN (SELECT hyponym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
482 conditions.push_back(cond);
483 }
484
485 if (!_not_hyponym_of.empty())
486 {
487 std::list<std::string> clauses(_not_hyponym_of.size(), "hypernym_id = @NHYPER");
488 std::string cond = "noun_id NOT IN (SELECT hyponym_id FROM hypernymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
489 conditions.push_back(cond);
490 }
491
492 if (_is_part_meronym)
493 {
494 conditions.push_back("noun_id IN (SELECT meronym_id FROM part_meronymy)");
495 }
496
497 if (!_part_meronym_of.empty())
498 {
499 std::list<std::string> clauses(_part_meronym_of.size(), "holonym_id = @PHOLO");
500 std::string cond = "noun_id IN (SELECT meronym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
501 conditions.push_back(cond);
502 }
503
504 if (!_not_part_meronym_of.empty())
505 {
506 std::list<std::string> clauses(_not_part_meronym_of.size(), "holonym_id = @NPHOLO");
507 std::string cond = "noun_id NOT IN (SELECT meronym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
508 conditions.push_back(cond);
509 }
510
511 if (_is_part_holonym)
512 {
513 conditions.push_back("noun_id IN (SELECT holonym_id FROM part_meronymy)");
514 }
515
516 if (!_part_holonym_of.empty())
517 {
518 std::list<std::string> clauses(_part_holonym_of.size(), "meronym_id = @PMERO");
519 std::string cond = "noun_id IN (SELECT holonym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
520 conditions.push_back(cond);
521 }
522
523 if (!_not_part_holonym_of.empty())
524 {
525 std::list<std::string> clauses(_not_part_holonym_of.size(), "meronym_id = @NPMERO");
526 std::string cond = "noun_id NOT IN (SELECT holonym_id FROM part_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
527 conditions.push_back(cond);
528 }
529
530 if (_is_substance_meronym)
531 {
532 conditions.push_back("noun_id IN (SELECT meronym_id FROM substance_meronymy)");
533 }
534
535 if (!_substance_meronym_of.empty())
536 {
537 std::list<std::string> clauses(_substance_meronym_of.size(), "holonym_id = @SHOLO");
538 std::string cond = "noun_id IN (SELECT meronym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
539 conditions.push_back(cond);
540 }
541
542 if (!_not_substance_meronym_of.empty())
543 {
544 std::list<std::string> clauses(_not_substance_meronym_of.size(), "holonym_id = @NSHOLO");
545 std::string cond = "noun_id NOT IN (SELECT meronym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
546 conditions.push_back(cond);
547 }
548
549 if (_is_substance_holonym)
550 {
551 conditions.push_back("noun_id IN (SELECT holonym_id FROM substance_meronymy)");
552 }
553
554 if (!_substance_holonym_of.empty())
555 {
556 std::list<std::string> clauses(_substance_holonym_of.size(), "meronym_id = @SMERO");
557 std::string cond = "noun_id IN (SELECT holonym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
558 conditions.push_back(cond);
559 }
560
561 if (!_not_substance_holonym_of.empty())
562 {
563 std::list<std::string> clauses(_not_substance_holonym_of.size(), "meronym_id = @NSMERO");
564 std::string cond = "noun_id NOT IN (SELECT holonym_id FROM substance_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
565 conditions.push_back(cond);
566 }
567
568 if (_is_member_meronym)
569 {
570 conditions.push_back("noun_id IN (SELECT meronym_id FROM member_meronymy)");
571 }
572
573 if (!_member_meronym_of.empty())
574 {
575 std::list<std::string> clauses(_member_meronym_of.size(), "holonym_id = @MHOLO");
576 std::string cond = "noun_id IN (SELECT meronym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
577 conditions.push_back(cond);
578 }
579
580 if (!_not_member_meronym_of.empty())
581 {
582 std::list<std::string> clauses(_not_member_meronym_of.size(), "holonym_id = @NMHOLO");
583 std::string cond = "noun_id NOT IN (SELECT meronym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
584 conditions.push_back(cond);
585 }
586
587 if (_is_member_holonym)
588 {
589 conditions.push_back("noun_id IN (SELECT holonym_id FROM member_meronym)");
590 }
591
592 if (!_member_holonym_of.empty())
593 {
594 std::list<std::string> clauses(_member_holonym_of.size(), "meronym_id = @MMERO");
595 std::string cond = "noun_id IN (SELECT holonym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
596 conditions.push_back(cond);
597 }
598
599 if (!_not_member_holonym_of.empty())
600 {
601 std::list<std::string> clauses(_not_member_holonym_of.size(), "meronym_id = @NMMERO");
602 std::string cond = "noun_id NOT IN (SELECT holonym_id FROM member_meronymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
603 conditions.push_back(cond);
604 }
605
606 if (_is_proper)
607 {
608 conditions.push_back("noun_id IN (SELECT instance_id FROM instantiation)");
609 }
610
611 if (!_instance_of.empty())
612 {
613 std::list<std::string> clauses(_instance_of.size(), "class_id = @CLSID");
614 std::string cond = "noun_id IN (SELECT instance_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
615 conditions.push_back(cond);
616 }
617
618 if (!_not_instance_of.empty())
619 {
620 std::list<std::string> clauses(_not_instance_of.size(), "class_id = @NCLSID");
621 std::string cond = "noun_id NOT IN (SELECT instance_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
622 conditions.push_back(cond);
623 }
624
625 if (_is_class)
626 {
627 conditions.push_back("noun_id IN (SELECT class_id FROM instantiation)");
628 }
629
630 if (!_class_of.empty())
631 {
632 std::list<std::string> clauses(_class_of.size(), "instance_id = @INSID");
633 std::string cond = "noun_id IN (SELECT class_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
634 conditions.push_back(cond);
635 }
636
637 if (!_not_class_of.empty())
638 {
639 std::list<std::string> clauses(_not_class_of.size(), "instance_id = @NINSID");
640 std::string cond = "noun_id NOT IN (SELECT class_id FROM instantiation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
641 conditions.push_back(cond);
642 }
643
644 if (_has_synonyms)
645 {
646 conditions.push_back("noun_id IN (SELECT adjective_2_id FROM adjective_synonymy)");
647 }
648
649 if (!_synonym_of.empty())
650 {
651 std::list<std::string> clauses(_synonym_of.size(), "adjective_1_id = @SYNID");
652 std::string cond = "noun_id IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
653 conditions.push_back(cond);
654 }
655
656 if (!_not_synonym_of.empty())
657 {
658 std::list<std::string> clauses(_not_synonym_of.size(), "adjective_1_id = @NSYNID");
659 std::string cond = "noun_id NOT IN (SELECT adjective_2_id FROM adjective_synonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
660 conditions.push_back(cond);
661 }
662
663 if (_has_antonyms)
664 {
665 conditions.push_back("noun_id IN (SELECT adjective_2_id FROM adjective_antonymy)");
666 }
667
668 if (!_antonym_of.empty())
669 {
670 std::list<std::string> clauses(_antonym_of.size(), "adjective_1_id = @ANTID");
671 std::string cond = "noun_id IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
672 conditions.push_back(cond);
673 }
674
675 if (!_not_antonym_of.empty())
676 {
677 std::list<std::string> clauses(_not_antonym_of.size(), "adjective_1_id = @NANTID");
678 std::string cond = "noun_id NOT IN (SELECT adjective_2_id FROM adjective_antonymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
679 conditions.push_back(cond);
680 }
681
682 if (_has_pertainym)
683 {
684 conditions.push_back("noun_id IN (SELECT noun_id FROM pertainymy)");
685 }
686
687 if (!_anti_pertainym_of.empty())
688 {
689 std::list<std::string> clauses(_anti_pertainym_of.size(), "pertainym_id = @PERID");
690 std::string cond = "noun_id IN (SELECT noun_id FROM pertainymy WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
691 conditions.push_back(cond);
692 }
693
694 if (_is_attribute)
695 {
696 conditions.push_back("noun_id IN (SELECT noun_id FROM variation)");
697 }
698
699 if (!_attribute_of.empty())
700 {
701 std::list<std::string> clauses(_attribute_of.size(), "adjective_id = @VALID");
702 std::string cond = "noun_id IN (SELECT noun_id FROM variation WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
703 conditions.push_back(cond);
704 }
705
706 if (!conditions.empty())
707 {
708 construct << " WHERE ";
709 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
710 }
711
712 if (_random)
713 {
714 construct << " ORDER BY RANDOM()";
715 }
716
717 if (_limit != unlimited)
718 {
719 construct << " LIMIT " << _limit;
720 }
721
722 sqlite3_stmt* ppstmt;
723 std::string query = construct.str();
724 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
725 {
726 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
727 }
728
729 if (!_rhymes.empty())
730 {
731 int i = 0;
732 for (auto rhyme : _rhymes)
733 {
734 std::string rhymer = "%" + rhyme;
735 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC);
736
737 i++;
738 }
739 }
740
741 for (auto except : _except)
742 {
743 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
744 }
745
746 for (auto hyponym : _hypernym_of)
747 {
748 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPO"), hyponym._id);
749 }
750
751 for (auto hyponym : _not_hypernym_of)
752 {
753 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NHYPO"), hyponym._id);
754 }
755
756 for (auto hypernym : _hyponym_of)
757 {
758 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPER"), hypernym._id);
759 }
760
761 for (auto hypernym : _not_hyponym_of)
762 {
763 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NHYPER"), hypernym._id);
764 }
765
766 for (auto holonym : _part_meronym_of)
767 {
768 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PHOLO"), holonym._id);
769 }
770
771 for (auto holonym : _not_part_meronym_of)
772 {
773 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NPHOLO"), holonym._id);
774 }
775
776 for (auto meronym : _part_holonym_of)
777 {
778 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PMERO"), meronym._id);
779 }
780
781 for (auto meronym : _not_part_holonym_of)
782 {
783 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NPMERO"), meronym._id);
784 }
785
786 for (auto holonym : _substance_meronym_of)
787 {
788 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SHOLO"), holonym._id);
789 }
790
791 for (auto holonym : _not_substance_meronym_of)
792 {
793 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSHOLO"), holonym._id);
794 }
795
796 for (auto meronym : _substance_holonym_of)
797 {
798 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SMERO"), meronym._id);
799 }
800
801 for (auto meronym : _not_substance_holonym_of)
802 {
803 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSMERO"), meronym._id);
804 }
805
806 for (auto holonym : _member_meronym_of)
807 {
808 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MHOLO"), holonym._id);
809 }
810
811 for (auto holonym : _not_member_meronym_of)
812 {
813 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NMHOLO"), holonym._id);
814 }
815
816 for (auto meronym : _member_holonym_of)
817 {
818 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MMERO"), meronym._id);
819 }
820
821 for (auto meronym : _not_member_holonym_of)
822 {
823 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NMMERO"), meronym._id);
824 }
825
826 for (auto cls : _instance_of)
827 {
828 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@CLSID"), cls._id);
829 }
830
831 for (auto cls : _not_instance_of)
832 {
833 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NCLSID"), cls._id);
834 }
835
836 for (auto inst : _class_of)
837 {
838 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@INSID"), inst._id);
839 }
840
841 for (auto inst : _not_class_of)
842 {
843 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NINSID"), inst._id);
844 }
845
846 for (auto synonym : _synonym_of)
847 {
848 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id);
849 }
850
851 for (auto synonym : _not_synonym_of)
852 {
853 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NSYNID"), synonym._id);
854 }
855
856 for (auto antonym : _antonym_of)
857 {
858 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id);
859 }
860
861 for (auto antonym : _not_antonym_of)
862 {
863 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@NANTID"), antonym._id);
864 }
865
866 for (auto pertainym : _anti_pertainym_of)
867 {
868 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PERID"), pertainym._id);
869 }
870
871 for (auto value : _attribute_of)
872 {
873 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@VALID"), value._id);
874 }
875
876 std::list<noun> output;
877 while (sqlite3_step(ppstmt) == SQLITE_ROW)
878 {
879 noun tnc {_data, sqlite3_column_int(ppstmt, 0)};
880 tnc._singular = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
881
882 if (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL)
883 {
884 tnc._plural = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
885 }
886
887 output.push_back(tnc);
888 }
889
890 sqlite3_finalize(ppstmt);
891
892 for (auto& noun : output)
893 {
894 query = "SELECT pronunciation FROM noun_pronunciations WHERE noun_id = ?";
895 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
896 {
897 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
898 }
899
900 sqlite3_bind_int(ppstmt, 1, noun._id);
901
902 while (sqlite3_step(ppstmt) == SQLITE_ROW)
903 {
904 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
905 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
906
907 noun.pronunciations.push_back(phonemes);
908 }
909
910 sqlite3_finalize(ppstmt);
911 }
912
913 return output;
914 }
915
916};
diff --git a/verbly/noun.h b/verbly/noun.h new file mode 100644 index 0000000..f5ba256 --- /dev/null +++ b/verbly/noun.h
@@ -0,0 +1,171 @@
1#ifndef NOUN_H_24A03C83
2#define NOUN_H_24A03C83
3
4namespace verbly {
5
6 class noun : public word {
7 private:
8 std::string _singular;
9 std::string _plural;
10
11 friend class noun_query;
12
13 public:
14 noun(const data& _data, int _id);
15
16 std::string base_form() const;
17 std::string singular_form() const;
18 std::string plural_form() const;
19
20 bool has_plural_form() const;
21
22 noun_query hypernyms() const;
23 noun_query hyponyms() const;
24 noun_query part_meronyms() const;
25 noun_query part_holonyms() const;
26 noun_query substance_meronyms() const;
27 noun_query substance_holonyms() const;
28 noun_query member_meronyms() const;
29 noun_query member_holonyms() const;
30 noun_query classes() const;
31 noun_query instances() const;
32 noun_query synonyms() const;
33 noun_query antonyms() const;
34 adjective_query pertainyms() const;
35 adjective_query variations() const;
36 };
37
38 class noun_query {
39 public:
40 noun_query(const data& _data);
41
42 noun_query& limit(int _limit);
43 noun_query& random(bool _random);
44 noun_query& except(const noun& _word);
45 noun_query& rhymes_with(const word& _word);
46 noun_query& has_pronunciation(bool _has_prn);
47
48 noun_query& is_hypernym(bool _arg);
49 noun_query& hypernym_of(const noun& _noun);
50 noun_query& not_hypernym_of(const noun& _noun);
51
52 noun_query& is_hyponym(bool _arg);
53 noun_query& hyponym_of(const noun& _noun);
54 noun_query& not_hyponym_of(const noun& _noun);
55
56 noun_query& is_part_meronym(bool _arg);
57 noun_query& part_meronym_of(const noun& _noun);
58 noun_query& not_part_meronym_of(const noun& _noun);
59
60 noun_query& is_part_holonym(bool _arg);
61 noun_query& part_holonym_of(const noun& _noun);
62 noun_query& not_part_holonym_of(const noun& _noun);
63
64 noun_query& is_substance_meronym(bool _arg);
65 noun_query& substance_meronym_of(const noun& _noun);
66 noun_query& not_substance_meronym_of(const noun& _noun);
67
68 noun_query& is_substance_holonym(bool _arg);
69 noun_query& substance_holonym_of(const noun& _noun);
70 noun_query& not_substance_holonym_of(const noun& _noun);
71
72 noun_query& is_member_meronym(bool _arg);
73 noun_query& member_meronym_of(const noun& _noun);
74 noun_query& not_member_meronym_of(const noun& _noun);
75
76 noun_query& is_member_holonym(bool _arg);
77 noun_query& member_holonym_of(const noun& _noun);
78 noun_query& not_member_holonym_of(const noun& _noun);
79
80 noun_query& is_proper(bool _arg);
81 noun_query& instance_of(const noun& _noun);
82 noun_query& not_instance_of(const noun& _noun);
83
84 noun_query& is_class(bool _arg);
85 noun_query& class_of(const noun& _noun);
86 noun_query& not_class_of(const noun& _noun);
87
88 noun_query& has_synonyms(bool _arg);
89 noun_query& synonym_of(const noun& _noun);
90 noun_query& not_synonym_of(const noun& _noun);
91
92 noun_query& has_antonyms(bool _arg);
93 noun_query& antonym_of(const noun& _noun);
94 noun_query& not_antonym_of(const noun& _noun);
95
96 noun_query& has_pertainym(bool _arg);
97 noun_query& anti_pertainym_of(const adjective& _adj);
98
99 noun_query& is_attribute(bool _arg);
100 noun_query& attribute_of(const adjective& _adj);
101
102 std::list<noun> run() const;
103
104 const static int unlimited = -1;
105
106 private:
107 const data& _data;
108 int _limit = unlimited;
109 bool _random = false;
110 std::list<std::string> _rhymes;
111 std::list<noun> _except;
112 bool _has_prn = false;
113
114 bool _is_hypernym = false;
115 std::list<noun> _hypernym_of;
116 std::list<noun> _not_hypernym_of;
117
118 bool _is_hyponym = false;
119 std::list<noun> _hyponym_of;
120 std::list<noun> _not_hyponym_of;
121
122 bool _is_part_meronym = false;
123 std::list<noun> _part_meronym_of;
124 std::list<noun> _not_part_meronym_of;
125
126 bool _is_substance_meronym = false;
127 std::list<noun> _substance_meronym_of;
128 std::list<noun> _not_substance_meronym_of;
129
130 bool _is_member_meronym = false;
131 std::list<noun> _member_meronym_of;
132 std::list<noun> _not_member_meronym_of;
133
134 bool _is_part_holonym = false;
135 std::list<noun> _part_holonym_of;
136 std::list<noun> _not_part_holonym_of;
137
138 bool _is_substance_holonym = false;
139 std::list<noun> _substance_holonym_of;
140 std::list<noun> _not_substance_holonym_of;
141
142 bool _is_member_holonym = false;
143 std::list<noun> _member_holonym_of;
144 std::list<noun> _not_member_holonym_of;
145
146 bool _is_proper = false;
147 std::list<noun> _instance_of;
148 std::list<noun> _not_instance_of;
149
150 bool _is_class = false;
151 std::list<noun> _class_of;
152 std::list<noun> _not_class_of;
153
154 bool _has_synonyms = false;
155 std::list<noun> _synonym_of;
156 std::list<noun> _not_synonym_of;
157
158 bool _has_antonyms = false;
159 std::list<noun> _antonym_of;
160 std::list<noun> _not_antonym_of;
161
162 bool _has_pertainym = false;
163 std::list<adjective> _anti_pertainym_of;
164
165 bool _is_attribute = false;
166 std::list<adjective> _attribute_of;
167 };
168
169};
170
171#endif /* end of include guard: NOUN_H_24A03C83 */
diff --git a/verbly/token.cpp b/verbly/token.cpp new file mode 100644 index 0000000..aa8f50e --- /dev/null +++ b/verbly/token.cpp
@@ -0,0 +1,53 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 token::token(token::type _type) : _type(_type)
6 {
7
8 }
9
10 token::type token::token_type() const
11 {
12 return _type;
13 }
14
15 verb_token::verb_token(const class verb& _verb) : token(token::type::verb), _verb(&_verb)
16 {
17
18 }
19
20 const class verb& verb_token::verb() const
21 {
22 return *_verb;
23 }
24
25 verb_token& verb_token::inflect(verb_token::inflection infl)
26 {
27 _inflection = infl;
28 return *this;
29 }
30
31 bool verb_token::complete() const
32 {
33 return true;
34 }
35
36 std::string verb_token::compile() const
37 {
38 switch (_inflection)
39 {
40 case inflection::infinitive: return _verb->infinitive_form();
41 case inflection::past_tense: return _verb->past_tense_form();
42 case inflection::past_participle: return _verb->past_participle_form();
43 case inflection::ing_form: return _verb->ing_form();
44 case inflection::s_form: return _verb->s_form();
45 }
46 }
47
48 token* verb_token::copy() const
49 {
50 return new verb_token(*this);
51 }
52
53};
diff --git a/verbly/token.h b/verbly/token.h index 2848fd0..44d99cb 100644 --- a/verbly/token.h +++ b/verbly/token.h
@@ -4,16 +4,10 @@
4#include <string> 4#include <string>
5#include <list> 5#include <list>
6#include <sstream> 6#include <sstream>
7#include "verb.h"
8 7
9namespace verbly { 8namespace verbly {
10 9
11 enum class type { 10 class verb;
12 verb,
13 fillin,
14 string,
15 utterance
16 };
17 11
18 class selrestr { 12 class selrestr {
19 }; 13 };
@@ -29,20 +23,22 @@ namespace verbly {
29 }; 23 };
30 24
31 class token { 25 class token {
26 public:
27 enum class type {
28 verb,
29 fillin,
30 string,
31 utterance
32 };
33
32 protected: 34 protected:
33 // General 35 // General
34 type type; 36 type _type;
35 37
36 token(enum type type) : type(type) 38 token(type _type);
37 {
38
39 }
40 39
41 public: 40 public:
42 enum type token_type() const 41 enum type token_type() const;
43 {
44 return type;
45 }
46 42
47 virtual bool complete() const = 0; 43 virtual bool complete() const = 0;
48 virtual std::string compile() const = 0; 44 virtual std::string compile() const = 0;
@@ -50,42 +46,32 @@ namespace verbly {
50 }; 46 };
51 47
52 class verb_token : public token { 48 class verb_token : public token {
49 public:
50 enum class inflection {
51 infinitive,
52 past_tense,
53 past_participle,
54 ing_form,
55 s_form
56 };
57
53 private: 58 private:
54 // Verb 59 // Verb
55 const verb* m_verb; 60 const verb* _verb;
56 conjugation verb_infl = conjugation::infinitive; 61 inflection _inflection = inflection::infinitive;
57 62
58 public: 63 public:
59 verb_token(const class verb& verb) : token(type::verb), m_verb(&verb) 64 verb_token(const class verb& _verb);
60 {
61
62 }
63 65
64 const class verb& verb() const 66 const class verb& verb() const;
65 {
66 return *m_verb;
67 }
68 67
69 verb_token& conjugate(conjugation infl) 68 verb_token& inflect(inflection infl);
70 {
71 verb_infl = infl;
72 return *this;
73 }
74 69
75 bool complete() const 70 bool complete() const;
76 {
77 return true;
78 }
79 71
80 std::string compile() const 72 std::string compile() const;
81 {
82 return m_verb->conjugate(verb_infl);
83 }
84 73
85 token* copy() const 74 token* copy() const;
86 {
87 return new verb_token(*this);
88 }
89 }; 75 };
90 76
91 class utterance_token : public token { 77 class utterance_token : public token {
@@ -140,7 +126,7 @@ namespace verbly {
140 } 126 }
141 };*/ 127 };*/
142 128
143 utterance_token(std::initializer_list<token*> tkns) : token(type::utterance) 129 utterance_token(std::initializer_list<token*> tkns) : token(token::type::utterance)
144 { 130 {
145 for (auto tkn : tkns) 131 for (auto tkn : tkns)
146 { 132 {
@@ -148,7 +134,7 @@ namespace verbly {
148 } 134 }
149 } 135 }
150 136
151 utterance_token(const utterance_token& other) : token(type::utterance) 137 utterance_token(const utterance_token& other) : token(token::type::utterance)
152 { 138 {
153 for (auto& tkn : other.utterance) 139 for (auto& tkn : other.utterance)
154 { 140 {
@@ -156,7 +142,7 @@ namespace verbly {
156 } 142 }
157 } 143 }
158 144
159 utterance_token(utterance_token&& other) : token(type::utterance), utterance(std::move(other.utterance)) 145 utterance_token(utterance_token&& other) : token(token::type::utterance), utterance(std::move(other.utterance))
160 { 146 {
161 147
162 } 148 }
@@ -237,7 +223,7 @@ namespace verbly {
237 fillin_type m_fillin_type; 223 fillin_type m_fillin_type;
238 224
239 public: 225 public:
240 fillin_token(fillin_type ft) : token(type::fillin), m_fillin_type(ft) 226 fillin_token(fillin_type ft) : token(token::type::fillin), m_fillin_type(ft)
241 { 227 {
242 228
243 } 229 }
@@ -301,7 +287,7 @@ namespace verbly {
301 std::string str; 287 std::string str;
302 288
303 public: 289 public:
304 string_token(std::string str) : token(type::string), str(str) 290 string_token(std::string str) : token(token::type::string), str(str)
305 { 291 {
306 292
307 } 293 }
diff --git a/verbly/util.h b/verbly/util.h new file mode 100644 index 0000000..815b47c --- /dev/null +++ b/verbly/util.h
@@ -0,0 +1,53 @@
1#ifndef UTIL_H_15DDCA2D
2#define UTIL_H_15DDCA2D
3
4#include <string>
5#include <iterator>
6#include <sstream>
7
8namespace verbly {
9
10 template <class InputIterator>
11 std::string implode(InputIterator first, InputIterator last, std::string delimiter)
12 {
13 std::stringstream result;
14
15 for (InputIterator it = first; it != last; it++)
16 {
17 if (it != first)
18 {
19 result << delimiter;
20 }
21
22 result << *it;
23 }
24
25 return result.str();
26 }
27
28 template <class Container>
29 Container split(std::string input, std::string delimiter)
30 {
31 Container result;
32
33 while (!input.empty())
34 {
35 int divider = input.find(" ");
36 if (divider == std::string::npos)
37 {
38 result.push_back(input);
39
40 input = "";
41 } else {
42 result.push_back(input.substr(0, divider));
43
44 input = input.substr(divider+1);
45 }
46 }
47
48 return result;
49 }
50
51};
52
53#endif /* end of include guard: UTIL_H_15DDCA2D */
diff --git a/verbly/verb.cpp b/verbly/verb.cpp new file mode 100644 index 0000000..23f7c92 --- /dev/null +++ b/verbly/verb.cpp
@@ -0,0 +1,193 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 verb::verb(const data& _data, int _id) : word(_data, _id)
6 {
7
8 }
9
10 std::string verb::base_form() const
11 {
12 return _infinitive;
13 }
14
15 std::string verb::infinitive_form() const
16 {
17 return _infinitive;
18 }
19
20 std::string verb::past_tense_form() const
21 {
22 return _past_tense;
23 }
24
25 std::string verb::past_participle_form() const
26 {
27 return _past_participle;
28 }
29
30 std::string verb::ing_form() const
31 {
32 return _ing_form;
33 }
34
35 std::string verb::s_form() const
36 {
37 return _s_form;
38 }
39
40 verb_query::verb_query(const data& _data) : _data(_data)
41 {
42
43 }
44
45 verb_query& verb_query::limit(int _limit)
46 {
47 if ((_limit > 0) || (_limit == unlimited))
48 {
49 this->_limit = _limit;
50 }
51
52 return *this;
53 }
54
55 verb_query& verb_query::random(bool _random)
56 {
57 this->_random = _random;
58
59 return *this;
60 }
61
62 verb_query& verb_query::except(const verb& _word)
63 {
64 _except.push_back(_word);
65
66 return *this;
67 }
68
69 verb_query& verb_query::rhymes_with(const word& _word)
70 {
71 for (auto rhyme : _word.rhyme_phonemes())
72 {
73 _rhymes.push_back(rhyme);
74 }
75
76 if (dynamic_cast<const verb*>(&_word) != nullptr)
77 {
78 _except.push_back(dynamic_cast<const verb&>(_word));
79 }
80
81 return *this;
82 }
83
84 verb_query& verb_query::has_pronunciation(bool _has_prn)
85 {
86 this->_has_prn = _has_prn;
87
88 return *this;
89 }
90
91 std::list<verb> verb_query::run() const
92 {
93 std::stringstream construct;
94 construct << "SELECT verb_id, infinitive, past_tense, past_participle, ing_form, s_form FROM verbs";
95 std::list<std::string> conditions;
96
97 if (_has_prn)
98 {
99 conditions.push_back("verb_id IN (SELECT verb_id FROM verb_pronunciations)");
100 }
101
102 if (!_rhymes.empty())
103 {
104 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN");
105 std::string cond = "verb_id IN (SELECT verb_id FROM verb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
106 conditions.push_back(cond);
107 }
108
109 for (auto except : _except)
110 {
111 conditions.push_back("verb_id != @EXCID");
112 }
113
114 if (!conditions.empty())
115 {
116 construct << " WHERE ";
117 construct << verbly::implode(std::begin(conditions), std::end(conditions), " AND ");
118 }
119
120 if (_random)
121 {
122 construct << " ORDER BY RANDOM()";
123 }
124
125 if (_limit != unlimited)
126 {
127 construct << " LIMIT " << _limit;
128 }
129
130 sqlite3_stmt* ppstmt;
131 std::string query = construct.str();
132 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
133 {
134 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
135 }
136
137 if (!_rhymes.empty())
138 {
139 int i = 0;
140 for (auto rhyme : _rhymes)
141 {
142 std::string rhymer = "%" + rhyme;
143 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC);
144
145 i++;
146 }
147 }
148
149 for (auto except : _except)
150 {
151 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
152 }
153
154 std::list<verb> output;
155 while (sqlite3_step(ppstmt) == SQLITE_ROW)
156 {
157 verb tnc {_data, sqlite3_column_int(ppstmt, 0)};
158 tnc._infinitive = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
159 tnc._past_tense = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
160 tnc._past_participle = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 3)));
161 tnc._ing_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 4)));
162 tnc._s_form = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 5)));
163
164 output.push_back(tnc);
165 }
166
167 sqlite3_finalize(ppstmt);
168
169 for (auto& verb : output)
170 {
171 query = "SELECT pronunciation FROM verb_pronunciations WHERE verb_id = ?";
172 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
173 {
174 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
175 }
176
177 sqlite3_bind_int(ppstmt, 1, verb._id);
178
179 while (sqlite3_step(ppstmt) == SQLITE_ROW)
180 {
181 std::string pronunciation(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 0)));
182 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
183
184 verb.pronunciations.push_back(phonemes);
185 }
186
187 sqlite3_finalize(ppstmt);
188 }
189
190 return output;
191 }
192
193};
diff --git a/verbly/verb.h b/verbly/verb.h index 42c8dc2..7cc87e2 100644 --- a/verbly/verb.h +++ b/verbly/verb.h
@@ -1,8 +1,6 @@
1#ifndef VERB_H_BCC929AD 1#ifndef VERB_H_BCC929AD
2#define VERB_H_BCC929AD 2#define VERB_H_BCC929AD
3 3
4#include <vector>
5
6namespace verbly { 4namespace verbly {
7 5
8 /*class frame_part { 6 /*class frame_part {
@@ -26,42 +24,50 @@ namespace verbly {
26 } 24 }
27 };*/ 25 };*/
28 26
29 enum class conjugation { 27 class verb : public word {
30 present_participle,
31 past_participle,
32 infinitive
33 };
34
35 class verb {
36 private: 28 private:
37 int id; 29 std::string _infinitive;
30 std::string _past_tense;
31 std::string _past_participle;
32 std::string _ing_form;
33 std::string _s_form;
34
35 friend class verb_query;
38 36
39 public: 37 public:
40 verb(int id) : id(id) 38 verb(const data& _data, int _id);
41 {
42
43 }
44 39
45 std::string infinitive; 40 std::string base_form() const;
46 std::string past_tense; 41 std::string infinitive_form() const;
47 std::string past_participle; 42 std::string past_tense_form() const;
48 std::string ing_form; 43 std::string past_participle_form() const;
49 std::string s_form; 44 std::string ing_form() const;
50 //std::vector<frame> frames; 45 std::string s_form() const;
46 };
47
48 class verb_query {
49 public:
50 verb_query(const data& _data);
51 51
52 std::string conjugate(conjugation infl) const 52 verb_query& limit(int _limit);
53 { 53 verb_query& random(bool _random);
54 switch (infl) 54 verb_query& except(const verb& _word);
55 { 55 verb_query& rhymes_with(const word& _word);
56 case conjugation::infinitive: return infinitive; 56 verb_query& has_pronunciation(bool _has_prn);
57 case conjugation::past_participle: return past_participle; 57
58 case conjugation::present_participle: return ing_form; 58 std::list<verb> run() const;
59 } 59
60 } 60 const static int unlimited = -1;
61
62 private:
63 const data& _data;
64 int _limit = unlimited;
65 bool _random = false;
66 std::list<std::string> _rhymes;
67 std::list<verb> _except;
68 bool _has_prn = false;
61 }; 69 };
62 70
63}; 71};
64 72
65#include "token.h"
66
67#endif /* end of include guard: VERB_H_BCC929AD */ 73#endif /* end of include guard: VERB_H_BCC929AD */
diff --git a/verbly/verbly.h b/verbly/verbly.h index 44fd3a8..b9f5367 100644 --- a/verbly/verbly.h +++ b/verbly/verbly.h
@@ -2,10 +2,13 @@
2#define VERBLY_H_5B39CE50 2#define VERBLY_H_5B39CE50
3 3
4#include "c++14.h" 4#include "c++14.h"
5#include "util.h"
5#include "token.h" 6#include "token.h"
7#include "data.h"
8#include "word.h"
6#include "verb.h" 9#include "verb.h"
7#include "adjective.h"
8#include "adverb.h" 10#include "adverb.h"
9#include "data.h" 11#include "adjective.h"
12#include "noun.h"
10 13
11#endif /* end of include guard: VERBLY_H_5B39CE50 */ 14#endif /* end of include guard: VERBLY_H_5B39CE50 */
diff --git a/verbly/word.cpp b/verbly/word.cpp new file mode 100644 index 0000000..c50e7d3 --- /dev/null +++ b/verbly/word.cpp
@@ -0,0 +1,32 @@
1#include "verbly.h"
2
3namespace verbly {
4
5 word::word(const data& _data, int _id) : _data(_data), _id(_id)
6 {
7
8 }
9
10 std::list<std::string> word::rhyme_phonemes() const
11 {
12 std::list<std::string> result;
13
14 for (auto pronunciation : pronunciations)
15 {
16 auto phemstrt = std::find_if(std::begin(pronunciation), std::end(pronunciation), [] (std::string phoneme) {
17 return phoneme.find("1") != std::string::npos;
18 });
19
20 std::stringstream rhymer;
21 for (auto it = phemstrt; it != std::end(pronunciation); it++)
22 {
23 rhymer << " " << *it;
24 }
25
26 result.push_back(rhymer.str());
27 }
28
29 return result;
30 }
31
32};
diff --git a/verbly/word.h b/verbly/word.h new file mode 100644 index 0000000..23ddb2b --- /dev/null +++ b/verbly/word.h
@@ -0,0 +1,35 @@
1#ifndef WORD_H_8FC89498
2#define WORD_H_8FC89498
3
4namespace verbly {
5
6 class adjective_query;
7 class verb_query;
8 class adverb_query;
9
10 template <class T>
11 class query;
12
13 class word {
14 protected:
15 const data& _data;
16 int _id;
17
18 std::list<std::list<std::string>> pronunciations;
19
20 word(const data& _data, int _id);
21
22 friend class adjective_query;
23 friend class verb_query;
24 friend class noun_query;
25 friend class adverb_query;
26
27 public:
28 virtual std::string base_form() const = 0;
29
30 std::list<std::string> rhyme_phonemes() const;
31 };
32
33};
34
35#endif /* end of include guard: WORD_H_8FC89498 */