summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--generator/generator.cpp190
-rw-r--r--generator/schema.sql12
-rw-r--r--lib/adjective_query.cpp207
-rw-r--r--lib/adjective_query.h10
-rw-r--r--lib/adverb_query.cpp163
-rw-r--r--lib/adverb_query.h10
-rw-r--r--lib/data.cpp119
-rw-r--r--lib/data.h32
-rw-r--r--lib/frame_query.cpp30
-rw-r--r--lib/noun.cpp17
-rw-r--r--lib/noun.h4
-rw-r--r--lib/noun_query.cpp339
-rw-r--r--lib/noun_query.h16
-rw-r--r--lib/preposition.cpp30
-rw-r--r--lib/verb_query.cpp99
-rw-r--r--lib/verb_query.h10
-rw-r--r--lib/word.cpp41
-rw-r--r--lib/word.h17
18 files changed, 980 insertions, 366 deletions
diff --git a/generator/generator.cpp b/generator/generator.cpp index 6fbbfb8..3201154 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp
@@ -76,12 +76,24 @@ struct group_t {
76 std::list<std::list<framepart_t>> frames; 76 std::list<std::list<framepart_t>> frames;
77}; 77};
78 78
79struct pronunciation_t {
80 std::string phonemes;
81 std::string prerhyme;
82 std::string rhyme;
83
84 bool operator<(const pronunciation_t& other) const
85 {
86 return phonemes < other.phonemes;
87 }
88};
89
79std::map<std::string, group_t> groups; 90std::map<std::string, group_t> groups;
80std::map<std::string, verb_t> verbs; 91std::map<std::string, verb_t> verbs;
81std::map<std::string, adjective_t> adjectives; 92std::map<std::string, adjective_t> adjectives;
82std::map<std::string, noun_t> nouns; 93std::map<std::string, noun_t> nouns;
83std::map<int, std::map<int, int>> wn; 94std::map<int, std::map<int, int>> wn;
84std::map<std::string, std::set<std::string>> pronunciations; 95std::map<int, int> images;
96std::map<std::string, std::set<pronunciation_t>> pronunciations;
85 97
86void print_usage() 98void print_usage()
87{ 99{
@@ -89,10 +101,10 @@ void print_usage()
89 std::cout << "-------------------------" << std::endl; 101 std::cout << "-------------------------" << std::endl;
90 std::cout << "Requires exactly six arguments." << std::endl; 102 std::cout << "Requires exactly six arguments." << std::endl;
91 std::cout << "1. The path to a VerbNet data directory." << std::endl; 103 std::cout << "1. The path to a VerbNet data directory." << std::endl;
92 std::cout << "2. The path to a SemLink vnpbMappings file." << std::endl; 104 std::cout << "2. The path to an AGID infl.txt file." << std::endl;
93 std::cout << "3. The path to an AGID infl.txt file." << std::endl; 105 std::cout << "3. The path to a WordNet prolog data directory." << std::endl;
94 std::cout << "4. The path to a WordNet prolog data directory." << std::endl; 106 std::cout << "4. The path to a CMUDICT pronunciation file." << std::endl;
95 std::cout << "5. The path to a CMUDICT pronunciation file." << std::endl; 107 std::cout << "5. The path to an ImageNet urls.txt file." << std::endl;
96 std::cout << "6. Datafile output path." << std::endl; 108 std::cout << "6. Datafile output path." << std::endl;
97 109
98 exit(1); 110 exit(1);
@@ -431,10 +443,10 @@ int main(int argc, char** argv)
431 // Get verbs from AGID 443 // Get verbs from AGID
432 std::cout << "Reading inflections..." << std::endl; 444 std::cout << "Reading inflections..." << std::endl;
433 445
434 std::ifstream agidfile(argv[3]); 446 std::ifstream agidfile(argv[2]);
435 if (!agidfile.is_open()) 447 if (!agidfile.is_open())
436 { 448 {
437 std::cout << "Could not open AGID file: " << argv[3] << std::endl; 449 std::cout << "Could not open AGID file: " << argv[2] << std::endl;
438 print_usage(); 450 print_usage();
439 } 451 }
440 452
@@ -562,10 +574,10 @@ int main(int argc, char** argv)
562 // Pronounciations 574 // Pronounciations
563 std::cout << "Reading pronunciations..." << std::endl; 575 std::cout << "Reading pronunciations..." << std::endl;
564 576
565 std::ifstream pronfile(argv[5]); 577 std::ifstream pronfile(argv[4]);
566 if (!pronfile.is_open()) 578 if (!pronfile.is_open())
567 { 579 {
568 std::cout << "Could not open CMUDICT file: " << argv[5] << std::endl; 580 std::cout << "Could not open CMUDICT file: " << argv[4] << std::endl;
569 print_usage(); 581 print_usage();
570 } 582 }
571 583
@@ -589,10 +601,80 @@ int main(int argc, char** argv)
589 std::string canonical(phoneme_data[1]); 601 std::string canonical(phoneme_data[1]);
590 std::transform(std::begin(canonical), std::end(canonical), std::begin(canonical), ::tolower); 602 std::transform(std::begin(canonical), std::end(canonical), std::begin(canonical), ::tolower);
591 603
592 pronunciations[canonical].insert(phoneme_data[2]); 604 std::string phonemes = phoneme_data[2];
605 auto phoneme_set = verbly::split<std::list<std::string>>(phonemes, " ");
606 auto phemstrt = std::find_if(std::begin(phoneme_set), std::end(phoneme_set), [] (std::string phoneme) {
607 return phoneme.find("1") != std::string::npos;
608 });
609
610 pronunciation_t p;
611 p.phonemes = phonemes;
612 if (phemstrt != std::end(phoneme_set))
613 {
614 std::stringstream rhymer;
615 for (auto it = phemstrt; it != std::end(phoneme_set); it++)
616 {
617 std::string naked;
618 std::remove_copy_if(std::begin(*it), std::end(*it), std::back_inserter(naked), [] (char ch) {
619 return isdigit(ch);
620 });
621
622 if (it != phemstrt)
623 {
624 rhymer << " ";
625 }
626
627 rhymer << naked;
628 }
629
630 p.rhyme = rhymer.str();
631
632 if (phemstrt != std::begin(phoneme_set))
633 {
634 phemstrt--;
635 p.prerhyme = *phemstrt;
636 } else {
637 p.prerhyme = "";
638 }
639 } else {
640 p.prerhyme = "";
641 p.rhyme = "";
642 }
643
644 pronunciations[canonical].insert(p);
645 }
646 }
647
648 // Images
649 std::cout << "Reading images..." << std::endl;
650
651 std::ifstream imagefile(argv[5]);
652 if (!imagefile.is_open())
653 {
654 std::cout << "Could not open ImageNet file: " << argv[5] << std::endl;
655 print_usage();
656 }
657
658 for (;;)
659 {
660 std::string line;
661 if (!getline(imagefile, line))
662 {
663 break;
593 } 664 }
665
666 if (line.back() == '\r')
667 {
668 line.pop_back();
669 }
670
671 std::string wnid_s = line.substr(1, 8);
672 int wnid = stoi(wnid_s) + 100000000;
673 images[wnid]++;
594 } 674 }
595 675
676 imagefile.close();
677
596 // Start writing output 678 // Start writing output
597 std::cout << "Writing schema..." << std::endl; 679 std::cout << "Writing schema..." << std::endl;
598 680
@@ -689,7 +771,7 @@ int main(int argc, char** argv)
689 db_error(ppdb, query); 771 db_error(ppdb, query);
690 } 772 }
691 773
692 sqlite3_bind_text(ppstmt, 1, prep.c_str(), prep.length(), SQLITE_STATIC); 774 sqlite3_bind_text(ppstmt, 1, prep.c_str(), prep.length(), SQLITE_TRANSIENT);
693 775
694 if (sqlite3_step(ppstmt) != SQLITE_DONE) 776 if (sqlite3_step(ppstmt) != SQLITE_DONE)
695 { 777 {
@@ -721,7 +803,7 @@ int main(int argc, char** argv)
721 } 803 }
722 804
723 sqlite3_bind_int(ppstmt, 1, rowid); 805 sqlite3_bind_int(ppstmt, 1, rowid);
724 sqlite3_bind_text(ppstmt, 2, group.c_str(), group.length(), SQLITE_STATIC); 806 sqlite3_bind_text(ppstmt, 2, group.c_str(), group.length(), SQLITE_TRANSIENT);
725 807
726 if (sqlite3_step(ppstmt) != SQLITE_DONE) 808 if (sqlite3_step(ppstmt) != SQLITE_DONE)
727 { 809 {
@@ -744,11 +826,11 @@ int main(int argc, char** argv)
744 db_error(ppdb, query); 826 db_error(ppdb, query);
745 } 827 }
746 828
747 sqlite3_bind_text(ppstmt, 1, mapping.second.infinitive.c_str(), mapping.second.infinitive.length(), SQLITE_STATIC); 829 sqlite3_bind_text(ppstmt, 1, mapping.second.infinitive.c_str(), mapping.second.infinitive.length(), SQLITE_TRANSIENT);
748 sqlite3_bind_text(ppstmt, 2, mapping.second.past_tense.c_str(), mapping.second.past_tense.length(), SQLITE_STATIC); 830 sqlite3_bind_text(ppstmt, 2, mapping.second.past_tense.c_str(), mapping.second.past_tense.length(), SQLITE_TRANSIENT);
749 sqlite3_bind_text(ppstmt, 3, mapping.second.past_participle.c_str(), mapping.second.past_participle.length(), SQLITE_STATIC); 831 sqlite3_bind_text(ppstmt, 3, mapping.second.past_participle.c_str(), mapping.second.past_participle.length(), SQLITE_TRANSIENT);
750 sqlite3_bind_text(ppstmt, 4, mapping.second.ing_form.c_str(), mapping.second.ing_form.length(), SQLITE_STATIC); 832 sqlite3_bind_text(ppstmt, 4, mapping.second.ing_form.c_str(), mapping.second.ing_form.length(), SQLITE_TRANSIENT);
751 sqlite3_bind_text(ppstmt, 5, mapping.second.s_form.c_str(), mapping.second.s_form.length(), SQLITE_STATIC); 833 sqlite3_bind_text(ppstmt, 5, mapping.second.s_form.c_str(), mapping.second.s_form.length(), SQLITE_TRANSIENT);
752 834
753 if (sqlite3_step(ppstmt) != SQLITE_DONE) 835 if (sqlite3_step(ppstmt) != SQLITE_DONE)
754 { 836 {
@@ -780,14 +862,26 @@ int main(int argc, char** argv)
780 862
781 for (auto pronunciation : pronunciations[canonical]) 863 for (auto pronunciation : pronunciations[canonical])
782 { 864 {
783 query = "INSERT INTO verb_pronunciations (verb_id, pronunciation) VALUES (?, ?)"; 865 if (!pronunciation.rhyme.empty())
866 {
867 query = "INSERT INTO verb_pronunciations (verb_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)";
868 } else {
869 query = "INSERT INTO verb_pronunciations (verb_id, pronunciation) VALUES (?, ?)";
870 }
871
784 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 872 if (sqlite3_prepare_v2(ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
785 { 873 {
786 db_error(ppdb, query); 874 db_error(ppdb, query);
787 } 875 }
788 876
789 sqlite3_bind_int(ppstmt, 1, rowid); 877 sqlite3_bind_int(ppstmt, 1, rowid);
790 sqlite3_bind_text(ppstmt, 2, pronunciation.c_str(), pronunciation.length(), SQLITE_STATIC); 878 sqlite3_bind_text(ppstmt, 2, pronunciation.phonemes.c_str(), pronunciation.phonemes.length(), SQLITE_TRANSIENT);
879
880 if (!pronunciation.rhyme.empty())
881 {
882 sqlite3_bind_text(ppstmt, 3, pronunciation.prerhyme.c_str(), pronunciation.prerhyme.length(), SQLITE_TRANSIENT);
883 sqlite3_bind_text(ppstmt, 4, pronunciation.rhyme.c_str(), pronunciation.rhyme.length(), SQLITE_TRANSIENT);
884 }
791 885
792 if (sqlite3_step(ppstmt) != SQLITE_DONE) 886 if (sqlite3_step(ppstmt) != SQLITE_DONE)
793 { 887 {
@@ -825,7 +919,7 @@ int main(int argc, char** argv)
825 db_error(ppdb, query); 919 db_error(ppdb, query);
826 } 920 }
827 921
828 sqlite3_bind_blob(ppstmt, 1, rdm.c_str(), rdm.size(), SQLITE_STATIC); 922 sqlite3_bind_blob(ppstmt, 1, rdm.c_str(), rdm.size(), SQLITE_TRANSIENT);
829 923
830 if (sqlite3_step(ppstmt) != SQLITE_DONE) 924 if (sqlite3_step(ppstmt) != SQLITE_DONE)
831 { 925 {
@@ -918,7 +1012,7 @@ int main(int argc, char** argv)
918 } 1012 }
919 1013
920 sqlite3_bind_int(ppstmt, 1, gid); 1014 sqlite3_bind_int(ppstmt, 1, gid);
921 sqlite3_bind_blob(ppstmt, 2, marshall.c_str(), marshall.length(), SQLITE_STATIC); 1015 sqlite3_bind_blob(ppstmt, 2, marshall.c_str(), marshall.length(), SQLITE_TRANSIENT);
922 1016
923 if (sqlite3_step(ppstmt) != SQLITE_DONE) 1017 if (sqlite3_step(ppstmt) != SQLITE_DONE)
924 { 1018 {
@@ -972,7 +1066,7 @@ int main(int argc, char** argv)
972 // - sa: specification (e.g. inaccurate (general) can mean imprecise or incorrect (specific)) 1066 // - sa: specification (e.g. inaccurate (general) can mean imprecise or incorrect (specific))
973 // - sim: synonymy (e.g. cheerful/happy, happy/cheerful) 1067 // - sim: synonymy (e.g. cheerful/happy, happy/cheerful)
974 // - syntax: positioning flags for some adjectives 1068 // - syntax: positioning flags for some adjectives
975 std::string wnpref {argv[4]}; 1069 std::string wnpref {argv[3]};
976 if (wnpref.back() != '/') 1070 if (wnpref.back() != '/')
977 { 1071 {
978 wnpref += '/'; 1072 wnpref += '/';
@@ -1009,7 +1103,7 @@ int main(int argc, char** argv)
1009 { 1103 {
1010 ppgs.update(); 1104 ppgs.update();
1011 1105
1012 std::regex relation("^s\\(([134]\\d{8}),(\\d+),'([\\w ]+)',"); 1106 std::regex relation("^s\\(([134]\\d{8}),(\\d+),'(.+)',\\w,\\d+,\\d+\\)\\.$");
1013 std::smatch relation_data; 1107 std::smatch relation_data;
1014 if (!std::regex_search(line, relation_data, relation)) 1108 if (!std::regex_search(line, relation_data, relation))
1015 { 1109 {
@@ -1019,6 +1113,11 @@ int main(int argc, char** argv)
1019 int synset_id = stoi(relation_data[1]); 1113 int synset_id = stoi(relation_data[1]);
1020 int wnum = stoi(relation_data[2]); 1114 int wnum = stoi(relation_data[2]);
1021 std::string word = relation_data[3]; 1115 std::string word = relation_data[3];
1116 size_t word_it;
1117 while ((word_it = word.find("''")) != std::string::npos)
1118 {
1119 word.erase(word_it, 1);
1120 }
1022 1121
1023 std::string query; 1122 std::string query;
1024 switch (synset_id / 100000000) 1123 switch (synset_id / 100000000)
@@ -1027,9 +1126,9 @@ int main(int argc, char** argv)
1027 { 1126 {
1028 if (nouns.count(word) == 1) 1127 if (nouns.count(word) == 1)
1029 { 1128 {
1030 query = "INSERT INTO nouns (singular, proper, complexity, plural) VALUES (?, ?, ?, ?)"; 1129 query = "INSERT INTO nouns (singular, proper, complexity, images, wnid, plural) VALUES (?, ?, ?, ?, ?, ?)";
1031 } else { 1130 } else {
1032 query = "INSERT INTO nouns (singular, proper, complexity) VALUES (?, ?, ?)"; 1131 query = "INSERT INTO nouns (singular, proper, complexity, images, wnid) VALUES (?, ?, ?, ?, ?)";
1033 } 1132 }
1034 1133
1035 break; 1134 break;
@@ -1073,7 +1172,7 @@ int main(int argc, char** argv)
1073 db_error(ppdb, query); 1172 db_error(ppdb, query);
1074 } 1173 }
1075 1174
1076 sqlite3_bind_text(ppstmt, 1, word.c_str(), word.length(), SQLITE_STATIC); 1175 sqlite3_bind_text(ppstmt, 1, word.c_str(), word.length(), SQLITE_TRANSIENT);
1077 switch (synset_id / 100000000) 1176 switch (synset_id / 100000000)
1078 { 1177 {
1079 case 1: // Noun 1178 case 1: // Noun
@@ -1083,10 +1182,12 @@ int main(int argc, char** argv)
1083 }) ? 1 : 0)); 1182 }) ? 1 : 0));
1084 1183
1085 sqlite3_bind_int(ppstmt, 3, verbly::split<std::list<std::string>>(word, " ").size()); 1184 sqlite3_bind_int(ppstmt, 3, verbly::split<std::list<std::string>>(word, " ").size());
1185 sqlite3_bind_int(ppstmt, 4, images[synset_id]);
1186 sqlite3_bind_int(ppstmt, 5, synset_id);
1086 1187
1087 if (nouns.count(word) == 1) 1188 if (nouns.count(word) == 1)
1088 { 1189 {
1089 sqlite3_bind_text(ppstmt, 4, nouns[word].plural.c_str(), nouns[word].plural.length(), SQLITE_STATIC); 1190 sqlite3_bind_text(ppstmt, 6, nouns[word].plural.c_str(), nouns[word].plural.length(), SQLITE_TRANSIENT);
1090 } 1191 }
1091 1192
1092 break; 1193 break;
@@ -1099,8 +1200,8 @@ int main(int argc, char** argv)
1099 1200
1100 if (adjectives.count(word) == 1) 1201 if (adjectives.count(word) == 1)
1101 { 1202 {
1102 sqlite3_bind_text(ppstmt, 3, adjectives[word].comparative.c_str(), adjectives[word].comparative.length(), SQLITE_STATIC); 1203 sqlite3_bind_text(ppstmt, 3, adjectives[word].comparative.c_str(), adjectives[word].comparative.length(), SQLITE_TRANSIENT);
1103 sqlite3_bind_text(ppstmt, 4, adjectives[word].superlative.c_str(), adjectives[word].superlative.length(), SQLITE_STATIC); 1204 sqlite3_bind_text(ppstmt, 4, adjectives[word].superlative.c_str(), adjectives[word].superlative.length(), SQLITE_TRANSIENT);
1104 } 1205 }
1105 1206
1106 break; 1207 break;
@@ -1140,21 +1241,36 @@ int main(int argc, char** argv)
1140 { 1241 {
1141 case 1: // Noun 1242 case 1: // Noun
1142 { 1243 {
1143 query = "INSERT INTO noun_pronunciations (noun_id, pronunciation) VALUES (?, ?)"; 1244 if (!pronunciation.rhyme.empty())
1245 {
1246 query = "INSERT INTO noun_pronunciations (noun_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)";
1247 } else {
1248 query = "INSERT INTO noun_pronunciations (noun_id, pronunciation) VALUES (?, ?)";
1249 }
1144 1250
1145 break; 1251 break;
1146 } 1252 }
1147 1253
1148 case 3: // Adjective 1254 case 3: // Adjective
1149 { 1255 {
1150 query = "INSERT INTO adjective_pronunciations (adjective_id, pronunciation) VALUES (?, ?)"; 1256 if (!pronunciation.rhyme.empty())
1257 {
1258 query = "INSERT INTO adjective_pronunciations (adjective_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)";
1259 } else {
1260 query = "INSERT INTO adjective_pronunciations (adjective_id, pronunciation) VALUES (?, ?)";
1261 }
1151 1262
1152 break; 1263 break;
1153 } 1264 }
1154 1265
1155 case 4: // Adverb 1266 case 4: // Adverb
1156 { 1267 {
1157 query = "INSERT INTO adverb_pronunciations (adverb_id, pronunciation) VALUES (?, ?)"; 1268 if (!pronunciation.rhyme.empty())
1269 {
1270 query = "INSERT INTO adverb_pronunciations (adverb_id, pronunciation, prerhyme, rhyme) VALUES (?, ?, ?, ?)";
1271 } else {
1272 query = "INSERT INTO adverb_pronunciations (adverb_id, pronunciation) VALUES (?, ?)";
1273 }
1158 1274
1159 break; 1275 break;
1160 } 1276 }
@@ -1166,7 +1282,13 @@ int main(int argc, char** argv)
1166 } 1282 }
1167 1283
1168 sqlite3_bind_int(ppstmt, 1, rowid); 1284 sqlite3_bind_int(ppstmt, 1, rowid);
1169 sqlite3_bind_text(ppstmt, 2, pronunciation.c_str(), pronunciation.length(), SQLITE_STATIC); 1285 sqlite3_bind_text(ppstmt, 2, pronunciation.phonemes.c_str(), pronunciation.phonemes.length(), SQLITE_TRANSIENT);
1286
1287 if (!pronunciation.rhyme.empty())
1288 {
1289 sqlite3_bind_text(ppstmt, 3, pronunciation.prerhyme.c_str(), pronunciation.prerhyme.length(), SQLITE_TRANSIENT);
1290 sqlite3_bind_text(ppstmt, 4, pronunciation.rhyme.c_str(), pronunciation.rhyme.length(), SQLITE_TRANSIENT);
1291 }
1170 1292
1171 if (sqlite3_step(ppstmt) != SQLITE_DONE) 1293 if (sqlite3_step(ppstmt) != SQLITE_DONE)
1172 { 1294 {
@@ -2155,7 +2277,7 @@ int main(int argc, char** argv)
2155 db_error(ppdb, query); 2277 db_error(ppdb, query);
2156 } 2278 }
2157 2279
2158 sqlite3_bind_text(ppstmt, 1, syn.c_str(), 1, SQLITE_STATIC); 2280 sqlite3_bind_text(ppstmt, 1, syn.c_str(), 1, SQLITE_TRANSIENT);
2159 sqlite3_bind_int(ppstmt, 2, wn[synset_id][wnum]); 2281 sqlite3_bind_int(ppstmt, 2, wn[synset_id][wnum]);
2160 2282
2161 if (sqlite3_step(ppstmt) != SQLITE_DONE) 2283 if (sqlite3_step(ppstmt) != SQLITE_DONE)
diff --git a/generator/schema.sql b/generator/schema.sql index f2445f0..1836c62 100644 --- a/generator/schema.sql +++ b/generator/schema.sql
@@ -55,7 +55,9 @@ CREATE TABLE `nouns` (
55 `singular` VARCHAR(32) NOT NULL, 55 `singular` VARCHAR(32) NOT NULL,
56 `plural` VARCHAR(32), 56 `plural` VARCHAR(32),
57 `proper` INTEGER(1) NOT NULL, 57 `proper` INTEGER(1) NOT NULL,
58 `complexity` INTEGER NOT NULL 58 `complexity` INTEGER NOT NULL,
59 `images` INTEGER NOT NULL,
60 `wnid` INTEGER NOT NULL
59); 61);
60 62
61DROP TABLE IF EXISTS `hypernymy`; 63DROP TABLE IF EXISTS `hypernymy`;
@@ -182,6 +184,8 @@ DROP TABLE IF EXISTS `noun_pronunciations`;
182CREATE TABLE `noun_pronunciations` ( 184CREATE TABLE `noun_pronunciations` (
183 `noun_id` INTEGER NOT NULL, 185 `noun_id` INTEGER NOT NULL,
184 `pronunciation` VARCHAR(64) NOT NULL, 186 `pronunciation` VARCHAR(64) NOT NULL,
187 `prerhyme` VARCHAR(8),
188 `rhyme` VARCHAR(64),
185 FOREIGN KEY (`noun_id`) REFERENCES `nouns`(`noun_id`) 189 FOREIGN KEY (`noun_id`) REFERENCES `nouns`(`noun_id`)
186); 190);
187 191
@@ -189,6 +193,8 @@ DROP TABLE IF EXISTS `verb_pronunciations`;
189CREATE TABLE `verb_pronunciations` ( 193CREATE TABLE `verb_pronunciations` (
190 `verb_id` INTEGER NOT NULL, 194 `verb_id` INTEGER NOT NULL,
191 `pronunciation` VARCHAR(64) NOT NULL, 195 `pronunciation` VARCHAR(64) NOT NULL,
196 `prerhyme` VARCHAR(8),
197 `rhyme` VARCHAR(64),
192 FOREIGN KEY (`verb_id`) REFERENCES `verbs`(`verb_id`) 198 FOREIGN KEY (`verb_id`) REFERENCES `verbs`(`verb_id`)
193); 199);
194 200
@@ -196,6 +202,8 @@ DROP TABLE IF EXISTS `adjective_pronunciations`;
196CREATE TABLE `adjective_pronunciations` ( 202CREATE TABLE `adjective_pronunciations` (
197 `adjective_id` INTEGER NOT NULL, 203 `adjective_id` INTEGER NOT NULL,
198 `pronunciation` VARCHAR(64) NOT NULL, 204 `pronunciation` VARCHAR(64) NOT NULL,
205 `prerhyme` VARCHAR(8),
206 `rhyme` VARCHAR(64),
199 FOREIGN KEY (`adjective_id`) REFERENCES `adjectives`(`adjective_id`) 207 FOREIGN KEY (`adjective_id`) REFERENCES `adjectives`(`adjective_id`)
200); 208);
201 209
@@ -203,6 +211,8 @@ DROP TABLE IF EXISTS `adverb_pronunciations`;
203CREATE TABLE `adverb_pronunciations` ( 211CREATE TABLE `adverb_pronunciations` (
204 `adverb_id` INTEGER NOT NULL, 212 `adverb_id` INTEGER NOT NULL,
205 `pronunciation` VARCHAR(64) NOT NULL, 213 `pronunciation` VARCHAR(64) NOT NULL,
214 `prerhyme` VARCHAR(8),
215 `rhyme` VARCHAR(64),
206 FOREIGN KEY (`adverb_id`) REFERENCES `adverbs`(`adverb_id`) 216 FOREIGN KEY (`adverb_id`) REFERENCES `adverbs`(`adverb_id`)
207); 217);
208 218
diff --git a/lib/adjective_query.cpp b/lib/adjective_query.cpp index 283fdca..2bea68f 100644 --- a/lib/adjective_query.cpp +++ b/lib/adjective_query.cpp
@@ -33,7 +33,7 @@ namespace verbly {
33 33
34 adjective_query& adjective_query::rhymes_with(const word& _word) 34 adjective_query& adjective_query::rhymes_with(const word& _word)
35 { 35 {
36 for (auto rhyme : _word.rhyme_phonemes()) 36 for (auto rhyme : _word.get_rhymes())
37 { 37 {
38 _rhymes.push_back(rhyme); 38 _rhymes.push_back(rhyme);
39 } 39 }
@@ -53,6 +53,34 @@ namespace verbly {
53 return *this; 53 return *this;
54 } 54 }
55 55
56 adjective_query& adjective_query::has_rhyming_noun()
57 {
58 _has_rhyming_noun = true;
59
60 return *this;
61 }
62
63 adjective_query& adjective_query::has_rhyming_adjective()
64 {
65 _has_rhyming_adjective = true;
66
67 return *this;
68 }
69
70 adjective_query& adjective_query::has_rhyming_adverb()
71 {
72 _has_rhyming_adverb = true;
73
74 return *this;
75 }
76
77 adjective_query& adjective_query::has_rhyming_verb()
78 {
79 _has_rhyming_verb = true;
80
81 return *this;
82 }
83
56 adjective_query& adjective_query::with_prefix(filter<std::string> _f) 84 adjective_query& adjective_query::with_prefix(filter<std::string> _f)
57 { 85 {
58 _f.clean(); 86 _f.clean();
@@ -218,6 +246,7 @@ namespace verbly {
218 std::stringstream construct; 246 std::stringstream construct;
219 construct << "SELECT adjective_id, base_form, comparative, superlative, position FROM adjectives"; 247 construct << "SELECT adjective_id, base_form, comparative, superlative, position FROM adjectives";
220 std::list<std::string> conditions; 248 std::list<std::string> conditions;
249 std::list<binding> bindings;
221 250
222 if (_has_prn) 251 if (_has_prn)
223 { 252 {
@@ -226,14 +255,41 @@ namespace verbly {
226 255
227 if (!_rhymes.empty()) 256 if (!_rhymes.empty())
228 { 257 {
229 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); 258 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
230 std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; 259 std::string cond = "adjective_id IN (SELECT adjective_id FROM adjective_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
231 conditions.push_back(cond); 260 conditions.push_back(cond);
261
262 for (auto rhy : _rhymes)
263 {
264 bindings.emplace_back(rhy.get_prerhyme());
265 bindings.emplace_back(rhy.get_rhyme());
266 }
267 }
268
269 if (_has_rhyming_noun)
270 {
271 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
272 }
273
274 if (_has_rhyming_adjective)
275 {
276 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.adjective_id != curp.adjective_id)");
277 }
278
279 if (_has_rhyming_adverb)
280 {
281 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
282 }
283
284 if (_has_rhyming_verb)
285 {
286 conditions.push_back("adjective_id IN (SELECT a.adjective_id FROM adjectives AS a INNER JOIN adjective_pronunciations AS curp ON curp.adjective_id = a.adjective_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
232 } 287 }
233 288
234 for (auto except : _except) 289 for (auto except : _except)
235 { 290 {
236 conditions.push_back("adjective_id != @EXCID"); 291 conditions.push_back("adjective_id != ?");
292 bindings.emplace_back(except._id);
237 } 293 }
238 294
239 if (_requires_comparative_form) 295 if (_requires_comparative_form)
@@ -261,11 +317,13 @@ namespace verbly {
261 { 317 {
262 case filter<std::string>::type::singleton: 318 case filter<std::string>::type::singleton:
263 { 319 {
320 bindings.emplace_back(f.get_elem() + "%");
321
264 if (notlogic == f.get_notlogic()) 322 if (notlogic == f.get_notlogic())
265 { 323 {
266 return "base_form LIKE @PREFIX"; 324 return "base_form LIKE ?";
267 } else { 325 } else {
268 return "base_form NOT LIKE @PREFIX"; 326 return "base_form NOT LIKE ?";
269 } 327 }
270 } 328 }
271 329
@@ -298,11 +356,13 @@ namespace verbly {
298 { 356 {
299 case filter<std::string>::type::singleton: 357 case filter<std::string>::type::singleton:
300 { 358 {
359 bindings.emplace_back("%" + f.get_elem());
360
301 if (notlogic == f.get_notlogic()) 361 if (notlogic == f.get_notlogic())
302 { 362 {
303 return "base_form LIKE @SUFFIX"; 363 return "base_form LIKE ?";
304 } else { 364 } else {
305 return "base_form NOT LIKE @SUFFIX"; 365 return "base_form NOT LIKE ?";
306 } 366 }
307 } 367 }
308 368
@@ -330,7 +390,8 @@ namespace verbly {
330 390
331 if (_with_complexity != unlimited) 391 if (_with_complexity != unlimited)
332 { 392 {
333 conditions.push_back("complexity = @COMPLEX"); 393 conditions.push_back("complexity = ?");
394 bindings.emplace_back(_with_complexity);
334 } 395 }
335 396
336 if (_is_variant) 397 if (_is_variant)
@@ -355,11 +416,13 @@ namespace verbly {
355 { 416 {
356 case filter<noun>::type::singleton: 417 case filter<noun>::type::singleton:
357 { 418 {
419 bindings.emplace_back(f.get_elem()._id);
420
358 if (notlogic == f.get_notlogic()) 421 if (notlogic == f.get_notlogic())
359 { 422 {
360 return "noun_id = @ATTRID"; 423 return "noun_id = ?";
361 } else { 424 } else {
362 return "noun_id != @ATTRID"; 425 return "noun_id != ?";
363 } 426 }
364 } 427 }
365 428
@@ -409,11 +472,13 @@ namespace verbly {
409 { 472 {
410 case filter<adjective>::type::singleton: 473 case filter<adjective>::type::singleton:
411 { 474 {
475 bindings.emplace_back(f.get_elem()._id);
476
412 if (notlogic == f.get_notlogic()) 477 if (notlogic == f.get_notlogic())
413 { 478 {
414 return "adjective_1_id = @ANTID"; 479 return "adjective_1_id = ?";
415 } else { 480 } else {
416 return "adjective_1_id != @ANTID"; 481 return "adjective_1_id != ?";
417 } 482 }
418 } 483 }
419 484
@@ -463,11 +528,13 @@ namespace verbly {
463 { 528 {
464 case filter<adjective>::type::singleton: 529 case filter<adjective>::type::singleton:
465 { 530 {
531 bindings.emplace_back(f.get_elem()._id);
532
466 if (notlogic == f.get_notlogic()) 533 if (notlogic == f.get_notlogic())
467 { 534 {
468 return "adjective_1_id = @SYNID"; 535 return "adjective_1_id = ?";
469 } else { 536 } else {
470 return "adjective_1_id != @SYNID"; 537 return "adjective_1_id != ?";
471 } 538 }
472 } 539 }
473 540
@@ -517,11 +584,13 @@ namespace verbly {
517 { 584 {
518 case filter<adjective>::type::singleton: 585 case filter<adjective>::type::singleton:
519 { 586 {
587 bindings.emplace_back(f.get_elem()._id);
588
520 if (notlogic == f.get_notlogic()) 589 if (notlogic == f.get_notlogic())
521 { 590 {
522 return "specific_id = @SPECID"; 591 return "specific_id = ?";
523 } else { 592 } else {
524 return "specific_id != @SPECID"; 593 return "specific_id != ?";
525 } 594 }
526 } 595 }
527 596
@@ -571,11 +640,13 @@ namespace verbly {
571 { 640 {
572 case filter<adjective>::type::singleton: 641 case filter<adjective>::type::singleton:
573 { 642 {
643 bindings.emplace_back(f.get_elem()._id);
644
574 if (notlogic == f.get_notlogic()) 645 if (notlogic == f.get_notlogic())
575 { 646 {
576 return "general_id = @GENID"; 647 return "general_id = ?";
577 } else { 648 } else {
578 return "general_id != @GENID"; 649 return "general_id != ?";
579 } 650 }
580 } 651 }
581 652
@@ -625,11 +696,13 @@ namespace verbly {
625 { 696 {
626 case filter<noun>::type::singleton: 697 case filter<noun>::type::singleton:
627 { 698 {
699 bindings.emplace_back(f.get_elem()._id);
700
628 if (notlogic == f.get_notlogic()) 701 if (notlogic == f.get_notlogic())
629 { 702 {
630 return "noun_id = @APERID"; 703 return "noun_id = ?";
631 } else { 704 } else {
632 return "noun_id != @APERID"; 705 return "noun_id != ?";
633 } 706 }
634 } 707 }
635 708
@@ -679,11 +752,13 @@ namespace verbly {
679 { 752 {
680 case filter<adverb>::type::singleton: 753 case filter<adverb>::type::singleton:
681 { 754 {
755 bindings.emplace_back(f.get_elem()._id);
756
682 if (notlogic == f.get_notlogic()) 757 if (notlogic == f.get_notlogic())
683 { 758 {
684 return "mannernym_id = @MANID"; 759 return "mannernym_id = ?";
685 } else { 760 } else {
686 return "mannernym_id != @MANID"; 761 return "mannernym_id != ?";
687 } 762 }
688 } 763 }
689 764
@@ -776,74 +851,29 @@ namespace verbly {
776 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 851 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
777 } 852 }
778 853
779 if (!_rhymes.empty()) 854 int i = 1;
855 for (auto& binding : bindings)
780 { 856 {
781 int i = 0; 857 switch (binding.get_type())
782 for (auto rhyme : _rhymes)
783 { 858 {
784 std::string rhymer = "%" + rhyme; 859 case binding::type::integer:
785 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); 860 {
861 sqlite3_bind_int(ppstmt, i, binding.get_integer());
862
863 break;
864 }
786 865
787 i++; 866 case binding::type::string:
867 {
868 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
869
870 break;
871 }
788 } 872 }
873
874 i++;
789 } 875 }
790 876
791 for (auto except : _except)
792 {
793 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
794 }
795
796 for (auto prefix : _with_prefix.inorder_flatten())
797 {
798 std::string pfat = prefix + "%";
799 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PREFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC);
800 }
801
802 for (auto suffix : _with_suffix.inorder_flatten())
803 {
804 std::string pfat = "%" + suffix;
805 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SUFFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC);
806 }
807
808 if (_with_complexity != unlimited)
809 {
810 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@COMPLEX"), _with_complexity);
811 }
812
813 for (auto attribute : _variant_of.inorder_flatten())
814 {
815 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ATTRID"), attribute._id);
816 }
817
818 for (auto antonym : _antonym_of.inorder_flatten())
819 {
820 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id);
821 }
822
823 for (auto synonym : _synonym_of.inorder_flatten())
824 {
825 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id);
826 }
827
828 for (auto specific : _generalization_of.inorder_flatten())
829 {
830 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SPECID"), specific._id);
831 }
832
833 for (auto general : _specification_of.inorder_flatten())
834 {
835 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@GENID"), general._id);
836 }
837
838 for (auto n : _pertainym_of.inorder_flatten())
839 {
840 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@APERID"), n._id);
841 }
842
843 for (auto mannernym : _anti_mannernym_of.inorder_flatten())
844 {
845 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MANID"), mannernym._id);
846 }
847 /* 877 /*
848 for (auto adj : _derived_from_adjective) 878 for (auto adj : _derived_from_adjective)
849 { 879 {
@@ -913,7 +943,7 @@ namespace verbly {
913 943
914 for (auto& adjective : output) 944 for (auto& adjective : output)
915 { 945 {
916 query = "SELECT pronunciation FROM adjective_pronunciations WHERE adjective_id = ?"; 946 query = "SELECT pronunciation, prerhyme, rhyme FROM adjective_pronunciations WHERE adjective_id = ?";
917 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 947 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
918 { 948 {
919 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 949 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
@@ -927,6 +957,13 @@ namespace verbly {
927 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " "); 957 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
928 958
929 adjective.pronunciations.push_back(phonemes); 959 adjective.pronunciations.push_back(phonemes);
960
961 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
962 {
963 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
964 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
965 adjective.rhymes.emplace_back(prerhyme, rhyming);
966 }
930 } 967 }
931 968
932 sqlite3_finalize(ppstmt); 969 sqlite3_finalize(ppstmt);
diff --git a/lib/adjective_query.h b/lib/adjective_query.h index b2859dc..030a494 100644 --- a/lib/adjective_query.h +++ b/lib/adjective_query.h
@@ -12,6 +12,10 @@ namespace verbly {
12 adjective_query& except(const adjective& _word); 12 adjective_query& except(const adjective& _word);
13 adjective_query& rhymes_with(const word& _word); 13 adjective_query& rhymes_with(const word& _word);
14 adjective_query& has_pronunciation(); 14 adjective_query& has_pronunciation();
15 adjective_query& has_rhyming_noun();
16 adjective_query& has_rhyming_adjective();
17 adjective_query& has_rhyming_adverb();
18 adjective_query& has_rhyming_verb();
15 19
16 adjective_query& requires_comparative_form(); 20 adjective_query& requires_comparative_form();
17 adjective_query& requires_superlative_form(); 21 adjective_query& requires_superlative_form();
@@ -54,9 +58,13 @@ namespace verbly {
54 const data& _data; 58 const data& _data;
55 int _limit = unlimited; 59 int _limit = unlimited;
56 bool _random = false; 60 bool _random = false;
57 std::list<std::string> _rhymes; 61 std::list<rhyme> _rhymes;
58 std::list<adjective> _except; 62 std::list<adjective> _except;
59 bool _has_prn = false; 63 bool _has_prn = false;
64 bool _has_rhyming_noun = false;
65 bool _has_rhyming_adjective = false;
66 bool _has_rhyming_adverb = false;
67 bool _has_rhyming_verb = false;
60 68
61 bool _requires_comparative_form = false; 69 bool _requires_comparative_form = false;
62 bool _requires_superlative_form = false; 70 bool _requires_superlative_form = false;
diff --git a/lib/adverb_query.cpp b/lib/adverb_query.cpp index c9d0d09..797e6a6 100644 --- a/lib/adverb_query.cpp +++ b/lib/adverb_query.cpp
@@ -33,7 +33,7 @@ namespace verbly {
33 33
34 adverb_query& adverb_query::rhymes_with(const word& _word) 34 adverb_query& adverb_query::rhymes_with(const word& _word)
35 { 35 {
36 for (auto rhyme : _word.rhyme_phonemes()) 36 for (auto rhyme : _word.get_rhymes())
37 { 37 {
38 _rhymes.push_back(rhyme); 38 _rhymes.push_back(rhyme);
39 } 39 }
@@ -53,6 +53,34 @@ namespace verbly {
53 return *this; 53 return *this;
54 } 54 }
55 55
56 adverb_query& adverb_query::has_rhyming_noun()
57 {
58 _has_rhyming_noun = true;
59
60 return *this;
61 }
62
63 adverb_query& adverb_query::has_rhyming_adjective()
64 {
65 _has_rhyming_adjective = true;
66
67 return *this;
68 }
69
70 adverb_query& adverb_query::has_rhyming_adverb()
71 {
72 _has_rhyming_adverb = true;
73
74 return *this;
75 }
76
77 adverb_query& adverb_query::has_rhyming_verb()
78 {
79 _has_rhyming_verb = true;
80
81 return *this;
82 }
83
56 adverb_query& adverb_query::requires_comparative_form() 84 adverb_query& adverb_query::requires_comparative_form()
57 { 85 {
58 _requires_comparative_form = true; 86 _requires_comparative_form = true;
@@ -172,6 +200,7 @@ namespace verbly {
172 std::stringstream construct; 200 std::stringstream construct;
173 construct << "SELECT adverb_id, base_form, comparative, superlative FROM adverbs"; 201 construct << "SELECT adverb_id, base_form, comparative, superlative FROM adverbs";
174 std::list<std::string> conditions; 202 std::list<std::string> conditions;
203 std::list<binding> bindings;
175 204
176 if (_has_prn) 205 if (_has_prn)
177 { 206 {
@@ -180,14 +209,41 @@ namespace verbly {
180 209
181 if (!_rhymes.empty()) 210 if (!_rhymes.empty())
182 { 211 {
183 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); 212 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
184 std::string cond = "adverb_id IN (SELECT adverb_id FROM adverb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; 213 std::string cond = "adverb_id IN (SELECT adverb_id FROM adverb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
185 conditions.push_back(cond); 214 conditions.push_back(cond);
215
216 for (auto rhy : _rhymes)
217 {
218 bindings.emplace_back(rhy.get_prerhyme());
219 bindings.emplace_back(rhy.get_rhyme());
220 }
221 }
222
223 if (_has_rhyming_noun)
224 {
225 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
226 }
227
228 if (_has_rhyming_adjective)
229 {
230 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
231 }
232
233 if (_has_rhyming_adverb)
234 {
235 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.adverb_id != curp.adverb_id)");
236 }
237
238 if (_has_rhyming_verb)
239 {
240 conditions.push_back("adverb_id IN (SELECT a.adverb_id FROM adverbs AS a INNER JOIN adverb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
186 } 241 }
187 242
188 for (auto except : _except) 243 for (auto except : _except)
189 { 244 {
190 conditions.push_back("adverb_id != @EXCID"); 245 conditions.push_back("adverb_id != ?");
246 bindings.emplace_back(except._id);
191 } 247 }
192 248
193 if (_requires_comparative_form) 249 if (_requires_comparative_form)
@@ -207,11 +263,13 @@ namespace verbly {
207 { 263 {
208 case filter<std::string>::type::singleton: 264 case filter<std::string>::type::singleton:
209 { 265 {
266 bindings.emplace_back(f.get_elem() + "%");
267
210 if (notlogic == f.get_notlogic()) 268 if (notlogic == f.get_notlogic())
211 { 269 {
212 return "base_form LIKE @PREFIX"; 270 return "base_form LIKE ?";
213 } else { 271 } else {
214 return "base_form NOT LIKE @PREFIX"; 272 return "base_form NOT LIKE ?";
215 } 273 }
216 } 274 }
217 275
@@ -244,11 +302,13 @@ namespace verbly {
244 { 302 {
245 case filter<std::string>::type::singleton: 303 case filter<std::string>::type::singleton:
246 { 304 {
305 bindings.emplace_back("%" + f.get_elem());
306
247 if (notlogic == f.get_notlogic()) 307 if (notlogic == f.get_notlogic())
248 { 308 {
249 return "base_form LIKE @SUFFIX"; 309 return "base_form LIKE ?";
250 } else { 310 } else {
251 return "base_form NOT LIKE @SUFFIX"; 311 return "base_form NOT LIKE ?";
252 } 312 }
253 } 313 }
254 314
@@ -276,7 +336,8 @@ namespace verbly {
276 336
277 if (_with_complexity != unlimited) 337 if (_with_complexity != unlimited)
278 { 338 {
279 conditions.push_back("complexity = @COMPLEX"); 339 conditions.push_back("complexity = ?");
340 bindings.emplace_back(_with_complexity);
280 } 341 }
281 342
282 if (_has_antonyms) 343 if (_has_antonyms)
@@ -301,11 +362,13 @@ namespace verbly {
301 { 362 {
302 case filter<adverb>::type::singleton: 363 case filter<adverb>::type::singleton:
303 { 364 {
365 bindings.emplace_back(f.get_elem()._id);
366
304 if (notlogic == f.get_notlogic()) 367 if (notlogic == f.get_notlogic())
305 { 368 {
306 return "adverb_1_id = @ANTID"; 369 return "adverb_1_id = ?";
307 } else { 370 } else {
308 return "adverb_1_id != @ANTID"; 371 return "adverb_1_id != ?";
309 } 372 }
310 } 373 }
311 374
@@ -355,11 +418,13 @@ namespace verbly {
355 { 418 {
356 case filter<adverb>::type::singleton: 419 case filter<adverb>::type::singleton:
357 { 420 {
421 bindings.emplace_back(f.get_elem()._id);
422
358 if (notlogic == f.get_notlogic()) 423 if (notlogic == f.get_notlogic())
359 { 424 {
360 return "adverb_1_id = @SYNID"; 425 return "adverb_1_id = ?";
361 } else { 426 } else {
362 return "adverb_1_id != @SYNID"; 427 return "adverb_1_id != ?";
363 } 428 }
364 } 429 }
365 430
@@ -409,11 +474,13 @@ namespace verbly {
409 { 474 {
410 case filter<adjective>::type::singleton: 475 case filter<adjective>::type::singleton:
411 { 476 {
477 bindings.emplace_back(f.get_elem()._id);
478
412 if (notlogic == f.get_notlogic()) 479 if (notlogic == f.get_notlogic())
413 { 480 {
414 return "adjective_id = @AMANID"; 481 return "adjective_id = ?";
415 } else { 482 } else {
416 return "adjective_id != @AMANID"; 483 return "adjective_id != ?";
417 } 484 }
418 } 485 }
419 486
@@ -506,54 +573,29 @@ namespace verbly {
506 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 573 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
507 } 574 }
508 575
509 if (!_rhymes.empty()) 576 int i = 1;
577 for (auto& binding : bindings)
510 { 578 {
511 int i = 0; 579 switch (binding.get_type())
512 for (auto rhyme : _rhymes)
513 { 580 {
514 std::string rhymer = "%" + rhyme; 581 case binding::type::integer:
515 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); 582 {
583 sqlite3_bind_int(ppstmt, i, binding.get_integer());
584
585 break;
586 }
516 587
517 i++; 588 case binding::type::string:
589 {
590 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
591
592 break;
593 }
518 } 594 }
595
596 i++;
519 } 597 }
520 598
521 for (auto except : _except)
522 {
523 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
524 }
525
526 for (auto prefix : _with_prefix.inorder_flatten())
527 {
528 std::string pfat = prefix + "%";
529 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PREFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC);
530 }
531
532 for (auto suffix : _with_suffix.inorder_flatten())
533 {
534 std::string pfat = "%" + suffix;
535 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SUFFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC);
536 }
537
538 if (_with_complexity != unlimited)
539 {
540 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@COMPLEX"), _with_complexity);
541 }
542
543 for (auto antonym : _antonym_of.inorder_flatten())
544 {
545 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id);
546 }
547
548 for (auto synonym : _synonym_of.inorder_flatten())
549 {
550 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id);
551 }
552
553 for (auto adj : _mannernym_of.inorder_flatten())
554 {
555 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@AMANID"), adj._id);
556 }
557 /* 599 /*
558 for (auto adj : _derived_from_adjective) 600 for (auto adj : _derived_from_adjective)
559 { 601 {
@@ -608,7 +650,7 @@ namespace verbly {
608 650
609 for (auto& adverb : output) 651 for (auto& adverb : output)
610 { 652 {
611 query = "SELECT pronunciation FROM adverb_pronunciations WHERE adverb_id = ?"; 653 query = "SELECT pronunciation, prerhyme, rhyme FROM adverb_pronunciations WHERE adverb_id = ?";
612 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 654 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
613 { 655 {
614 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 656 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
@@ -622,6 +664,13 @@ namespace verbly {
622 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " "); 664 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
623 665
624 adverb.pronunciations.push_back(phonemes); 666 adverb.pronunciations.push_back(phonemes);
667
668 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
669 {
670 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
671 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
672 adverb.rhymes.emplace_back(prerhyme, rhyming);
673 }
625 } 674 }
626 675
627 sqlite3_finalize(ppstmt); 676 sqlite3_finalize(ppstmt);
diff --git a/lib/adverb_query.h b/lib/adverb_query.h index e9354bb..403a616 100644 --- a/lib/adverb_query.h +++ b/lib/adverb_query.h
@@ -12,6 +12,10 @@ namespace verbly {
12 adverb_query& except(const adverb& _word); 12 adverb_query& except(const adverb& _word);
13 adverb_query& rhymes_with(const word& _word); 13 adverb_query& rhymes_with(const word& _word);
14 adverb_query& has_pronunciation(); 14 adverb_query& has_pronunciation();
15 adverb_query& has_rhyming_noun();
16 adverb_query& has_rhyming_adjective();
17 adverb_query& has_rhyming_adverb();
18 adverb_query& has_rhyming_verb();
15 19
16 adverb_query& requires_comparative_form(); 20 adverb_query& requires_comparative_form();
17 adverb_query& requires_superlative_form(); 21 adverb_query& requires_superlative_form();
@@ -41,9 +45,13 @@ namespace verbly {
41 const data& _data; 45 const data& _data;
42 int _limit = unlimited; 46 int _limit = unlimited;
43 bool _random = false; 47 bool _random = false;
44 std::list<std::string> _rhymes; 48 std::list<rhyme> _rhymes;
45 std::list<adverb> _except; 49 std::list<adverb> _except;
46 bool _has_prn = false; 50 bool _has_prn = false;
51 bool _has_rhyming_noun = false;
52 bool _has_rhyming_adjective = false;
53 bool _has_rhyming_adverb = false;
54 bool _has_rhyming_verb = false;
47 55
48 bool _requires_comparative_form = false; 56 bool _requires_comparative_form = false;
49 bool _requires_superlative_form = false; 57 bool _requires_superlative_form = false;
diff --git a/lib/data.cpp b/lib/data.cpp index 5a9397b..db42487 100644 --- a/lib/data.cpp +++ b/lib/data.cpp
@@ -1,7 +1,7 @@
1#include "verbly.h" 1#include "verbly.h"
2 2
3namespace verbly { 3namespace verbly {
4 4
5 data::data(std::string datafile) 5 data::data(std::string datafile)
6 { 6 {
7 if (sqlite3_open_v2(datafile.c_str(), &ppdb, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) 7 if (sqlite3_open_v2(datafile.c_str(), &ppdb, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK)
@@ -57,4 +57,121 @@ namespace verbly {
57 return preposition_query(*this); 57 return preposition_query(*this);
58 } 58 }
59 59
60 binding::type binding::get_type() const
61 {
62 return _type;
63 }
64
65 binding::binding(const binding& other)
66 {
67 _type = other._type;
68
69 switch (_type)
70 {
71 case type::integer:
72 {
73 _integer = other._integer;
74
75 break;
76 }
77
78 case type::string:
79 {
80 new(&_string) std::string(other._string);
81
82 break;
83 }
84 }
85 }
86
87 binding::~binding()
88 {
89 switch (_type)
90 {
91 case type::string:
92 {
93 using string_type = std::string;
94 _string.~string_type();
95
96 break;
97 }
98 }
99 }
100
101 binding& binding::operator=(const binding& other)
102 {
103 this->~binding();
104
105 _type = other._type;
106
107 switch (_type)
108 {
109 case type::integer:
110 {
111 _integer = other._integer;
112
113 break;
114 }
115
116 case type::string:
117 {
118 new(&_string) std::string(other._string);
119
120 break;
121 }
122 }
123
124 return *this;
125 }
126
127 binding::binding(int _arg)
128 {
129 _type = type::integer;
130 _integer = _arg;
131 }
132
133 int binding::get_integer() const
134 {
135 assert(_type == type::integer);
136
137 return _integer;
138 }
139
140 void binding::set_integer(int _arg)
141 {
142 *this = binding(_arg);
143 }
144
145 binding& binding::operator=(int _arg)
146 {
147 *this = binding(_arg);
148
149 return *this;
150 }
151
152 binding::binding(std::string _arg)
153 {
154 _type = type::string;
155 new(&_string) std::string(_arg);
156 }
157
158 std::string binding::get_string() const
159 {
160 assert(_type == type::string);
161
162 return _string;
163 }
164
165 void binding::set_string(std::string _arg)
166 {
167 *this = binding(_arg);
168 }
169
170 binding& binding::operator=(std::string _arg)
171 {
172 *this = binding(_arg);
173
174 return *this;
175 }
176
60}; 177};
diff --git a/lib/data.h b/lib/data.h index 0d599c4..b8b12b9 100644 --- a/lib/data.h +++ b/lib/data.h
@@ -343,6 +343,38 @@ namespace verbly {
343 }; 343 };
344 }; 344 };
345 345
346 class binding {
347 public:
348 enum class type {
349 integer,
350 string
351 };
352
353 type get_type() const;
354 binding(const binding& other);
355 ~binding();
356 binding& operator=(const binding& other);
357
358 // Integer
359 binding(int _arg);
360 int get_integer() const;
361 void set_integer(int _arg);
362 binding& operator=(int _arg);
363
364 // String
365 binding(std::string _arg);
366 std::string get_string() const;
367 void set_string(std::string _arg);
368 binding& operator=(std::string _arg);
369
370 private:
371 union {
372 int _integer;
373 std::string _string;
374 };
375 type _type;
376 };
377
346}; 378};
347 379
348#endif /* end of include guard: DATA_H_C4AEC3DD */ 380#endif /* end of include guard: DATA_H_C4AEC3DD */
diff --git a/lib/frame_query.cpp b/lib/frame_query.cpp index 6583da4..11f0432 100644 --- a/lib/frame_query.cpp +++ b/lib/frame_query.cpp
@@ -37,13 +37,19 @@ namespace verbly {
37 { 37 {
38 std::stringstream construct; 38 std::stringstream construct;
39 construct << "SELECT frames.data, groups.data FROM frames INNER JOIN groups ON frames.group_id = groups.group_id"; 39 construct << "SELECT frames.data, groups.data FROM frames INNER JOIN groups ON frames.group_id = groups.group_id";
40 std::list<binding> bindings;
40 41
41 if (!_for_verb.empty()) 42 if (!_for_verb.empty())
42 { 43 {
43 std::list<std::string> clauses(_for_verb.size(), "verb_id = @VERID"); 44 std::list<std::string> clauses(_for_verb.size(), "verb_id = ?");
44 construct << " WHERE frames.group_id IN (SELECT group_id FROM verb_groups WHERE "; 45 construct << " WHERE frames.group_id IN (SELECT group_id FROM verb_groups WHERE ";
45 construct << verbly::implode(std::begin(clauses), std::end(clauses), " OR "); 46 construct << verbly::implode(std::begin(clauses), std::end(clauses), " OR ");
46 construct << ")"; 47 construct << ")";
48
49 for (auto v : _for_verb)
50 {
51 bindings.emplace_back(v._id);
52 }
47 } 53 }
48 54
49 sqlite3_stmt* ppstmt; 55 sqlite3_stmt* ppstmt;
@@ -53,9 +59,27 @@ namespace verbly {
53 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 59 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
54 } 60 }
55 61
56 for (auto verb : _for_verb) 62 int i = 1;
63 for (auto& binding : bindings)
57 { 64 {
58 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@VERID"), verb._id); 65 switch (binding.get_type())
66 {
67 case binding::type::integer:
68 {
69 sqlite3_bind_int(ppstmt, i, binding.get_integer());
70
71 break;
72 }
73
74 case binding::type::string:
75 {
76 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
77
78 break;
79 }
80 }
81
82 i++;
59 } 83 }
60 84
61 std::list<frame> output; 85 std::list<frame> output;
diff --git a/lib/noun.cpp b/lib/noun.cpp index 71c9af0..d8b34c9 100644 --- a/lib/noun.cpp +++ b/lib/noun.cpp
@@ -34,6 +34,13 @@ namespace verbly {
34 34
35 return _plural; 35 return _plural;
36 } 36 }
37
38 int noun::wnid() const
39 {
40 assert(_valid == true);
41
42 return _wnid;
43 }
37 44
38 bool noun::has_plural_form() const 45 bool noun::has_plural_form() const
39 { 46 {
@@ -196,6 +203,16 @@ namespace verbly {
196 return _data->adjectives().variant_of(*this); 203 return _data->adjectives().variant_of(*this);
197 } 204 }
198 205
206 std::string noun::imagenet_url() const
207 {
208 std::stringstream url;
209 url << "http://www.image-net.org/api/text/imagenet.synset.geturls?wnid=n";
210 url.width(8);
211 url.fill('0');
212 url << (_wnid % 100000000);
213 return url.str();
214 }
215
199 bool noun::operator<(const noun& other) const 216 bool noun::operator<(const noun& other) const
200 { 217 {
201 return _id < other._id; 218 return _id < other._id;
diff --git a/lib/noun.h b/lib/noun.h index 969d2c8..bd71e57 100644 --- a/lib/noun.h +++ b/lib/noun.h
@@ -7,6 +7,7 @@ namespace verbly {
7 private: 7 private:
8 std::string _singular; 8 std::string _singular;
9 std::string _plural; 9 std::string _plural;
10 int _wnid;
10 11
11 friend class noun_query; 12 friend class noun_query;
12 13
@@ -17,6 +18,7 @@ namespace verbly {
17 std::string base_form() const; 18 std::string base_form() const;
18 std::string singular_form() const; 19 std::string singular_form() const;
19 std::string plural_form() const; 20 std::string plural_form() const;
21 int wnid() const;
20 22
21 bool has_plural_form() const; 23 bool has_plural_form() const;
22 24
@@ -43,6 +45,8 @@ namespace verbly {
43 adjective_query pertainyms() const; 45 adjective_query pertainyms() const;
44 adjective_query variations() const; 46 adjective_query variations() const;
45 47
48 std::string imagenet_url() const;
49
46 bool operator<(const noun& other) const; 50 bool operator<(const noun& other) const;
47 }; 51 };
48 52
diff --git a/lib/noun_query.cpp b/lib/noun_query.cpp index 04e567d..8f37bf6 100644 --- a/lib/noun_query.cpp +++ b/lib/noun_query.cpp
@@ -33,7 +33,7 @@ namespace verbly {
33 33
34 noun_query& noun_query::rhymes_with(const word& _word) 34 noun_query& noun_query::rhymes_with(const word& _word)
35 { 35 {
36 for (auto rhyme : _word.rhyme_phonemes()) 36 for (auto rhyme : _word.get_rhymes())
37 { 37 {
38 _rhymes.push_back(rhyme); 38 _rhymes.push_back(rhyme);
39 } 39 }
@@ -53,6 +53,34 @@ namespace verbly {
53 return *this; 53 return *this;
54 } 54 }
55 55
56 noun_query& noun_query::has_rhyming_noun()
57 {
58 _has_rhyming_noun = true;
59
60 return *this;
61 }
62
63 noun_query& noun_query::has_rhyming_adjective()
64 {
65 _has_rhyming_adjective = true;
66
67 return *this;
68 }
69
70 noun_query& noun_query::has_rhyming_adverb()
71 {
72 _has_rhyming_adverb = true;
73
74 return *this;
75 }
76
77 noun_query& noun_query::has_rhyming_verb()
78 {
79 _has_rhyming_verb = true;
80
81 return *this;
82 }
83
56 noun_query& noun_query::with_singular_form(std::string _arg) 84 noun_query& noun_query::with_singular_form(std::string _arg)
57 { 85 {
58 _with_singular_form.push_back(_arg); 86 _with_singular_form.push_back(_arg);
@@ -377,6 +405,21 @@ namespace verbly {
377 405
378 return *this; 406 return *this;
379 } 407 }
408
409 noun_query& noun_query::at_least_n_images(int _arg)
410 {
411 _at_least_n_images = _arg;
412
413 return *this;
414 }
415
416 noun_query& noun_query::with_wnid(int _arg)
417 {
418 _with_wnid.insert(_arg);
419
420 return *this;
421 }
422
380 /* 423 /*
381 noun_query& noun_query::derived_from(const word& _w) 424 noun_query& noun_query::derived_from(const word& _w)
382 { 425 {
@@ -464,8 +507,9 @@ namespace verbly {
464 construct << " "; 507 construct << " ";
465 } 508 }
466 509
467 construct << "SELECT noun_id, singular, plural FROM nouns"; 510 construct << "SELECT noun_id, singular, plural, wnid FROM nouns";
468 std::list<std::string> conditions; 511 std::list<std::string> conditions;
512 std::list<binding> bindings;
469 513
470 if (_has_prn) 514 if (_has_prn)
471 { 515 {
@@ -474,21 +518,53 @@ namespace verbly {
474 518
475 if (!_rhymes.empty()) 519 if (!_rhymes.empty())
476 { 520 {
477 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); 521 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
478 std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; 522 std::string cond = "noun_id IN (SELECT noun_id FROM noun_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
479 conditions.push_back(cond); 523 conditions.push_back(cond);
524
525 for (auto rhy : _rhymes)
526 {
527 bindings.emplace_back(rhy.get_prerhyme());
528 bindings.emplace_back(rhy.get_rhyme());
529 }
480 } 530 }
481 531
532 if (_has_rhyming_noun)
533 {
534 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.noun_id != curp.noun_id)");
535 }
536
537 if (_has_rhyming_adjective)
538 {
539 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
540 }
541
542 if (_has_rhyming_adverb)
543 {
544 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
545 }
546
547 if (_has_rhyming_verb)
548 {
549 conditions.push_back("noun_id IN (SELECT a.noun_id FROM nouns AS a INNER JOIN noun_pronunciations AS curp ON curp.noun_id = a.noun_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
550 }
551
482 for (auto except : _except) 552 for (auto except : _except)
483 { 553 {
484 conditions.push_back("noun_id != @EXCID"); 554 conditions.push_back("noun_id != ?");
555 bindings.emplace_back(except._id);
485 } 556 }
486 557
487 if (!_with_singular_form.empty()) 558 if (!_with_singular_form.empty())
488 { 559 {
489 std::list<std::string> clauses(_with_singular_form.size(), "singular = @SFORM"); 560 std::list<std::string> clauses(_with_singular_form.size(), "singular = ?");
490 std::string cond = "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; 561 std::string cond = "(" + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
491 conditions.push_back(cond); 562 conditions.push_back(cond);
563
564 for (auto form : _with_singular_form)
565 {
566 bindings.emplace_back(form);
567 }
492 } 568 }
493 569
494 if (_requires_plural_form) 570 if (_requires_plural_form)
@@ -503,11 +579,13 @@ namespace verbly {
503 { 579 {
504 case filter<std::string>::type::singleton: 580 case filter<std::string>::type::singleton:
505 { 581 {
582 bindings.emplace_back(f.get_elem() + "%");
583
506 if (notlogic == f.get_notlogic()) 584 if (notlogic == f.get_notlogic())
507 { 585 {
508 return "singular LIKE @PREFIX"; 586 return "singular LIKE ?";
509 } else { 587 } else {
510 return "singular NOT LIKE @PREFIX"; 588 return "singular NOT LIKE ?";
511 } 589 }
512 } 590 }
513 591
@@ -540,11 +618,13 @@ namespace verbly {
540 { 618 {
541 case filter<std::string>::type::singleton: 619 case filter<std::string>::type::singleton:
542 { 620 {
621 bindings.emplace_back("%" + f.get_elem());
622
543 if (notlogic == f.get_notlogic()) 623 if (notlogic == f.get_notlogic())
544 { 624 {
545 return "singular LIKE @SUFFIX"; 625 return "singular LIKE ?";
546 } else { 626 } else {
547 return "singular NOT LIKE @SUFFIX"; 627 return "singular NOT LIKE ?";
548 } 628 }
549 } 629 }
550 630
@@ -572,7 +652,8 @@ namespace verbly {
572 652
573 if (_with_complexity != unlimited) 653 if (_with_complexity != unlimited)
574 { 654 {
575 conditions.push_back("complexity = @COMPLEX"); 655 conditions.push_back("complexity = ?");
656 bindings.emplace_back(_with_complexity);
576 } 657 }
577 658
578 if (_is_hypernym) 659 if (_is_hypernym)
@@ -597,11 +678,13 @@ namespace verbly {
597 { 678 {
598 case filter<noun>::type::singleton: 679 case filter<noun>::type::singleton:
599 { 680 {
681 bindings.emplace_back(f.get_elem()._id);
682
600 if (notlogic == f.get_notlogic()) 683 if (notlogic == f.get_notlogic())
601 { 684 {
602 return "hyponym_id = @HYPO"; 685 return "hyponym_id = ?";
603 } else { 686 } else {
604 return "hyponym_id != @HYPO"; 687 return "hyponym_id != ?";
605 } 688 }
606 } 689 }
607 690
@@ -725,11 +808,13 @@ namespace verbly {
725 { 808 {
726 case filter<noun>::type::singleton: 809 case filter<noun>::type::singleton:
727 { 810 {
811 bindings.emplace_back(f.get_elem()._id);
812
728 if (notlogic == f.get_notlogic()) 813 if (notlogic == f.get_notlogic())
729 { 814 {
730 return "hypernym_id = @HYPER"; 815 return "hypernym_id = ?";
731 } else { 816 } else {
732 return "hypernym_id != @HYPER"; 817 return "hypernym_id != ?";
733 } 818 }
734 } 819 }
735 820
@@ -779,11 +864,13 @@ namespace verbly {
779 { 864 {
780 case filter<noun>::type::singleton: 865 case filter<noun>::type::singleton:
781 { 866 {
867 bindings.emplace_back(f.get_elem()._id);
868
782 if (notlogic == f.get_notlogic()) 869 if (notlogic == f.get_notlogic())
783 { 870 {
784 return "holonym_id = @PHOLO"; 871 return "holonym_id = ?";
785 } else { 872 } else {
786 return "holonym_id != @PHOLO"; 873 return "holonym_id != ?";
787 } 874 }
788 } 875 }
789 876
@@ -870,11 +957,13 @@ namespace verbly {
870 { 957 {
871 case filter<noun>::type::singleton: 958 case filter<noun>::type::singleton:
872 { 959 {
960 bindings.emplace_back(f.get_elem()._id);
961
873 if (notlogic == f.get_notlogic()) 962 if (notlogic == f.get_notlogic())
874 { 963 {
875 return "meronym_id = @PMERO"; 964 return "meronym_id = ?";
876 } else { 965 } else {
877 return "meronym_id != @PMERO"; 966 return "meronym_id != ?";
878 } 967 }
879 } 968 }
880 969
@@ -961,11 +1050,13 @@ namespace verbly {
961 { 1050 {
962 case filter<noun>::type::singleton: 1051 case filter<noun>::type::singleton:
963 { 1052 {
1053 bindings.emplace_back(f.get_elem()._id);
1054
964 if (notlogic == f.get_notlogic()) 1055 if (notlogic == f.get_notlogic())
965 { 1056 {
966 return "holonym_id = @SHOLO"; 1057 return "holonym_id = ?";
967 } else { 1058 } else {
968 return "holonym_id != @SHOLO"; 1059 return "holonym_id != ?";
969 } 1060 }
970 } 1061 }
971 1062
@@ -1052,11 +1143,13 @@ namespace verbly {
1052 { 1143 {
1053 case filter<noun>::type::singleton: 1144 case filter<noun>::type::singleton:
1054 { 1145 {
1146 bindings.emplace_back(f.get_elem()._id);
1147
1055 if (notlogic == f.get_notlogic()) 1148 if (notlogic == f.get_notlogic())
1056 { 1149 {
1057 return "meronym_id = @SMERO"; 1150 return "meronym_id = ?";
1058 } else { 1151 } else {
1059 return "meronym_id != @SMERO"; 1152 return "meronym_id != ?";
1060 } 1153 }
1061 } 1154 }
1062 1155
@@ -1143,11 +1236,13 @@ namespace verbly {
1143 { 1236 {
1144 case filter<noun>::type::singleton: 1237 case filter<noun>::type::singleton:
1145 { 1238 {
1239 bindings.emplace_back(f.get_elem()._id);
1240
1146 if (notlogic == f.get_notlogic()) 1241 if (notlogic == f.get_notlogic())
1147 { 1242 {
1148 return "holonym_id = @MHOLO"; 1243 return "holonym_id = ?";
1149 } else { 1244 } else {
1150 return "holonym_id != @MHOLO"; 1245 return "holonym_id != ?";
1151 } 1246 }
1152 } 1247 }
1153 1248
@@ -1234,11 +1329,13 @@ namespace verbly {
1234 { 1329 {
1235 case filter<noun>::type::singleton: 1330 case filter<noun>::type::singleton:
1236 { 1331 {
1332 bindings.emplace_back(f.get_elem()._id);
1333
1237 if (notlogic == f.get_notlogic()) 1334 if (notlogic == f.get_notlogic())
1238 { 1335 {
1239 return "meronym_id = @MMERO"; 1336 return "meronym_id = ?";
1240 } else { 1337 } else {
1241 return "meronym_id != @MMERO"; 1338 return "meronym_id != ?";
1242 } 1339 }
1243 } 1340 }
1244 1341
@@ -1335,11 +1432,13 @@ namespace verbly {
1335 { 1432 {
1336 case filter<noun>::type::singleton: 1433 case filter<noun>::type::singleton:
1337 { 1434 {
1435 bindings.emplace_back(f.get_elem()._id);
1436
1338 if (notlogic == f.get_notlogic()) 1437 if (notlogic == f.get_notlogic())
1339 { 1438 {
1340 return "class_id = @CLSID"; 1439 return "class_id = ?";
1341 } else { 1440 } else {
1342 return "class_id != @CLSID"; 1441 return "class_id != ?";
1343 } 1442 }
1344 } 1443 }
1345 1444
@@ -1389,11 +1488,13 @@ namespace verbly {
1389 { 1488 {
1390 case filter<noun>::type::singleton: 1489 case filter<noun>::type::singleton:
1391 { 1490 {
1491 bindings.emplace_back(f.get_elem()._id);
1492
1392 if (notlogic == f.get_notlogic()) 1493 if (notlogic == f.get_notlogic())
1393 { 1494 {
1394 return "instance_id = @INSID"; 1495 return "instance_id = ?";
1395 } else { 1496 } else {
1396 return "instance_id != @INSID"; 1497 return "instance_id != ?";
1397 } 1498 }
1398 } 1499 }
1399 1500
@@ -1443,11 +1544,13 @@ namespace verbly {
1443 { 1544 {
1444 case filter<noun>::type::singleton: 1545 case filter<noun>::type::singleton:
1445 { 1546 {
1547 bindings.emplace_back(f.get_elem()._id);
1548
1446 if (notlogic == f.get_notlogic()) 1549 if (notlogic == f.get_notlogic())
1447 { 1550 {
1448 return "noun_1_id = @SYNID"; 1551 return "noun_1_id = ?";
1449 } else { 1552 } else {
1450 return "noun_1_id != @SYNID"; 1553 return "noun_1_id != ?";
1451 } 1554 }
1452 } 1555 }
1453 1556
@@ -1497,11 +1600,13 @@ namespace verbly {
1497 { 1600 {
1498 case filter<noun>::type::singleton: 1601 case filter<noun>::type::singleton:
1499 { 1602 {
1603 bindings.emplace_back(f.get_elem()._id);
1604
1500 if (notlogic == f.get_notlogic()) 1605 if (notlogic == f.get_notlogic())
1501 { 1606 {
1502 return "noun_1_id = @ANTID"; 1607 return "noun_1_id = ?";
1503 } else { 1608 } else {
1504 return "noun_1_id != @ANTID"; 1609 return "noun_1_id != ?";
1505 } 1610 }
1506 } 1611 }
1507 1612
@@ -1551,11 +1656,13 @@ namespace verbly {
1551 { 1656 {
1552 case filter<adjective>::type::singleton: 1657 case filter<adjective>::type::singleton:
1553 { 1658 {
1659 bindings.emplace_back(f.get_elem()._id);
1660
1554 if (notlogic == f.get_notlogic()) 1661 if (notlogic == f.get_notlogic())
1555 { 1662 {
1556 return "pertainym_id = @PERID"; 1663 return "pertainym_id = ?";
1557 } else { 1664 } else {
1558 return "pertainym_id != @PERID"; 1665 return "pertainym_id != ?";
1559 } 1666 }
1560 } 1667 }
1561 1668
@@ -1605,11 +1712,13 @@ namespace verbly {
1605 { 1712 {
1606 case filter<adjective>::type::singleton: 1713 case filter<adjective>::type::singleton:
1607 { 1714 {
1715 bindings.emplace_back(f.get_elem()._id);
1716
1608 if (notlogic == f.get_notlogic()) 1717 if (notlogic == f.get_notlogic())
1609 { 1718 {
1610 return "adjective_id = @VALID"; 1719 return "adjective_id = ?";
1611 } else { 1720 } else {
1612 return "adjective_id != @VALID"; 1721 return "adjective_id != ?";
1613 } 1722 }
1614 } 1723 }
1615 1724
@@ -1636,6 +1745,25 @@ namespace verbly {
1636 cond << ")"; 1745 cond << ")";
1637 conditions.push_back(cond.str()); 1746 conditions.push_back(cond.str());
1638 } 1747 }
1748
1749 if (_at_least_n_images != unlimited)
1750 {
1751 conditions.push_back("images >= ?");
1752 bindings.emplace_back(_at_least_n_images);
1753 }
1754
1755 if (!_with_wnid.empty())
1756 {
1757 std::vector<std::string> clauses(_with_wnid.size(), "wnid = ?");
1758 std::string cond = verbly::implode(std::begin(clauses), std::end(clauses), " OR ");
1759 conditions.push_back("(" + cond + ")");
1760
1761 for (auto wnid : _with_wnid)
1762 {
1763 bindings.emplace_back(wnid);
1764 }
1765 }
1766
1639 /* 1767 /*
1640 if (!_derived_from_adjective.empty()) 1768 if (!_derived_from_adjective.empty())
1641 { 1769 {
@@ -1701,115 +1829,30 @@ namespace verbly {
1701 { 1829 {
1702 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 1830 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
1703 } 1831 }
1704 1832
1705 if (!_rhymes.empty()) 1833 int i = 1;
1834 for (auto& binding : bindings)
1706 { 1835 {
1707 int i = 0; 1836 switch (binding.get_type())
1708 for (auto rhyme : _rhymes)
1709 { 1837 {
1710 std::string rhymer = "%" + rhyme; 1838 case binding::type::integer:
1711 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); 1839 {
1840 sqlite3_bind_int(ppstmt, i, binding.get_integer());
1841
1842 break;
1843 }
1712 1844
1713 i++; 1845 case binding::type::string:
1846 {
1847 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
1848
1849 break;
1850 }
1714 } 1851 }
1852
1853 i++;
1715 } 1854 }
1716 1855
1717 for (auto except : _except)
1718 {
1719 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
1720 }
1721
1722 for (auto sform : _with_singular_form)
1723 {
1724 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SFORM"), sform.c_str(), sform.size(), SQLITE_STATIC);
1725 }
1726
1727 for (auto prefix : _with_prefix.inorder_flatten())
1728 {
1729 std::string pfat = prefix + "%";
1730 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PREFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC);
1731 }
1732
1733 for (auto suffix : _with_suffix.inorder_flatten())
1734 {
1735 std::string pfat = "%" + suffix;
1736 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SUFFIX"), pfat.c_str(), pfat.length(), SQLITE_STATIC);
1737 }
1738
1739 if (_with_complexity != unlimited)
1740 {
1741 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@COMPLEX"), _with_complexity);
1742 }
1743
1744 for (auto hyponym : _hypernym_of.inorder_flatten())
1745 {
1746 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPO"), hyponym._id);
1747 }
1748
1749 for (auto hypernym : _hyponym_of.inorder_flatten())
1750 {
1751 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@HYPER"), hypernym._id);
1752 }
1753
1754 for (auto holonym : _part_meronym_of.inorder_flatten())
1755 {
1756 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PHOLO"), holonym._id);
1757 }
1758
1759 for (auto meronym : _part_holonym_of.inorder_flatten())
1760 {
1761 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PMERO"), meronym._id);
1762 }
1763
1764 for (auto holonym : _substance_meronym_of.inorder_flatten())
1765 {
1766 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SHOLO"), holonym._id);
1767 }
1768
1769 for (auto meronym : _substance_holonym_of.inorder_flatten())
1770 {
1771 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SMERO"), meronym._id);
1772 }
1773
1774 for (auto holonym : _member_meronym_of.inorder_flatten())
1775 {
1776 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MHOLO"), holonym._id);
1777 }
1778
1779 for (auto meronym : _member_holonym_of.inorder_flatten())
1780 {
1781 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@MMERO"), meronym._id);
1782 }
1783
1784 for (auto cls : _instance_of.inorder_flatten())
1785 {
1786 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@CLSID"), cls._id);
1787 }
1788
1789 for (auto inst : _class_of.inorder_flatten())
1790 {
1791 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@INSID"), inst._id);
1792 }
1793
1794 for (auto synonym : _synonym_of.inorder_flatten())
1795 {
1796 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@SYNID"), synonym._id);
1797 }
1798
1799 for (auto antonym : _antonym_of.inorder_flatten())
1800 {
1801 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@ANTID"), antonym._id);
1802 }
1803
1804 for (auto pertainym : _anti_pertainym_of.inorder_flatten())
1805 {
1806 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@PERID"), pertainym._id);
1807 }
1808
1809 for (auto value : _attribute_of.inorder_flatten())
1810 {
1811 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@VALID"), value._id);
1812 }
1813 /* 1856 /*
1814 for (auto adj : _derived_from_adjective) 1857 for (auto adj : _derived_from_adjective)
1815 { 1858 {
@@ -1851,6 +1894,8 @@ namespace verbly {
1851 { 1894 {
1852 tnc._plural = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2))); 1895 tnc._plural = std::string(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
1853 } 1896 }
1897
1898 tnc._wnid = sqlite3_column_int(ppstmt, 3);
1854 1899
1855 output.push_back(tnc); 1900 output.push_back(tnc);
1856 } 1901 }
@@ -1859,7 +1904,7 @@ namespace verbly {
1859 1904
1860 for (auto& noun : output) 1905 for (auto& noun : output)
1861 { 1906 {
1862 query = "SELECT pronunciation FROM noun_pronunciations WHERE noun_id = ?"; 1907 query = "SELECT pronunciation, prerhyme, rhyme FROM noun_pronunciations WHERE noun_id = ?";
1863 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 1908 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
1864 { 1909 {
1865 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 1910 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
@@ -1873,6 +1918,14 @@ namespace verbly {
1873 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " "); 1918 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
1874 1919
1875 noun.pronunciations.push_back(phonemes); 1920 noun.pronunciations.push_back(phonemes);
1921
1922 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
1923 {
1924 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
1925 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
1926
1927 noun.rhymes.emplace_back(prerhyme, rhyming);
1928 }
1876 } 1929 }
1877 1930
1878 sqlite3_finalize(ppstmt); 1931 sqlite3_finalize(ppstmt);
diff --git a/lib/noun_query.h b/lib/noun_query.h index 44a1c70..19fbc60 100644 --- a/lib/noun_query.h +++ b/lib/noun_query.h
@@ -12,6 +12,10 @@ namespace verbly {
12 noun_query& except(const noun& _word); 12 noun_query& except(const noun& _word);
13 noun_query& rhymes_with(const word& _word); 13 noun_query& rhymes_with(const word& _word);
14 noun_query& has_pronunciation(); 14 noun_query& has_pronunciation();
15 noun_query& has_rhyming_noun();
16 noun_query& has_rhyming_adjective();
17 noun_query& has_rhyming_adverb();
18 noun_query& has_rhyming_verb();
15 19
16 noun_query& with_singular_form(std::string _arg); 20 noun_query& with_singular_form(std::string _arg);
17 noun_query& with_prefix(filter<std::string> _f); 21 noun_query& with_prefix(filter<std::string> _f);
@@ -74,6 +78,9 @@ namespace verbly {
74 noun_query& is_attribute(); 78 noun_query& is_attribute();
75 noun_query& attribute_of(filter<adjective> _f); 79 noun_query& attribute_of(filter<adjective> _f);
76 80
81 noun_query& at_least_n_images(int _arg);
82 noun_query& with_wnid(int _arg);
83
77/* noun_query& derived_from(const word& _w); 84/* noun_query& derived_from(const word& _w);
78 noun_query& not_derived_from(const word& _w);*/ 85 noun_query& not_derived_from(const word& _w);*/
79 86
@@ -85,9 +92,13 @@ namespace verbly {
85 const data& _data; 92 const data& _data;
86 int _limit = unlimited; 93 int _limit = unlimited;
87 bool _random = false; 94 bool _random = false;
88 std::list<std::string> _rhymes; 95 std::list<rhyme> _rhymes;
89 std::list<noun> _except; 96 std::list<noun> _except;
90 bool _has_prn = false; 97 bool _has_prn = false;
98 bool _has_rhyming_noun = false;
99 bool _has_rhyming_adjective = false;
100 bool _has_rhyming_adverb = false;
101 bool _has_rhyming_verb = false;
91 102
92 std::list<std::string> _with_singular_form; 103 std::list<std::string> _with_singular_form;
93 filter<std::string> _with_prefix; 104 filter<std::string> _with_prefix;
@@ -150,6 +161,9 @@ namespace verbly {
150 bool _is_attribute = false; 161 bool _is_attribute = false;
151 filter<adjective> _attribute_of; 162 filter<adjective> _attribute_of;
152 163
164 int _at_least_n_images = unlimited;
165 std::set<int> _with_wnid;
166
153/* std::list<adjective> _derived_from_adjective; 167/* std::list<adjective> _derived_from_adjective;
154 std::list<adjective> _not_derived_from_adjective; 168 std::list<adjective> _not_derived_from_adjective;
155 std::list<adverb> _derived_from_adverb; 169 std::list<adverb> _derived_from_adverb;
diff --git a/lib/preposition.cpp b/lib/preposition.cpp index c619bbf..cea9165 100644 --- a/lib/preposition.cpp +++ b/lib/preposition.cpp
@@ -37,13 +37,19 @@ namespace verbly {
37 { 37 {
38 std::stringstream construct; 38 std::stringstream construct;
39 construct << "SELECT form FROM prepositions"; 39 construct << "SELECT form FROM prepositions";
40 std::list<binding> bindings;
40 41
41 if (!_in_group.empty()) 42 if (!_in_group.empty())
42 { 43 {
43 std::list<std::string> clauses(_in_group.size(), "groupname = @GNAME"); 44 std::list<std::string> clauses(_in_group.size(), "groupname = ?");
44 construct << " WHERE preposition_id IN (SELECT preposition_id FROM preposition_groups WHERE "; 45 construct << " WHERE preposition_id IN (SELECT preposition_id FROM preposition_groups WHERE ";
45 construct << verbly::implode(std::begin(clauses), std::end(clauses), " OR "); 46 construct << verbly::implode(std::begin(clauses), std::end(clauses), " OR ");
46 construct << ")"; 47 construct << ")";
48
49 for (auto g : _in_group)
50 {
51 bindings.emplace_back(g);
52 }
47 } 53 }
48 54
49 if (_random) 55 if (_random)
@@ -63,9 +69,27 @@ namespace verbly {
63 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 69 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
64 } 70 }
65 71
66 for (auto& group : _in_group) 72 int i = 1;
73 for (auto& binding : bindings)
67 { 74 {
68 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@GNAME"), group.c_str(), group.length(), SQLITE_STATIC); 75 switch (binding.get_type())
76 {
77 case binding::type::integer:
78 {
79 sqlite3_bind_int(ppstmt, i, binding.get_integer());
80
81 break;
82 }
83
84 case binding::type::string:
85 {
86 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
87
88 break;
89 }
90 }
91
92 i++;
69 } 93 }
70 94
71 std::list<preposition> output; 95 std::list<preposition> output;
diff --git a/lib/verb_query.cpp b/lib/verb_query.cpp index 173a04e..654bc33 100644 --- a/lib/verb_query.cpp +++ b/lib/verb_query.cpp
@@ -33,7 +33,7 @@ namespace verbly {
33 33
34 verb_query& verb_query::rhymes_with(const word& _word) 34 verb_query& verb_query::rhymes_with(const word& _word)
35 { 35 {
36 for (auto rhyme : _word.rhyme_phonemes()) 36 for (auto rhyme : _word.get_rhymes())
37 { 37 {
38 _rhymes.push_back(rhyme); 38 _rhymes.push_back(rhyme);
39 } 39 }
@@ -53,6 +53,34 @@ namespace verbly {
53 return *this; 53 return *this;
54 } 54 }
55 55
56 verb_query& verb_query::has_rhyming_noun()
57 {
58 _has_rhyming_noun = true;
59
60 return *this;
61 }
62
63 verb_query& verb_query::has_rhyming_adjective()
64 {
65 _has_rhyming_adjective = true;
66
67 return *this;
68 }
69
70 verb_query& verb_query::has_rhyming_adverb()
71 {
72 _has_rhyming_adverb = true;
73
74 return *this;
75 }
76
77 verb_query& verb_query::has_rhyming_verb()
78 {
79 _has_rhyming_verb = true;
80
81 return *this;
82 }
83
56 verb_query& verb_query::has_frames() 84 verb_query& verb_query::has_frames()
57 { 85 {
58 this->_has_frames = true; 86 this->_has_frames = true;
@@ -65,6 +93,7 @@ namespace verbly {
65 std::stringstream construct; 93 std::stringstream construct;
66 construct << "SELECT verb_id, infinitive, past_tense, past_participle, ing_form, s_form FROM verbs"; 94 construct << "SELECT verb_id, infinitive, past_tense, past_participle, ing_form, s_form FROM verbs";
67 std::list<std::string> conditions; 95 std::list<std::string> conditions;
96 std::list<binding> bindings;
68 97
69 if (_has_prn) 98 if (_has_prn)
70 { 99 {
@@ -73,14 +102,41 @@ namespace verbly {
73 102
74 if (!_rhymes.empty()) 103 if (!_rhymes.empty())
75 { 104 {
76 std::list<std::string> clauses(_rhymes.size(), "pronunciation LIKE @RHMPRN"); 105 std::list<std::string> clauses(_rhymes.size(), "(prerhyme != ? AND rhyme = ?)");
77 std::string cond = "verb_id IN (SELECT verb_id FROM verb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")"; 106 std::string cond = "verb_id IN (SELECT verb_id FROM verb_pronunciations WHERE " + verbly::implode(std::begin(clauses), std::end(clauses), " OR ") + ")";
78 conditions.push_back(cond); 107 conditions.push_back(cond);
108
109 for (auto rhy : _rhymes)
110 {
111 bindings.emplace_back(rhy.get_prerhyme());
112 bindings.emplace_back(rhy.get_rhyme());
113 }
114 }
115
116 if (_has_rhyming_noun)
117 {
118 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN noun_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
119 }
120
121 if (_has_rhyming_adjective)
122 {
123 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adjective_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
124 }
125
126 if (_has_rhyming_adverb)
127 {
128 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN adverb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme)");
129 }
130
131 if (_has_rhyming_verb)
132 {
133 conditions.push_back("verb_id IN (SELECT a.verb_id FROM verbs AS a INNER JOIN verb_pronunciations AS curp ON curp.noun_id = a.adverb_id INNER JOIN verb_pronunciations AS rhmp ON rhmp.prerhyme != curp.prerhyme AND rhmp.rhyme = curp.rhyme AND rhmp.verb_id != curp.verb_id)");
79 } 134 }
80 135
81 for (auto except : _except) 136 for (auto except : _except)
82 { 137 {
83 conditions.push_back("verb_id != @EXCID"); 138 conditions.push_back("verb_id != ?");
139 bindings.emplace_back(except._id);
84 } 140 }
85 141
86 if (!_has_frames) 142 if (!_has_frames)
@@ -111,21 +167,27 @@ namespace verbly {
111 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 167 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
112 } 168 }
113 169
114 if (!_rhymes.empty()) 170 int i = 1;
171 for (auto& binding : bindings)
115 { 172 {
116 int i = 0; 173 switch (binding.get_type())
117 for (auto rhyme : _rhymes)
118 { 174 {
119 std::string rhymer = "%" + rhyme; 175 case binding::type::integer:
120 sqlite3_bind_text(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@RHMPRN"), rhymer.c_str(), rhymer.length(), SQLITE_STATIC); 176 {
177 sqlite3_bind_int(ppstmt, i, binding.get_integer());
178
179 break;
180 }
121 181
122 i++; 182 case binding::type::string:
183 {
184 sqlite3_bind_text(ppstmt, i, binding.get_string().c_str(), binding.get_string().length(), SQLITE_TRANSIENT);
185
186 break;
187 }
123 } 188 }
124 } 189
125 190 i++;
126 for (auto except : _except)
127 {
128 sqlite3_bind_int(ppstmt, sqlite3_bind_parameter_index(ppstmt, "@EXCID"), except._id);
129 } 191 }
130 192
131 std::list<verb> output; 193 std::list<verb> output;
@@ -145,7 +207,7 @@ namespace verbly {
145 207
146 for (auto& verb : output) 208 for (auto& verb : output)
147 { 209 {
148 query = "SELECT pronunciation FROM verb_pronunciations WHERE verb_id = ?"; 210 query = "SELECT pronunciation, prerhyme, rhyme FROM verb_pronunciations WHERE verb_id = ?";
149 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK) 211 if (sqlite3_prepare_v2(_data.ppdb, query.c_str(), query.length(), &ppstmt, NULL) != SQLITE_OK)
150 { 212 {
151 throw std::runtime_error(sqlite3_errmsg(_data.ppdb)); 213 throw std::runtime_error(sqlite3_errmsg(_data.ppdb));
@@ -159,6 +221,13 @@ namespace verbly {
159 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " "); 221 auto phonemes = verbly::split<std::list<std::string>>(pronunciation, " ");
160 222
161 verb.pronunciations.push_back(phonemes); 223 verb.pronunciations.push_back(phonemes);
224
225 if ((sqlite3_column_type(ppstmt, 1) != SQLITE_NULL) && (sqlite3_column_type(ppstmt, 2) != SQLITE_NULL))
226 {
227 std::string prerhyme(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 1)));
228 std::string rhyming(reinterpret_cast<const char*>(sqlite3_column_text(ppstmt, 2)));
229 verb.rhymes.emplace_back(prerhyme, rhyming);
230 }
162 } 231 }
163 232
164 sqlite3_finalize(ppstmt); 233 sqlite3_finalize(ppstmt);
diff --git a/lib/verb_query.h b/lib/verb_query.h index 24f5732..a07dc18 100644 --- a/lib/verb_query.h +++ b/lib/verb_query.h
@@ -12,6 +12,10 @@ namespace verbly {
12 verb_query& except(const verb& _word); 12 verb_query& except(const verb& _word);
13 verb_query& rhymes_with(const word& _word); 13 verb_query& rhymes_with(const word& _word);
14 verb_query& has_pronunciation(); 14 verb_query& has_pronunciation();
15 verb_query& has_rhyming_noun();
16 verb_query& has_rhyming_adjective();
17 verb_query& has_rhyming_adverb();
18 verb_query& has_rhyming_verb();
15 19
16 verb_query& has_frames(); 20 verb_query& has_frames();
17 21
@@ -23,10 +27,14 @@ namespace verbly {
23 const data& _data; 27 const data& _data;
24 int _limit = unlimited; 28 int _limit = unlimited;
25 bool _random = false; 29 bool _random = false;
26 std::list<std::string> _rhymes; 30 std::list<rhyme> _rhymes;
27 std::list<verb> _except; 31 std::list<verb> _except;
28 bool _has_prn = false; 32 bool _has_prn = false;
29 bool _has_frames = false; 33 bool _has_frames = false;
34 bool _has_rhyming_noun = false;
35 bool _has_rhyming_adjective = false;
36 bool _has_rhyming_adverb = false;
37 bool _has_rhyming_verb = false;
30 }; 38 };
31 39
32}; 40};
diff --git a/lib/word.cpp b/lib/word.cpp index 13c611f..49e34a1 100644 --- a/lib/word.cpp +++ b/lib/word.cpp
@@ -3,6 +3,26 @@
3 3
4namespace verbly { 4namespace verbly {
5 5
6 rhyme::rhyme(std::string prerhyme, std::string phonemes) : _prerhyme(prerhyme), _rhyme(phonemes)
7 {
8
9 }
10
11 std::string rhyme::get_prerhyme() const
12 {
13 return _prerhyme;
14 }
15
16 std::string rhyme::get_rhyme() const
17 {
18 return _rhyme;
19 }
20
21 bool rhyme::operator==(const rhyme& other) const
22 {
23 return std::tie(_prerhyme, _rhyme) == std::tie(other._prerhyme, other._rhyme);
24 }
25
6 word::word() 26 word::word()
7 { 27 {
8 28
@@ -13,28 +33,11 @@ namespace verbly {
13 33
14 } 34 }
15 35
16 std::list<std::string> word::rhyme_phonemes() const 36 std::list<rhyme> word::get_rhymes() const
17 { 37 {
18 assert(_valid == true); 38 assert(_valid == true);
19 39
20 std::list<std::string> result; 40 return rhymes;
21
22 for (auto pronunciation : pronunciations)
23 {
24 auto phemstrt = std::find_if(std::begin(pronunciation), std::end(pronunciation), [] (std::string phoneme) {
25 return phoneme.find("1") != std::string::npos;
26 });
27
28 std::stringstream rhymer;
29 for (auto it = phemstrt; it != std::end(pronunciation); it++)
30 {
31 rhymer << " " << *it;
32 }
33
34 result.push_back(rhymer.str());
35 }
36
37 return result;
38 } 41 }
39 42
40 bool word::starts_with_vowel_sound() const 43 bool word::starts_with_vowel_sound() const
diff --git a/lib/word.h b/lib/word.h index dc6fac8..08797a3 100644 --- a/lib/word.h +++ b/lib/word.h
@@ -3,6 +3,20 @@
3 3
4namespace verbly { 4namespace verbly {
5 5
6 class rhyme {
7 public:
8 rhyme(std::string prerhyme, std::string phonemes);
9
10 std::string get_prerhyme() const;
11 std::string get_rhyme() const;
12
13 bool operator==(const rhyme& other) const;
14
15 private:
16 std::string _prerhyme;
17 std::string _rhyme;
18 };
19
6 class word { 20 class word {
7 protected: 21 protected:
8 const data* _data; 22 const data* _data;
@@ -10,6 +24,7 @@ namespace verbly {
10 bool _valid = false; 24 bool _valid = false;
11 25
12 std::list<std::list<std::string>> pronunciations; 26 std::list<std::list<std::string>> pronunciations;
27 std::list<rhyme> rhymes;
13 28
14 word(); 29 word();
15 word(const data& _data, int _id); 30 word(const data& _data, int _id);
@@ -24,7 +39,7 @@ namespace verbly {
24 public: 39 public:
25 virtual std::string base_form() const = 0; 40 virtual std::string base_form() const = 0;
26 41
27 std::list<std::string> rhyme_phonemes() const; 42 std::list<rhyme> get_rhymes() const;
28 bool starts_with_vowel_sound() const; 43 bool starts_with_vowel_sound() const;
29 }; 44 };
30 45