1. IMPLEMENTATION OF THE MECHANISM FOR CATCHING UNDEFINED PREDICATE/METHODS

ALGORITHM
   1) When compiling a flora program with debug option turned on, we 
      take the intermediate representation of the program from the 
      compiler, compute skeletons for rule heads and facts (see below), and
      remove duplications. These skeletons will be dumped into a file with 
      extension .fld. When this program is loaded, the skeletons will
      be loaded into the fld storage trie of the corresponding module.
      
   2) The basic idea is to add patch rules to trap undefined predicates.
      For example, if we have the following patch rules: 
      		flapply(X) :- storage_find_fact(fldstorage, flapply(X)),
			      !, fail.
		flapply(X) :- flora_error_undefined(flapply(X)), abort.
      All undefined HiLog predicates whose arities are 0 will be trapped.
      Such rules can be found in genincludes/flrpreddef.flh.

      Unfortunately, this doesn't work for F-logic predicates because of
      the inheritance rules.
      For example, in closure/flrtrailer.fli, we have
      		isa(O,C) :-
			silent_sub(S,C),
			inferred_isa(O,S).
      It is possible that sub(_,C) is not defined, we will get an error
      message saying "_::C" is undefined when the query is "_:C".

      We can handle this problem in the following way:
      F-logic wrappers in the bodies of user program rules and queries
      (except in database operations) are prefixed by 'd_'.
      This has the effect that the wrappers in the rule bodies in the program 
      (e.g., d_isa/2) are different from the wrappers in the rule bodies in
      the trailers (e.g., isa/2). The undefinedness checking rules (below)
      are then attached to the d_* versions of the wrappers, but not to the
      wrappers used in the trailer. As a result, Flora won't complain that
      trailer predicates are undefined (because they are allowed to).

      a) When debug option is turned on, we need patch rules such as:
		check_undefined(O,C) :-
		  storage_find_fact(fldstorage,isa(O,C)), !, fail.
		check_undefined(O,C) :-
		  storage_find_fact(fldstorage,sub(O,C)), !, fail.
		check_undefined(_,_).
      		d_isa(O,C) :- check_undefined(O,C),
		              !,
			      flora_error_undefined(isa(O,C)),
		              abort.
      		d_isa(O,C) :- isa(O,C).
	 These patch rules are in genincludes/flrpreddef.flh; they are
      	 generated from templates in genincludes/flrpreddef.fli.
      b) When debug option is turned off, we need patch rules such as:
      		d_isa(O,C) :- isa(O,C).
	 These patch rules are in genincludes/flrnopreddef.flh.

      If a flora program has the debug option turned on, its .P file will
      include flrpreddef.flh in the end; otherwise, its .P file will include
      flrnopreddef.flh in the end.

   3) When insert, insertall, btinsert, btinsertall is executed, we need
      to compute the skeleton(s) of the inserted fact(s) and insert the
      skeleton(s) into the fld storage.

   4) debug option is local to module. This is done by keeping track of the
      loaded modules that require debugging in flora_debug_module_registry

