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