<commit_before>
:- object(modules_diagram_support).

	:- info([
		version is 0.9,
		author is '<NAME>',
		date is 2014/07/25,
		comment is 'Utility predicates for supporting Prolog modules in diagrams.'
	]).

	:- public(module_property/2).
	:- mode(module_property(?atom, ?callable), zero_or_more).
	:- info(module_property/2, [
		comment is 'Access to module properties, at least exports/1, file/1, and file/2 but also defines/2, calls/2, and provides/3 when possible.',
		argnames is ['Module', 'Property']
	]).

	:- public(loaded_file_property/2).
	:- mode(loaded_file_property(?atom, ?callable), zero_or_more).
	:- info(loaded_file_property/2, [
		comment is 'Access to loaded source file properties, at least basename/1, directory/1 but also parent/1 when possible.',
		argnames is ['File', 'Property']
	]).

	:- public(source_file_extension/1).
	:- mode(source_file_extension(?atom), one_or_more).
	:- info(source_file_extension/1, [
		comment is 'Valid source file extension for Prolog source files.',
		argnames is ['Extension']
	]).

	:- if(current_logtalk_flag(prolog_dialect, yap)).

		{:- use_module(library(prolog_xref))}.

		module_property(Module, Property) :-
			property_module(Property, Module).

		property_module(exports(Exports), Module) :-
			{module_property(Module, exports(Exports))}.
		property_module(defines(Functor/Arity, []), Module) :-
			{module_property(Module, file(File)),
			 xref_source(File),
			 (	setof(Location, xref_defined(File, Predicate, local(Location)), _)
			 ;	setof(Location, xref_defined(File, Predicate, dynamic(Location)), _)
			 ;	setof(Location, xref_defined(File, Predicate, multifile(Location)), _)
			 ;	setof(Location, xref_defined(File, Predicate, thread_local(Location)), _)
			 ),
			 Predicate \= ':'(_,_),
			 functor(Predicate, Functor, Arity)
			}.
		property_module(provides(Functor/Arity, To, []), Module) :-
			{module_property(Module, file(File)),
			 xref_source(File),
			 setof(Location, xref_defined(File, To:Predicate, local(Location)), _),
			 To \== Module,
			 functor(Predicate, Functor, Arity)
			}.
		property_module(file(File), Module) :-
			{module_property(Module, file(File))}.
		property_module(file(Basename, Directory), Module) :-
			{module_property(Module, file(File)),
			 file_directory_name(File, Directory0),
			 atom_concat(Directory0, '/', Directory),
			 file_base_name(File, Basename)			
			}.
		property_module(calls(Callee, [caller(Caller)]), Module) :-
			{module_property(Module, file(File)),
			 xref_source(File),
			 xref_called(File, Callee0, Caller0),
			 (	Caller0 = ':'(ForModule,Caller1) ->
			 	functor(Caller1, CallerFunctor, CallerArity),
				Caller = ':'(ForModule,CallerFunctor/CallerArity)
			 ;	functor(Caller0, CallerFunctor, CallerArity),
			 	Caller = CallerFunctor/CallerArity
			 ),
			 functor(Caller, CallerFunctor, CallerArity),
			 (	Callee0 = Object::Callee1 ->
			 	functor(Callee1, CalleeFunctor, CalleeArity),
				Callee = Object::CalleeFunctor/CalleeArity
			 ;	Callee0 = ':'(OtherModule,Callee1) ->
			 	functor(Callee1, CalleeFunctor, CalleeArity),
				Callee = ':'(OtherModule,CalleeFunctor/CalleeArity)
			 ;	xref_defined(File, Callee0, imported(FromFile)) ->
			 	once(module_property(FromModule, file(FromFile))),
			 	functor(Callee0, CalleeFunctor, CalleeArity),
			 	Callee = ':'(FromModule,CalleeFunctor/CalleeArity)
			 ;	% assume local predicate
			 	functor(Callee0, CalleeFunctor, CalleeArity),
			 	Callee = CalleeFunctor/CalleeArity
			 )
			}.

		loaded_file_property(File, Property) :-
			property_source_file(Property, File),
			\+ sub_atom(File, _, 4, 0, '.lgt'),
			\+ sub_atom(File, _, 8, 0, '.logtalk').

		property_source_file(parent(Parent), File) :-
			{source_file_property(File, load_context(Parent0, _, _))},
			(	logtalk::loaded_file_property(Parent, target(Parent0)) ->
				true
			;	Parent = Parent0
			).
		property_source_file(directory(Directory), File) :-
			{source_file(File),
			 file_directory_name(File, Directory0),
			 atom_concat(Directory0, '/', Directory)}.
		property_source_file(basename(Basename), File) :-
			{source_file(File),
			 file_base_name(File, Basename)}.

		source_file_extension('.pl').
		source_file_extension('.prolog').
		source_file_extension('.yap').

	:- elif(current_logtalk_flag(prolog_dialect, swi)).

		{:- use_module(library(prolog_xref))}.

		module_property(Module, Property) :-
			property_module(Property, Module).

		property_module(exports(Exports), Module) :-
			{module_property(Module, exports(Exports))}.
		property_module(defines(Functor/Arity, []), Module) :-
			{module_property(Module, file(File)),
			 xref_source(File),
			 (	setof(Location, xref_defined(File, Predicate, local(Location)), _)
			 ;	setof(Location, xref_defined(File, Predicate, dynamic(Location)), _)
			 ;	setof(Location, xref_defined(File, Predicate, multifile(Location)), _)
			 ;	setof(Location, xref_defined(File, Predicate, thread_local(Location)), _)
			 ),
			 Predicate \= ':'(_,_),
			 functor(Predicate, Functor, Arity)
			}.
		property_module(provides(Functor/Arity, To, []), Module) :-
			{module_property(Module, file(File)),
			 xref_source(File),
			 setof(Location, xref_defined(File, To:Predicate, local(Location)), _),
			 To \== Module,
			 functor(Predicate, Functor, Arity)
			}.
		property_module(file(File), Module) :-
			{module_property(Module, file(File))}.
		property_module(file(Basename, Directory), Module) :-<commit_msg>Ensure non-duplicated solutions for module `defines/2` property<commit_after>