ALGORITHM REVISED
   1) When compiling a flora program, we take the intermediate representation
      of the program from the compiler, compute skeletons for rule heads and
      facts (see below), and remove duplications. These skeletons will be
      dumped into a file with extension .fld. When this program is loaded, the
      skeletons will be loaded into the fld storage trie of the corresponding
      module.
      
   2) The basic idea is to add patch rules to trap undefined predicates.
      For hilog predicates, we have patch rules such as:
      		flapply(X) :-
			this_module_is_in_debugging_mode,
			storage_find_fact(fldstorage, flapply(X)),
			!,
			fail.
		flapply(X) :-
			this_module_is_in_debugging_mode,
			flora_error_undefined(flapply(X)).

      where
	* this_module_is_in_debugging_mode succeeds only when the debug option
          of the module is turned on. See section 3) for more detail.
	* flora_error_undefined handles the case where the skeleton of the
	  predicate never appears in any rule head or fact. It's not necessarily
	  undefined because of database operations. See section 4).

      With thses two rules, all undefined HiLog predicates whose arities are 0
      will be trapped when the debug option is turned on.
      Such patch rules can be found in genincludes/flrpreddef.fli.

      Unfortunately, this doesn't work for F-logic predicates because of
      the inheritance rules.
      For example, in closure/flrtrailer.fli, we have
      		isa(O,C) :-
			silent_sub(S,C),
			inferred_isa(O,S).
      It is possible that sub(_,C) is not defined, we will get an error
      message saying "_::C" is undefined when the query is "_:C".

      We can handle this problem in the following way:
      F-logic wrappers in the bodies of user program rules and queries
      (except in database operations) are prefixed by 'd_'.
      This has the effect that the wrappers in the rule bodies in the program 
      (e.g., d_isa/2) are different from the wrappers in the rule bodies in
      the trailers (e.g., isa/2). The undefinedness checking rules (below)
      are then attached to the d_* versions of the wrappers, but not to the
      wrappers used in the trailer. As a result, Flora won't complain that
      trailer predicates are undefined (because they are allowed to).

      Patch rules for trapping undefined isa are:
		d_isa(X,Y) :-
			this_module_is_in_debugging_mode,
			not storage_find_fact(fldstorage, isa(X,Y)),
			not storage_find_fact(fldstorage, sub(X,Y)),
			flora_error_undefined(isa(X,Y)).
		d_isa(X,Y) :-
			isa(X,Y).

      Such rules are also in genincludes/flrpreddef.fli.
      flWrapAround('flrpreddef.fli') generates flrpreddef.flh, which is included
      in the end of .P files 

   3) Debug option is local to module and can be dynamically turned on/off.
      This is done by keeping track of the loaded modules that require debugging
      in flora_debug_module_registry. In the system module flora(sys), we have
		debug[#check_undefined(Flag)]
		debug[#check_undefined(Flag,Module)] 
      to query, turn on, or turn off the debug option of a certain module or
      all modules.

   4) Insert operations(insert, insertall, btinsert, btinsertall) may produce
      some new skeletons which are not in any fact or rule head. If we check
      and insert skeletons for every insert operation, insert operations will
      be slowed down a lot. We can do it in a lazy way as follows.

      When flora_error_undefined(P) is called, we compute the skeleton of P,
      check whether there is a fact in the fdb storage that have the same
      skeleton.  If so, build the skeleton of the fact, insert it into fld
      storage, then fail; otherwise, throw 
      FLORA_UNDEFINED_EXCEPTION(P,ErrorMessage).


SKELETONS

    A skeleton represents a generalization of the terms in the rule heads.
      For instance, for
	  p(X)(a,Z)(b,D) :- ...
      the skeleton is 
          flapply(flapply(flapply(p,_),_,_) _, _)
      for 
          Z(X)(c,Z)(c,D) :- ...
      it is 
          flapply(flapply(flapply(_,_),_,_) _, _)
      For F-logic molecules, say,

	T[Z(X)(c,Z)(c,D) -> ...] :- ...
	Q[p(X)(a,Z)(b,D) ->> ...] :- ...

      you put into the trie the following skeletons:

	fd(_, flapply(flapply(flapply(_,_),_,_) _, _), _)
	mvd(_, flapply(flapply(flapply(p,_),_,_) _, _), _)


2. IMPLEMENTATION OF NUMBERED ANONYMOUS OID SYNTAX

   The goal is to allow _#1, _#2, in addition to _#.
     
   The idea is that two occurrences of, say, _#2 within the same rule would
   be assigned the same oid and _#1,_#2, _# would be different.  Also,
   occurrences of _#1 across different rules would be different as well.

   The implementation is as follows. First, numbered (_#1, _#2) etc and
   unnumbered (_#) oids should use difference naming schemas. The numbered
   oids can use, say, _$_$_flora_newoid<rule-number>|<oid-number>.  For
   instance, _#345 that appears in the clause number 9876 would be replaced
   with _$_$_flora_newoid9876|345.

   We should also check that each numbered oid that occurs inside a rule is
   referenced there at least twice and issue a warning if not. This can be
   done by asserting ruleoid(345,1) when the compiler sees _#345 within the
   clause 9876 the first time. While processing that rule, the compiler
   would increment the count. For instance, in our case it would retract
   the above fact and assert ruleoid(345,2)

   When it is done working with the rule, it should check if there are
   facts of the form ruleoid(_,1) and issue an error if there are.  The
   ruleoid/2 relation is reset by the compiler at the beginning of each new
   rule.

3. Translation of @prologall()
   p(X,Y)@prologall() becomes:

   flora_plg2hilog(NewX,X,flapply,0), % don't unify vars
   flora_plg2hilog(NewY,Y,flapply,0),
   p(NewX,NewY),
   flora_post_p2h_convertion(NewX,X), % unify vars
   flora_post_p2h_convertion(NewY,Y)

   This works because:

   a. flora_plg2hilog(NewX,X,0) creates a new variable NewX and doesn't
      unify it with X
   b. p/2 is evaluated with respect to the new variables
   c. The resulting bindings for NewX, NewY are converted to hilog and
      unified with X,Y.
   d. If X or Y are already prolog then NewX, NewY are unified as Prolog
      predicates. This is because flora_post_p2h_convertion/2 is defined as

      flora_post_p2h_convertion(PrologTerm,HiLogTerm) :-
	(flora_plg2hlg(PrologTerm,HiLogTerm,WRAP_HILOG,P2H_UNIFY_VARS), !
	; PrologTerm = HiLogTerm
	).

      In our situation, flora_plg2hlg/4 fails ONLY if HiLogTerm (i.e., X or Y)
      were originally Prolog terms.

