/************************************************************************* * * * YAP Prolog * * * * Yap Prolog was developed at NCCUP - Universidade do Porto * * * * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 * * * ************************************************************************** * * File: modules.c * * Last rev: * * mods: * * comments: module support * * * *************************************************************************/ #ifdef SCCSLookupSystemModule static char SccsId[] = "%W% %G%"; #endif #include "Yap.h" #include "Yatom.h" #include "YapHeap.h" static Int current_module(USES_REGS1); static Int current_module1(USES_REGS1); static ModEntry *LookupModule(Term a); static ModEntry *LookupSystemModule(Term a); static ModEntry *GetModuleEntry(Atom at USES_REGS); static ModEntry *FetchModuleEntry(Atom at); /** * initialize module data-structure * * @param to parent module (CurrentModule) * @param ae module name. * * @return a new module structure *//** */ static ModEntry * initMod( AtomEntry *toname, AtomEntry *ae) { CACHE_REGS ModEntry *n, *parent; if (toname == NULL) parent = NULL; else { parent = FetchModuleEntry( toname ); } n = (ModEntry *)Yap_AllocAtomSpace(sizeof(*n)); INIT_RWLOCK(n->ModRWLock); n->KindOfPE = ModProperty; n->PredForME = NULL; n->NextME = CurrentModules; CurrentModules = n; n->AtomOfME = ae; n->OwnerFile = Yap_ConsultingFile( PASS_REGS1); AddPropToAtom(ae, (PropEntry *)n); Yap_setModuleFlags(n, parent); return n; } /** * get predicate entry for ap/arity; create it if neccessary * * @param[in] at * * @return module descriptorxs */ static ModEntry *GetModuleEntry(Atom at USES_REGS) { Prop p0; AtomEntry *ae = RepAtom(at); READ_LOCK(ae->ARWLock); p0 = ae->PropsOfAE; while (p0) { ModEntry *me = RepModProp(p0); if (me->KindOfPE == ModProperty) { READ_UNLOCK(ae->ARWLock); return me; } p0 = me->NextOfPE; } READ_UNLOCK(ae->ARWLock); return initMod( ( CurrentModule == PROLOG_MODULE ? NULL : AtomOfTerm( CurrentModule ) ), at ); } /** get entry for ap/arity; assumes one is there. */ static ModEntry *FetchModuleEntry(Atom at) { Prop p0; AtomEntry *ae = RepAtom(at); READ_LOCK(ae->ARWLock); p0 = ae->PropsOfAE; while (p0) { ModEntry *me = RepModProp(p0); if (me->KindOfPE == ModProperty) { READ_UNLOCK(ae->ARWLock); return me; } p0 = me->NextOfPE; } READ_UNLOCK(ae->ARWLock); return NULL; } Term Yap_getUnknownModule(ModEntry *m) { if (m && m->flags & UNKNOWN_ERROR) { return TermError; } else if (m && m->flags & UNKNOWN_WARNING) { return TermWarning; } else if (m && m->flags & UNKNOWN_FAST_FAIL) { return TermFastFail; } else { return TermFail; } } bool Yap_getUnknown ( Term mod) { ModEntry *m = LookupModule( mod ); return Yap_getUnknownModule( m ); } bool Yap_CharacterEscapes(Term mt) { CACHE_REGS if (mt == PROLOG_MODULE) mt = TermProlog; return GetModuleEntry(AtomOfTerm(mt) PASS_REGS)->flags & M_CHARESCAPE; } #define ByteAdr(X) ((char *)&(X)) Term Yap_Module_Name(PredEntry *ap) { CACHE_REGS if (!ap) return TermUser; if (!ap->ModuleOfPred) /* If the system predicate is a meta-call I should return the module for the metacall, which I will suppose has to be reachable from the current module anyway. So I will return the current module in case the system predicate is a meta-call. Otherwise it will still work. */ return TermProlog; else { return ap->ModuleOfPred; } } static ModEntry *LookupSystemModule(Term a) { CACHE_REGS Atom at; ModEntry *me; /* prolog module */ if (a == 0) { a = TermProlog; } at = AtomOfTerm(a); me = GetModuleEntry(at PASS_REGS); if (!me) return NULL; me->flags |= M_SYSTEM; me->OwnerFile = Yap_ConsultingFile( PASS_REGS1 ); return me; } static ModEntry *LookupModule(Term a) { CACHE_REGS Atom at; ModEntry *me; /* prolog module */ if (a == 0) { return GetModuleEntry(AtomProlog PASS_REGS); } at = AtomOfTerm(a); me = GetModuleEntry(at PASS_REGS); return me; } bool Yap_isSystemModule(Term a) { ModEntry *me = LookupModule(a); return me != NULL && me->flags & M_SYSTEM; } Term Yap_Module(Term tmod) { LookupModule(tmod); return tmod; } ModEntry *Yap_GetModuleEntry(Term mod) { ModEntry *me; if (!(me = LookupModule(mod))) return NULL; return me; } Term Yap_GetModuleFromEntry(ModEntry *me) { return MkAtomTerm(me->AtomOfME); ; } struct pred_entry *Yap_ModulePred(Term mod) { ModEntry *me; if (!(me = LookupModule(mod))) return NULL; return me->PredForME; } void Yap_NewModulePred(Term mod, struct pred_entry *ap) { ModEntry *me; if (!(me = LookupModule(mod))) return; WRITE_LOCK(me->ModRWLock); ap->NextPredOfModule = me->PredForME; me->PredForME = ap; WRITE_UNLOCK(me->ModRWLock); } static Int current_module(USES_REGS1) { /* $current_module(Old,N) */ Term t; if (CurrentModule) { if (!Yap_unify_constant(ARG1, CurrentModule)) return FALSE; } else { if (!Yap_unify_constant(ARG1, TermProlog)) return FALSE; } t = Deref(ARG2); if (IsVarTerm(t) || !IsAtomTerm(t)) return FALSE; if (t == TermProlog) { CurrentModule = PROLOG_MODULE; } else { // make it very clear that t inherits from cm. LookupModule(t); CurrentModule = t; } LOCAL_SourceModule = CurrentModule; return TRUE; } static Int change_module(USES_REGS1) { /* $change_module(N) */ Term mod = Deref(ARG1); LookupModule(mod); CurrentModule = mod; LOCAL_SourceModule = mod; return TRUE; } static Int current_module1(USES_REGS1) { /* $current_module(Old) */ if (CurrentModule) return Yap_unify_constant(ARG1, CurrentModule); return Yap_unify_constant(ARG1, TermProlog); } static Int cont_current_module(USES_REGS1) { ModEntry *imod = AddressOfTerm(EXTRA_CBACK_ARG(1, 1)), *next; Term t = MkAtomTerm(imod->AtomOfME); next = imod->NextME; /* ARG1 is unbound */ Yap_unify(ARG1, t); if (!next) cut_succeed(); EXTRA_CBACK_ARG(1, 1) = MkAddressTerm(next); return TRUE; } static Int init_current_module( USES_REGS1) { /* current_module(?ModuleName) */ Term t = Deref(ARG1); if (!IsVarTerm(t)) { if (!IsAtomTerm(t)) { Yap_Error(TYPE_ERROR_ATOM, t, "module name must be an atom"); return FALSE; } if (FetchModuleEntry(AtomOfTerm(t)) != NULL) cut_succeed(); cut_fail(); } EXTRA_CBACK_ARG(1, 1) = MkIntegerTerm((Int)CurrentModules); return cont_current_module(PASS_REGS1); } static Int cont_ground_module(USES_REGS1) { ModEntry *imod = AddressOfTerm(EXTRA_CBACK_ARG(3, 1)), *next; Term t2 = MkAtomTerm(imod->AtomOfME); next = imod->NextME; /* ARG2 is unbound */ if (!next) cut_succeed(); EXTRA_CBACK_ARG(3, 1) = MkAddressTerm(next); return Yap_unify(ARG2, t2); } static Int init_ground_module(USES_REGS1) { /* current_module(?ModuleName) */ Term t1 = Deref(ARG1), tmod = CurrentModule, t3; if (tmod == PROLOG_MODULE) { tmod = TermProlog; } t3 = Yap_YapStripModule(t1, &tmod); if (!t3) { Yap_Error(TYPE_ERROR_CALLABLE, t3, "trying to obtain module"); return FALSE; } if (!IsVarTerm(tmod)) { if (!IsAtomTerm(tmod)) { Yap_Error(TYPE_ERROR_ATOM, tmod, "module name must be an atom"); cut_fail(); } if (FetchModuleEntry(AtomOfTerm(tmod)) != NULL && Yap_unify(tmod, ARG2) && Yap_unify(t3, ARG3)) { cut_succeed(); } cut_fail(); } if (!Yap_unify(ARG2, tmod) || !Yap_unify(ARG3, t3) ) { cut_fail(); } // make sure we keep the binding B->cp_tr = TR; B->cp_h = HR; EXTRA_CBACK_ARG(3, 1) = MkAddressTerm(CurrentModules); return cont_ground_module(PASS_REGS1); } /** * @pred system_module( + _Mod_) * * @param module * * @return */ static Int is_system_module( USES_REGS1 ) { Term t; if (IsVarTerm(t = Deref (ARG1))) { return false; } if (!IsAtomTerm(t)) { Yap_Error(TYPE_ERROR_ATOM, t, "load_files/2"); return false; } return Yap_isSystemModule( t ); } static Int new_system_module( USES_REGS1 ) { ModEntry *me; Term t; if (IsVarTerm(t = Deref (ARG1))) { Yap_Error( INSTANTIATION_ERROR, t, NULL); return false; } if (!IsAtomTerm(t)) { Yap_Error(TYPE_ERROR_ATOM, t, NULL); return false; } if ((me = LookupSystemModule( t ) )) me->OwnerFile = Yap_ConsultingFile( PASS_REGS1); return me != NULL; } static Int strip_module(USES_REGS1) { Term t1 = Deref(ARG1), tmod = CurrentModule; if (tmod == PROLOG_MODULE) { tmod = TermProlog; } t1 = Yap_StripModule(t1, &tmod); if (!t1) { Yap_Error(TYPE_ERROR_CALLABLE, t1, "trying to obtain module"); return FALSE; } return Yap_unify(ARG3, t1) && Yap_unify(ARG2, tmod); } Term Yap_YapStripModule(Term t, Term *modp) { CACHE_REGS Term tmod; if (modp) tmod = *modp; else { tmod = CurrentModule; if (tmod == PROLOG_MODULE) { tmod = TermProlog; } } restart: if (IsVarTerm(t) || !IsApplTerm(t)) { if (modp) *modp = tmod; return t; } else { Functor fun = FunctorOfTerm(t); if (fun == FunctorModule) { Term t1 = ArgOfTerm(1, t); tmod = t1; if (!IsVarTerm(tmod) && !IsAtomTerm(tmod)) { return 0L; } t = ArgOfTerm(2, t); goto restart; } if (modp) *modp = tmod; return t; } return 0L; } static Int yap_strip_module(USES_REGS1) { Term t1 = Deref(ARG1), tmod = CurrentModule; if (tmod == PROLOG_MODULE) { tmod = TermProlog; } t1 = Yap_YapStripModule(t1, &tmod); if (!t1) { Yap_Error(TYPE_ERROR_CALLABLE, t1, "trying to obtain module"); return FALSE; } return Yap_unify(ARG3, t1) && Yap_unify(ARG2, tmod); } static Int context_module(USES_REGS1) { yamop *parentcp = P; CELL *yenv; PredEntry *ap = EnvPreg(parentcp); if (ap->ModuleOfPred && !(ap->PredFlags & MetaPredFlag)) return Yap_unify(ARG1, ap->ModuleOfPred); parentcp = CP; yenv = ENV; do { ap = EnvPreg(parentcp); if (ap->ModuleOfPred && !(ap->PredFlags & MetaPredFlag)) return Yap_unify(ARG1, ap->ModuleOfPred); parentcp = (yamop *)yenv[E_CP]; yenv = (CELL *)yenv[E_E]; } while (yenv); return Yap_unify(ARG1, CurrentModule); } /** * @pred source_module(-Mod) * * @param Mod is the current text source module. * * : _Mod_ is the current read-in or source module. */ static Int source_module(USES_REGS1) { if (LOCAL_SourceModule == PROLOG_MODULE) { return Yap_unify(ARG1, TermProlog); } return Yap_unify(ARG1, LOCAL_SourceModule); } Term Yap_StripModule(Term t, Term *modp) { CACHE_REGS Term tmod; if (modp) tmod = *modp; else { tmod = CurrentModule; if (tmod == PROLOG_MODULE) { tmod = TermProlog; } } restart: if (IsVarTerm(t) || !IsApplTerm(t)) { if (modp) *modp = tmod; return t; } else { Functor fun = FunctorOfTerm(t); if (fun == FunctorModule) { Term t1 = ArgOfTerm(1, t); if (IsVarTerm(t1)) { *modp = tmod; return t; } tmod = t1; if (!IsVarTerm(tmod) && !IsAtomTerm(tmod)) { return 0L; } t = ArgOfTerm(2, t); goto restart; } if (modp) *modp = tmod; return t; } return 0L; } void Yap_InitModulesC(void) { Yap_InitCPred("$current_module", 2, current_module, SafePredFlag | SyncPredFlag); Yap_InitCPred("$current_module", 1, current_module1, SafePredFlag | SyncPredFlag); Yap_InitCPred("$change_module", 1, change_module, SafePredFlag | SyncPredFlag); Yap_InitCPred("strip_module", 3, strip_module, SafePredFlag | SyncPredFlag); Yap_InitCPred("source_module", 1, source_module, SafePredFlag | SyncPredFlag); Yap_InitCPred("$yap_strip_module", 3, yap_strip_module, SafePredFlag | SyncPredFlag); Yap_InitCPred("context_module", 1, context_module, 0); Yap_InitCPred("$is_system_module", 1, is_system_module, SafePredFlag); Yap_InitCPred("new_system_module", 1, new_system_module, SafePredFlag); Yap_InitCPredBack("$all_current_modules", 1, 1, init_current_module, cont_current_module, SafePredFlag | SyncPredFlag); Yap_InitCPredBack("$ground_module", 3, 1, init_ground_module, cont_ground_module, SafePredFlag | SyncPredFlag); } void Yap_InitModules(void) { CACHE_REGS LookupSystemModule(MkAtomTerm(AtomProlog)); LOCAL_SourceModule = MkAtomTerm(AtomProlog); LookupModule(USER_MODULE); LookupModule(IDB_MODULE); LookupModule(ATTRIBUTES_MODULE); LookupSystemModule(CHARSIO_MODULE); LookupSystemModule(TERMS_MODULE); LookupSystemModule(SYSTEM_MODULE); LookupSystemModule(READUTIL_MODULE); LookupSystemModule(HACKS_MODULE); LookupModule(ARG_MODULE); LookupSystemModule(GLOBALS_MODULE); LookupSystemModule(DBLOAD_MODULE); LookupSystemModule(RANGE_MODULE); CurrentModule = PROLOG_MODULE; }