Commit 86d866a1 authored by Thierry Martinez's avatar Thierry Martinez

Documentation

parent 8d0282bf
MODULES= \
biocham.pl \
about.pl \
commandline.pl \
toplevel.pl \
models.pl \
rules.pl \
objects.pl \
ode.pl \
initial_state.pl \
kinetics.pl \
numerical_simulation.pl \
util.pl \
simplify_arithmetic.pl \
formal_derivation.pl \
formal_derivation.plt \
gsl.pl \
gsl.plt \
counters.pl
MODULES=$(shell grep "^- " toc.org | cut -c 3-)
all: biocham biocham_debug tests
all: biocham biocham_debug tests doc
.PHONY: tests doc
biocham: $(MODULES) Makefile
echo $(MODULES)
swipl -o biocham --goal=start --toplevel=toplevel -c $(MODULES)
biocham_debug: $(MODULES) Makefile
......@@ -29,6 +14,9 @@ biocham_debug: $(MODULES) Makefile
tests: biocham_tests
./biocham_tests
doc: biocham
./biocham --generate-doc
biocham_tests: $(MODULES) Makefile
swipl -o biocham_tests \
--goal="call_cleanup((run_tests, halt(0)), halt(1))" -c $(MODULES)
......@@ -4,9 +4,7 @@
start/0,
initialize/0,
biocham_command/0,
biocham_command/1,
load/1,
load_biocham/1
biocham_command/1
]).
......@@ -18,7 +16,8 @@ start :-
initialize :-
prolog_history(enable),
set_counter(item_id, 0).
set_counter(item_id, 0),
new_model.
biocham_command.
......@@ -27,34 +26,3 @@ biocham_command.
biocham_command(Functor/Arity) :-
functor(Head, Functor, Arity),
once(clause(Head, (biocham_command, _))).
load(Filename) :-
biocham_command,
load_biocham(Filename).
load_biocham(Filename) :-
biocham_command,
setup_call_cleanup(
open(Filename, read, Stream),
load_biocham_stream(Stream),
close(Stream)
).
load_biocham_stream(Stream) :-
\+ (
repeat,
read_term(Stream, Command, [variable_names(VariableNames)]),
(
Command = end_of_file
->
!,
fail
;
name_vars_and_anonymous(Command, VariableNames),
execute_command(Command),
fail
)
).
......@@ -5,17 +5,21 @@
]
).
do_arguments :-
current_prolog_flag(argv, Argv),
do_arguments(Argv).
:- dynamic(file/1).
do_arguments(Argv) :-
retractall(file(_)),
parse_arguments(Argv),
load_files.
load_files :-
\+ (
file(File),
......@@ -24,6 +28,7 @@ load_files :-
)
).
parse_arguments([]).
parse_arguments([Arg | Argv]) :-
......@@ -47,10 +52,14 @@ parse_arguments([Arg | Argv]) :-
).
option('t', '--trace', Arg, Arg) :-
option('', '--trace', Arg, Arg) :-
leash(-all),
trace.
option('', '--generate-doc', Arg, Arg) :-
generate_doc,
quit.
add_files(Files) :-
\+ (
member(File, Files),
......@@ -59,5 +68,6 @@ add_files(Files) :-
)
).
add_file(File) :-
assertz(file(File)).
:- module(
doc,
[
doc/1,
generate_doc/0
]
).
doc(_).
generate_doc :-
catch(
make_directory('doc'),
error(existence_error(directory, _), _),
true
),
setup_call_cleanup(
open('doc/index.html', write, Stream),
generate_doc(Stream),
close(Stream)
).
generate_doc(Doc) :-
version(Version),
format(atom(Title), 'Biocham ~a Reference Manual', [Version]),
format(Doc, '\c
<!DOCTYPE html>
<html>
<head>
<title>~a</title>
</head>
<body>
<h1>~a</h1>
', [Title, Title]),
generate_toc(Doc),
generate_body(Doc),
write(Doc, '
</body>
</html>').
:- dynamic(toc/1).
generate_toc(Doc) :-
retractall(toc(_)),
read_toc,
write(Doc, ' <h2 id="Contents">Contents</h2>\n'),
nb_setval(current_counters, []),
\+ (
toc(section(Level, Title)),
\+ (
generate_toc_section(Doc, Level, Title)
)
),
goto_toc_level(Doc, 0).
generate_toc_section(Doc, Level, Title) :-
goto_toc_level(Doc, Level),
indent(Doc, Level),
increment_counter,
write(Doc, '<li>'),
write_counters(Doc),
make_id(Title, Id),
format(Doc, ' <a href="#~a">~a</a></li>\n', [Id, Title]).
goto_toc_level(Doc, Level) :-
nb_getval(current_counters, OldCounters),
length(OldCounters, OldLevel),
(
OldLevel > Level
->
LevelDiff is OldLevel - Level,
\+ (
between(1, LevelDiff, I),
\+ (
CurrentLevel is OldLevel - I,
indent(Doc, CurrentLevel),
write(Doc, '</ul>\n')
)
)
;
OldLevel = Level
->
true
;
OldLevel is Level - 1
->
indent(Doc, OldLevel),
write(Doc, '<ul>\n')
;
throw(error(bad_toc_structure))
),
goto_level(Level).
goto_level(Level) :-
nb_getval(current_counters, OldCounters),
length(OldCounters, OldLevel),
(
OldLevel > Level
->
LevelDiff is OldLevel - Level,
length(FormerCounters, LevelDiff),
append(NewCounters, FormerCounters, OldCounters),
nb_setval(current_counters, NewCounters)
;
OldLevel = Level
->
true
;
OldLevel is Level - 1
->
append(OldCounters, [0], NewCounters),
nb_setval(current_counters, NewCounters)
;
throw(error(bad_toc_structure))
).
indent(Doc, Level) :-
\+ (
between(0, Level, _),
\+ (
write(Doc, ' ')
)
).
increment_counter :-
nb_getval(current_counters, OldCounters),
append(HigherCounters, [LastCounter], OldCounters),
NewCounter is LastCounter + 1,
append(HigherCounters, [NewCounter], NewCounters),
nb_setval(current_counters, NewCounters).
write_counters(Doc) :-
nb_getval(current_counters, Counters),
\+ (
member(Counter, Counters),
\+ (
format(Doc, '~d.', [Counter])
)
).
make_id(Title, Id) :-
atom_chars(Title, Chars),
filter_id(Chars, CharsId),
atom_chars(Id, CharsId).
filter_id([], []).
filter_id([Char | Tail], [Char | TailId]) :-
(
'0' @=< Char, Char @=< '9'
;
'A' @=< Char, Char @=< 'Z'
;
'a' @=< Char, Char @=< 'z'
;
Char = '_'
;
Char = '-'
;
Char = '.'
),
!,
filter_id(Tail, TailId).
filter_id([' ' | Tail], ['_' | TailId]) :-
!,
filter_id(Tail, TailId).
filter_id(['/' | Tail], ['-' | TailId]) :-
!,
filter_id(Tail, TailId).
filter_id([_ | Tail], Id) :-
filter_id(Tail, Id).
read_toc :-
setup_call_cleanup(
open('toc.org', read, Stream),
read_toc(Stream),
close(Stream)
).
read_toc(Stream) :-
\+ (
repeat,
read_line_to_codes(Stream, Line),
(
Line = end_of_file
->
!
;
atom_codes(Atom, Line),
(
atom_concat('* ', Section, Atom)
->
assertz(toc(section(1, Section)))
;
atom_concat('** ', Section, Atom)
->
assertz(toc(section(2, Section)))
;
atom_concat('*** ', Section, Atom)
->
assertz(toc(section(3, Section)))
;
atom_concat('- ', File, Atom)
->
assertz(toc(file(File)))
)
),
fail
).
generate_body(Doc) :-
nb_setval(current_counters, []),
\+ (
toc(Item),
\+ (
generate_body_item(Item, Doc)
)
).
generate_body_item(section(Level, Title), Doc) :-
goto_level(Level),
increment_counter,
make_id(Title, Id),
(
Level = 1
->
nb_getval(current_counters, [Counter]),
format(Doc, '<h2 id="~a">Chapter ~d<br />~a</h2>', [Id, Counter, Title])
;
HLevel is Level + 1,
format(Doc, '<h~d id="~a">', [HLevel, Id]),
write_counters(Doc),
format(Doc, ' ~a</h~d>\n', [Title, HLevel])
).
generate_body_item(file(File), Doc) :-
setup_call_cleanup(
open(File, read, Stream),
generate_body_item_stream(Stream, Doc),
close(Stream)
).
generate_body_item_stream(Stream, Doc) :-
\+ (
repeat,
read_term(
Stream, Clause, [variables(Variables), variable_names(VariableNames)]
),
(
Clause = end_of_file
->
!
;
name_variables_and_anonymous(Variables, VariableNames),
generate_body_item_clause(Clause, Doc)
),
fail
).
:- dynamic(argument_type/2).
generate_body_item_clause(Clause, Doc) :-
(
Clause = (Head :- biocham_command, Body)
->
Head =.. [Command | Arguments],
retractall(argument_type(_, _)),
nb_setval(doc_body, undocumented),
collect_doc(Body),
make_id(Command, Id),
length(Arguments, Arity),
format(Doc, '<h5 id="~a-~d""><code>~a', [Id, Arity, Command]),
write_arguments(Arguments, Doc),
write(Doc, '.</code></h5>\n'),
nb_getval(doc_body, DocBody),
write_doc(Doc, DocBody)
;
true
).
collect_doc((type(Argument, Type), Body)) :-
!,
assertz(argument_type(Argument, Type)),
collect_doc(Body).
collect_doc((doc(DocBody), _)) :-
!,
nb_setval(doc_body, DocBody).
collect_doc(_) :-
!.
write_arguments([], _Doc) :-
!,
true.
write_arguments([First | Arguments], Doc) :-
write(Doc, '('),
write_argument(First, Doc),
\+ (
member(Argument, Arguments),
\+ (
write(Doc, ', '),
write_argument(Argument, Doc)
)
),
write(Doc, ')').
write_argument(Argument, Doc) :-
(
argument_type(Argument, Type)
->
camel_case(Type, CamelCaseType),
(
Argument = CamelCaseType
->
format(Doc, '~a', [Type])
;
atom_concat(CamelCaseType, Suffix, Argument)
->
format(Doc, '~a<sub><var>~a</var></sub>', [Type, Suffix])
;
format(Doc, '<var>~a</var>', [Argument])
)
;
format(Doc, '<var>~a</var>', [Argument])
).
write_doc(Doc, DocBody) :-
atom_chars(DocBody, DocChars),
write_doc_chars(DocChars, Doc),
write(Doc, '\n').
write_doc_chars([], _).
write_doc_chars(['\\' | Tail], Doc) :-
!,
(
append(CommandChars, ['{' | TailArgument], Tail)
->
(
append(ArgumentChars, ['}' | TailDoc], TailArgument)
->
atom_chars(Command, CommandChars),
atom_chars(Argument, ArgumentChars),
write_command(Command, Argument, Doc),
write_doc_chars(TailDoc, Doc)
;
throw(error(unterminated_command))
)
;
throw(error(missing_argument))
).
write_doc_chars(['-', '-' | Tail], Doc) :-
!,
write(Doc, '&ndash;'),
write_doc_chars(Tail, Doc).
write_doc_chars(['<' | Tail], Doc) :-
!,
write(Doc, '&lt;'),
write_doc_chars(Tail, Doc).
write_doc_chars([Char | Tail], Doc) :-
write(Doc, Char),
write_doc_chars(Tail, Doc).
write_command(texttt, Text, Doc) :-
!,
format(Doc, '<code>~a</code>', [Text]).
write_command(command, Command, Doc) :-
!,
make_id(Command, Id),
format(Doc, '<a href="#~a"><code>~a</code></a>', [Id, Command]).
write_command(argument, Argument, Doc) :-
!,
write(Doc, '<code>'),
write_argument(Argument, Doc),
write(Doc, '</code>').
write_command(emph, Argument, Doc) :-
!,
write(Doc, '<em>'),
atom_chars(Argument, ArgumentChars),
write_doc_chars(ArgumentChars, Doc),
write(Doc, '</em>').
write_command(Command, _Argument, _Doc) :-
throw(error(unknown_command(Command))).
:- module(
filename,
[
filename/2,
chop_suffix/2,
automatic_suffix/3
]
).
filename('.'(Prefix, Suffix), Filename) :-
!,
filename(Prefix, PrefixAtom),
filename(Suffix, SuffixAtom),
format(atom(Filename), '~a.~a', [PrefixAtom, SuffixAtom]).
filename(Filename, Filename).
chop_suffix(Filename, Suffix) :-
atom_chars(Filename, Chars),
(
append(_, ['.' | SuffixChars], Chars),
\+ member('.', SuffixChars),
path_delimiter(PathDelimiter),
\+ member(PathDelimiter, SuffixChars)
->
atom_chars(Suffix, ['.' | SuffixChars])
;
Suffix = Filename
).
automatic_suffix(Filename, DefaultSuffix, FullFilename) :-
chop_suffix(Filename, Suffix),
(
Suffix = '',
atom_concat(Filename, DefaultSuffix, FullFilename),
file_exists(FullFilename)
->
true
;
FullFilename = Filename
).
:- module(
models,
[
load/1,
load_biocham/1,
new_model/0,
add_item/3,
list_items/1,
remove_item/1,
......@@ -8,16 +11,201 @@
]
).
:- dynamic(fresh/0).
load(InputFile) :-
biocham_command,
type(InputFile, input_file),
doc('
acts as the corresponding \\command{load_biocham/1} / \\command{load_sbml/1}
/ \\command{load_ode/1} / \\command{load_trace/1},
depending on the file extension
(respectively \\texttt{.bc}, \\texttt{.xml}, \\texttt{.ode}, \\texttt{.csv}
-- assuming no extension is \\texttt{.bc}).'),
new_model,
add(InputFile).
add(InputFile) :-
biocham_command,
type(InputFile, input_file),
doc('
acts as the corresponding \\command{add_biocham/1} / \\command{add_sbml/1}
/ \\command{add_ode/1} / \\command{add_trace/1},
depending on the file extension
(respectively \\texttt{.bc}, \\texttt{.xml}, \\texttt{.ode}, \\texttt{.csv}
-- assuming no extension is \\texttt{.bc}).'),
filename(InputFile, Filename),
chop_suffix(Filename, Suffix),
(
(
Suffix = '.bc'
;
Suffix = ''
)
->
add_biocham(Filename)
;
Suffix = '.xml'
->
add_sbml(Filename)
;
Suffix = '.ode'
->
add_ode(Filename)
;
Suffix = '.csv'
->
add_trace(Filename)
;
throw(error(unknown_suffix(Suffix)))
).
load_biocham(InputFile) :-
biocham_command,
type(InputFile, input_file),
doc('
opens a new model, loads the reaction rules and executes the commands
(with the file directory as current directory)
contained in the given Biocham \\texttt{.bc} file.
The suffix \\texttt{.bc} is automatically added to the name if such a
file exists.'),
new_model,
set_model_name(InputFile),
add_biocham(InputFile).
add_biocham(InputFile) :-
biocham_command,
type(InputFile, input_file),
doc('
the rules of the given \\texttt{.bc} file are loaded and
\\emph{added} to the current set of rules.
The commands contained in the file are executed
(with the file directory as current directory).'),
filename(InputFile, Filename),
automatic_suffix(Filename, '.bc', FilenameBc),
setup_call_cleanup(
open(FilenameBc, read, Stream),
load_biocham_stream(Stream),
close(Stream)
).
load_biocham_stream(Stream) :-
\+ (
repeat,
read_term(Stream, Command, [variable_names(VariableNames)]),
(
Command = end_of_file
->
!,
fail
;
name_vars_and_anonymous(Command, VariableNames),
execute_command(Command),
fail
)
).
set_current_models(Models) :-
nb_setval(current_models, Models).
new_model :-
biocham_command,
doc('opens a new fresh model.'),
(
fresh
->
create_item_id(NewModel),
set_current_models([NewModel])
;
assertz(fresh)
).
clear_model :-
biocham_command,
doc('clears the current model.'),
single_model(Model),
retractall(item(_, Model, _, _)).