:- object(modules_diagram_support).

	:- info([
		version is 0.9,
		author is '<NAME>',
		date is 2014/07/25,
		comment is 'Utility predicates for supporting Prolog modules in diagrams.'
	]).

	:- public(module_property/2).
	:- mode(module_property(?atom, ?callable), zero_or_more).
	:- info(module_property/2, [
		comment is 'Access to module properties, at least exports/1, file/1, and file/2 but also defines/2, calls/2, and provides/3 when possible.',
		argnames is ['Module', 'Property']
	]).

	:- public(loaded_file_property/2).
	:- mode(loaded_file_property(?atom, ?callable), zero_or_more).
	:- info(loaded_file_property/2, [
		comment is 'Access to loaded source file properties, at least basename/1, directory/1 but also parent/1 when possible.',
		argnames is ['File', 'Property']
	]).

	:- public(source_file_extension/1).
	:- mode(source_file_extension(?atom), one_or_more).
	:- info(source_file_extension/1, [
		comment is 'Valid source file extension for Prolog source files.',
		argnames is ['Extension']
	]).

	:- if(current_logtalk_flag(prolog_dialect, yap)).

		{:- use_module(library(prolog_xref))}.

		module_property(Module, Property) :-
			property_module(Property, Module).

		property_module(exports(Exports), Module) :-
			{module_property(Module, exports(Exports))}.
		property_module(defines(Functor/Arity, []), Module) :-
			{module_property(Module, file(File)),
			 xref_source(File),
			 setof(How, xref_defined(File, Predicate, How), _),
			 Predicate \= ':'(_,_),
			 \+ xref_defined(File, Predicate, imported(_)),
			 functor(Predicate, Functor, Arity)
			}.
		property_module(provides(Functor/Arity, To, []), Module) :-
			{module_property(Module, file(File)),
			 xref_source(File),
			 setof(Location, xref_defined(File, To:Predicate, local(Location)), _),
			 To \== Module,
			 functor(Predicate, Functor, Arity)
			}.
		property_module(file(File), Module) :-
			{module_property(Module, file(File))}.
		property_module(file(Basename, Directory), Module) :-
			{module_property(Module, file(File)),
			 file_directory_name(File, Directory0),
			 atom_concat(Directory0, '/', Directory),
			 file_base_name(File, Basename)			
			}.
		property_module(calls(Callee, [caller(Caller)]), Module) :-
			{module_property(Module, file(File)),
			 xref_source(File),
			 xref_called(File, Callee0, Caller0),
			 (	Caller0 = ':'(ForModule,Caller1) ->
			 	functor(Caller1, CallerFunctor, CallerArity),
				Caller = ':'(ForModule,CallerFunctor/CallerArity)
			 ;	functor(Caller0, CallerFunctor, CallerArity),
			 	Caller = CallerFunctor/CallerArity
			 ),
			 functor(Caller, CallerFunctor, CallerArity),
			 (	Callee0 = Object::Callee1 ->
			 	functor(Callee1, CalleeFunctor, CalleeArity),
				Callee = Object::CalleeFunctor/CalleeArity
			 ;	Callee0 = ':'(OtherModule,Callee1) ->
			 	functor(Callee1, CalleeFunctor, CalleeArity),
				Callee = ':'(OtherModule,CalleeFunctor/CalleeArity)
			 ;	xref_defined(File, Callee0, imported(FromFile)) ->
			 	once(module_property(FromModule, file(FromFile))),
			 	functor(Callee0, CalleeFunctor, CalleeArity),
			 	Callee = ':'(FromModule,CalleeFunctor/CalleeArity)
			 ;	% assume local predicate
			 	functor(Callee0, CalleeFunctor, CalleeArity),
			 	Callee = CalleeFunctor/CalleeArity
			 )
			}.

		loaded_file_property(File, Property) :-
			property_source_file(Property, File),
			\+ sub_atom(File, _, 4, 0, '.lgt'),
			\+ sub_atom(File, _, 8, 0, '.logtalk').

		property_source_file(parent(Parent), File) :-
			{source_file_property(File, load_context(Parent0, _, _))},
			(	logtalk::loaded_file_property(Parent, target(Parent0)) ->
				true
			;	Parent = Parent0
			).
		property_source_file(directory(Directory), File) :-
			{source_file(File),
			 file_directory_name(File, Directory0),
			 atom_concat(Directory0, '/', Directory)}.
		property_source_file(basename(Basename), File) :-
			{source_file(File),
			 file_base_name(File, Basename)}.

		source_file_extension('.pl').
		source_file_extension('.prolog').
		source_file_extension('.yap').

	:- elif(current_logtalk_flag(prolog_dialect, swi)).

		{:- use_module(library(prolog_xref))}.

		module_property(Module, Property) :-
			property_module(Property, Module).

		property_module(exports(Exports), Module) :-
			{module_property(Module, exports(Exports))}.
		property_module(defines(Functor/Arity, []), Module) :-
			{module_property(Module, file(File)),
			 xref_source(File),
			 setof(How, xref_defined(File, Predicate, How), _),
			 Predicate \= ':'(_,_),
			 \+ xref_defined(File, Predicate, imported(_)),
			 functor(Predicate, Functor, Arity)
			}.
		property_module(provides(Functor/Arity, To, []), Module) :-
			{module_property(Module, file(File)),
			 xref_source(File),
			 setof(Location, xref_defined(File, To:Predicate, local(Location)), _),
			 To \== Module,
			 functor(Predicate, Functor, Arity)
			}.
		property_module(file(File), Module) :-
			{module_property(Module, file(File))}.
		property_module(file(Basename, Directory), Module) :-
{'fraction_non_alphanumeric': 0.1511981742107265, 'fraction_numerical': 0.009794598706732598, 'mean_word_length': 4.73758865248227, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4728618', 'n_tokens_mistral': 4166, 'n_tokens_neox': 3514, 'n_words': 608}