00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <plang/database.h>
00021 #include "database-priv.h"
00022 #include "context-priv.h"
00023 #include "rbtree-priv.h"
00024
00030
00031
00125 void _p_db_init(p_context *context)
00126 {
00127 struct p_db_op_info
00128 {
00129 const char *name;
00130 p_op_specifier specifier;
00131 int priority;
00132 };
00133 static struct p_db_op_info const ops[] = {
00134
00135 {":-", P_OP_XFX, 1200},
00136 {"-->", P_OP_XFX, 1200},
00137 {":-", P_OP_FX, 1200},
00138 {"?-", P_OP_FX, 1200},
00139 {";", P_OP_XFY, 1100},
00140 {"->", P_OP_XFY, 1050},
00141 {",", P_OP_XFY, 1000},
00142 {"\\+", P_OP_FY, 900},
00143 {"=", P_OP_XFX, 700},
00144 {"\\=", P_OP_XFX, 700},
00145 {"==", P_OP_XFX, 700},
00146 {"\\==", P_OP_XFX, 700},
00147 {"@<", P_OP_XFX, 700},
00148 {"@=<", P_OP_XFX, 700},
00149 {"@>", P_OP_XFX, 700},
00150 {"@>=", P_OP_XFX, 700},
00151 {"=..", P_OP_XFX, 700},
00152 {"is", P_OP_XFX, 700},
00153 {"=:=", P_OP_XFX, 700},
00154 {"=\\=", P_OP_XFX, 700},
00155 {"<", P_OP_XFX, 700},
00156 {"=<", P_OP_XFX, 700},
00157 {">", P_OP_XFX, 700},
00158 {">=", P_OP_XFX, 700},
00159 {"+", P_OP_YFX, 500},
00160 {"-", P_OP_YFX, 500},
00161 {"/\\", P_OP_YFX, 500},
00162 {"\\/", P_OP_YFX, 500},
00163 {"*", P_OP_YFX, 400},
00164 {"/", P_OP_YFX, 400},
00165 {"//", P_OP_YFX, 400},
00166 {"rem", P_OP_YFX, 400},
00167 {"mod", P_OP_YFX, 400},
00168 {"<<", P_OP_YFX, 400},
00169 {">>", P_OP_YFX, 400},
00170 {"**", P_OP_XFX, 200},
00171 {"^", P_OP_XFY, 200},
00172 {"-", P_OP_FY, 200},
00173 {"\\", P_OP_FY, 200},
00174
00175
00176
00177 {"||", P_OP_XFY, 1100},
00178 {"&&", P_OP_XFY, 1000},
00179 {"!", P_OP_FY, 900},
00180 {"!=", P_OP_XFX, 700},
00181 {"!==", P_OP_XFX, 700},
00182 {"=!=", P_OP_XFX, 700},
00183 {"@<=", P_OP_XFX, 700},
00184 {"<=", P_OP_XFX, 700},
00185 {"%", P_OP_YFX, 400},
00186 {"~", P_OP_FY, 200},
00187
00188
00189 {"<=>", P_OP_YFX, 1130},
00190 {"=>", P_OP_YFX, 1120},
00191 {":=", P_OP_XFX, 700},
00192 {":==", P_OP_XFX, 700},
00193 {"::=", P_OP_XFX, 700},
00194 {"::==", P_OP_XFX, 700},
00195 {"in", P_OP_XFX, 700},
00196 {">>>", P_OP_YFX, 400},
00197
00198 {0, 0, 0}
00199 };
00200 int index;
00201 for (index = 0; ops[index].name; ++index) {
00202 p_db_set_operator_info
00203 (p_term_create_atom(context, ops[index].name),
00204 ops[index].specifier, ops[index].priority);
00205 }
00206 }
00207
00208 P_INLINE p_database_info *p_db_find_arity(const p_term *atom, unsigned int arity)
00209 {
00210 p_database_info *info = atom->atom.db_info;
00211 while (info && info->arity != arity)
00212 info = info->next;
00213 return info;
00214 }
00215
00216 p_database_info *_p_db_find_arity(const p_term *atom, unsigned int arity)
00217 {
00218 return p_db_find_arity(atom, arity);
00219 }
00220
00221 P_INLINE p_database_info *p_db_create_arity(p_term *atom, unsigned int arity)
00222 {
00223 p_database_info *info = p_db_find_arity(atom, arity);
00224 if (!info) {
00225 info = GC_NEW(p_database_info);
00226 if (!info)
00227 return 0;
00228 info->next = atom->atom.db_info;
00229 info->arity = arity;
00230 atom->atom.db_info = info;
00231 }
00232 return info;
00233 }
00234
00235 p_database_info *_p_db_create_arity(p_term *atom, unsigned int arity)
00236 {
00237 return p_db_create_arity(atom, arity);
00238 }
00239
00250 p_op_specifier p_db_operator_info(const p_term *name, int arity, int *priority)
00251 {
00252 p_database_info *info;
00253
00254
00255 name = p_term_deref(name);
00256 if (!name || name->header.type != P_TERM_ATOM) {
00257 *priority = 0;
00258 return P_OP_NONE;
00259 }
00260
00261
00262 info = p_db_find_arity(name, (unsigned int)arity);
00263 if (!info) {
00264 *priority = 0;
00265 return P_OP_NONE;
00266 }
00267
00268
00269 *priority = (int)(info->op_priority);
00270 return (p_op_specifier)(info->op_specifier);
00271 }
00272
00283 void p_db_set_operator_info(p_term *name, p_op_specifier specifier, int priority)
00284 {
00285 unsigned int arity;
00286 p_database_info *info;
00287
00288
00289 name = p_term_deref(name);
00290 if (!name || name->header.type != P_TERM_ATOM)
00291 return;
00292
00293
00294 switch (specifier) {
00295 case P_OP_XF:
00296 case P_OP_YF:
00297 case P_OP_FX:
00298 case P_OP_FY: arity = 1; break;
00299 case P_OP_XFX:
00300 case P_OP_XFY:
00301 case P_OP_YFX: arity = 2; break;
00302 default: return;
00303 }
00304
00305
00306 if (!priority)
00307 specifier = P_OP_NONE;
00308
00309
00310 info = p_db_create_arity(name, arity);
00311 if (!info)
00312 return;
00313
00314
00315 info->op_specifier = (unsigned int)specifier;
00316 info->op_priority = (unsigned int)priority;
00317 }
00318
00344 p_db_builtin p_db_builtin_predicate(const p_term *name, int arity)
00345 {
00346 p_database_info *info;
00347
00348
00349 name = p_term_deref(name);
00350 if (!name || name->header.type != P_TERM_ATOM)
00351 return 0;
00352
00353
00354 info = p_db_find_arity(name, (unsigned int)arity);
00355 if (info)
00356 return info->builtin_func;
00357 else
00358 return 0;
00359 }
00360
00372 void p_db_set_builtin_predicate(p_term *name, int arity, p_db_builtin builtin)
00373 {
00374 p_database_info *info;
00375
00376
00377 name = p_term_deref(name);
00378 if (!name || name->header.type != P_TERM_ATOM)
00379 return;
00380
00381
00382 info = p_db_create_arity(name, (unsigned int)arity);
00383 if (!info)
00384 return;
00385
00386
00387 info->builtin_func = builtin;
00388 if (builtin)
00389 info->flags |= P_PREDICATE_BUILTIN;
00390 else
00391 info->flags &= ~P_PREDICATE_BUILTIN;
00392 }
00393
00394
00395 void _p_db_register_builtins(p_context *context, const struct p_builtin *builtins)
00396 {
00397 while (builtins->name != 0) {
00398 p_db_set_builtin_predicate
00399 (p_term_create_atom(context, builtins->name),
00400 builtins->arity, builtins->func);
00401 ++builtins;
00402 }
00403 }
00404
00431 p_db_arith p_db_builtin_arith(const p_term *name, int arity)
00432 {
00433 p_database_info *info;
00434
00435
00436 name = p_term_deref(name);
00437 if (!name || name->header.type != P_TERM_ATOM)
00438 return 0;
00439
00440
00441 info = p_db_find_arity(name, (unsigned int)arity);
00442 if (info)
00443 return info->arith_func;
00444 else
00445 return 0;
00446 }
00447
00458 void p_db_set_builtin_arith
00459 (p_term *name, int arity, p_db_arith builtin)
00460 {
00461 p_database_info *info;
00462
00463
00464 name = p_term_deref(name);
00465 if (!name || name->header.type != P_TERM_ATOM)
00466 return;
00467
00468
00469 info = p_db_create_arity(name, (unsigned int)arity);
00470 if (!info)
00471 return;
00472
00473
00474 info->arith_func = builtin;
00475 }
00476
00477
00478 void _p_db_register_ariths(p_context *context, const struct p_arith *ariths)
00479 {
00480 while (ariths->name != 0) {
00481 p_db_set_builtin_arith
00482 (p_term_create_atom(context, ariths->name),
00483 ariths->arity, ariths->arith_func);
00484 ++ariths;
00485 }
00486 }
00487
00488
00489 void _p_db_register_sources(p_context *context, const char * const *sources)
00490 {
00491 while (*sources != 0) {
00492 p_context_consult_string(context, *sources);
00493 ++sources;
00494 }
00495 }
00496
00497
00498 static p_term *p_db_predicate_name
00499 (p_context *context, p_term *clause, int *arity)
00500 {
00501 p_term *head;
00502 clause = p_term_deref(clause);
00503 if (!clause || clause->header.type != P_TERM_FUNCTOR ||
00504 clause->header.size != 2 ||
00505 clause->functor.functor_name != context->clause_atom)
00506 return 0;
00507 head = p_term_deref(clause->functor.arg[0]);
00508 if (!head)
00509 return 0;
00510 if (head->header.type == P_TERM_ATOM) {
00511 *arity = 0;
00512 return head;
00513 } else if (head->header.type == P_TERM_FUNCTOR) {
00514 *arity = (int)(head->header.size);
00515 return head->functor.functor_name;
00516 }
00517 return 0;
00518 }
00519
00520
00521 P_INLINE p_term *p_db_convert_clause(p_context *context, p_term *clause)
00522 {
00523 return p_term_create_dynamic_clause
00524 (context, p_term_arg(clause, 0), p_term_arg(clause, 1));
00525 }
00526
00540 int p_db_clause_assert_first(p_context *context, p_term *clause)
00541 {
00542 p_database_info *info;
00543 p_term *name;
00544 int arity;
00545 p_term *predicate;
00546
00547
00548 name = p_db_predicate_name(context, clause, &arity);
00549 if (!name)
00550 return 0;
00551
00552
00553 info = p_db_create_arity(name, (unsigned int)arity);
00554 if (!info)
00555 return 0;
00556
00557
00558 if (info->flags & (P_PREDICATE_BUILTIN | P_PREDICATE_COMPILED))
00559 return 0;
00560
00561
00562 predicate = info->predicate;
00563 if (!predicate) {
00564 predicate = p_term_create_predicate(context, name, arity);
00565 if (!predicate)
00566 return 0;
00567 info->predicate = predicate;
00568 }
00569 p_term_add_clause_first
00570 (context, predicate, p_db_convert_clause(context, clause));
00571 return 1;
00572 }
00573
00574
00575 p_term *_p_db_clause_assert_last(p_context *context, p_term *clause)
00576 {
00577 p_database_info *info;
00578 p_term *name;
00579 int arity;
00580 p_term *predicate;
00581
00582
00583 name = p_db_predicate_name(context, clause, &arity);
00584 if (!name)
00585 return 0;
00586
00587
00588 info = p_db_create_arity(name, (unsigned int)arity);
00589 if (!info)
00590 return 0;
00591
00592
00593 if (info->flags & (P_PREDICATE_BUILTIN | P_PREDICATE_COMPILED))
00594 return 0;
00595
00596
00597 predicate = info->predicate;
00598 if (!predicate) {
00599 predicate = p_term_create_predicate(context, name, arity);
00600 if (!predicate)
00601 return 0;
00602 info->predicate = predicate;
00603 }
00604 p_term_add_clause_last
00605 (context, predicate, p_db_convert_clause(context, clause));
00606 return predicate;
00607 }
00608
00622 int p_db_clause_assert_last(p_context *context, p_term *clause)
00623 {
00624 return _p_db_clause_assert_last(context, clause) != 0;
00625 }
00626
00640 int p_db_clause_retract(p_context *context, p_term *clause)
00641 {
00642 p_database_info *info;
00643 p_term *name;
00644 int arity;
00645 struct p_term_clause *list;
00646 struct p_term_clause *prev;
00647 p_term *predicate;
00648
00649
00650 name = p_db_predicate_name(context, clause, &arity);
00651 if (!name)
00652 return 0;
00653
00654
00655 info = p_db_find_arity(name, (unsigned int)arity);
00656 if (!info)
00657 return -1;
00658
00659
00660 if (info->flags & (P_PREDICATE_BUILTIN | P_PREDICATE_COMPILED))
00661 return 0;
00662
00663
00664 predicate = info->predicate;
00665 if (!predicate)
00666 return -1;
00667 list = predicate->predicate.clauses.head;
00668 prev = 0;
00669 while (list) {
00670 if (_p_term_retract_clause(context, predicate, list, clause)) {
00671 if (prev)
00672 prev->next_clause = list->next_clause;
00673 else
00674 predicate->predicate.clauses.head = list->next_clause;
00675 --(predicate->predicate.clause_count);
00676 if (!list->next_clause)
00677 predicate->predicate.clauses.tail = prev;
00678 if (!predicate->predicate.clauses.head)
00679 info->predicate = 0;
00680 return 1;
00681 }
00682 prev = list;
00683 list = list->next_clause;
00684 }
00685 return -1;
00686 }
00687
00699 int p_db_clause_abolish(p_context *context, const p_term *name, int arity)
00700 {
00701 p_database_info *info;
00702
00703
00704 name = p_term_deref(name);
00705 if (!name || name->header.type != P_TERM_ATOM)
00706 return 1;
00707
00708
00709 info = p_db_find_arity(name, (unsigned int)arity);
00710 if (!info)
00711 return 1;
00712
00713
00714 if (info->flags & (P_PREDICATE_BUILTIN | P_PREDICATE_COMPILED))
00715 return 0;
00716
00717
00718 info->predicate = 0;
00719 return 1;
00720 }
00721
00735 int p_db_local_clause_assert_first(p_context *context, p_term *database, p_term *clause)
00736 {
00737 p_database_info *info;
00738 p_term *name;
00739 int arity;
00740 p_term *predicate;
00741 p_rbkey key;
00742 p_rbnode *node;
00743
00744
00745 database = p_term_deref(database);
00746 if (!database || database->header.type != P_TERM_DATABASE)
00747 return 0;
00748
00749
00750 name = p_db_predicate_name(context, clause, &arity);
00751 if (!name)
00752 return 0;
00753
00754
00755
00756 info = p_db_find_arity(name, (unsigned int)arity);
00757 if (info && (info->flags & P_PREDICATE_BUILTIN) != 0)
00758 return 0;
00759
00760
00761 key.type = P_TERM_FUNCTOR;
00762 key.size = arity;
00763 key.name = name;
00764 node = _p_rbtree_insert(&(database->database.predicates), &key);
00765 if (!node)
00766 return 0;
00767 predicate = node->value;
00768 if (!predicate) {
00769 predicate = p_term_create_predicate(context, name, arity);
00770 if (!predicate)
00771 return 0;
00772 node->value = predicate;
00773 }
00774
00775
00776 p_term_add_clause_first
00777 (context, predicate, p_db_convert_clause(context, clause));
00778 return 1;
00779 }
00780
00794 int p_db_local_clause_assert_last(p_context *context, p_term *database, p_term *clause)
00795 {
00796 p_database_info *info;
00797 p_term *name;
00798 int arity;
00799 p_term *predicate;
00800 p_rbkey key;
00801 p_rbnode *node;
00802
00803
00804 database = p_term_deref(database);
00805 if (!database || database->header.type != P_TERM_DATABASE)
00806 return 0;
00807
00808
00809 name = p_db_predicate_name(context, clause, &arity);
00810 if (!name)
00811 return 0;
00812
00813
00814
00815 info = p_db_find_arity(name, (unsigned int)arity);
00816 if (info && (info->flags & P_PREDICATE_BUILTIN) != 0)
00817 return 0;
00818
00819
00820 key.type = P_TERM_FUNCTOR;
00821 key.size = arity;
00822 key.name = name;
00823 node = _p_rbtree_insert(&(database->database.predicates), &key);
00824 if (!node)
00825 return 1;
00826 predicate = node->value;
00827 if (!predicate) {
00828 predicate = p_term_create_predicate(context, name, arity);
00829 if (!predicate)
00830 return 0;
00831 node->value = predicate;
00832 }
00833
00834
00835 p_term_add_clause_last
00836 (context, predicate, p_db_convert_clause(context, clause));
00837 return 1;
00838 }
00839
00853 int p_db_local_clause_retract(p_context *context, p_term *database, p_term *clause)
00854 {
00855 p_term *name;
00856 int arity;
00857 p_term *predicate;
00858 p_rbkey key;
00859 p_rbnode *node;
00860 struct p_term_clause *list;
00861 struct p_term_clause *prev;
00862
00863
00864 database = p_term_deref(database);
00865 if (!database || database->header.type != P_TERM_DATABASE)
00866 return 0;
00867
00868
00869 name = p_db_predicate_name(context, clause, &arity);
00870 if (!name)
00871 return 0;
00872
00873
00874 key.type = P_TERM_FUNCTOR;
00875 key.size = arity;
00876 key.name = name;
00877 node = _p_rbtree_lookup(&(database->database.predicates), &key);
00878 if (!node)
00879 return -1;
00880
00881
00882 predicate = node->value;
00883 list = predicate->predicate.clauses.head;
00884 prev = 0;
00885 while (list) {
00886 if (_p_term_retract_clause(context, predicate, list, clause)) {
00887 if (prev)
00888 prev->next_clause = list->next_clause;
00889 else
00890 predicate->predicate.clauses.head = list->next_clause;
00891 --(predicate->predicate.clause_count);
00892 if (!list->next_clause)
00893 predicate->predicate.clauses.tail = prev;
00894 if (!predicate->predicate.clauses.head) {
00895
00896 _p_rbtree_remove
00897 (&(database->database.predicates), &key);
00898 }
00899 return 1;
00900 }
00901 prev = list;
00902 list = list->next_clause;
00903 }
00904 return -1;
00905 }
00906
00918 int p_db_local_clause_abolish(p_context *context, p_term *database, const p_term *name, int arity)
00919 {
00920 p_rbkey key;
00921
00922
00923 database = p_term_deref(database);
00924 if (!database || database->header.type != P_TERM_DATABASE)
00925 return 0;
00926
00927
00928 name = p_term_deref(name);
00929 if (!name || name->header.type != P_TERM_ATOM)
00930 return 1;
00931
00932
00933 key.type = P_TERM_FUNCTOR;
00934 key.size = arity;
00935 key.name = name;
00936 if (!_p_rbtree_lookup(&(database->database.predicates), &key))
00937 return 1;
00938
00939
00940 _p_rbtree_remove(&(database->database.predicates), &key);
00941 return 1;
00942 }
00943
00951 p_predicate_flags p_db_predicate_flags(p_context *context, const p_term *name, int arity)
00952 {
00953 p_database_info *info;
00954
00955
00956 name = p_term_deref(name);
00957 if (!name || name->header.type != P_TERM_ATOM)
00958 return P_PREDICATE_NONE;
00959
00960
00961 info = p_db_find_arity(name, (unsigned int)arity);
00962 if (!info)
00963 return P_PREDICATE_NONE;
00964
00965
00966 return (p_predicate_flags)(info->flags);
00967 }
00968
00976 void p_db_set_predicate_flag(p_context *context, p_term *name, int arity, p_predicate_flags flag, int value)
00977 {
00978 p_database_info *info;
00979
00980
00981 name = p_term_deref(name);
00982 if (!name || name->header.type != P_TERM_ATOM)
00983 return;
00984
00985
00986 info = p_db_create_arity(name, arity);
00987 if (!info)
00988 return;
00989
00990
00991 if (value)
00992 info->flags |= flag;
00993 else
00994 info->flags &= ~flag;
00995 }
00996
00997