From: Roberto Di Cosmo <roberto@dicosmo.org>
To: Jonathan Protzenko <jonathan.protzenko@gmail.com>
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] Literate (sort-of) programming in OCaml
Date: Mon, 2 Sep 2013 18:03:52 +0200 [thread overview]
Message-ID: <20130902160352.GA27759@voyager> (raw)
In-Reply-To: <5224B137.8070706@gmail.com>
Hi Jonathan,
for writing course notes, many of us used in the old times
a script (written in ... cough, cough .. Perl) that sort of
answered your needs.
I honestly do not remember who from the old Formel team wrote
it for CamlLight in the first place, and who adapted it to OCaml,
but you can see the old code in a message from Xavier in 1996 :-)
http://caml.inria.fr/pub/old_caml_site/caml-list-ar/0651.html
Here is the version I still use to produce course notes with a recent
OCaml and lstlistings environments (that knows how to highlight OCaml syntax).
One writes a source LaTeX file with environments like
\begin{caml_example}
let x = "this code will be executed, and printed out with toplevel output"
\end{caml_example}
\begin{caml_example*}
let x = "this code will be executed, and printed out without toplevel output"
\end{caml_example*}
\begin{caml_eval}
let x = "this code will be executed, but not printed out"
\end{caml_eval}
and passes it through ocaml-tex to get the LaTeX file with the results
properly inlined.
Ah, by the way, beware, this old code doew not do a very good job at identifying
phrases, so you need to use ;; all too often in the code.
Having a better (OCaml?) version with proper handling of all this would
certainly be nice.
--
Roberto
#!/usr/bin/perl
# ocaml-tex
$camllight = "TERM=dumb ocaml";
$camlbegin = "\\begin{lstlisting}[escapechar=§]\n";
$camlend = "\\end{lstlisting}\n";
$camlin = "";
$camloutstart = "§\\camloutbol §";
$camloutstop = "§\\camlouteol §";
$camlblank = "\n";
$linelen = 72;
$output = "";
$cut_at_blanks = 0;
while ($#ARGV >= 0) {
$_ = $ARGV[0];
last unless (/^-/);
$linelen = $ARGV[1], shift, shift, next if (/^-n$/);
$output = $ARGV[1], shift, shift, next if (/^-o$/);
$camllight = $ARGV[1], shift, shift, next if (/^-caml$/);
$cut_at_blanks = 1, shift, next if (/^-w$/);
printf STDERR ("Unknown option '%s', ignored\n", $_);
shift;
}
# First pass: extract the Caml phrases to evaluate
open(ML, "> .input.ml") || die("Cannot create .input.ml : $!");
foreach $infile (@ARGV) {
open(IN, $infile) || die("Cannot open $infile : $!");
while(<IN>) {
if (m/^\\begin{caml_(example|example\*|eval)}\s*$/) {
while(<IN>) {
last if m/^\\end{caml_(example|example\*|eval)}\s*$/;
print ML $_;
}
}
}
close(IN);
}
close(ML);
# Feed the phrases to a Caml toplevel
open(TOPLEVEL, "$camllight 2>&1 < .input.ml |") ||
die("Cannot start camllight : $!");
<TOPLEVEL>; <TOPLEVEL>; # skip the banner
$lastread = <TOPLEVEL>;
$lastread =~ s/^# //;
# Second pass: shuffle the TeX source and the output of the toplevel
if ($output) {
if ($output eq "-") {
open(OUT, ">&STDOUT");
} else {
open(OUT, ">$output") || die("Cannot create $output: $!");
}
}
foreach $infile (@ARGV) {
open(IN, $infile) || die("Cannot open $infile: $!");
if (! $output) {
$outfile = $infile;
$outfile =~ s/\.tex$//;
open(OUT, "> $outfile.ml.tex") || die("Cannot create $outfile.ml.tex: $!");
}
while(<IN>) {
if (m/^\\begin{caml_example(\*?)}\s*$/) {
$omit_answer = $1; # true if caml_example*, false if caml_example
print OUT $camlbegin;
$severalphrases = 0;
while(<IN>) {
last if m/\\end{caml_example\*?}\s*$/;
print OUT $camlblank if ($severalphrases);
while(1) {
s/\\/\\\\/g;
print OUT $camlin, $_;
last if m/;; *$/;
$_ = <IN>;
}
while ($lastread =~ s/^ //) { }
while($lastread) {
last if $lastread =~ s/^# //;
print STDERR $lastread;
if (! $omit_answer) {
while (length($lastread) > $linelen) {
if ($cut_at_blanks) {
$cutpos = rindex($lastread, ' ', $linelen);
if ($cutpos == -1) { $cutpos = $linelen; } else { $cutpos++; }
} else {
$cutpos = $linelen;
}
$line = substr($lastread, 0, $cutpos);
$line =~ s/\\/\\\\/g;
print OUT $camloutstart, $line, $camloutstop, "\n";
$lastread = substr($lastread, $cutpos,
length($lastread) - $cutpos);
}
$lastread =~ s/\\/\\\\/g;
print OUT $camloutstart, $lastread, $camloutstop;
}
$lastread = <TOPLEVEL>;
}
$severalphrases = 1;
}
print OUT $camlend;
}
elsif (m/^\\begin{caml_eval}\s*$/) {
while(<IN>) {
last if m/^\\end{caml_eval}\s*$/;
if (m/;; *$/) {
while ($lastread =~ s/^#//) { }
while($lastread) {
last if $lastread =~ s/^#//;
print $lastread;
$lastread = <TOPLEVEL>;
}
}
}
}
else {
print OUT $_;
}
}
close(IN);
}
close(TOPLEVEL);
On Mon, Sep 02, 2013 at 05:39:35PM +0200, Jonathan Protzenko wrote:
> Hi,
>
> I am currently writing a big, mostly textual document in format blah
> (blah being of a course a meta-variable). Are there any tools that
> would allow me to interleave OCaml code with the contents of my
> document?
>
> More on my use-case. Creating this document requires me to perform
> various subtasks, such as:
> - write a code snippet in the document,
> - put the code snippet in a file,
> - call an external program on the file,
> - paste the output into the document.
>
> Naturally, I wish to automate this. I could roll my own set of
> commands, and parse them with OCaml, but I would be re-creating a
> scripting language, and it seems to me that interleaving OCaml code
> within my document would be better. Here's what I have in mind:
>
>
> blah blah blah blah blah blah blah blah blah blah blah blah blah blah
> blah blah
> blah blah blah blah blah blah blah blah blah blah blah blah blah blah
> blah blah
> blah ... we thus write the following code ... :
>
> {%
> let code = "<sample code>" in
> output code
> %}
>
> blah blah blah ... after running the command blah ... the output is as
> follows ... blah
>
> {%
> let f = write_into_temp_file code in
> let s = run_and_read "myprogram" [f] in
> output s
> %}
>
> blah blah blah blah blah blah blah blah blah blah blah blah blah blah
> blah blah ...
>
>
> Are you aware of any tool that would allow me to achieve this?
>
> Thanks,
>
> ~ jonathan
>
> --
> Caml-list mailing list. Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
--
Roberto Di Cosmo
------------------------------------------------------------------
Professeur En delegation a l'INRIA
PPS E-mail: roberto@dicosmo.org
Universite Paris Diderot WWW : http://www.dicosmo.org
Case 7014 Tel : ++33-(0)1-57 27 92 20
5, Rue Thomas Mann
F-75205 Paris Cedex 13 Identica: http://identi.ca/rdicosmo
FRANCE. Twitter: http://twitter.com/rdicosmo
------------------------------------------------------------------
Attachments:
MIME accepted, Word deprecated
http://www.gnu.org/philosophy/no-word-attachments.html
------------------------------------------------------------------
Office location:
Bureau 3020 (3rd floor)
Batiment Sophie Germain
Avenue de France
Metro Bibliotheque Francois Mitterrand, ligne 14/RER C
-----------------------------------------------------------------
GPG fingerprint 2931 20CE 3A5A 5390 98EC 8BFC FCCA C3BE 39CB 12D3
next prev parent reply other threads:[~2013-09-02 16:03 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-02 15:39 Jonathan Protzenko
2013-09-02 15:55 ` Alain Frisch
2013-09-02 15:59 ` Török Edwin
2013-09-02 17:26 ` Maxence Guesdon
2013-09-02 16:03 ` Roberto Di Cosmo [this message]
2013-09-02 16:29 ` Ashish Agarwal
2013-09-02 20:16 ` Jonathan Protzenko
2013-09-03 8:34 ` Alain Frisch
2013-09-03 14:34 ` Philippe Wang
2013-09-02 16:39 ` Raphaël Proust
2013-09-02 16:50 ` Simon Cruanes
2013-09-03 0:15 ` oliver
2013-09-03 9:17 ` Alan Schmitt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130902160352.GA27759@voyager \
--to=roberto@dicosmo.org \
--cc=caml-list@inria.fr \
--cc=jonathan.protzenko@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox