diff --git a/anubis_dev/library/doc_tools/basis.maml b/anubis_dev/library/doc_tools/basis.maml new file mode 100644 index 0000000..8dc529e --- /dev/null +++ b/anubis_dev/library/doc_tools/basis.maml @@ -0,0 +1,94 @@ + + + basis.maml + + A set of common usage macros for MAML. + +$begin +$////////////////////////////////////////////////////// +$// Some colors +$define(_ivory) (0)(230,230,210) $define(ivory) (1)($rgb($_ivory)($1)) +$define(_azure) (0)(190,210,210) $define(azure) (1)($rgb($_azure)($1)) +$define(_lavender) (0)(200,200,220) $define(lavender) (1)($rgb($_lavender)($1)) +$define(_white) (0)(255,255,255) $define(white) (1)($rgb($_white)($1)) +$define(_black) (0)(000,000,000) $define(black) (1)($rgb($_black)($1)) +$define(_grey) (0)(190,190,190) $define(grey) (1)($rgb($_grey)($1)) +$define(_navy) (0)(000,000,128) $define(navy) (1)($rgb($_navy)($1)) +$define(_blue) (0)(000,000,255) $define(blue) (1)($rgb($_blue)($1)) +$define(_turquoise) (0)(064,224,208) $define(turquoise) (1)($rgb($_turquoise)($1)) +$define(_cyan) (0)(000,255,255) $define(cyan) (1)($rgb($_cyan)($1)) +$define(_darkgreen) (0)(000,100,000) $define(darkgreen) (1)($rgb($_darkgreen)($1)) +$define(_green) (0)(000,255,000) $define(green) (1)($rgb($_green)($1)) +$define(_yellow) (0)(255,255,000) $define(yellow) (1)($rgb($_yellow)($1)) +$define(_gold) (0)(255,195,000) $define(gold) (1)($rgb($_gold)($1)) +$define(_sienna) (0)(160,082,045) $define(sienna) (1)($rgb($_sienna)($1)) +$define(_caramel) (0)(210,105,030) $define(caramel) (1)($rgb($_caramel)($1)) +$define(_chocolate) (0)(105,055,020) $define(chocolate) (1)($rgb($_chocolate)($1)) +$define(_salmon) (0)(233,150,122) $define(salmon) (1)($rgb($_salmon)($1)) +$define(_orange) (0)(255,165,000) $define(orange) (1)($rgb($_orange)($1)) +$define(_red) (0)(255,000,000) $define(red) (1)($rgb($_red)($1)) +$define(_darkred) (0)(110,000,000) $define(darkred) (1)($rgb($_darkred)($1)) +$define(_pink) (0)(255,182,193) $define(pink) (1)($rgb($_pink)($1)) +$define(_magenta) (0)(255,000,255) $define(magenta) (1)($rgb($_magenta)($1)) +$define(_purple) (0)(160,032,240) $define(purple) (1)($rgb($_purple)($1)) + + + + +$////////////////////////////////////////////////////// +$// The style 'article'. +$// This style requires that $article is defined. +$if($defined(article)) +( +$pushcounter(sec)(0)$pushcounter(subsec)(0)$pushcounter(subsubsec)(0)$// counters for sections etc... +$accumulator(tableofcontents)$// accumulator for the table of contents +$// Layout for section titles. +$if($defined(seclayout))()($define(seclayout)(1)($par$big($big($bold($1)))$par$par)) +$if($defined(subseclayout))()($define(subseclayout)(1)($par$big($bold($1))$par)) +$if($defined(subsubseclayout))()($define(subsubseclayout)(1)($par$bold($1)$par)) +$// Layout for table of contents lines. +$if($defined(tocsec))()($define(tocsec)(1)($bold($1)$par)) +$if($defined(tocsubsec))()($define(tocsubsec)(1)($box(20)()$1$par)) +$if($defined(tocsubsubsec))()($define(tocsubsubsec)(1)($box(40)()$1$par)) +$define(tableofcontents)(0)($postpone($content(tableofcontents))) +$define(section)(2) + ($setcounter(subsec)(0)$addtocounter(sec)(1)$label($1)$seclayout($countervalue(sec). $2)$// +$append(tableofcontents)($ref($1)($tocsec($countervalue(sec). $2)))) +$define(subsection)(2) + ($setcounter(subsubsec)(0)$addtocounter(subsec)(1)$label($1)$subseclayout($countervalue(sec).$countervalue(subsec). $2)$// +$append(tableofcontents)($ref($1)($tocsubsec($countervalue(sec).$countervalue(subsec). $2)))) +$define(subsubsection)(2) + ($addtocounter(subsubsec)(1)$label($1)$subsubseclayout($countervalue(sec).$countervalue(subsec).$countervalue(subsubsec). $2)$// +$append(tableofcontents)($ref($1)($tocsubsubsec($countervalue(sec).$countervalue(subsec).$countervalue(subsubsec). $2)))) +)() + + +$////////////////////////////////////////////////////// +$// The style 'book'. +$// This style requires that $book is defined. +$if($defined(book)) +( +$pushcounter(chap)(0)$pushcounter(sec)(0)$pushcounter(subsec)(0)$pushcounter(subsubsec)(0)$// counters for sections etc... +$accumulator(tableofcontents)$// accumulator for the table of contents +$define(tableofcontents)(0)($postpone($content(tableofcontents))) +$define(chapter)(2) + ($setcounter(sec)(0)$addtocounter(chap)(1)$label($1)$chaplayout($countervalue(chap). $2)$// +$append(tableofcontents)($ref($1)($tocchap($countervalue(chap). $2)))) +$define(section)(2) + ($setcounter(subsec)(0)$addtocounter(sec)(1)$label($1)$seclayout($countervalue(sec). $2)$// +$append(tableofcontents)($ref($1)($tocsec($countervalue(sec). $2)))) +$define(subsection)(2) + ($setcounter(subsubsec)(0)$addtocounter(subsec)(1)$label($1)$subseclayout($countervalue(sec).$countervalue(subsec). $2)$// +$append(tableofcontents)($ref($1)($tocsubsec($countervalue(sec).$countervalue(subsec). $2)))) +$define(subsubsection)(2) + ($addtocounter(subsubsec)(1)$label($1)$subsubseclayout($countervalue(sec).$countervalue(subsec).$countervalue(subsubsec). $2)$// +$append(tableofcontents)($ref($1)($tocsubsubsec($countervalue(sec).$countervalue(subsec).$countervalue(subsubsec). $2)))) +)() + + +$////////////////////////////////////////////////////// + + + +$end + \ No newline at end of file diff --git a/anubis_dev/library/doc_tools/maml4.anubis b/anubis_dev/library/doc_tools/maml4.anubis new file mode 100644 index 0000000..27bfe86 --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4.anubis @@ -0,0 +1,300 @@ + + + MAML4 + + The Minimalist Anubis Markup Language (version 4). + + Author: Alain Prouté Jan. 2017 + + The file 'maml4_interface.anubis' contains the user's documentation in MAML format. + This file 'maml4.anubis' contains the technical documentation in MAML format. + + $begin + $input(../anubis_doc.maml) + $define(title)(1)($big($bold($rgb(120,40,0)($1)))$p) + + $center($big($big($big($bold(MAML (version 4) technical documentation))))) + $p + + This document explains the structure of the (somehow complex) source of the program MAML version 4. + Another document (in MAML format in $fname(maml4_interface.anubis)) explains how to use MAML in your programs. + There is also a tutorial and reference (in MAML format in $fname(maml4_tutorial.maml)) for writing MAML texts. + $p + + $title(Files) + This program MAML version 4 is made of the following files: + $define(file)(2)($item$box(160)($fname($1))$par$2) + $list( + $file(maml4_interface.anubis) (contains the public declarations and the programer documentation + (this is an Anubis and MAML file)) + $file(maml4_types.anubis) (types and declarations which are not part of the interface) + $file(maml4_private.anubis) (various private tools) + $file(maml4_lexers.anubis) (contains the lexers (constructed by fast_lexer_5)) + $file(maml4_png.anubis) (making PNG images to be inserted into the HTML output when the mark + $tt($$latex) is used) + $file(maml4_colorize.anubis) (execution of colorizations) + $file(maml4_eval.anubis) (evaluator (expansions of macros and execution of category 1 marks)) + $file(maml4_parser.anubis) (contains the 'hand written' parser (APG not suitable for MAML syntax which is + not LALR1, but nevertheless quite simple)) + $file(maml4_html.anubis) (produce HTML output) + $file(maml4_pdf.anubis) (produce LaTeX/PDF output) + $file(maml4.anubis) (the 'main' file' (this file) to be compiled for creating 'maml.adm') + ) + $undefine(file) + Each file 'transmits' its public content to the next one (in the order above). + $p + + Furthermore, when the program is compiled, it generates the following files: + $define(file)(2)($item$box(160)($fname(generated/$1))$par$2) + $list( + $file(prim1.anubis)(types and functions related to primitive marks (part 1)) + $file(prim2.anubis)(types and functions related to primitive marks (part 2)) + $file(skip_lexer.anubis)(lexer for skipping until $tt($$begin)) + $file(out_lexer.anubis)(lexer for parsing between $tt($$begin) and $tt($$end)) + $file(blank_lexer.anubis)(lexer for skipping blanks before operands of marks) + $file(in_lexer.anubis)(lexer for parsing within operands of marks) + $file(verb_lexer.anubis)(lexer for parsing $em(verbatim) operands) + $file(color_value_lexer.anubis)(lexer for checking colors) + $file(symbol_lexer.anubis)(lexer for checking symbols) + $file(html_lexer.anubis)(lexer for handling special HTML characters) + ) + $undefine(file) + + $title(Marks by category) + Marks are dispatched into three $em(categories): + $list( + $item $bold(Category 1): marks not producing an output by themselves. + $item $bold(Category 2): the mark $tt($$colorize), and the $em(internal) marks $tt($$call) and $tt($$return), + $item $bold(Category 3): marks actually translated into HTML and LaTeX. + ) + For example, $tt($$addtocounter) is in category 1, whereas $tt($$rgb) is in category 3. The official lists of marks + of categories 1 and 3 are given by $att(primitives1) and $att(primitives3) in $fname(maml4_types.anubis). These lists + record some informations about the marks, which allow to produce automatically some types and functions. Two files + are generated that way: + $list( + $item $fname(generated/prim1.anubis) + $item $fname(generated/prim2.anubis) + ) + + + $title(Compiler operation) + The MAML compiler proceeds as follows: + $list( + $item (1) The MAML source text is parsed. This produces syntax trees of type $att(MAML1). + $item (2) $att(MAML1) entities are $em(evaluated). This consists in expanding macros and executing all category 1 marks. + This produces data of type $att(MAML2). + $item (3) $att(MAML2) data are processed for colorization. This produces data of type $att(MAML3). + $item (4) $att(MAML3) data are translated into HTML and/or LaTeX. + ) + Of course, $att(MAML1) has one alternative for each sort of syntactic MAML concept. This also includes errors, which + are stored into the $att(MAML1) datum, so that several errors can be transmitted to the user. $att(MAML2) is similar + but the alternatives for category 1 marks and for macros have desappeared. Finally, $att(MAML3) data are even simpler + because the alternative for the category 2 mark and MAML variables also desappear.$p + + We also make use of two variants of $att(MAML2) named $att(MAML2a) and $att(MAML2b).$p + + + $title(Lexers) + The MAML parser uses several lexers (constructed by $fname(fast_lexer_5)): + $list( + $item the $em(skip) lexer is used outside pairs ($tt($$begin),$tt($$end)), + $item the $em(out) lexer is used $em(at top level) between $tt($$begin) and $tt($$end). + $item the $em(blank) lexer is used for skipping blanks until the next expected operand of a mark. + $item the $em(in) lexer is used for parsing MAML texts within operands of marks. + $item the $em(verb) lexer is used for parsing the operands which must be read in $em(verbatim) mode. + ) + By ``$em(at top level)'', we mean: $em(not within an argument of a mark).$p + + Actually, evaluation takes place during parsing after each top level mark is parsed together with its operands.$p + + Other lexers are constructed for parsing colors (of the form $tt(r,g,b)) or checking that the result of parsing and + evaluating an operand yields a string of a particular form (for example a $em(symbol) for naming colorizers, etc...). + Finally, two lexers are also constructed during the execution of the MAML compiler for each colorizer.$p + + All lexers, including colorizer lexers, are saved in $fname(generated) so that they are not reconstructed at each + recompilation, except of course if they are modified (this is an automatic mecanism of $fname(fast_lexer_5)).$p + + $title(The toolbox) + The system uses a $em(toolbox) (of type $att(Toolbox)), which contains a subtoolbox named $att(keep). The subtoolbox + contains all the stuff which is not reinitialized when we change the input source via $tt($$input). On the contrary, + the stuff specifically depending on the input source is stored directly into the toolbox. The toolbox contains: + $list( + $item $em(input source dependent): + $list( + $item current (absolute) file path, + $item current file name, + $item lexing stream through which the source is read, + $item the five lexers already plugged onto the lexing stream. + ) + $item $em(input source independent ($att(keep))): + $list( + $item options of the MAML compiler, + $item B-tree containing the stacks of definitions of macros (within a dynamic variable), + $item list of all color rules (within a dynamic variable), + $item list of all colorizers (within a dynamic variable), + $item list of all colorizer call rules (within a dynamic variable), + $item B-tree of all stacks of counters (within a dynamic variable), + $item counter of errors (within a dynamic variable), + $item HTML options, + $item PDF options. + ) + ) + + $title(The colorization process) + For each colorizer, we construct two lexers: + $list( + $item a first lexer for handling calls and returns (constructed from informations provided by $tt($$colorizercall)), + $item a second lexer for handling the colorization itself (constructed from informations provided by $tt($$colorize)). + ) + Colorizing a text is performed in two passes: + $list( + $item a first pass for handling colorizer calls using the first lexer, + $item a second pass for handling colorisation itself using the second lexer. + ) + The first lexer is constructed as follows. For each $tt($$colorizercall()()(?)(?)), there is a lexer item + with $tt() as its regular expression and returning a token of the form $att(call(,)). For each + $tt($$colorizercall(?)(?)()()), there is a lexer item with $tt() as its regular expression + and returning a token of the form $att(return()). There are other standard lexer items for the rest of the + text returning tokens of the form $att(text()).$p + + Using this lexer, we can insert (actually virtual) + $tt($$call()) and $tt($$return) special marks into the text, even if this text is not a + character string. Indeed, this process acts on $att(MAML2) data. It produces $att(MAML2b) data, where $att(MAML2b) + is the same as $att(MAML2) except that it has two more alternatives for representing $tt($$call()) and + $tt($$return).$p + + The second lexer, for a given colorizer name, is constructed with one lexer item for each + $tt($$colorrule()()()) such that $tt() is the colorizer name. This lexer item has + $tt() as its regular expression and returns a token of the form $att(color(,)), where + $att() is the expression for colorizing $att() as given as the third operand of $tt($$colorrule). Other + standard lexer items are added for handling the rest of the text, returning tokens of the form $att(text()).$p + + Now, this second lexer is used for the actual colorization of a $att(MAML2b) data. A token of the form + $att(text()) is left unchanged, whereas a token of the form $att(color(,)) produces what we + obtain by replacing $tt($$1) by $att() in $att(). This is for characters strings, i.e. for the + alternative $att(text()) of $att(MAML2b). Otherwise, we have to + handle the other alternatives of $att(MAML2b), and in particular $att(call()) and $att(return).$p + + When the colorizer program sees a $att(call()), it pushes the current colorizer on the colorizer stack and + considers $att() as the name of the now current colorizer. When it encounters a $att(return) is pops a + coloriser from the stack which becomes the current colorizer.$p + + A colorizer already constructed by $tt($$colorizer) cannot be reconstructed. Hence, a tentative to reconstruct it + or to add a new rule to it is ignored and generates a warning. + + $p + $center($title(---------------------------------------)) + $par + This is all for the general overview of the MAML version 4 source. Other more specific informations can + be found in the source files. + + $p + $end + +read maml4_pdf.anubis + + + *** Separating options from other command line arguments. + +define (List(MAML_Option),List(String)) + separate_options + ( + List(String) args + ) = + if args is + { + [ ] then ([ ],[ ]), + [h . t] then + since separate_options(t) is (opts1,others1), + if h = "-pdf" then ([pdf . opts1],others1) else + if h = "-verbose" | h = "-v" then ([verbose . opts1],others1) else + (opts1,[h . others1]) + }. + + + *** 'Usage' message. + +define One + usage + = + iprint("Usage: anbexec maml4 [options]\n" + + " Options:\n"+ + " -pdf produce LaTeX and PDF outputs\n"+ + " -verbose \n"). + + + *** 'maml' as a command line tool. + +global define One + maml + ( + List(String) args + ) = + since separate_options(args) is (opts,other_args), + if other_args is + { + [ ] then usage, + [fname . _] then + if file(fname,read) is + { + failure then iprint("File '"+fname+"' not found.\n"), + success(fp) then if make_lexing_stream("",fp,1000,10) is + { + failure then iprint("Cannot read file '"+fname+"'.\n"), + success(ls) then + with gcount_v = var((Int)0), + with kbox = toolboxkeep(opts, + var((MacroTree)new_tree(bt24cmp)), + var((ArityTree)new_tree(bt24cmp)), + var((List(ColorRule))[]), + var((List(ColorCall))[]), + var((CallLexerTree)new_tree(bt24cmp)), + var((ColorLexerTree)new_tree(bt24cmp)), + var((CounterTree)new_tree(bt24cmp)), + var((AccumulatorTree)new_tree(bt24cmp)), + var((Int)30), + default + ), + since ((String,String))split_path(fname) is (rel_path,fname1), + with start_path = get_current_directory/rel_path, + with tbox = make_toolbox(start_path,fname1,ls,kbox), + with result = if_verbose(tbox,"--> '"+fname+"' ...\n",parse_eval(tbox),"<--\n"), + with presult = execute_postponed(tbox,result), + with cresult = colorize(tbox, // needed because values of colorrules must be evaluated during colorization + *tbox.keep.call_lexer_tree_v, + *tbox.keep.color_lexer_tree_v, + presult), + with errors = extract_errors(cresult), + map_forget((MAML_Error me) |-> + print(cyan("Error: ")+to_English(me)+"\n"), + errors); + with html_text = if_verbose(tbox,"Producing HTML ... ",to_HTML(start_path,default,cresult),"done\n"), + if file(fname+".html",new) is + { + failure then print("Canot create file '"+fname+"4.html"+"'\n"), + success(htmlfp) then if_verbose(tbox,"Outputing HTML ... ",print(weaken(htmlfp), + html_encapsulate(tbox.keep.html_options,html_text)),"done\n") + } + + /* + if errors is + { + [ ] then + with html_text = if_verbose(tbox,"Producing HTML ... ",to_HTML(start_path,default,result),"done\n"), + if file(fname+".html",new) is + { + failure then print("Canot create file '"+fname+"4.html"+"'\n"), + success(htmlfp) then if_verbose(tbox,"Outputing HTML ... ",print(weaken(htmlfp), + html_encapsulate(tbox.keep.html_options,html_text)),"done\n") + }, + [_ . _] then map_forget((MAML_Error me) |-> + print(cyan("Error: ")+to_English(me)+"\n"), + errors) + } + */ + + } + } + }. + + diff --git a/anubis_dev/library/doc_tools/maml4_colorize.anubis b/anubis_dev/library/doc_tools/maml4_colorize.anubis new file mode 100644 index 0000000..429eb5d --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_colorize.anubis @@ -0,0 +1,595 @@ + + + MAML4 + + Colorizer stuff. + + +transmit maml4_png.anubis + + + *** This file defines the following function: + + +public define MAML3 colorize (CallLexerTree call_lexers, + ColorLexerTree color_lexers, + MAML2 m). + + + Each colorizer has two lexers attached to it. + + - (1) a 'call lexer' of type LexingStream -> CallLexer, + where CallLexer is an alias for One -> Result(LexicalError(One),ColorCallToken), + + - (2) a 'color lexer' of type LexingStream -> ColorLexer, + where ColorLexer is an alias for One -> Result(LexicalError(One),ColorToken). + + These lexers are stored into the keep subtoolbox into two B-trees of respective types CallLexerTree, and + ColorLexerTree. + + Colorizing is performed in two phases. The first phase uses 'call lexers' in order to introduce 'call' and 'return' + marks into the MAML2 text. This produces a MAML2b text. The second phase is the colorisation proper which uses + 'color lexers'. + + The first phase is preformed by the function 'handle_calls' acting on a MAML2 datum, and it uses the function + 'color_call_parser' for handling the case of the 'text' alternative, the only one which needs to use call lexers. + This first phase produces a MAML2b from a MAML2, and consists in replacing all 'text(s)' by MAML2b compound data + containing 'call(name,tok)' and 'return(tok)' items. + + 'color_call_parser' works as follows. When a string (alternative 'text' of MAML2) need colorization, + a lexing stream is constructed from this string. The colorization + uses a stack of plugged call lexers (whereas the B-tree contains unplugged call lexers). We start with a stack + containing only one plugged call lexer, and the string is always analysed using the call lexer on top of stack. + When a call lexer returns a token of the form 'call(name,tok)', the lexer corresponding to name is plugged onto + the lexing stream and pushed onto the stack. When the lexer returns a token of the form 'return(tok)' a lexer is poped + from the stack. The tokens 'tok' are in both cases inserted in tothe result in the form 'text(tok)'. When a lexer returns a token + of the form 'text(s)', this produces a element of the form 'text(s)'. + + The second phase is performed by 'colorize_2b' taking a MAML2b datum and producing a MAML3 datum. 'colorize_2b' + uses a stack of color lexers, and when a string is to be colorized this is performed using the lexer on top of stack. + Of course, 'colorize_2b' handles instructions 'call' and 'return' by pushing/poping lexers on the stack. Strings + (alternative 'text' of MAML2b) are colorized by the function 'color_parser' using the lexer on top of stack. + This lexer returns tokens of the form 'color(value,text)' where 'value' is a MAML2a datum which is actually an + evaluation of the body of a color rule, and where 'text' is a string. In this case, 'color_parser' just produces + a MAML3 item which is the result of the replacement of the MAML variable $1 by 'text' in 'value'. Otherwise, the + lexer returns tokens of the form 'text(...)' producing 'text(...)' (non colorized piece of text). + + + + + + --- That's all for the public part ! ------------------------------------------------- + + + 'canonical' map from MAML2 to MAML2b. + +define MAML2b + can + ( + MAML2 m + ) = + if m is + { + error(me) then error(me), + erroneous(me,text) then erroneous(me,text), + empty then empty, + false then empty, + true then empty, + text(value) then text(value), + variable(id) then variable(id), + list(l,_) then list(map(can,l)), + alpha(m1) then can(m1), + colorize(pos,cname,operand) then colorize(pos,cname,can(operand)), + postpone(pos,text) then should_not_happen(empty), + prim3(p3) then prim3(map(can,p3)), + m1 + m2 then can(m1) + can(m2) + }. + + 'canonical' map from MAML2 to MAML2a. + +define MAML2a + can + ( + MAML2 m + ) = + if m is + { + error(me) then error(me), + erroneous(me,text) then erroneous(me,text), + empty then empty, + false then empty, + true then empty, + text(value) then text(value), + variable(id) then variable(id), + list(l,_) then list(map(can,l)), + alpha(m1) then can(m1), + colorize(pos,cname,operand) then empty, + postpone(pos,text) then should_not_happen(empty), + prim3(p3) then prim3(map(can,p3)), + m1 + m2 then can(m1) + can(m2) + }. + + 'canonical' map from MAML2b to MAML3. + +define MAML3 + can + ( + MAML2b m + ) = + if m is + { + error(me) then error(me), + erroneous(me,text) then erroneous(me,text), + empty then empty, + call(cname) then empty, + return then empty, + text(value) then text(value), + variable(id) then empty, + list(l) then sum(map(can,l)), + colorize(pos,cname,operand) then can(operand), + prim3(p3) then prim3(map(can,p3)), + m1 + m2 then can(m1) + can(m2) + }. + + + +public define MAML2 + can + ( + MAML3 m + ) = + if m is + { + error(me) then error(me), + erroneous(me,text) then erroneous(me,text), + empty then empty, + text(value) then text(value), + list(l) then list(map(can,l),[]), + postpone(pos,text) then postpone(pos,text), + prim3(p3) then prim3(map(can,p3)), + m1+m2 then can(m1)+can(m2) + }. + + +public define MAML3 + can + ( + MAML2 m + ) = + if m is + { + error(me) then error(me), + erroneous(me,text) then erroneous(me,text), + empty then empty, + false then empty, + true then empty, + text(value) then text(value), + variable(id) then empty, + list(l,deco) then list(map(can,l)), + alpha(m1) then can(m1), + colorize(pos,cname,operand) then can(operand), + postpone(pos,text) then postpone(pos,text), + prim3(p3) then prim3(map(can,p3)), + m1+m2 then can(m1)+can(m2) + }. + + + + *** Gluing texts in MAML2. + + The function below looks for consecutive text("bla") and text("blu") and replaces them by text ("blablu"), + so that the colorizer can recognize a token spanning over several pieces of texts. It also elimnates 'empty' + when it is added (on the left or on the right) to something. + +public define MAML2 + glue_texts + ( + MAML2 m + ) = + //print("gluing MAML2 "); + if m is + { + error(me) then m, + erroneous(me,m1) then m, + empty then m, + false then m, + true then m, + text(value) then m, + variable(id) then m, + list(l,d) then list(map(glue_texts,l),d), + alpha(m1) then alpha(glue_texts(m1)), + colorize(pos,cname,op) then colorize(pos,cname,glue_texts(op)), + postpone(pos,text) then m, // text is MAML1 + prim3(p3) then glue_texts(p3), + _m1 + _m2 then + if _m1 is empty then glue_texts(_m2) else + if _m2 is empty then glue_texts(_m1) else + with m1 = glue_texts(_m1), + m2 = glue_texts(_m2), + if m1 is text(t1) + then if m2 is text(t2) + then text(t1+t2) + else if m2 is m2a+m2b + then if m2a is text(t2a) + then glue_texts(text(t1+t2a)+m2b) + else m1+m2 + else m1+m2 + else if m1 is m1a+m1b + then if m1b is text(t1b) + then if m2 is text(t2) + then glue_texts(m1a+text(t1b+t2)) + else m1+m2 + else m1+m2 + else m1+m2 + }. + + The same one for MAML2b. + +public define MAML2b + glue_texts + ( + MAML2b m + ) = + //print("gluing MAML2b "); + if m is + { + error(me) then m, + erroneous(me,m1) then m, + empty then m, + call(name) then m, + return then m, + text(value) then m, + variable(id) then m, + list(l) then list(map(glue_texts,l)), + colorize(pos,cname,op) then colorize(pos,cname,glue_texts(op)), + prim3(p3) then glue_texts(p3), + _m1 + _m2 then + if _m1 is empty then glue_texts(_m2) else + if _m2 is empty then glue_texts(_m1) else + with m1 = glue_texts(_m1), + m2 = glue_texts(_m2), + if m1 is text(t1) + then if m2 is text(t2) + then text(t1+t2) + else if m2 is m2a+m2b + then if m2a is text(t2a) + then glue_texts(text(t1+t2a)+m2b) + else m1+m2 + else m1+m2 + else if m1 is m1a+m1b + then if m1b is text(t1b) + then if m2 is text(t2) + then glue_texts(m1a+text(t1b+t2)) + else m1+m2 + else m1+m2 + else m1+m2 + }. + + + + *** Creating colorizers. + + A colorizer is created when we encounter a $colorizer(name). This amounts to create two lexers (a call lexer and + a color lexer) and to store them in the B-trees of the keep subtoolbox. + + *** Creating the call lexer. + +define Result(RegExprError,One) + create_call_lexer + ( + Toolbox tbox, + String name, // of colorizer + List(ColorCall) callrules + ) = + with my_call_rules = map_select((ColorCall cc) |-> + if cc is colorcall(mode,cname1,open,cname2,close) then + if name = cname1 + then success(cc) + else failure, + callrules), + with my_return_rules = map_select((ColorCall cc) |-> + if cc is colorcall(mode,cname1,open,cname2,close) then + if name = cname2 + then success(cc) + else failure, + callrules), + with ldesc = (List(LexerItem(ColorCallToken,One))) + map((ColorCall cc) |-> + if cc is colorcall(mode,_,open,cname2,_) then + //print("call lexer "+name+": "+open+" (call)\n"); + lexer_item(open, return((ByteArray b, LexingTools t, One u) |-> ok(call(mode_for_call(mode),cname2,to_string(b))))) + ,my_call_rules) + + map((ColorCall cc) |-> + if cc is colorcall(mode,_,_,_,close) then + //print("call lexer "+name+": "+close+" (return)\n"); + lexer_item(close, return((ByteArray b, LexingTools t, One u) |-> ok(return(mode_for_return(mode),to_string(b))))) + ,my_return_rules) + + [ + lexer_item("#n", return((ByteArray b, LexingTools t, One u) |-> ok(text(to_string(b))))), + lexer_item(".", return((ByteArray b, LexingTools t, One u) |-> ok(text(to_string(b))))) + ], + if if_verbose(tbox,"(1) Making colorizer '"+name+"' ... ",make_saved_lexer(ldesc,end_of_input,'#'),"done\n") is + { + error(e) then error(e), + ok(lex) then + with lexer = (LexingStream ls) |-> lex(ls,unique), + v = tbox.keep.call_lexer_tree_v, + ok(v <- insert(name,lexer,*v)) + }. + + + *** Creating the color lexer. + +define Result(RegExprError,One) + create_color_lexer + ( + Toolbox tbox, + String name, // of colorizer + List(ColorRule) rules + ) = + with myrules = map_select((ColorRule r) |-> + if r is rule(n,_,_) then if n = name + then success(r) + else failure, + rules), + // 'reverse' is needed because the order conventions must be the same as in fast_lexer_5.anubis. + ldesc = (List(LexerItem(ColorToken,One)))reverse( + [ + lexer_item(".", return((ByteArray b, LexingTools t, One u) |-> ok(text(to_string(b))))), + lexer_item("([# #r#t]+)|(#n)", return((ByteArray b, LexingTools t, One u) |-> ok(text(to_string(b))))) + . map((ColorRule r) |-> if r is rule(_,re,c) then + lexer_item(re,return((ByteArray b, LexingTools t, One u) |-> ok(color(c,to_string(b))))),myrules) + ] + ), + if if_verbose(tbox,"(2) Making colorizer '"+name+"' ... ",make_saved_lexer(ldesc,end_of_input,'#'),"done\n") is + { + error(e) then error(e), + ok(lex) then + with lexer = (LexingStream ls) |-> lex(ls,unique), + v = tbox.keep.color_lexer_tree_v, + ok(v <- insert(name,lexer,*v)) + }. + + + *** Creating the whole colorizer. + +public define MAML2 + create_colorizer + ( + Toolbox tbox, + MAML_Pos pos, + String name + ) = + if get(name,*tbox.keep.call_lexer_tree_v) is + { + failure then + if create_call_lexer(tbox,name,*tbox.keep.colorcall_v) is + { + error(e) then error(regexpr(pos,e)), + ok(_) then if create_color_lexer(tbox,name,*tbox.keep.colorrules_v) is + { + error(e) then error(regexpr(pos,e)), + ok(_) then empty + } + }, + success(_) then error(colorizer_already_exists(pos,name)) + }. + + + + *** Handling colorizer calls. + +define MAML2b + color_call_parser + ( + CallLexerTree call_lexers, // all known (unplugged) call lexers + List(CallLexer) stk, // a stack of plugged call lexers + LexingStream ls // the source of bytes to be lexered + ) = + if stk is + { + [ ] then empty, + [lex1 . _] then if lex1(unique) is + { + error(e) then empty, + ok(s) then if s is + { + end_of_input then empty, + call(mode,cn,tok) then //print("got a call("+cn+","+tok+")\n"); + if get(cn,call_lexers) is + { + failure then error(unknown_colorizer(cn)), + success(lex2) then + (if mode is e then (text(tok) + call(cn)) else (call(cn) + text(tok))) + + color_call_parser(call_lexers,[lex2(ls) . stk],ls) + }, + return(mode,tok) then //print("got a return("+tok+")\n"); + if stk is + { + [ ] then text(tok) + color_call_parser(call_lexers,[],ls), + [_ . t] then (if mode is e then (return + text(tok)) else (text(tok) + return)) + + color_call_parser(call_lexers,t,ls), + }, + text(tx) then //print("got a text: "+tx+"\n"); + text(tx) + color_call_parser(call_lexers,stk,ls) + } + } + }. + + + The function 'handle_calls' inserts the instructions 'call(cname)' and 'return' into a MAML2 + (this produces a MAML2b). It needs a stack of colorizers because when it is within the text + of a $colorize(cname)(operand), it must remember 'cname' in order to call the right color_call_parser + on pieces of text in 'operand' + +public define MAML2b + handle_calls + ( + CallLexerTree call_lexers, // all call lexers as they are stored in the keep subtoolbox + List(String) stack, // stack of names of call lexers + MAML2 m + ) = + if m is + { + error(me) then error(me), + erroneous(me,text) then erroneous(me,text), + empty then empty, + false then empty, + true then empty, + text(value) then + if stack is + { + [ ] then text(value), // we are not within a $colorize()() + [h . t] then if get(h,call_lexers) is + { + failure then error(unknown_colorizer(h)), + success(col) then with ls = make_lexing_stream("",value), + color_call_parser(call_lexers,[col(ls)],ls) + } + }, + variable(id) then variable(id), + list(l,_) then list(map((MAML2 m2) |-> handle_calls(call_lexers,stack,m2),l)), + alpha(m1) then handle_calls(call_lexers,stack,m1), + colorize(pos,cname,operand) then colorize(pos,cname,handle_calls(call_lexers,[cname . stack],operand)), + postpone(pos,text) then should_not_happen(empty), + prim3(p3) then prim3(map((MAML2 m2) |-> handle_calls(call_lexers,[],m2),p3)), + m1 + m2 then handle_calls(call_lexers,stack,m1) + handle_calls(call_lexers,stack,m2) + }. + + + + *** Actual colorization (phase 2). + + + *** Colorizing a string. + +define MAML3 + color_parser + ( + Toolbox tbox, + ColorLexer lex // already plugged color lexer + ) = + if lex(unique) is + { + error(e) then empty, + ok(s) then if s is + { + end_of_input then empty, + color(c,tx) then with m1 = //replace_vars_in_MAML(can(eval(tbox,c)),[text(tx)]), + (MAML3)can(eval(tbox,replace_vars_in_MAML(c,[text(tx)]))), + m2 = color_parser(tbox,lex), + m1+m2, + text(tx) then text(tx) + color_parser(tbox,lex) + } + }. + + + + *** Colorizing a MAML2b. + + The function 'colorize_2b' performs the actual colorization. + +define MAML2b + sum + ( + List(MAML2b) l + ) = + if l is + { + [ ] then empty, + [h . t] then h + sum(t) + }. + +define (List(LexingStream -> ColorLexer),MAML3) + colorize_2b_aux + ( + Toolbox tbox, + ColorLexerTree color_lexers, + List(LexingStream -> ColorLexer) stk, + MAML2b m + ) = + if m is + { + error(me) then (stk,error(me)), + erroneous(me,text) then (stk,erroneous(me,text)), + empty then (stk,empty), + call(cname) then if get(cname,color_lexers) is + { + failure then (stk,error(unknown_colorizer(cname))), + success(col) then ([col . stk], empty) + }, + return then if stk is + { + [ ] then ([ ],empty), + [_ . t] then (t,empty) + }, + text(value) then if stk is + { + [ ] then ([ ],text(value)), + [h . _] then (stk,color_parser(tbox,h(make_lexing_stream("",value)))) + }, + variable(id) then (stk,empty), + list(l) then colorize_2b_aux(tbox,color_lexers,stk,sum(l)), + colorize(pos,cname,operand) then if get(cname,color_lexers) is + { + failure then (stk,error(unknown_colorizer(cname))), + success(col) then since colorize_2b_aux(tbox, + color_lexers, + [col . stk], + operand) is (_,r), (stk,r) + }, + prim3(p3) then (stk,prim3(map((MAML2b m2b) |-> since colorize_2b_aux(tbox,color_lexers,[],m2b) is (_,r), r, p3))) + m1 + m2 then since colorize_2b_aux(tbox,color_lexers,stk,m1) is (stk1,r1), + since colorize_2b_aux(tbox,color_lexers,stk1,m2) is (stk2,r2), + (stk2,r1+r2) + }. + + +public define MAML3 + colorize_2b + ( + Toolbox tbox, + ColorLexerTree color_lexers, + List(LexingStream -> ColorLexer) stk, + MAML2b m + ) = + since colorize_2b_aux(tbox,color_lexers,stk,m) is (_,r), r. + + + + +public define MAML3 + colorize + ( + Toolbox tbox, + CallLexerTree call_lexers, + ColorLexerTree color_lexers, + MAML2 m + ) = + if m is + { + error(me) then error(me), + erroneous(me,text) then erroneous(me,text), + empty then empty, + false then empty, + true then empty, + text(value) then text(value), + variable(id) then empty, + list(l,_) then colorize(tbox,call_lexers,color_lexers,sum(l)), + alpha(m1) then colorize(tbox,call_lexers,color_lexers,m1), + colorize(pos,cname,operand) then with a = glue_texts(handle_calls(call_lexers,[cname],glue_texts(operand))), + //print(to_string(a)+"\n"); + if get(cname,color_lexers) is + { + failure then error(unknown_colorizer(cname)), + success(col) then colorize_2b(tbox,color_lexers,[col],a) + }, + postpone(pos,text) then should_not_happen(empty), + prim3(p3) then prim3(map((MAML2 m2) |-> colorize(tbox,call_lexers,color_lexers,m2),p3)), + m1+m2 then colorize(tbox,call_lexers,color_lexers,m1) + colorize(tbox,call_lexers,color_lexers,m2) + }. + + + + + \ No newline at end of file diff --git a/anubis_dev/library/doc_tools/maml4_eval.anubis b/anubis_dev/library/doc_tools/maml4_eval.anubis new file mode 100644 index 0000000..5429fcb --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_eval.anubis @@ -0,0 +1,1343 @@ + + MAML4 + + The evaluator. + +transmit maml4_colorize.anubis + + +public define MAML2 glue_eval (Toolbox tbox, MAML1 m). +public define MAML2 eval (Toolbox tbox, MAML1 m). +public define MAML2 parse_eval (Toolbox tbox). + + + --- That's all for the public part ! --------------------------------------------------- + + + +define MAML2 eval_prim1 (Toolbox tbox, Stack stk, MAML_Prim1 p1). +define MAML2 eval_macro (Toolbox tbox, MAML_Pos pos, String name, List(MAML1) operands). +define List(MAML2) eval_several (Toolbox tbox, List(MAML1) operands). + +public define MAML2 glue_eval (Toolbox tbox, MAML1 m) = glue_texts(eval(tbox,m)). + + public define MAML2 + glue_eval + ( + Toolbox tbox, + MAML1 m + ) = + with m2 = glue_texts(eval(tbox,m)), + can(colorize(tbox, + *tbox.keep.call_lexer_tree_v, + *tbox.keep.color_lexer_tree_v, + m2)). + + --- Executing the actions. + +public define MAML2 create_colorizer (Toolbox tbox, + MAML_Pos pos, + String name). + +define MAML2 record_colorizercall (Toolbox tbox, + CCMode mode, + String cn1, + String _call, + String cn2, + String _return). + +define MAML2 record_colorrule (Toolbox tbox, + String cn, + String regexpr, + MAML1 value). + +define MAML2 get_counter_value (Toolbox tbox, + MAML_Pos pos, + String name). + + + + + *** A tool for checking if we are currently within a given stackable mark. + +define Bool + within + ( + Stack stk, + PrimName name + ) = + if stk is + { + [ ] then false, + [h . t] then + if name = h + then true + else within(t,name) + }. + + + + + *** Simulating HTML or PDF result by evaluating $ifhtml or $ifpdf. + +define MAML2 + html_reduce + ( + MAML2 m + ) = + if m is + { + error(me) then m, + erroneous(me,text) then m, + empty then m, + false then m, + true then m, + text(value) then m, + variable(id) then m, + list(l,d) then list(map(html_reduce,l),d), + alpha(m1) then alpha(html_reduce(m1)), + colorize(pos,cname,operand) then colorize(pos,cname,html_reduce(operand)), + postpone(pos,text) then m, + prim3(p3) then if p3 is ifhtml(_,n) then html_reduce(n) else + if p3 is ifpdf(_,n) then empty else + prim3(map(html_reduce,p3)), + m1 + m2 then html_reduce(m1) + html_reduce(m2) + }. + +define MAML2 + pdf_reduce + ( + MAML2 m + ) = + if m is + { + error(me) then m, + erroneous(me,text) then m, + empty then m, + false then m, + true then m, + text(value) then m, + variable(id) then m, + list(l,d) then list(map(pdf_reduce,l),d), + alpha(m1) then alpha(pdf_reduce(m1)), + colorize(pos,cname,operand) then colorize(pos,cname,pdf_reduce(operand)), + postpone(pos,text) then m, + prim3(p3) then if p3 is ifhtml(_,n) then empty else + if p3 is ifpdf(_,n) then pdf_reduce(n) else + prim3(map(pdf_reduce,p3)), + m1 + m2 then pdf_reduce(m1) + pdf_reduce(m2) + }. + +define Maybe(Value($T)) + simulate_html_pdf + ( + MAML2 -> Maybe($T) test, + MAML2 m + ) = + with m_html = html_reduce(m), + m_pdf = pdf_reduce(m), + if test(m_html) is + { + failure then failure, + success(mh) then if test(m_pdf) is + { + failure then failure, + success(mp) then success(value(mh,mp)) + } + }. + + + *** Checking that a MAML operand has the required 'form'. + +define Maybe(One) + parse_color_value + ( + One -> LexOut(ColorValueToken,One) lex, + Int done // number of correct tokens read + ) = + if lex(unique) is + { + error(_) then failure, + ok(tok) then if tok is + { + end_of_input then if done = 5 + then success(unique) + else failure, + int(n) then if (0 =< n & n =< 255 & (done:[0,2,4])) + then parse_color_value(lex,done+1) + else failure, + comma then if done:[1,3] + then parse_color_value(lex,done+1) + else failure + } + }. + + +define Maybe(String) // produces "r,g,b" + must_be_color + ( + MAML2 m + ) = + with s = to_string(glue_texts(m)), + if parse_color_value(retrieve_lexer(color_value_lexer_desc,color_value_lexer,end_of_input) + (make_lexing_stream("",s),unique),0) is + { + failure then failure, + success(_) then success(s) + }. + + +public define Result(MAML_Error,Value(String)) + eval_as_color + ( + Toolbox tbox, + MAML_Pos pos, + MAML1 m + ) = + if simulate_html_pdf(must_be_color,glue_eval(tbox,m)) is + { + failure then error(must_be_a_color(pos,to_string(m))), + success(n) then ok(n) + }. + + + +define Maybe(Int) + must_be_int + ( + MAML2 m + ) = + decimal_scan(to_string(glue_texts(m))). + +public define Result(MAML_Error,Value(Int)) + eval_as_int + ( + Toolbox tbox, + MAML_Pos pos, + MAML1 m + ) = + if simulate_html_pdf(must_be_int,glue_eval(tbox,m)) is + { + failure then error(must_be_an_int(pos,to_string(m))), + success(n) then ok(n) + }. + +define Maybe(Int) + must_be_nzint + ( + MAML2 m + ) = + if decimal_scan(to_string(glue_texts(m))) is + { + failure then failure, + success(n) then if n = 0 + then failure + else success(n) + }. + +public define Result(MAML_Error,Value(Int)) + eval_as_nzint + ( + Toolbox tbox, + MAML_Pos pos, + MAML1 m + ) = + if simulate_html_pdf(must_be_nzint,glue_eval(tbox,m)) is + { + failure then error(must_be_a_nzint(pos,to_string(m))), + success(n) then ok(n) + }. + + +public define Maybe(Int) + must_be_pint + ( + MAML2 m + ) = + if decimal_scan(to_string(glue_texts(m))) is + { + failure then failure, + success(n) then if n < 0 + then failure + else success(n) + }. + +public define Result(MAML_Error,Value(Int)) + eval_as_pint + ( + Toolbox tbox, + MAML_Pos pos, + MAML1 m + ) = + if simulate_html_pdf(must_be_pint,glue_eval(tbox,m)) is + { + failure then error(must_be_a_positive_int(pos,to_string(m))), + success(n) then ok(n) + }. + + + + Test if an evaluated expression represents a boolean. + +define Maybe(Bool) + must_be_bool + ( + MAML2 m + ) = + if glue_texts(m) is // glue_texts is necessary because we can have $false+empty for example + { + error(me) then failure, + erroneous(me,text) then failure, + empty then failure, + false then success(false), + true then success(true), + text(value) then failure, + variable(id) then failure, + list(l,d) then failure, + alpha(m1) then failure, + colorize(pos,cname,operand) then failure, + postpone(pos,text) then failure, + prim3(p3) then failure, + m1+m2 then failure + }. + + + The same one with debugging stuff: + define Maybe(Bool) + must_be_bool + ( + MAML2 m + ) = + if glue_texts(m) is // glue_texts is necessary because we can have $false+empty for example + { + error(me) then iprint("[error]\n"); failure, + erroneous(me,text) then iprint("[erroneous]\n"); failure, + empty then iprint("[empty]\n"); failure, + false then iprint("[false]\n"); success(false), + true then iprint("[true]\n"); success(true), + text(value) then iprint("[text: "+value+"]\n"); failure, + variable(id) then iprint("[variable]\n"); failure, + colorize(pos,cname,operand) then iprint("[colorize]\n"); failure, + postpone(pos,text) then iprint("[postpone]\n"); failure, + prim3(p3) then iprint("[prim3]\n"); failure, + m1+m2 then iprint(to_string(m1)+"+"+to_string(m2)+"\n"); failure + }. + + +public define Result(MAML_Error,Value(Bool)) + eval_as_bool + ( + Toolbox tbox, + MAML_Pos pos, + MAML1 m + ) = + if simulate_html_pdf(must_be_bool,glue_eval(tbox,m)) is + { + failure then error(boolean_expected(pos,to_string(m))), + success(n) then ok(n) + }. + + + +define Maybe(String) + must_be_string + ( + MAML2 m + ) = + success(to_string(glue_texts(m))). + +public define Result(MAML_Error,Value(String)) + eval_as_string + ( + Toolbox tbox, + MAML_Pos pos, + MAML1 m + ) = + if simulate_html_pdf(must_be_string,glue_eval(tbox,m)) is + { + failure then should_not_happen(error(string_expected(pos,to_string(m)))), + success(n) then ok(n) + }. + + + +define Maybe(One) + parse_symbol + ( + One -> LexOut(SymbolToken,One) lex, + Bool done + ) = + if lex(unique) is + { + error(_) then failure, + ok(tok) then if tok is + { + end_of_input then if done then success(unique) else failure, + symbol then if done then failure else parse_symbol(lex,true) + } + }. + + +define Maybe(CCMode) + must_be_colorizercall_mode + ( + MAML2 m + ) = + with s = to_string(glue_texts(m)), + if s = "ee" then success(ee) else + if s = "ei" then success(ei) else + if s = "ie" then success(ie) else + if s = "ii" then success(ii) else + failure. + + +public define Result(MAML_Error,Value(CCMode)) + eval_as_colorizercall_mode + ( + Toolbox tbox, + MAML_Pos pos, + MAML1 m + ) = + if simulate_html_pdf(must_be_colorizercall_mode,glue_eval(tbox,m)) is + { + failure then error(not_a_colorizercall_mode(pos,to_string(m))), + success(mode) then ok(mode) + }. + + +public define Maybe(String) + must_be_symbol + ( + MAML2 m + ) = + with s = to_string(glue_texts(m)), + if parse_symbol(retrieve_lexer(symbol_lexer_desc,symbol_lexer,end_of_input) + (make_lexing_stream("",s),unique),false) is + { + failure then failure, + success(_) then success(s) + }. + +public define Result(MAML_Error,Value(String)) + eval_as_symbol + ( + Toolbox tbox, + MAML_Pos pos, + MAML1 m + ) = + if simulate_html_pdf(must_be_symbol,glue_eval(tbox,m)) is + { + failure then error(must_be_a_symbol(pos,to_string(m))), + success(n) then ok(n) + }. + + +define Value($T) + same + ( + $T t + ) = + value(t,t). + + + + *** Expanding macros, without evaluating. + +define MAML1 -> MAML1 + expand_macros + ( + MacroTree mt + ) = + (MAML1 m) |-f-> + if m is + { + error(me) then m, + erroneous(me,text) then m, + empty then m, + text(value) then m, + variable(id) then m, + prim1(p1) then prim1(map(f,p1)), + list(l,d) then list(map(f,l),d), + alpha(m1) then alpha(f(m1)), + colorize(pos,cname,operand) then colorize(pos,cname,f(operand)), + define(pos,name,ar,val) then define(pos,name,ar,f(val)), + undefine(pos,name) then m, + _if(pos,test,ift,iff) then _if(pos,f(test),f(ift),f(iff)), + prim3(p3) then prim3(map(f,p3)), + computed(m2) then m, + macro(pos,name,operands) then with eops = map(f,operands), + if get(name,mt) is + { + failure then error(unknown_macro_name(pos,name)), + success(l) then if l is + { + [ ] then error(unknown_macro_name(pos,name)), + [h . t] then since h is macro(_,ar,body), + f(replace_vars_in_MAML(body,eops)) + } + }, + m1 + m2 then f(m1) + f(m2) + }. + + + + Comparison for sorting MAML lists. + +define Maybe(MAML2) alpha_part (List(MAML2) l). + +public define Maybe(MAML2) + alpha_part // find $alphabetic(m1) in m and return m1 + ( + MAML2 m + ) = + if m is + { + error(me) then failure, + erroneous(me,text) then failure, + empty then failure, + false then failure, + true then failure, + text(value) then failure, + variable(id) then failure, + list(l,_) then alpha_part(l), + alpha(m1) then success(m1), + colorize(pos,cname,operand) then alpha_part(operand), + postpone(pos,text) then failure, + prim3(p3) then alpha_part(p3), + m1+m2 then if alpha_part(m1) is + { + failure then alpha_part(m2), + success(m1a) then success(m1a) + } + }. + + +define Maybe(MAML2) + alpha_part // find $alphabetic(m1) in m and return m1 + ( + List(MAML2) l + ) = + if l is + { + [ ] then failure, + [h . t] then if alpha_part(h) is + { + failure then alpha_part(t), + success(p) then success(p) + } + }. + + + +define Bool + maml_alpha_compare + ( + MAML2 m1, + MAML2 m2 + ) = + if alpha_part(m1) is + { + failure then true, + success(p1) then if alpha_part(m2) is + { + failure then false, + success(p2) then string_less(to_string(p1),to_string(p2)) + } + }. + + +define Maybe(List(MAML2)) + is_list + ( + MAML2 m + ) = + if m is + { + error(me) then failure, + erroneous(me,text) then failure, + empty then failure, + false then failure, + true then failure, + text(value) then failure, + variable(id) then failure, + list(l,d) then success(l), + alpha(m1) then failure, + colorize(pos,cname,operand) then failure, // maybe something to do here + postpone(pos,text) then failure, + prim3(p3) then failure, + m1+m2 then failure + }. + + +define Maybe(List(List(MAML2))) + are_lists + ( + List(MAML2) l + ) = + if l is + { + [ ] then success([ ]), + [h . t] then if are_lists(t) is + { + failure then failure, + success(rest) then if is_list(h) is + { + failure then failure, + success(h1) then success([h1 . rest]) + } + } + }. + +define Maybe(List(List(MAML2))) + is_list_of_lists + ( + MAML2 m + ) = + if is_list(m) is + { + failure then failure, + success(l) then are_lists(l) + }. + +define Bool is_empty(MAML2 m) = to_string(m) = "". + + +define List(List(MAML2)) + add_in_front + ( + List(MAML2) line, + List(List(MAML2)) rest, + ) = + if line is + { + [ ] then [ ], + [a1 . as] then if rest is + { + [ ] then map((MAML2 a) |-> [a],line), + [r1 . rs] then [[a1 . r1] . add_in_front(as,rs)] + } + }. + +define List(List(MAML2)) + add_in_front_fill + ( + List(MAML2) line, + List(List(MAML2)) rest, + ) = + if line is + { + [ ] then map((List(MAML2) l) |-> [text("") . l],rest), + [a1 . as] then if rest is + { + [ ] then map((MAML2 a) |-> [a],line), + [r1 . rs] then [[a1 . r1] . add_in_front_fill(as,rs)] + } + }. + + +define List(List(MAML2)) + transpose + ( + List(List(MAML2)) ll + ) = + if ll is + { + [ ] then [ ], + [line1 . lines] then with rest = transpose(lines), + if length(line1) = length(rest) + then add_in_front(line1,rest) + else add_in_front_fill(line1,rest) + }. + + +define List($T) + sublist + ( + Int start, // already known as positive or zero and start =< end + Int end, // return all elements between number start (included) to number end (not included) + List($T) l + ) = + if end =< 0 then [ ] else + if l is + { + [ ] then [ ], + [h . t] then + if start > 0 + then sublist(start-1,end-1,t) + else [h . sublist(0,end-1,t)] + }. + + +define MAML2 + shuffle + ( + List(String) d, + List(MAML2) l + ) = + if l is + { + [ ] then text(concat(d)), + [l1 . ls] then if d is + { + [ ] then sum(l), + [d1 . ds] then + text(d1)+l1+shuffle(ds,ls) + } + }. + +define MAML2 + do_nolist + ( + MAML2 m + ) = + if m is + { + error(me) then m, + erroneous(me,text) then m, + empty then m, + false then m, + true then m, + text(value) then m, + variable(id) then m, + list(l,deco) then with l1 = map(do_nolist,l), + shuffle(deco,l1), + alpha(m1) then alpha(do_nolist(m1)), + colorize(pos,cname,operand) then colorize(pos,cname,do_nolist(operand)), + postpone(pos,text) then m, + prim3(p3) then prim3(map(do_nolist,p3)), + m1+m2 then do_nolist(m1) + do_nolist(m2) + }. + + + + *** Evaluating category 1 marks. + + For each category 1 mark, we must: + - (1) evaluate the operands, + - (2) check they have the required form, + - (3) execute the action. + + In the function 'eval_prim1', we don't use 'eval_as_symbol', etc... because since category 1 marks + desapppear, they should not contain any $ifhtml nor any $ifpdf. + +define MAML2 + eval_prim1 + ( + Toolbox tbox, + List(PrimName) stk, + MAML_Prim1 pr1 // the mark together with its operands + ) = + ////////////////////// Category 1a //////////////////////////////////////////// + //iprint("eval_prim1\n"); + if pr1 is + { + /// $accumulator(name) + _accumulator(pos,_name) then + if must_be_symbol(glue_eval(tbox,_name)) is + { + failure then error(must_be_a_symbol(pos,to_string(_name))), + success(name) then + with v = tbox.keep.accumulator_tree_v, + v <- insert(name,[],*v); empty + }, + + /// $addtocounter(symbol)(int) + _addtocounter(pos,_name,_val) then + if must_be_symbol(glue_eval(tbox,_name)) is + { + failure then error(unknown_counter(pos,to_string(_name))), + success(name) then if must_be_int(glue_eval(tbox,_val)) is + { + failure then error(invalid_number_to_add(pos,to_string(_val))), + success(val) then + with v = tbox.keep.counter_tree_v, + since ((CounterTree,(Maybe(List(Int)),MAML2)))get_update(name,*v,(Maybe(List(Int)) mb_l) |-> + if mb_l is + { + failure then (failure, error(unknown_counter(pos,name))), + success(l) then if l is + { + [ ] then (failure, error(unknown_counter(pos,name))), + [h . t] then (success([h+val . t]),empty) + } + }) is (new_tree,p), + v <- new_tree; + since p is (_,result), result + } + }, + + /// $append(name)(text) + _append(pos,_name,_text) then + if must_be_symbol(glue_eval(tbox,_name)) is + { + failure then error(must_be_a_symbol(pos,to_string(_name))), + success(name) then with text = glue_eval(tbox,_text), + v = tbox.keep.accumulator_tree_v, + since get_update(name,*v,(Maybe(List(MAML2)) mbm) |-> if mbm is + { + failure then failure, + success(text1) then success([text . text1]) + }) is (new_tree,mbv), + v <- new_tree; + if mbv is + { + failure then error(unknown_accumulator(pos,name)), + success(_) then empty + } + }, + + /// $colorizer(symbol) + _colorizer(pos,_name) then + if must_be_symbol(glue_eval(tbox,_name)) is + { + failure then error(must_be_a_symbol(pos,to_string(_name))), + success(name) then create_colorizer(tbox,pos,name) + }, + + /// $colorizercall(mode)(symbol)(string)(symbol)(string) + _colorizercall(pos,_mode,_cn1,_call,_cn2,_return) then + if must_be_colorizercall_mode(glue_eval(tbox,_mode)) is + { + failure then error(not_a_colorizercall_mode(pos,to_string(_mode))), + success(mode) then if must_be_symbol(glue_eval(tbox,_cn1)) is + { + failure then error(must_be_a_symbol(pos,to_string(_cn1))), + success(cn1) then if must_be_symbol(glue_eval(tbox,_cn2)) is + { + failure then error(must_be_a_symbol(pos,to_string(_cn2))), + success(cn2) then record_colorizercall(tbox, + mode, + cn1, + to_string(glue_eval(tbox,_call)), + cn2, + to_string(glue_eval(tbox,_return))) + } + } + }, + + /// $colorrule(symbol)(string)(maml) + _colorrule(pos,_cn,_reg,_val) then + if must_be_symbol(glue_eval(tbox,_cn)) is + { + failure then error(must_be_a_symbol(pos,to_string(_cn))), + success(cn) then record_colorrule(tbox, + cn, + to_string(glue_eval(tbox,_reg)), + _val) + }, + + /// $output(maml)(maml) + _output(pos,_path,text) then + with path = to_string(glue_eval(tbox,_path)), + if file(path,new) is + { + failure then error(cannot_write_file(path)), + success(fp) then print(weaken(fp),to_string(text)); empty + }, + + /// $popcounter(symbol) + _popcounter(pos,_name) then + if must_be_symbol(glue_eval(tbox,_name)) is + { + failure then error(unknown_counter(pos,to_string(_name))), + success(name) then + with v = tbox.keep.counter_tree_v, + v <- update(name,*v,(Maybe(List(Int)) mbl) |-> if mbl is + { + failure then failure, + success(l) then if l is + { + [ ] then failure, + [h . t] then success(t) + } + }); + empty + }, + + /// $pushcounter(symbol)(int) + _pushcounter(pos,_name,_init) then + if must_be_symbol(glue_eval(tbox,_name)) is + { + failure then error(must_be_a_symbol(pos,to_string(_name))), + success(name) then if must_be_int(glue_eval(tbox,_init)) is + { + failure then error(must_be_an_int(pos,to_string(_init))), + success(init) then with v = tbox.keep.counter_tree_v, + v <- update(name,*v,(Maybe(List(Int)) mbl) |-> if mbl is + { + failure then success([init]), + success(l) then success([init . l]) + }); empty + } + }, + + /// $setcounter(symbol)(int) + _setcounter(pos,_name,_val) then + if must_be_symbol(glue_eval(tbox,_name)) is + { + failure then error(must_be_a_symbol(pos,to_string(_name))), + success(name) then if must_be_int(glue_eval(tbox,_val)) is + { + failure then error(must_be_an_int(pos,to_string(_val))), + success(val) then with v = tbox.keep.counter_tree_v, + since ((CounterTree,(Maybe(List(Int)),MAML2)))get_update(name,*v,(Maybe(List(Int)) mbl) |-> if mbl is + { + failure then (failure,error(unknown_counter(pos,name))), + success(l) then if l is + { + [ ] then (failure,error(unknown_counter(pos,name))), + [h . t] then (success([val . t]),empty) + } + } + ) is (new_tree,p), + v <- new_tree; + since p is (_,result), result + } + }, + + + /////////////////////////////// Category 1b ////////////////////////////////////////: + /// $add(n)(m) + _add(pos,_n,_m) then + if must_be_int(glue_eval(tbox,_n)) is + { + failure then error(must_be_an_int(pos,to_string(_n))), + success(n) then if must_be_int(glue_eval(tbox,_m)) is + { + failure then error(must_be_an_int(pos,to_string(_m))), + success(m) then text(to_decimal(n+m)) + } + }, + + /// $apply(name)(list) + _apply(pos,_name,_list) then + with op = (MAML2)glue_eval(tbox,_list), // the computed operand + //iprint("_apply: op = "+to_string_all(op)+" at "+format(pos)+"\n"); + if must_be_symbol(glue_eval(tbox,_name)) is + { + failure then error(must_be_a_symbol(pos,to_string(_name))), + success(name) then + // since we must know if '_list' actually represents a list, we must compute it. + // Then, we have to apply the macro to an already computed operand. The body of definition + // of the macro is a MAML1 containing a $1. We can evaluate this body since $1 will remain + // $1. Then we can replace $1 by the (MAML2)operand, but we still need to compute, because + // this replacement can create non completely computed stuff. It is well known in logic that + // replacement creates new redexes. + if get_apply_function(tbox,pos,name) is + // getting a function representing the macro especially designed for $apply (see maml4_lexers.anubis) + { + error(e) then error(e), // incorrect name or macro not found or macro of bad arity + ok(f) then // the macro in the form of a function MAML2 -> MAML2 + if is_list(op) is + { + failure then error(not_a_list(pos,to_string(op))), + success(l) then list(map(f,l),[]) + } + } + }, + + /// $content(name) + _content(pos,_name) then + if must_be_symbol(glue_eval(tbox,_name)) is + { + failure then error(must_be_a_symbol(pos,to_string(_name))), + success(name) then + with v = tbox.keep.accumulator_tree_v, + if get(name,*v) is + { + failure then error(unknown_accumulator(pos,name)), + success(t) then //v <- remove(name,*v); // $content destroys the accumulator + //iprint("_content: got "+to_string(sum(t))+"\n"); + list(reverse(t),[]) + } + }, + + /// $countervalue(symbol) + _countervalue(pos,_name) then + if must_be_symbol(glue_eval(tbox,_name)) is + { + failure then error(must_be_a_symbol(pos,to_string(_name))), + success(name) then get_counter_value(tbox,pos,name) + }, + + /// $defined(symbol) + _defined(pos,_name) then + //iprint("---> at "+format(pos)+" $defined("+to_string(_name)+") = "); + if must_be_symbol(text(to_string(_name))) is + { + failure then error(must_be_a_symbol(pos,to_string(_name))), + success(name) then with v = tbox.keep.macro_tree_v, + if get(name,*v) is + { + failure then //iprint("false\n"); + false, + success(l) then if l is + { + [ ] then //iprint("false\n"); + false, + [_ . _] then //iprint("true\n"); + true + } + } + }, + + /// $$ + _dollar(pos) then text("$"), + + /// $equals(maml)(maml) + _equals(pos,_e1,_e2) then + with e1 = glue_eval(tbox,_e1), + e2 = glue_eval(tbox,_e2), + ers = extract_errors(e1+e2), + if ers is + { + [ ] then //iprint("===== "+to_string(e1)+" == "+to_string(e2)+" ====\n"); + if to_string(e1) = to_string(e2) // will identify more + then (MAML2)true // the explicit typing is not necessary here + else (MAML2)false, + [_ . _] then add_errors(ers) + }, + + /// $false + _false(pos) then false, + + /// $input(path) + _input(pos,_path) then + with path = to_string(_path), + since ((String,String))split_path(path) is (rel_path,fname), + with abs_path = (tbox.file_path)/path, + if file(abs_path,read) is + { + failure then error(file_not_found(pos,abs_path)), + success(fp) then + if make_lexing_stream("",fp,1000,10) is + { + failure then error(cannot_read_file(pos,abs_path)), + success(ls) then + with tbox1 = make_toolbox((tbox.file_path)/rel_path, + fname, + ls, + tbox.keep), + parse_eval(tbox1), + } + }, + + /// $latex(string) + _latex(pos,_text) then + with text = to_string(_text), + with html_opts = tbox.keep.html_options, + with fsize = font_size(html_opts), + with note_fsize = note_font_size(html_opts), + with rf = if within(stk,note) then (30.0/note_fsize) else (26.4/fsize), + with r = latex_to_png(text,html_opts), + //iprint("back from latex_to_png\n"); + if r is + { + error(msg) then error(msg), + log_file(path) then error(latex_error(pos,path)), + png_file_down(fname,w,h,down) then + if has_a_display(text) + then prim3(displaylatex(pos,same(text),same(fname),same(w/rf),same(h/rf),same(down/rf))) + else prim3(inlinelatex (pos,same(text),same(fname),same(w/rf),same(h/rf),same(down/rf))) + }, + + /// $length(list) + _length(pos,_list) then + //iprint("_length: _list = "+to_string_all(_list)+"\n"); + with op = glue_eval(tbox,_list), + //iprint("_length: op = "+to_string_all(op)+"\n"); + if is_list(op) is + { + failure then error(not_a_list(pos,to_string(_list))), + success(l) then text(to_decimal(length(l))) + }, + + /// $lpar + _lpar(pos) then text("("), + + /// $minus(n)(m) + _minus(pos,_n,_m) then + if must_be_int(glue_eval(tbox,_n)) is + { + failure then error(must_be_an_int(pos,to_string(_n))), + success(n) then if must_be_int(glue_eval(tbox,_m)) is + { + failure then error(must_be_an_int(pos,to_string(_m))), + success(m) then text(to_decimal(n-m)) + } + }, + + /// $mul(n)(m) + _mul(pos,_n,_m) then + if must_be_int(glue_eval(tbox,_n)) is + { + failure then error(must_be_an_int(pos,to_string(_n))), + success(n) then if must_be_int(glue_eval(tbox,_m)) is + { + failure then error(must_be_an_int(pos,to_string(_m))), + success(m) then text(to_decimal(n*m)) + } + }, + + /// $nolist(text) + _nolist(pos,_text) then + with text = eval(tbox,_text), + do_nolist(text), + + /// $opp(n) + _opp(pos,_n) then + if must_be_int(glue_eval(tbox,_n)) is + { + failure then error(must_be_an_int(pos,to_string(_n))), + success(n) then text(to_decimal(-n)) + }, + + /// $postpone(text) + _postpone(pos,_text) then + postpone(pos,_text), + + /// $quotient(n)(m) + _quotient(pos,_n,_m) then + if must_be_int(glue_eval(tbox,_n)) is + { + failure then error(must_be_an_int(pos,to_string(_n))), + success(n) then if must_be_nzint(glue_eval(tbox,_m)) is + { + failure then error(must_be_a_nzint(pos,to_string(_m))), + success(m) then if n/m is + { + failure then error(must_be_a_nzint(pos,to_string(_m))), + success(p) then since p is (q,r), text(to_decimal(q)) + } + } + }, + + /// $remainder(n)(m) + _remainder(pos,_n,_m) then + if must_be_int(glue_eval(tbox,_n)) is + { + failure then error(must_be_an_int(pos,to_string(_n))), + success(n) then if must_be_nzint(glue_eval(tbox,_m)) is + { + failure then error(must_be_a_nzint(pos,to_string(_m))), + success(m) then if n/m is + { + failure then error(must_be_a_nzint(pos,to_string(_m))), + success(p) then since p is (q,r), text(to_decimal(r)) + } + } + }, + + /// $reverse(list) + _reverse(pos,_op) then + with op = glue_eval(tbox,_op), + if is_list(op) is + { + failure then error(not_a_list(pos,to_string(_op))), + success(l) then list(reverse(l),[]) + }, + + /// $rpar + _rpar(pos) then text(")"), + + /// $sort(list) + _sort(pos,_op) then + //iprint("sorting item: "+to_string_all(_op)+"\n"); + with op = glue_eval(tbox,_op), + if is_list(op) is + { + failure then //iprint(" which is not a list\n"); + op, + success(l) then ///iprint(" which is a list of "+length(l)+" element.\n"); + list(merge_sort(l,maml_alpha_compare),[]) + }, + + /// $sublist(start)(end)(list) + _sublist(pos,_start,_end,_list) then + if must_be_int(glue_eval(tbox,_start)) is + { + failure then error(must_be_an_int(pos,to_string(_start))), + success(start) then if must_be_int(glue_eval(tbox,_end)) is + { + failure then error(must_be_an_int(pos,to_string(_end))), + success(end) then if is_list(glue_eval(tbox,_list)) is + { + failure then error(not_a_list(pos,to_string(_list))), + success(l) then + with s = (if start < 0 then 0 else start), + e = (if end > length(l) then length(l) else end), + if e =< s + then list([],[]) + else list(sublist(s,e,l),[]) + } + } + }, + + /// $thisfilepath + _thisfilepath(pos) then text(tbox.file_path), + + /// $transpose(list) + _transpose(pos,_list) then + with mblol = glue_eval(tbox,_list), + if is_list_of_lists(mblol) is + { + failure then mblol, + success(lol) then list(map((List(MAML2) r) |-> list(r,[]),transpose(lol)),[]), + }, + + /// $true + _true(pos) then true, + + /// $verbatim(text) + _verbatim(pos,txt) then text(to_string(txt)) + }. + + + + +public define MAML2 + eval + ( + Toolbox tbox, + MAML1 m + ) = + //iprint("eval\n"); + if m is + { + error(me) then error(me), + erroneous(me,text) then erroneous(me,text), + empty then empty, + text(value) then text(value), + variable(id) then variable(id), + prim1(p1) then eval_prim1(tbox,[],p1), + list(l,d) then list(map((MAML1 m1) |-> eval(tbox,m1),l),d), + alpha(m1) then alpha(glue_eval(tbox,m1)), + + + + colorize(pos,cname,text) then //colorize(pos,to_string(glue_eval(tbox,cname)),glue_eval(tbox,text)), + with name = to_string(glue_eval(tbox,cname)), + txt = glue_eval(tbox,text), + with a = glue_texts(handle_calls(*tbox.keep.call_lexer_tree_v,[name],glue_texts(txt))), + color_lexers = *tbox.keep.color_lexer_tree_v, + //print(to_string(a)+"\n"); + if get(name,color_lexers) is + { + failure then error(unknown_colorizer(name)), + success(col) then can(colorize_2b(tbox,color_lexers,[col],a)) + }, + + + + + + define(pos,name,ar,val) then //iprint("eval $define("+name+")... at "+format(pos)+"\n"); + with v = tbox.keep.macro_tree_v, + value = expand_macros(*v)(val), + v <- update(name,*v,(Maybe(List(MacroDef)) mbl) |-> if mbl is + { + failure then success([macro(name,cst_maml_arity(ar),value)]), + success(l) then success([macro(name,cst_maml_arity(ar),value) . l]) + }); empty, + undefine(pos,name) then with v = tbox.keep.macro_tree_v, + v <- update(name,*v,(Maybe(List(MacroDef)) mbl) |-> if mbl is + { + failure then failure, + success(l) then if l is + { + [ ] then failure, + [h . t] then success(t) + } + }); empty, + _if(pos,test,ift,iff) then if must_be_bool(glue_eval(tbox,test)) is + { + failure then error(boolean_expected(pos,to_string(test))), + success(b) then if b + then eval(tbox,ift) + else eval(tbox,iff) + }, + prim3(p3) then eval_prim3(tbox,p3), + computed(m2) then m2, + macro(pos,name,operands) then eval_macro(tbox,pos,name,operands), + m1 + m2 then with m1a = eval(tbox,m1), // the two 'with' are necessary for preserving + m2a = eval(tbox,m2), // execution order ('eval' is non deterministic) + m1a + m2a + }. + + + +define MAML2 + eval_macro + ( + Toolbox tbox, + MAML_Pos pos, + String name, + List(MAML1) operands + ) = + //iprint("eval_macro: "+name+"\n"); + if get(name,*tbox.keep.macro_tree_v) is + { + failure then should_not_happen(error(unknown_macro_name(make_pos(tbox),name))), + success(l) then if l is + { + [ ] then should_not_happen(error(unknown_macro_name(make_pos(tbox),name))), + [h . t] then since h is macro(_,arity,body), + with r = replace_vars_in_MAML(body,operands), + glue_eval(tbox,r) + } + }. + + + + +define MAML2 + record_colorizercall + ( + Toolbox tbox, + CCMode mode, + String cn1, + String _call, + String cn2, + String _return + ) = + with v = tbox.keep.colorcall_v, + v <- [colorcall(mode,cn1,_call,cn2,_return) . *v]; + empty. + + +define MAML2 + record_colorrule + ( + Toolbox tbox, + String cn, + String regexpr, + MAML1 value + ) = + with v = tbox.keep.colorrules_v, + v <- [rule(cn,regexpr,value) . *v]; + empty. + +define MAML2 + get_counter_value + ( + Toolbox tbox, + MAML_Pos pos, + String name + ) = + with v = tbox.keep.counter_tree_v, + if get(name,*v) is + { + failure then error(unknown_counter(pos,name)), + success(l) then if l is + { + [ ] then error(unknown_counter(pos,name)), + [h . _] then text(to_decimal(h)) + } + }. + + + + + ----------------------------------------------------------------------------------------- + + \ No newline at end of file diff --git a/anubis_dev/library/doc_tools/maml4_html.anubis b/anubis_dev/library/doc_tools/maml4_html.anubis new file mode 100644 index 0000000..96b6460 --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_html.anubis @@ -0,0 +1,195 @@ + + MAML 4 + + Generating the HTML output. + +transmit maml4_parser.anubis + + +public define Text to_HTML (MAML_HTML_Options options, + MAML3 text). + +public define MAML_HTML_Options default. + + + --- That's all for the public part ! ------------------------------------------------------------- + + + *** Default options for HTML. + +public define MAML_HTML_Options + default + = + options( + "png", // png_path_server + "png", // png_path_client + "tmp", // tmp_path + 12, // font size + 10, // footnote font size + 600 // width of text (pixels) + ). + + + *** MAML3 -> HTML + +type HTML_SpecialChar: + lt, + gt, + amp. + +type HTML_Token: + end_of_input, + text (String), + special (HTML_SpecialChar). + +define List(LexerItem(HTML_Token,One)) + html_lex_desc + = + [ + lexer_item("#<", return((ByteArray b, LexingTools t, One u) |-> ok(special(lt)))), + lexer_item("#>", return((ByteArray b, LexingTools t, One u) |-> ok(special(gt)))), + lexer_item("#&", return((ByteArray b, LexingTools t, One u) |-> ok(special(amp)))), + lexer_item("[^#<#>#&]+", return((ByteArray b, LexingTools t, One u) |-> ok(text(to_string(b))))) + ]. + +global define One + make_html_lexer + ( + List(String) _ + ) = + make_precompiled_lexer("html_lexer", html_lex_desc, '#'). + +execute anbexec make_html_lexer +read generated/html_lexer.anubis + +define List(HTML_Token) + parse_html_specials + ( + One -> LexOut(HTML_Token,One) lex + ) = + if lex(unique) is + { + error(_) then should_not_happen([]), + ok(tok) then if tok is + { + end_of_input then [], + text(s) then [text(s) . parse_html_specials(lex)], + special(c) then [special(c) . parse_html_specials(lex)] + } + }. + +define List(String) + html_assemble + ( + List(HTML_Token) l + ) = + if l is + { + [ ] then [ ], + [h . t] then if h is + { + end_of_input then should_not_happen(html_assemble(t)), + text(s) then [s . html_assemble(t)], + special(c) then [if c is + { + lt then "<", + gt then ">", + amp then "&" + } . html_assemble(t)] + } + }. + +define String + handle_html_special_chars // replace < by < etc... + ( + String s + ) = + with ls = make_lexing_stream("",s), + lex = retrieve_lexer(html_lex_desc, html_lexer, end_of_input)(ls,unique), + text = parse_html_specials(lex), + concat(html_assemble(text)). + + + + + +public define Text + to_HTML_text + ( + String path, + MAML_HTML_Options opts, + MAML3 text + ) = + if text is + { + error(me) then t(to_English(me)), + erroneous(me,m1) then t(to_English(me)), + empty then t(""), + text(value) then t(handle_html_special_chars(value)), + list(l) then sum(map((MAML3 m3) |-> to_HTML_text(path,opts,m3),l)), + postpone(pos,txt) then should_not_happen(t("")), + prim3(p3) then to_HTML_text(path,opts,p3), + m1 + m2 then to_HTML_text(path,opts,m1)+to_HTML_text(path,opts,m2) + }. + +public define Text + to_HTML + ( + String path, + MAML_HTML_Options opts, + MAML3 text + ) = + to_HTML_text(path,opts,text). + + +define String + html_head + ( + MAML_HTML_Options opts + ) = + since opts is options(spath,cpath,tpath,fsize,fnsize,twidth), +" + +". + + + +public define Text + html_encapsulate + ( + MAML_HTML_Options opts, + Text html_text + ) = + ""+html_head(default)+ + "
"+ + "
"+ + html_text+"
". + + + \ No newline at end of file diff --git a/anubis_dev/library/doc_tools/maml4_interface.anubis b/anubis_dev/library/doc_tools/maml4_interface.anubis new file mode 100644 index 0000000..46f53d5 --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_interface.anubis @@ -0,0 +1,353 @@ + + MAML4 + + The public interface (and documentation). + + +transmit tools/basis.anubis +transmit tools/ANSI-colors.anubis +transmit_tools/file_and_dir.anubis +transmit tools/2-4tree.anubis +transmit lexical_analysis/fast_lexer_5.anubis + + + + + $begin + $input(../anubis_doc.maml) + $define(mark)(1)($rgb(100,0,0)($$$1)) + + $section(MAML (The Minimalist Anubis Markup Language)) + + + MAML was first implemented in 2005 and was mainly to be used for writing texts within a + web page. It was called 'minimalist' since it was to be used by web site users, hence had + to remain very simple.$p + + After some time, a need for a more generic and flexible tool appeared. + This led to some modifications in the original MAML (this was version 2). However, we wanted + to make everything cleaner, more efficient concerning LaTeX code generation, and also easier + to use for the programer. This was version 3, and finally, this version 4 is mainly equivalent + to version 3 except that it is about 8 times faster, due to the use of the tools available in + $fname(lexical_analysis/fast_lexer_5.anubis) and $fname(tools/2-4tree.anubis).$p + + MAML texts can be translated into HTML and PDF (via LaTeX). Notice that producing HTML output + also uses LaTeX if the $mark(latex) mark is used in the MAML source text.$p + + This program requires that the following are installed if LaTeX is to be used: + $list( + $item LaTeX2e (together with some LaTeX packages; see below) + $item dvipng (used only for producing images for the HTML output in presence of the $mark(latex) mark) + ) + LaTeX2e and dvipng are available under Linux and Windows (you can use MiKTeX under Windows). + The LaTeX packages used by MAML are: + $list( + $item babel + $item inputenc + $item amsfonts + $item amsmath + $item amssymb + $item latexsym + $item xy + $item color + $item graphicx + ) + Normally, they should be all present in a standard distribution. + + $subsection(How to write texts in MAML) + + A $em(user's guide) for writing texts in MAML can be found in $fname(maml4_tutorial.maml) in $fname(library/doc_tools). + This is a MAML file that you can process as follows (provided that $fname(library/doc_tools/maml4.anubis) is first + compiled): + + $ecode(anbexec maml maml4_tutorial.maml -pdf) + + This requires that LaTeX2e and dvipng are installed because, of course, the tutorial examplifies the + $mark(latex) mark. This produces $fname(maml4_tutorial.maml.html) and $fname(maml4_tutorial.maml.pdf). Actually, + these two files are already + part of the distribution. The HTML file refers to images which are also stored in $fname(library/doc_tools).$p + + Actually, $fname(maml4_tutorial) is mainly intended for insertion into the online documentation of a web site, if this web + site wants to offer some text formating facilities to its users (for example, if it is a forum). + + + $subsection(Errors) + + Of course, syntax errors can be found during the parsing of the MAML text, and also later during + the output. Positions within source texts are formalized as: + $acode( +public type MAML_Pos: // position in a MAML text + position + (String file_path, // absolute path of the file where the error was found + String file_name, // name of this file + Int line, // line number at which the error was found + Int column, // column number + Int offset). // offset in file + +public type LexerAux: + laux (String path, + String fname). + ) + + $acode( +public type MAML_Error: + lexical (MAML_Pos pos, + LexicalError(One) lexical_error), + lexical (MAML_Pos pos, + LexicalError(LexerAux) lexical_error), + missing_end (String path, + String fname), + end_in_operand (MAML_Pos pos), + end_in_list (MAML_Pos pos), + unknown_mark (MAML_Pos pos, + String mark_name), + premature_end_of_file (String path, + String file), + missing_operand (MAML_Pos pos, + String mark_name), + file_not_found (MAML_Pos pos, + String path), + cannot_read_file (MAML_Pos pos, + String path), + cannot_open_file (String path), + cannot_create_file (String path), + cannot_write_file (String path), + cannot_execute_latex, + cannot_execute_dvipng, + png_file_corrupted (String path), + dvipng_error (Int code), + regexpr (MAML_Pos pos, + RegExprError e), + latex_error (MAML_Pos pos, + String logfname), + latex_error (Int code, + String logfname), + integer_expected (MAML_Pos pos), + must_be_a_color (MAML_Pos pos, + String s), + boolean_expected (MAML_Pos pos, + String s), + must_be_an_int (MAML_Pos pos, + String s), + must_be_a_nzint (MAML_Pos pos, + String s), + must_be_a_positive_int (MAML_Pos pos, + String s), + must_be_a_symbol (MAML_Pos pos, + String s), + string_expected (MAML_Pos pos, + String s), + invalid_initial_counter_value (MAML_Pos pos, + String value), + unknown_counter (MAML_Pos pos, + String counter_name), + unknown_macro_name (MAML_Pos pos, + String s), + invalid_number_to_add (MAML_Pos pos, + String value), + unknown_colorizer (String name), + colorizer_already_exists (MAML_Pos pos, + String name), + not_a_colorizercall_mode (MAML_Pos pos, + String s), + unknown_accumulator (MAML_Pos pos, + String name), + invalid_apply_name (MAML_Pos pos, + String name), + bad_apply_arity (MAML_Pos pos, + String name), + not_a_list (MAML_Pos pos, + String s), + misplaced_right_bracket (MAML_Pos pos), + misplaced_right_par (MAML_Pos pos). + ) + + The function below formats a MAML error into an English text. + + $acode( +public define String to_English (MAML_Error e). + ) + + + $subsection(Parsing options) + + Options can be transmitted to the MAML parser. + + $acode( +public type MAML_Option: + verbose, + pdf. // produce a PDF output (HTML only by default) + ) + + + $subsection(Generating an HTML output) + + A MAML source text is read through the use of a $em(lexing stream) as defined in: + $acode( +read lexical_analysis/fast_lexer_5.anubis + ) + This allows to read MAML texts from files, network connections and character strings (and more; see + $fname(fast_lexer_5.anubis)). You can of course also use the $ref(cmdlinetool)(command line tool + $att(maml)).$p + + In order to produce an HTML or a PDF output, you need to provide some parameters. These parameters + are gathered into a datum of type $att(MAML_HTML_Options) for HTML output and $att(MAML_PDF_Options) for + PDF output. + $acode( +public type MAML_HTML_Options:... (explained below) + ) + There is a default value: + $acode( +public define MAML_HTML_Options default. + ) + + We use the type $att(Text) for storing texts. This is a variant of $att(Printable_tree). Such data can + be printed. + $acode( +public type Text:... +public define One print(WStream s, Text text). + ) + In order to produce an HTML output, use the following: + $acode( +public define Result(MAML_Error,Text) + to_HTML + ( + List(MAML_Option) maml_options, + LexingStream maml_source, + MAML_HTML_Options options // you can put 'default' here + ). + ) + + $subsection(Generating LaTeX and PDF output) + + Again there are options and a default value: + $acode( +public type MAML_PDF_Options:... +public define MAML_PDF_Options default. + ) + + $acode( +public define Result(MAML_Error,Text) + to_PDF + ( + List(MAML_Option) maml_options, + LexingStream maml_source, + Maybe((String,String)) pdf_output_path_and_name, + // no output file if 'failure' + MAML_PDF_Options options + // you can put 'default' here + ). + ) + + Putting $att(failure) for $att(pdf_output_path_and_name) is used if one wants only the LaTeX text. + + + $subsection(Managing options) + + If you are not satisfied by the default options, you can create your own by defining data of + these types: + $acode( +public type MAML_HTML_Options: + options + ( + // directories: + String png_path_server, + // the directory where dvipng generated images will be stored + // for example: site_directory/"public/png" + String png_path_client, + // the same one but seen from the client viewpoint (i.e. included + // in the HTML text) in this case: "png" since site_directory/"public" + // is the root from the client viewpoint + String tmp_path, + // the directory for temporary files on the server (.tex, .dvi, .aux, ...) + + // Sizes: + Int font_size, + // font size for main text (in pixels) + Int note_font_size, + // font size for text in footnotes + Int text_width + // width of text in pixels + ). + ) + + $acode( +public type MAML_PDF_Options: + options + ( + // directories: + String tmp_path, + // the directory for temporary files (.tex, .dvi, .aux, .log, ...) + + // LaTeX specific: + String babel_language, + // the language for the Babel package ("english", "french", ...) + String add_to_preambule, + // what you want to add just before \begin{document} + Int page_width, + // in millimeters + Int page_height + // in millimeters + ). + ) + + You can of course use the value $att("") for $att(add_to_preambule). If you want to include a table of contents, + use $att($mark(ifpdf)(\tableofcontents)) in your MAML source, etc... + + + $subsection(Parsing MAML first) + + Here is how to avoid parsing twice the MAML source text if you want to produce both outputs. + You can first parse the MAML source, which yields a datum of type: + $acode( +public type MAML3:... + public type alias MAML = MAML3. + +public define Result(MAML_Error,MAML3) + parse_MAML + ( + List(MAML_Option) maml_options, + LexingStream s + ). + ) + and from this datum produce the HTML, LaTeX and PDF outputs: + $acode( +public define Result(MAML_Error,Text) + to_HTML + ( + MAML3 maml_text, + MAML_HTML_Options options // you can put 'default' here + ). + +public define Result(MAML_Error,Text) + to_PDF + ( + MAML3 maml_text, + Maybe(String) pdf_output_path_and_name, // no output file if 'failure' + MAML_PDF_Options options // you can put 'default' here + ). + ) + + $define(nl)(0)( +) + + $label(cmdlinetool) + $subsection(Command line tool) + $acode($id($nl)anbexec maml $nt(file) $nt(options) + ) + The command line tool $att(maml) reads the file given as its argument, but only between + the marks $mark(begin) and $mark(end). These pairs of marks can be present several times + in the file and the texts they delimit are all parsed.$p + + The option $att(-pdf) tells maml to produce a PDF output (by default, it produces a HTML + output only).$p + + An option $att(-verbose) is also available. + + + $end + + + + + diff --git a/anubis_dev/library/doc_tools/maml4_lexers.anubis b/anubis_dev/library/doc_tools/maml4_lexers.anubis new file mode 100644 index 0000000..d6bdb34 --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_lexers.anubis @@ -0,0 +1,352 @@ + + + MAML4 + The lexers. + +transmit maml4_private.anubis + + We need 5 lexers (to be constructed by fast_lexer_5), which are: + + - (1) the 'skip' lexer for reading outside the pairs $begin $end + - (2) the 'out' lexer for reading between $begin and $end but outside any mark operand + - (3) the 'blank' lexer for skipping blanks before operands + - (4) the 'in' lexer for reading mark operands as MAML texts + - (5) the 'verb' lexer for reading mark operands as verbatim text + + The reason why there is an 'out' and an 'in' lexer is that the 'out' lexer doesn't care about + parentheses (which can be unbalanced), whereas the 'in' lexer must care about parenthese + (which must be balanced). Of course, the 'verb' lexer also has to care about parentheses, but not + about mark names. + + We precompile these lexers separately (i.e. as 'single state lexers'). Each lexer has + his own type of tokens. + + + + + *** A tool for stripping the dollar. + +define ByteArray + strip_dollar + ( + ByteArray b + ) = + extract(b,1,length(b)). + + + *** The 'skip' lexer. + +define List(LexerItem(SkipToken,One)) + skip_lexer_desc + = + [ + lexer_item("#$begin", return((ByteArray b, LexingTools t, One u) |-> ok(begin))), + + lexer_item("#$b[^e]", ignore), + lexer_item("#$be[^g]", ignore), + lexer_item("#$beg[^i]", ignore), + lexer_item("#$begi[^n]", ignore), + lexer_item("(.)|(#n)", ignore) + ]. + + + *** The 'out' lexer. + +define List(LexerItem(OutToken,LexerAux)) + out_lexer_desc + = + [ + // $end, $colorize, ... + lexer_item("#$end", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(end))), + lexer_item("#$colorize", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(colorize(make_pos(t,a))))), + lexer_item("#$define", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(define(make_pos(t,a))))), + lexer_item("#$undefine", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(undefine(make_pos(t,a))))), + lexer_item("#$if", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(_if(make_pos(t,a))))) + ] + // primitive marks + +prims_lexer_items(prim1,prim3)+ + [ + // special syntaxes for $ + lexer_item("(#$# )|(#$#$)", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(prim1(_dollar(make_pos(t,a)))))), + + // other mark names + lexer_item("#$[a-zA-Z_][a-zA-Z_0-9]*", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(macro(make_pos(t,a),to_string(strip_dollar(b)))))), + + // line comments $// bla bla + lexer_item("#$//.*" , ignore), + + // lines of text + lexer_item("[^#$#n]+", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(text(to_string(b))))), + + // newline + lexer_item("#n", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(text("\n")))) + ]. + + + *** The 'blank' lexer. + +define List(LexerItem(BlankToken,One)) + blank_lexer_desc + = + [ + // line comments $// bla bla + lexer_item("[# #r#n#t]*#$//.*" , ignore), + + // skipping blanks until lpar. + lexer_item("[# #r#n#t]*#(", + return((ByteArray b, LexingTools t, One u) |-> ok(lpar))) + ]. + + + *** The 'in' lexer. + +public define Int // also used in 'maml4_eval.anubis' + decscan // a decimal_scan which cannot fail + ( + String s + ) = + if decimal_scan(s) is + { + failure then should_not_happen(0), + success(n) then n + }. + + + + The 'in' lexer description. + +define List(LexerItem(InToken,LexerAux)) + in_lexer_desc + = + [ + // $end, $colorize, ... + lexer_item("#$end", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(end))), + lexer_item("#$colorize", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(colorize(make_pos(t,a))))), + lexer_item("#$define", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(define(make_pos(t,a))))), + lexer_item("#$undefine", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(undefine(make_pos(t,a))))), + lexer_item("#$if", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(_if(make_pos(t,a))))), + lexer_item("#$alphabetic", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(alpha(make_pos(t,a))))), + + // square brackets and the comma + lexer_item("[# #r#n]*#[[# #r#n]*", + return((ByteArray b, LexingTools t, LexerAux a) |-> //iprint("in_lexer: saw a [ at "+format(make_pos(t,a))+"\n"); + ok(lbrk(to_string(b))))), + lexer_item("[# #r#n]*#][# #r#n]*", + return((ByteArray b, LexingTools t, LexerAux a) |-> //iprint("in_lexer: saw a ] at "+format(make_pos(t,a))+"\n"); + ok(rbrk(to_string(b))))), + lexer_item("[# #r#n]*#,[# #r#n]*", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(comma(to_string(b))))), + + // special characters + lexer_item("#(", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(lpar))), + lexer_item("#)", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(rpar))) + ] + // primitive marks + +prims_lexer_items(prim1,prim3)+ + [ + // inhibited special characters + lexer_item("#$#,", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(text(",")))), + lexer_item("#$#(", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(text("(")))), + lexer_item("#$#)", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(text(")")))), + lexer_item("#$#[", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(text("[")))), + lexer_item("#$#]", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(text("]")))), + lexer_item("#$#$", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(text("$")))), + lexer_item("#$", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(text("$")))), + + // mark names + lexer_item("#$[a-zA-Z_][a-zA-Z_0-9]*", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(macro(make_pos(t,a),to_string(strip_dollar(b)))))), + + // MAML variables + lexer_item("#$[0-9]+", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(variable(decscan(to_string(strip_dollar(b))))))), + + // lines of text + lexer_item("[^#$#n#(#)#[#]#,]+", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(text(to_string(b))))), + + // line comments $// bla bla + lexer_item("#$//.*" , ignore), + + // newline + lexer_item("#n", + return((ByteArray b, LexingTools t, LexerAux a) |-> ok(text("\n")))) + ]. + + + *** The 'verb' lexer. + + +define List(LexerItem(VerbToken,One)) + verb_lexer_desc + = + [ + lexer_item("#$lpar", return((ByteArray b, LexingTools t, One u) |-> ok(text("(")))), + lexer_item("#$rpar", return((ByteArray b, LexingTools t, One u) |-> ok(text(")")))), + lexer_item("#$", return((ByteArray b, LexingTools t, One u) |-> ok(dollar))), + lexer_item("[^#(#)#n#$]+", return((ByteArray b, LexingTools t, One u) |-> //iprint("verb_lex: text: "+to_string(b)+"\n"); + ok(text(to_string(b))))), + lexer_item("#n", return((ByteArray b, LexingTools t, One u) |-> ok(text("\n")))), + lexer_item("#(", return((ByteArray b, LexingTools t, One u) |-> ok(lpar))), + lexer_item("#)", return((ByteArray b, LexingTools t, One u) |-> ok(rpar))) + ]. + + + *** The 'color_value' lexer. + +public define List(LexerItem(ColorValueToken,One)) + color_value_lexer_desc + = + [ + lexer_item("[0-9]+", return((ByteArray b, LexingTools t, One u) |-> ok(int(decscan(to_string(b)))))), + lexer_item("#,", return((ByteArray b, LexingTools t, One u) |-> ok(comma))) + ]. + + *** The 'symbol' lexer. + +public define List(LexerItem(SymbolToken,One)) + symbol_lexer_desc + = + [ + lexer_item("[A-Za-z#_][A-Za-z0-9#_]*", return((ByteArray b, LexingTools t, One u) |-> ok(symbol))), + ]. + + +global define One + make_maml4_lexers + ( + List(String) _ + ) = + make_precompiled_lexer("skip_lexer", skip_lexer_desc, '#'); + make_precompiled_lexer("out_lexer", out_lexer_desc, '#'); + make_precompiled_lexer("blank_lexer", blank_lexer_desc, '#'); + make_precompiled_lexer("in_lexer", in_lexer_desc, '#'); + make_precompiled_lexer("verb_lexer", verb_lexer_desc, '#'); + make_precompiled_lexer("color_value_lexer", color_value_lexer_desc, '#'); + make_precompiled_lexer("symbol_lexer", symbol_lexer_desc, '#'). + + +execute anbexec make_maml4_lexers + +read generated/skip_lexer.anubis +read generated/out_lexer.anubis +read generated/blank_lexer.anubis +read generated/in_lexer.anubis +read generated/verb_lexer.anubis + + Below we must use 'transmit' because the lexers are used in another file. + +transmit generated/color_value_lexer.anubis +transmit generated/symbol_lexer.anubis + + + *** Making a toolbox for parsing a file. + + +public define Toolbox + make_toolbox + ( + String fpath, + String fname, + LexingStream ls, + ToolboxKeep keep + ) = + with skip_lex = retrieve_lexer( skip_lexer_desc, skip_lexer, end_of_input)(ls,unique), + out_lex = retrieve_lexer( out_lexer_desc, out_lexer, end_of_input)(ls,laux(fpath,fname)), + blank_lex = retrieve_lexer( blank_lexer_desc, blank_lexer, end_of_input)(ls,unique), + in_lex = retrieve_lexer( in_lexer_desc, in_lexer, end_of_input)(ls,laux(fpath,fname)), + verb_lex = retrieve_lexer( verb_lexer_desc, verb_lexer, end_of_input)(ls,unique), + toolbox( + fpath, + fname, + ls, + skip_lex, + out_lex, + blank_lex, + in_lex, + verb_lex, + keep). + +public define SpecLex(ColorValueToken) + make_color_value_lexer + ( + One u + ) = + retrieve_lexer(color_value_lexer_desc, color_value_lexer, end_of_input). + +public define SpecLex(SymbolToken) + make_symbol_lexer + ( + One u + ) = + retrieve_lexer(symbol_lexer_desc, symbol_lexer, end_of_input). + +public define MAML2 glue_eval (Toolbox tbox, MAML1 m). + + + +define MAML2 + apply_macro + ( + Toolbox tbox, + String name, + MAML1 body, // of macro definition + List(MAML1) ops // already computed operands + ) = + //iprint("\nmacro name: "+name+"\n"); + //iprint("body = "+to_string_all(body)+"\n"); + //iprint("ops: "+concat(map(to_string_all,ops),"-----")+"\n"); + with result = replace_vars_in_MAML(body,ops), + //iprint("result: "+to_string(result)+"\n"); + eval(tbox,result). + + + + +public define Result(MAML_Error,MAML2 -> MAML2) + get_apply_function + ( + Toolbox tbox, + MAML_Pos pos, + String name // must be the name of a macro + ) = + with ls = make_lexing_stream("$",name), + lex = retrieve_lexer(in_lexer_desc,in_lexer,end_of_input)(ls,laux("","")), + if lex(unique) is + { + error(e) then error(lexical(pos,e)), + ok(tok) then + if tok is macro(_,mname) + then if get(mname,*tbox.keep.macro_tree_v) is + { + failure then error(unknown_macro_name(pos,name)), + success(defs) then if defs is + { + [ ] then error(unknown_macro_name(pos,name)), + [h . t] then since h is macro(_,arity,body), + if length(arity) = 1 + then ok((MAML2 m) |-> apply_macro(tbox,name,body,[computed(m)])) + else error(bad_apply_arity(pos,name)) + } + } + else error(invalid_apply_name(pos,name)) + }. + + + + + + \ No newline at end of file diff --git a/anubis_dev/library/doc_tools/maml4_parser.anubis b/anubis_dev/library/doc_tools/maml4_parser.anubis new file mode 100644 index 0000000..e724dfd --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_parser.anubis @@ -0,0 +1,597 @@ + + MAML4 + + The parser. + +transmit maml4_eval.anubis + + The MAML4 parser is 'hand made' because APG appears to be inappropriate in this case. + Indeed, the MAML grammar is not LALR1 because detecting the end of a sequence of + operands depends on the arity of the mark, which is not of a syntactic nature in the + case of macros (for primitives, the arity is known to the lexer; recall that a macro + cannot be defined with the name of a primitive). Furthermore, + the MAML syntax is also quite simple. Hence, we have a 'hand made' parser, using the + lexers defined in maml4_lexers.anubis. + + Nevertheless, the MAML grammar is not as simple as it may seem at first glance. Indeed, + we must keep in mind that: + + - (1) Parentheses must be balanced within operands of marks, but can very well not be + balanced outside any operand. + - (2) Some operands must be parsed in verbatim mode, others in maml mode. + + For designing our parser we must choose one of these methods: + + - (1) the parser stops after the first error encountered, + - (2) the parser stores errors into the maml result and doesn't stop (possibly before + a given number of errors is found). + + The second method is better for at least two reasons: + - the programming is simpler, + - the user can discover several errors in a single compilation. + + So, we choose the second method. This is why the type MAML1 has an alternative 'error' + (and an alternative 'erroneous'), allowing to insert errors into the output of the parser. + + + + In this file, we define: + +public define MAML2 parse_eval (Toolbox tbox). + + which parses and evaluates a MAML text, beginning in 'skip' mode. + + + --- That's all for the public part ! --------------------------------------------------- + + + *** Return type for parsing elements of list. + + +type ListElem: // returning a list element together with how it was delimited + error (MAML1), // in case of an error the delimiter is not known + rbrk (MAML1, String), // list element delimited by a right bracket (with its decoration) + comma (MAML1, String). // list element delimited by a comma (with its decoration) + + + + *** Auxiliary (cross-recursive) functions. + +define MAML2 parse_skip (Toolbox tbox). +define MAML2 parse_out (Toolbox tbox). +define MAML1 parse_in (Toolbox tbox). +define MAML1 parse_colorize (Toolbox tbox, MAML_Pos pos). +define MAML1 parse_define (Toolbox tbox, MAML_Pos pos). +define MAML1 parse_undefine (Toolbox tbox, MAML_Pos pos). +define MAML1 parse_alpha (Toolbox tbox, MAML_Pos pos). +define (List(MAML1), + List(String)) parse_list (Toolbox tbox, List(MAML1) m_so_far, List(String) d_so_far). +define MAML1 parse_if (Toolbox tbox, MAML_Pos pos). +define MAML1 parse_in_operand (Toolbox tbox). +define ListElem parse_list_elem (Toolbox tbox). +define MAML1 parse_in_verbatim (Toolbox tbox). +define MAML1 parse_maml_operand (Toolbox tbox, String mark_name). +public define MAML1 parse_operand (Toolbox tbox, ParseMode mode, String mark_name). +define MAML1 parse_verbatim_operand (Toolbox tbox, String mark_name). +define MAML1 parse_macro (Toolbox tbox, MAML_Pos pos, String name). +define List(MAML1) parse_several_operands (Toolbox tbox, Int arity, String mark_name). +define (MAML1,MAML1) parse_2_operands (Toolbox tbox, ParseMode mode1, ParseMode mode2, String mark_name). +define (MAML1,MAML1,MAML1) parse_3_operands (Toolbox tbox, ParseMode mode1, ParseMode mode2, ParseMode mode3, String mark_name). + + + 'parse_prim1' and 'parse_prim3' are defined in generated/prim2.anubis, and need + 'parse_operand(Toolbox,ParseMode)'. This is why this function is declared 'public' above. + + + *** From Here, parse functions produce MAML1 data because they don't evaluate. + + + + Now parsing an operand of list element. + +define MAML1 + parse_in // parsing within an operand. The opening parenthese is already parsed. + ( + Toolbox tbox, + ) = + if tbox.in_lex(unique) is + { + error(e) then error(lexical(make_pos(tbox),e)), + ok(tok) then if tok is + { + end_of_input then error(premature_end_of_file(tbox.file_path,tbox.file_name)), + end then error(end_in_operand(make_pos(tbox))), + lpar then with m = parse_in(tbox), + with n = parse_in(tbox), + text("(")+m+text(")")+n, + rpar then empty, // end of operand + lbrk(d) then //iprint("parse_in: At "+format(make_pos(tbox))+" seen a [\n"); + with m = parse_list(tbox,[],[d]), + with n = parse_in(tbox), + since m is (l,dec), + list(l,dec)+n, + rbrk(d) then error(misplaced_right_bracket(make_pos(tbox))), + comma(d) then with n = parse_in(tbox), + text(d)+n, + prim1(name) then //iprint("parse_in: prim1\n"); + with m = parse_prim1(tbox,name), + //iprint("got a: "+to_string(m)+"\n"); + with n = parse_in(tbox), + m+n, + alpha(pos) then with m = parse_alpha(tbox,pos), + with n = parse_in(tbox), + m+n, + colorize(pos) then with m = parse_colorize(tbox,pos), + with n = parse_in(tbox), + m+n, + define(pos) then with m = parse_define(tbox,pos), + with n = parse_in(tbox), + m+n, + undefine(pos) then with m = parse_undefine(tbox,pos), + with n = parse_in(tbox), + m+n, + _if(pos) then with m = parse_if(tbox,pos), + with n = parse_in(tbox), + m+n, + prim3(name) then with m = parse_prim3(tbox,name), + with n = parse_in(tbox), + m+n, + text(value) then with m = (MAML1)text(value), + with n = parse_in(tbox), + m+n, + macro(pos,name) then with m = parse_macro(tbox,pos,name), + with n = parse_in(tbox), + m+n, + variable(id) then with n = parse_in(tbox), + variable(id)+n + } + }. + + +define ListElem + MAML1 m + ListElem n + = + if n is + { + error(e) then error(m+e), + rbrk(e,d) then rbrk(m+e,d), + comma(e,d) then comma(m+e,d) + }. + +define ListElem + parse_list_elem // parsing within square brackets. The opening bracket or leading comma is already parsed. + ( + Toolbox tbox, + ) = + if tbox.in_lex(unique) is + { + error(e) then error(error(lexical(make_pos(tbox),e))), + ok(tok) then if tok is + { + end_of_input then error(error(premature_end_of_file(tbox.file_path,tbox.file_name))), + end then error(error(end_in_list(make_pos(tbox)))), + lpar then with m = parse_in(tbox), + with n = parse_list_elem(tbox), + (text("(")+m+text(")"))+n, + rpar then error(error(misplaced_right_par(make_pos(tbox)))), + lbrk(d) then //iprint("parse_list_elem: At "+format(make_pos(tbox))+" seen a [\n"); + with m = parse_list(tbox,[],[d]), + //iprint("Got this: "+to_string(list(m))+"\n"); + with n = parse_list_elem(tbox), + since m is (l,dec), + list(l,dec)+n, + rbrk(d) then //iprint("parse_list_elem: At "+format(make_pos(tbox))+" seen a ]\n"); + rbrk(empty,d), + comma(d) then //iprint("parse_list_elem: At "+format(make_pos(tbox))+" seen a ,\n"); + comma(empty,d), + prim1(name) then with m = parse_prim1(tbox,name), + with n = parse_list_elem(tbox), + m+n, + alpha(pos) then with m = parse_alpha(tbox,pos), + with n = parse_list_elem(tbox), + m+n, + colorize(pos) then with m = parse_colorize(tbox,pos), + with n = parse_list_elem(tbox), + m+n, + define(pos) then with m = parse_define(tbox,pos), + with n = parse_list_elem(tbox), + m+n, + undefine(pos) then with m = parse_undefine(tbox,pos), + with n = parse_list_elem(tbox), + m+n, + _if(pos) then with m = parse_if(tbox,pos), + with n = parse_list_elem(tbox), + m+n, + prim3(name) then with m = parse_prim3(tbox,name), + with n = parse_list_elem(tbox), + m+n, + text(value) then with m = (MAML1)text(value), + with n = parse_list_elem(tbox), + m+n, + macro(pos,name) then with m = parse_macro(tbox,pos,name), + with n = parse_list_elem(tbox), + m+n, + variable(id) then with n = parse_list_elem(tbox), + variable(id)+n + } + }. + + + +define (List(MAML1),List(String)) + parse_list + ( + Toolbox tbox, + List(MAML1) m_so_far, + List(String) d_so_far + ) = + if parse_list_elem(tbox) is + { + error(e) then (reverse([e . m_so_far]),reverse(d_so_far)), + rbrk(elem,d) then (reverse([elem . m_so_far]),reverse([d . d_so_far])), + comma(elem,d) then parse_list(tbox,[elem . m_so_far],[d . d_so_far]) + }. + + + + + + + *** Parsing the next expected operand (assumed not verbatim). + +define MAML1 + parse_maml_operand + ( + Toolbox tbox, + String mark_name + ) = + if tbox.blank_lex(unique) is + { + error(e) then error(missing_operand(make_pos(tbox),mark_name)), + ok(tok) then if tok is + { + end_of_input then error(premature_end_of_file(tbox.file_path,tbox.file_name)), + lpar then parse_in(tbox) + } + }. + + + *** Parsing the next expected operand (assumed verbatim). + +define MAML1 + parse_verbatim_operand // parsing an expected verbatim operand + ( + Toolbox tbox, + String mark_name + ) = + if tbox.blank_lex(unique) is + { + error(e) then error(missing_operand(make_pos(tbox),mark_name)), + ok(tok) then if tok is + { + end_of_input then error(premature_end_of_file(tbox.file_path,tbox.file_name)), + lpar then parse_in_verbatim(tbox) + } + }. + +define MAML1 + parse_in_verbatim // parsing within a verbatim operand + ( + Toolbox tbox + ) = + if tbox.verb_lex(unique) is + { + error(e) then error(lexical(make_pos(tbox),e)), + ok(tok) then if tok is + { + end_of_input then error(premature_end_of_file(tbox.file_path,tbox.file_name)), + lpar then with m = parse_in_verbatim(tbox), + with n = parse_in_verbatim(tbox), + text("(")+m+text(")")+n, + rpar then empty, + dollar then with n = parse_in_verbatim(tbox), + text("$")+n, + text(content) then with n = parse_in_verbatim(tbox), + text(content)+n + } + }. + + + + *** Parsing all sorts of expected operands. + +public define MAML1 + parse_operand + ( + Toolbox tbox, + ParseMode mode, + String mark_name + ) = + if mode is + { + maml then parse_maml_operand(tbox,mark_name), + maml(mb) then parse_maml_operand(tbox,mark_name), // checking the form is done after eval. + verb then parse_verbatim_operand(tbox,mark_name) + }. + + + *** Parsing 2 and 3 operands. + +define (MAML1,MAML1) + parse_2_operands + ( + Toolbox tbox, + ParseMode mode1, + ParseMode mode2, + String mark_name + ) = + // with is necessary because of the order of execution of non deterministic parsing + with m1 = parse_operand(tbox,mode1,mark_name), + m2 = parse_operand(tbox,mode2,mark_name), + (m1,m2). + +define (MAML1,MAML1,MAML1) + parse_3_operands + ( + Toolbox tbox, + ParseMode mode1, + ParseMode mode2, + ParseMode mode3, + String mark_name + ) = + with m1 = parse_operand(tbox,mode1,mark_name), + m2 = parse_operand(tbox,mode2,mark_name), + m3 = parse_operand(tbox,mode3,mark_name), + (m1,m2,m3). + + + *** Parsing several operands (used for parsing operands of macros). + +define List(MAML1) + parse_several_operands // parse several operands as indicated by 'arity' + ( + Toolbox tbox, + Int arity, + String mark_name + ) = + if arity =< 0 then [ ] else + with a1 = parse_operand(tbox,maml,mark_name), + t1 = parse_several_operands(tbox,arity-1,mark_name), + [a1 . t1]. + + + *** Parsing macros. + +define MAML1 + parse_macro + ( + Toolbox tbox, + MAML_Pos pos, + String name + ) = + //iprint("Parsing macro "+name+": "); + if get_macro_arity(tbox,name) is + { + failure then //iprint("error name not found\n"); + error(unknown_macro_name(pos,name)), + success(ar) then //iprint("ok "+ar+" operands\n"); + with ops = parse_several_operands(tbox,ar,name), + macro(pos,name,ops) + }. + + + + + + + + *** Special cases. + + *** Parsing a '$colorize...'. + +define MAML1 + parse_colorize + ( + Toolbox tbox, + MAML_Pos pos + ) = + if parse_2_operands(tbox,maml(symbol),maml,"$colorize") is (m1,m2) then + colorize(pos,m1,m2). + + + + + *** Parsing a '$define...'. + +define One + record_macro_arity + ( + Toolbox tbox, + String name, + Int ar, + ) = + //iprint("Recording macro '"+name+"' arity = "+ar+"\n"); + with v = tbox.keep.arity_tree_v, + v <- update(name,*v,(Maybe(List(Int)) mbl) |-> if mbl is + { + failure then success([ar]), + success(l) then success([ar . l]) + }). + +define MAML1 + parse_define + ( + Toolbox tbox, + MAML_Pos pos + ) = + //iprint("Parsing a $define\n"); + since parse_3_operands(tbox,maml(symbol),maml(pint),maml,"$define") is (_name,_arity,_value), + if must_be_symbol(text(to_string(_name))) is + { + failure then error(must_be_a_symbol(pos,to_string(_name))), + success(name) then if must_be_pint(text(to_string(_arity))) is + { + failure then error(must_be_a_positive_int(pos,to_string(_arity))), + success(arity) then record_macro_arity(tbox,name,arity); + define(pos,name,arity,_value) + } + }. + + + *** Parsing an '$undefine...'. + +define MAML1 + parse_undefine + ( + Toolbox tbox, + MAML_Pos pos + ) = + with _name = parse_operand(tbox,maml(symbol),"$undefine"), + if must_be_symbol(text(to_string(_name))) is + { + failure then error(must_be_a_symbol(pos,to_string(_name))), + success(name) then with v = tbox.keep.arity_tree_v, + since ((ArityTree,(Maybe(List(Int)),MAML2)))get_update(name,*v,(Maybe(List(Int)) mbl) |-> if mbl is + { + failure then (failure,empty), + success(l) then if l is + { + [ ] then (failure,empty), + [h . t] then (success(t),empty) + } + }) is (new_tree,_), + v <- new_tree; + undefine(pos,name) + }. + + +define MAML1 + parse_alpha + ( + Toolbox tbox, + MAML_Pos pos + ) = + with a = parse_maml_operand(tbox,"$alphabetic"), + alpha(a). + + define MAML1 + parse_alpha_in_list + ( + Toolbox tbox, + MAML_Pos pos + ) = + with a = parse_maml_operand_in_list(tbox,"$alphabetic"), + alpha(a). + + +define MAML1 + parse_if + ( + Toolbox tbox, + MAML_Pos pos + ) = + since parse_3_operands(tbox,maml(bool),maml,maml,"$if") is (_test,_iftrue,_iffalse), + _if(pos,_test,_iftrue,_iffalse). + + + + *** Parsing before $begin. + +define MAML2 + parse_skip + ( + Toolbox tbox + ) = + if tbox.skip_lex(unique) is // skip until the first $begin + { + error(e) then error(lexical(make_pos(tbox),e)), + ok(tok) then if tok is + { + end_of_input then empty, // no $begin found + begin then parse_out(tbox) + } + }. + + + + *** Parsing between $begin and $end (and evaluating). + +define MAML2 + parse_out // this is for parsing outside any operand + ( + Toolbox tbox + ) = + if tbox.out_lex(unique) is + { + error(e) then error(lexical(make_pos(tbox),e)), + ok(tok) then if tok is + { + end_of_input then error(premature_end_of_file(tbox.file_path,tbox.file_name)), + end then parse_skip(tbox), // returning to 'skip' mode. + prim1(name) then with m = glue_eval(tbox,parse_prim1(tbox,name)), + with n = parse_out(tbox), + m+n, + colorize(pos) then with m = glue_eval(tbox,parse_colorize(tbox,pos)), + with n = parse_out(tbox), + m+n, + define(pos) then with m = glue_eval(tbox,parse_define(tbox,pos)), + with n = parse_out(tbox), + m+n, + undefine(pos) then with m = glue_eval(tbox,parse_undefine(tbox,pos)), + with n = parse_out(tbox), + m+n, + _if(pos) then with m = glue_eval(tbox,parse_if(tbox,pos)), + with n = parse_out(tbox), + m+n, + prim3(name) then with m = glue_eval(tbox,parse_prim3(tbox,name)), + with n = parse_out(tbox), + m+n, + text(value) then with n = parse_out(tbox), + text(value)+n, + macro(pos,name) then with m = glue_eval(tbox,parse_macro(tbox,pos,name)), + with n = parse_out(tbox), + m+n + } + }. + + + *** The public tool (parse and eval). + +public define MAML2 + parse_eval + ( + Toolbox tbox + ) = + parse_skip(tbox). + + + *** Executing postponed expressions. + +public define MAML2 + execute_postponed + ( + Toolbox tbox, + MAML2 m + ) = + if m is + { + error(me) then m, + erroneous(me,text) then m, + empty then m, + false then m, + true then m, + text(value) then m, + variable(id) then m, + list(l,d) then list(map((MAML2 m2) |-> execute_postponed(tbox,m2),l),d), + alpha(m1) then alpha(execute_postponed(tbox,m1)), + colorize(pos,cname,operand) then colorize(pos,cname,execute_postponed(tbox,operand)), + postpone(pos,text) then eval(tbox,text), + prim3(p3) then prim3(map((MAML2 p) |-> execute_postponed(tbox,p),p3)), + m1 + m2 then with m1e = execute_postponed(tbox,m1), + m2e = execute_postponed(tbox,m2), + m1e + m2e + }. + + + + \ No newline at end of file diff --git a/anubis_dev/library/doc_tools/maml4_pdf.anubis b/anubis_dev/library/doc_tools/maml4_pdf.anubis new file mode 100644 index 0000000..813e311 --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_pdf.anubis @@ -0,0 +1,4 @@ + + +transmit maml4_html.anubis + diff --git a/anubis_dev/library/doc_tools/maml4_png.anubis b/anubis_dev/library/doc_tools/maml4_png.anubis new file mode 100644 index 0000000..a58f7ea --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_png.anubis @@ -0,0 +1,212 @@ + + + MAML 4 + + The PNG stuff. + +transmit maml4_lexers.anubis + + Because there is a $latex mark in MAML, we need to transform peices of LaTeX text into images + to be inserted into the HTML output. Hopefully, there is a tool, 'dvipng' able to transform + a .dvi file (produced by LaTeX) into a PNG image with transparent background. + + We also have to ensure that the base line of LaTeX formulas is at the same height as the base + line of the surrounding HTML text. In order to achieve this, we create a first image with a + TeX \rule of height 50 points so that we know that the TeX base line in 50 point below the top + of the image. Next, we create a second without the \rule, and comparing the heights of the two + images allows to compute the number of pixels that the image must be shifted up or down in the + HTML text. + + +read web/web_arg_encode.anubis (used for creating file names) +read graphism/png_size.anubis ('png_image_size' needed) +read system/files.anubis ('copy_file' needed) + + + We need to know the number of pixels a PNG image must be moved down in the HTML output (so that the + LaTeX baseline is at the same height as the surrounding HTML baseline). + +public type ResultPNG_down: + error (MAML_Error), // MAML error + log_file (String fname), // LaTeX error + png_file_down (String fname, // name of PNG image file + Int width, // of image + Int height, + Int down). // number of pixels the image must be shifted down in the HTML page + + +public define ResultPNG_down latex_to_png (String text, // a LaTex body + MAML_HTML_Options opts). + + + --- That's all for the public part ! ----------------------------------------------------- + + + We define a LaTeX preambule and a LaTeX postambule for constructing the LaTeX source file. + +define String + latex_png_preambule + = +"\\documentclass[12pt]{article} +\\usepackage[english]{babel} +\\usepackage[utf8]{inputenc} +\\usepackage[T1]{fontenc} +\\usepackage{amsfonts,amsmath,amssymb} +\\usepackage{latexsym} +\\usepackage[all]{xy} +\\usepackage{color} +\\pagestyle{empty} +\\textwidth20cm +\\textheight30cm +\\begin{document} +{\\Huge +". + + +define String + latex_png_postambule + = +" +} +\\end{document} + +". + + + *** Checking if a LaTeX body contains a display $$....$$. + +public define Bool + has_a_display + ( + String latex_text + ) = + if find_string(latex_text,"$$",0) is + { + failure then false, + success(_) then true + }. + + + + *** Making a PNG image file. + + The type below is for returning a pair (,) where is the height in + pixels of the image contained in the PNG file. It can return a MAML error or a LaTeX error. + +type ResultPNG_height: + error (MAML_Error), // MAML error + log_file (String fname), // LaTeX error + png_file_height (String fname, Int height). // height of image in pixels + + +define ResultPNG_height + make_png_file + ( + String text, // LaTeX body + String fname, // a common name for the files + Bool true_png_file, // false for the temporary png file + MAML_HTML_Options opts + ) = + //iprint("(1) LaTeX text: ["+text+"]\n"); + since opts is options(spath,cpath,tpath,fsize,fnsize,twidth), + forget(make_directory(spath,default_directory_mode)); + forget(make_directory(cpath,default_directory_mode)); + forget(make_directory(tpath,default_directory_mode)); + with fnametex = fname+".tex", // actual name of the .tex file + fnamedvi = fname+".dvi", // idem .dvi file + fnamepng = fname+".png", // idem .png file + if write_to_file(tpath/fnametex, + to_byte_array(latex_png_preambule+text+latex_png_postambule)) is + { + cannot_open_file then error(cannot_create_file(tpath/fnametex)), + write_error(_) then error(cannot_write_file(tpath/fnametex)), + ok then if (Maybe(Word8))execute(success(tpath),"latex", + ["-no-shell-escape", // avoid security problems + "-interaction=batchmode", // quiet mode + //"nonstopmode", // avoid stopping + fnametex]) is + { + failure then error(cannot_execute_latex), + success(rcode1) then if rcode1 /= 0 + then + ( + /* return the error code and path of log file */ + log_file((tpath/fname)+".log") + ) + else + // The DVI file is okay. Convert it to PNG. + if (Maybe(Word8))execute(success(tpath),"dvipng", + ["-T","tight","-Q","8","-bg","Transparent","-o",fnamepng,fnamedvi]) is + { + failure then error(cannot_execute_dvipng), + success(rcode2) then + if rcode2 /= 0 + then error(dvipng_error(to_Int([rcode2]))) + else if png_image_size(tpath/fnamepng) is + { + failure then error(png_file_corrupted(tpath/fnamepng)), + success(p) then + (if tpath = spath + then unique + else if true_png_file + then forget(copy_file(tpath/fnamepng,spath/fnamepng)) + else unique); + since p is (w,h), png_file_height(cpath/fnamepng,to_Int(h)) + } + } + } + }. + + + + *** Vertical positionning of PNG images. + +public define ResultPNG_down + latex_to_png + ( + String text, // a LaTex body + MAML_HTML_Options opts + ) = + //iprint("(2) LaTeX text: ["+text+"]\n"); + with hash = sha1(text), // create a unique name for all our files + corefname = web_arg_encode(hash), + spath = png_path_server(opts), + if file_exists(spath/("/f"+corefname+".png")) + then with dims = if png_image_size(spath+"/f"+corefname+".png") is + { + failure then (0,0), + success(p) then p + }, + since dims is (w,h), + png_file_down(spath/("f"+corefname+".png"),to_Int(w),to_Int(h), + to_Int(if png_image_size(spath+"/t"+corefname+".png") is + { + failure then 0, + success(p) then if p is (w1,h1) then + if h1 +=< 100 then 0 else h1-100 + })) + else if make_png_file(text,"f"+corefname,true,opts) is + { + error(msg) then error(msg), + log_file(fname) then log_file(fname), + png_file_height(true_fnamepng,true_height) then + with dims = if png_image_size(spath+"/f"+corefname+".png") is + { + failure then (0,0), + success(p) then p + }, + since dims is (w,h), + if has_a_display(text) + then png_file_down(true_fnamepng,to_Int(w),to_Int(h),0) + else if make_png_file("\\rule{1mm}{1in}"+text,"t"+corefname,true,opts) is + { + error(msg) then error(msg), + log_file(fname) then log_file(fname), + png_file_height(_,fake_height) then + png_file_down(true_fnamepng, + to_Int(w),to_Int(h), + if fake_height =< 100 then 0 else fake_height-100) + } + }. + + diff --git a/anubis_dev/library/doc_tools/maml4_private.anubis b/anubis_dev/library/doc_tools/maml4_private.anubis new file mode 100644 index 0000000..ce70366 --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_private.anubis @@ -0,0 +1,1515 @@ + + MAML 4 + + Definition of most tools used in this program. + +transmit maml4_types.anubis + + + + *** Making a position from the toolbox. + +public define MAML_Pos + make_pos + ( + Toolbox tbox + ) = + since tbox is toolbox(path,fname,ls,_,_,_,_,_,kp), + with t = tools(ls), + position(path,fname,line(t)(unique),column(t)(unique),offset(t)(unique)). + + + *** Formating a list of parsing modes. + +define String + format + ( + MustBe mb + ) = + if mb is + { + any then "any", + bool then "bool", + color then "color", + ccmode then "ccmode", + int then "int", + pint then "pint", + nzint then "nzint", + string then "string", + symbol then "symbol" + }. + +public define String + format + ( + ParseMode m + ) = + if m is + { + maml then "maml", + maml(mb) then "maml("+format(mb)+")", + verb then "verb" + }. + +public define String + format + ( + CCMode m + ) = + if m is + { + ee then "ee", + ei then "ei", + ie then "ie", + ii then "ii" + }. + +public define CCMode1 + mode_for_call + ( + CCMode m + ) = + if m is + { + ee then e, + ei then e, + ie then i, + ii then i + }. + +public define CCMode1 + mode_for_return + ( + CCMode m + ) = + if m is + { + ee then e, + ei then i, + ie then e, + ii then i + }. + +public define String + format + ( + List(ParseMode) l + ) = + "["+concat(map(format,l),",")+"]". + + + Create a constant 'maml' arity. +public define List(ParseMode) + cst_maml_arity // for example: 3 |-> [maml,maml,maml] + ( + Int n + ) = + if n =< 0 then [ ] else [maml . cst_maml_arity(n-1)]. + + + + *** Printing a 'Text' into a file. + +public define One + print + ( + WStream fp, + Text text + ) = + if text is + { + t(s) then print(fp,s), + t1 + t2 then print(fp,t1); print(fp,t2) + }. + + + + + *** Transforming a Text or VText into a string. + + The functions below are used for generating 'generated/prim2.anubis'. + + A variant of 'sub_string' forcing the result to be a 'String'. Used just below for backslashing + the double quotes within a string. + +define String + sub_str + ( + String s, + Int start, + Int end + ) = + if sub_string(s,start,end) is + { + failure then should_not_happen(""), + success(t) then t + }. + +define String + backslash_the_doublequotes + ( + String s + ) = + if find_string(s,"\"",0) is + { + failure then s, + success(n) then sub_str(s,0,n)+"\\\""+backslash_the_doublequotes(sub_str(s,n+1,length(s)-n-1)) + }. + + + + +public define String + to_string + ( + VText t + ) = + if t is + { + t(text) then "t(\""+backslash_the_doublequotes(text)+"\")", + v(i) then "v("+i+")", + fnsize then "fnsize", + textwidth then "textwidth", + vt1 + vt2 then to_string(vt1)+"+\n "+to_string(vt2) + }. + +public define String + to_string + ( + Text t + ) = + if t is + { + t(s) then s, + t1+t2 then to_string(t1)+to_string(t2) + }. + + + *** Generating the file 'generated/prim2.anubis'. + +define One + dump_prims_names_format + ( + WStream fp + ) = + print(fp,"\n\npublic define String\n"); + print(fp," format\n"); + print(fp," (\n"); + print(fp," Prim1 rp\n"); + print(fp," ) =\n"); + print(fp," if rp is \n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark1 m) |-> " _"+padn(name(m)+"(_)")+" then \""+name(m)+"\"", + primitives1),",\n")); + print(fp,"\n }.\n"); + print(fp,"\n\npublic define String\n"); + print(fp," format\n"); + print(fp," (\n"); + print(fp," Prim3 rp\n"); + print(fp," ) =\n"); + print(fp," if rp is \n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> " "+padn(name(m)+"(_)")+" then \""+name(m)+"\"", + primitives3),",\n")); + print(fp,"\n }.\n"). + +define One + dump_prims_lexer_items + ( + WStream fp + ) = + print(fp,"\npublic define List(LexerItem($T,LexerAux))\n"); + print(fp," prims_lexer_items(Prim1 -> $T prim1, Prim3 -> $T prim3)\n"); + print(fp," =\n"); + print(fp," [\n"); + print(fp,concat(map((PrimMark1 m) |-> + " lexer_item(\"#$"+name(m)+"\""+constant_string(20-length(name(m)),' ')+ + ", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(prim1(_"+name(m)+"(make_pos(t,a))))))", + primitives1),",\n")+",\n"); + print(fp,concat(map((PrimMark3 m) |-> + " lexer_item(\"#$"+name(m)+"\""+constant_string(20-length(name(m)),' ')+ + ", return((ByteArray b, LexingTools t, LexerAux a) |-> ok(prim3("+name(m)+"(make_pos(t,a))))))", + primitives3),",\n")); + print(fp,"\n ].\n"). + + + + + + A special 'map' function to be used just below. + Example: map_number(f,[a,b,c],0) yields [f(a,0),f(b,1),f(c,2)] + +define List($U) + map_number + ( + ($T,Int) -> $U f, + List($T) l, + Int i + ) = + if l is + { + [ ] then [ ], + [h . t] then [f(h,i) . map_number(f,t,i+1)] + }. + + +define One + dump_make_parse_prim1 + ( + WStream fp + ) = + print(fp,"\n\npublic define MAML1 parse_operand(Toolbox tbox, ParseMode m, String mark_name).\n"); + print(fp,"\npublic define MAML1\n"); + print(fp," parse_prim1(Toolbox tbox, Prim1 p) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark1 m) |-> if m is + { + primitive1(name,stackable,arity,_) then + " _"+padn(name+"(pos)")+" then\n"+ + concat(map_number((ParseMode mod, Int i) |-> + " with m"+i+" = parse_operand(tbox" + +","+format(mod)+",\"$"+name+"\"),\n", + arity,0),"")+ + " prim1(_"+name+(if arity is [] then "(pos)" else "(pos,"+ + concat(map_number((ParseMode mod, Int i) |-> "m"+i,arity,0),",")+")")+")" + }, primitives1),",\n")); + print(fp,"\n }.\n"). + +define One + dump_make_parse_prim1_in_list + ( + WStream fp + ) = + print(fp,"\n\npublic define MAML1 parse_operand_in_list(Toolbox tbox, ParseMode m, String mark_name).\n"); + print(fp,"\npublic define MAML1\n"); + print(fp," parse_prim1_in_list(Toolbox tbox, Prim1 p) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark1 m) |-> if m is + { + primitive1(name,stackable,arity,_) then + " _"+padn(name+"(pos)")+" then\n"+ + concat(map_number((ParseMode mod, Int i) |-> + " with m"+i+" = parse_operand_in_list(tbox" + +","+format(mod)+",\"$"+name+"\"),\n", + arity,0),"")+ + " prim1(_"+name+(if arity is [] then "(pos)" else "(pos,"+ + concat(map_number((ParseMode mod, Int i) |-> "m"+i,arity,0),",")+")")+")" + }, primitives1),",\n")); + print(fp,"\n }.\n"). + +define One + dump_make_parse_prim3 + ( + WStream fp + ) = + //print(fp,"\n\npublic define MAML1 parse_operand(Toolbox tbox, ParseMode m, String mark_name).\n"); + print(fp,"\npublic define MAML1\n"); + print(fp," parse_prim3(Toolbox tbox, Prim3 p) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is + { + primitive3(name,stackable,arity,_,_) then + " "+padn(name+"(pos)")+" then\n"+ + concat(map_number((ParseMode mod, Int i) |-> + " with m"+i+" = parse_operand(tbox" + +","+format(mod)+",\"$"+name+"\"),\n", + arity,0),"")+ + " prim3("+name+(if arity is [ ] then "(pos)" else "(pos,"+ + concat(map_number((ParseMode mod, Int i) |-> "m"+i,arity,0),",")+")")+")" + }, primitives3),",\n")); + print(fp,"\n }.\n"). + + +define One + dump_make_parse_prim3_in_list + ( + WStream fp + ) = + //print(fp,"\n\npublic define MAML1 parse_operand(Toolbox tbox, ParseMode m, String mark_name).\n"); + print(fp,"\npublic define MAML1\n"); + print(fp," parse_prim3_in_list(Toolbox tbox, Prim3 p) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is + { + primitive3(name,stackable,arity,_,_) then + " "+padn(name+"(pos)")+" then\n"+ + concat(map_number((ParseMode mod, Int i) |-> + " with m"+i+" = parse_operand_in_list(tbox" + +","+format(mod)+",\"$"+name+"\"),\n", + arity,0),"")+ + " prim3("+name+(if arity is [ ] then "(pos)" else "(pos,"+ + concat(map_number((ParseMode mod, Int i) |-> "m"+i,arity,0),",")+")")+")" + }, primitives3),",\n")); + print(fp,"\n }.\n"). + + +define One + dump_make_extract_errors_prim3 + ( + WStream fp, + String parm, + ) = + print(fp,"\npublic define List(MAML_Error) extract_errors(MAML_Prim3("+parm+") p3) = \n"); + print(fp," if p3 is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> since m is primitive3(name,_,arity,_,_), + " "+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then\n"+ + if arity is + { + [ ] then " [ ]", + [_ . _] then " "+stdvars(arity,(String v) |-> "extract_errors("+v+")"," + ") + }, primitives3), + ",\n")); + print(fp," }.\n"). + + + From an arity such as [maml,maml(Int),verb] produce the following string: + + with __0 = to_HTML_text(path,opts,_0), + with __1 = t(to_decimal(_1)), + with __2 = t(_2), + +define String + arity_to_HTML + ( + Arity arity + ) = + concat(map_iterate((Int i, ParseMode mod) |-> if mod is + { + maml then " with __"+i+" = to_HTML_text(path,opts,_"+i+")", + maml(mb) then if mb is + { + any then " with __"+i+" = to_HTML_text(path,opts,_"+i+")", + bool then should_not_happen(""), + color then " with __"+i+" = (Text)t(for_html(_"+i+"))", + ccmode then " with __"+i+" = (Text)t(format(for_html(_"+i+")))", + int then " with __"+i+" = (Text)t(to_decimal(for_html(_"+i+")))", + pint then " with __"+i+" = (Text)t(to_decimal(for_html(_"+i+")))", + nzint then " with __"+i+" = (Text)t(to_decimal(for_html(_"+i+")))", + string then " with __"+i+" = (Text)t(for_html(_"+i+"))", + symbol then " with __"+i+" = (Text)t(for_html(_"+i+"))", + }, + verb then " with __"+i+" = (Text)t(for_html(_"+i+"))" + }, arity,0,(Int i) |-> i+1),",\n"). + + +define One + dump_html_formater + ( + WStream fp + ) = + print(fp,"\n Forward declarations:"); + print(fp,"\npublic define Text replace_vars_etc(String path, MAML_HTML_Options opts, VText text, List(Text) values)."); +// print(fp,"\npublic define Text replace_vars_etc(Text _0,String path, MAML_HTML_Options opts, VText text)."); +// print(fp,"\npublic define Text replace_vars_etc(Text _0,Text _1,String path, MAML_HTML_Options opts, VText text)."); +// print(fp,"\npublic define Text replace_vars_etc(Text _0,Text _1,Text _2,String path, MAML_HTML_Options opts, VText text)."); +// print(fp,"\npublic define Text replace_vars_etc(Text _0,Text _1,Text _2,Text _3,String path, MAML_HTML_Options opts, VText text)."); +// print(fp,"\npublic define Text replace_vars_etc(Text _0,Text _1,Text _2,Text _3,Text _4,String path, MAML_HTML_Options opts, VText text)."); + print(fp,"\npublic define Text to_HTML_text(String path, MAML_HTML_Options opts, MAML3 m).\n"); + + print(fp,"\npublic define Text to_HTML_text (String path, MAML_HTML_Options opts, MAML_Prim3(MAML3) p) = \n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is + { + primitive3(name,stackable,arity,html_code,_) then + " "+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String s) |-> s,",")+")")+" then\n"+ + arity_to_HTML(arity)+(if arity is [] then " " else ",\n ")+ + if arity is [] then to_string(html_code) else + "replace_vars_etc(path,opts,"+to_string(html_code)+","+ + "["+stdvars_no_par(arity,(String v) |-> "_"+v,",")+"])" + }, primitives3), + ",\n")); + print(fp,"\n }.\n"). + + +define One + dump_arity_functions + ( + WStream fp + ) = + print(fp,"\npublic define List(ParseMode) get_arity(Prim3 p) = \n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is + { + primitive3(name,stackable,arity,html_code,_) then + " "+padn(name+"(pos)")+" then "+format(arity) + }, primitives3),",\n")); + print(fp,"\n }.\n"). + + +define One + dump_replace_vars_in_prim1 + ( + WStream fp + ) = + print(fp,"\npublic define MAML1 replace_vars_in_prim1(MAML_Prim1 p, List(MAML1) values) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark1 m) |-> if m is primitive1(name,_,arity,_) then + " _"+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then\n "+ + "prim1(_"+name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> "replace_vars_in_MAML("+v+",values)",",")+"))", + primitives1),",\n")); + print(fp,"\n }.\n"). + +define One + dump_make_lists_prim1 + ( + WStream fp + ) = + print(fp,"\npublic define MAML1 make_lists(MAML_Prim1 p) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark1 m) |-> if m is primitive1(name,_,arity,_) then + " _"+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then\n "+ + "prim1(_"+name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> "make_lists("+v+")",",")+"))", + primitives1),",\n")); + print(fp,"\n }.\n"). + +define One + dump_replace_vars_in_prim3 + ( + WStream fp, + String src_parm, + String trg_parm + ) = + print(fp,"\npublic define "+trg_parm+" replace_vars_in_prim3(MAML_Prim3("+src_parm+") p, List("+trg_parm+") values) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is primitive3(name,_,arity,_,_) then + " "+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then\n "+ + "prim3("+name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> "replace_vars_in_MAML("+v+",values)",",")+"))", + primitives3),",\n")); + print(fp,"\n }.\n"). + +define One + dump_replace_vars_in_prim3_MAML1 + ( + WStream fp + ) = + print(fp,"\npublic define MAML1 replace_vars_in_prim3(MAML_Prim3_MAML1 p, List(MAML1) values) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is primitive3(name,_,arity,_,_) then + " "+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then\n "+ + //" iprint(\"replace_vars_in_prim3: "+name+"\\n \");\n"+ + "prim3("+name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> "replace_vars_in_MAML("+v+",values)",",")+"))", + primitives3),",\n")); + print(fp,"\n }.\n"). + + +define One + dump_glue_texts_MAML2 + ( + WStream fp + ) = + print(fp,"\npublic define MAML2 glue_texts(MAML_Prim3(MAML2) p) = \n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is primitive3(name,_,arity,_,_) then + " "+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then\n "+ + "prim3("+name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> "glue_texts("+v+")",",")+"))", + primitives3),",\n")); + print(fp,"\n }.\n"). + +define One + dump_glue_texts_MAML2b + ( + WStream fp + ) = + print(fp,"\npublic define MAML2b glue_texts(MAML_Prim3(MAML2b) p) = \n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is primitive3(name,_,arity,_,_) then + " "+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then\n "+ + "prim3("+name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> "glue_texts("+v+")",",")+"))", + primitives3),",\n")); + print(fp,"\n }.\n"). + +define One + dump_map_MAML_Prim3 + ( + WStream fp + ) = + print(fp,"\npublic define MAML_Prim3($U) map($T -> $U f, MAML_Prim3($T) p) = \n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is primitive3(name,_,arity,_,_) then + " "+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then\n "+ + name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v, ParseMode mod) |-> + if mod is + { + maml then "f("+v+")", + maml(mb) then if mb is + { + any then "f("+v+")", + bool then v, + color then v, + ccmode then v, + int then v, + pint then v, + nzint then v, + string then v, + symbol then v + }, + verb then v + },",")+")", + primitives3),",\n")); + print(fp,"\n }.\n"). + +define One + dump_map_MAML_Prim1 + ( + WStream fp + ) = + print(fp,"\npublic define MAML_Prim1 map(MAML1 -> MAML1 f, MAML_Prim1 p) = \n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark1 m) |-> if m is primitive1(name,_,arity,_) then + " _"+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then\n "+ + "_"+name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v, ParseMode mod) |-> "f("+v+")",",")+")", + primitives1),",\n")); + print(fp,"\n }.\n"). + +define One + dump_map_MAML_Prim3_MAML1 + ( + WStream fp + ) = + print(fp,"\npublic define MAML_Prim3_MAML1 map(MAML1 -> MAML1 f, MAML_Prim3_MAML1 p) = \n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is primitive3(name,_,arity,_,_) then + " "+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then\n "+ + name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v, ParseMode mod) |-> "f("+v+")",",")+")", + primitives3),",\n")); + print(fp,"\n }.\n"). + + +define String + make_with_evals + ( + Arity ar, + Int i + ) = + if ar is + { + [ ] then "", + [h . t] then + (if h is + { + maml then " with __"+i+" = eval(tbox,_"+i+"),\n", + maml(mb) then if mb is + { + any then " with __"+i+" = eval(tbox,_"+i+"),\n", + bool then " if eval_as_bool(tbox,pos,_"+i+") is { error(e) then error(e), ok(__"+i+") then\n", + color then " if eval_as_color(tbox,pos,_"+i+") is { error(e) then error(e), ok(__"+i+") then\n", + ccmode then " if eval_as_ccmode(tbox,pos,_"+i+") is { error(e) then error(e), ok(__"+i+") then\n", + int then " if eval_as_int(tbox,pos,_"+i+") is { error(e) then error(e), ok(__"+i+") then\n", + pint then " if eval_as_pint(tbox,pos,_"+i+") is { error(e) then error(e), ok(__"+i+") then\n", + nzint then " if eval_as_nzint(tbox,pos,_"+i+") is { error(e) then error(e), ok(__"+i+") then\n", + string then " if eval_as_string(tbox,pos,_"+i+") is { error(e) then error(e), ok(__"+i+") then\n", + symbol then " if eval_as_symbol(tbox,pos,_"+i+") is { error(e) then error(e), ok(__"+i+") then\n", + }, + verb then " if eval_as_string(tbox,pos,_"+i+") is { error(e) then error(e), ok(__"+i+") then\n" + }) + make_with_evals(t,i+1) + }. + +define Int + num_non_maml_arities + ( + Arity ar + ) = + if ar is + { + [ ] then 0, + [h . t] then if h is + { + maml then num_non_maml_arities(t), + maml(mb) then if mb is + { + any then num_non_maml_arities(t), + bool then 1 + num_non_maml_arities(t), + color then 1 + num_non_maml_arities(t), + ccmode then 1 + num_non_maml_arities(t), + int then 1 + num_non_maml_arities(t), + pint then 1 + num_non_maml_arities(t), + nzint then 1 + num_non_maml_arities(t), + string then 1 + num_non_maml_arities(t), + symbol then 1 + num_non_maml_arities(t), + }, + verb then 1 + num_non_maml_arities(t) + } + }. + +define One + dump_eval_prim3 + ( + WStream fp + ) = + print(fp,"\npublic define MAML2 eval (Toolbox tbox, MAML1 m)."); + print(fp,"\npublic define Result(MAML_Error,Value(String)) eval_as_string (Toolbox tbox, MAML_Pos pos, MAML1 m)."); + print(fp,"\npublic define Result(MAML_Error,Value(Int)) eval_as_int (Toolbox tbox, MAML_Pos pos, MAML1 m)."); + print(fp,"\npublic define Result(MAML_Error,Value(Int)) eval_as_pint (Toolbox tbox, MAML_Pos pos, MAML1 m)."); + print(fp,"\npublic define Result(MAML_Error,Value(Bool)) eval_as_bool (Toolbox tbox, MAML_Pos pos, MAML1 m)."); + print(fp,"\npublic define Result(MAML_Error,Value(CCMode)) eval_as_ccmode (Toolbox tbox, MAML_Pos pos, MAML1 m)."); + print(fp,"\npublic define Result(MAML_Error,Value(String)) eval_as_color (Toolbox tbox, MAML_Pos pos, MAML1 m)."); + print(fp,"\npublic define Result(MAML_Error,Value(String)) eval_as_symbol (Toolbox tbox, MAML_Pos pos, MAML1 m).\n"); + print(fp,"\npublic define MAML2 eval_prim3 (Toolbox tbox, MAML_Prim3_MAML1 p) = \n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is primitive3(name,_,arity,_,_) then + " "+padn(name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then\n"+ + make_with_evals(arity,0)+ + " prim3("+name+(if arity is [] then "(pos" else "(pos,")+ + stdvars_no_par(arity,(String v) |-> "_"+v,",")+"))"+constant_string(num_non_maml_arities(arity),'}') + ,primitives3),",\n")); + print(fp,"\n }.\n"). + + +define One + dump_alpha_part_Prim3 + ( + WStream fp + ) = + print(fp,"\npublic define Maybe(MAML2) alpha_part(MAML2 m).\n"); + print(fp,"\npublic define Maybe(MAML2) alpha_part(MAML_Prim3(MAML2) m) = \n"); + print(fp," if m is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> since m is primitive3(name,_,arity,_,_), + " "+padn(name+ + ( if arity is [] then "(pos)" else + "(pos,"+stdvars_no_par(arity,(String v) |-> v,",")+")"))+" then\n"+ + concat(map_iterate((Int i, ParseMode mod) |-> if mod is + { + maml then " if alpha_part(_"+i+") is success(__"+i+") then success(__"+i+") else\n", + maml(mb) then if mb is + { + any then " if alpha_part(_"+i+") is success(__"+i+") then success(__"+i+") else\n" + bool then "", + color then "", + ccmode then "", + int then "", + pint then "", + nzint then "", + string then "", + symbol then "" + }, + verb then "" + }, arity, 0, (Int i) |-> i+1))+" failure" + ,primitives3),",\n")); + print(fp,"\n }.\n"). + + + +global define One + make_prim2_file + ( + List(String) _ + ) = + forget(make_directory("generated",default_directory_mode)); + if file("generated/prim2.anubis",new) is + { + failure then print("Cannot create file 'generated/prim2.anubis'\n"), + success(filep) then with fp = (WStream)weaken(filep), + + print(fp,"\n\n This file was automatically generated from within ../maml4_private.anubis\n"); + print(fp," by 'make_prim2_file'.\n"); + print(fp,"\nread lexical_analysis/fast_lexer_5.anubis\n"); + print(fp,"\nread ../maml4_types.anubis\n"); + print(fp,"\npublic define MAML1 replace_vars_in_MAML(MAML1 m, List(MAML1) values).\n"); + print(fp,"\npublic define MAML3 replace_vars_in_MAML(MAML2 m, List(MAML3) values).\n"); + print(fp,"\npublic define MAML2 replace_vars_in_MAML(MAML2 m, List(MAML2) values).\n"); + print(fp,"\npublic define MAML3 replace_vars_in_MAML(MAML2a m, List(MAML3) values).\n"); + print(fp,"\npublic define List(MAML_Error) extract_errors(MAML2 m).\n"); + dump_prims_names_format(fp); + print(fp,"\npublic define MAML_Pos make_pos(LexingTools t, LexerAux a).\n"); + dump_prims_lexer_items(fp); + dump_make_parse_prim1(fp); + dump_make_parse_prim1_in_list(fp); + dump_replace_vars_in_prim1(fp); + print(fp,"\npublic define MAML1 make_lists(MAML1 m).\n"); + dump_make_lists_prim1(fp); + print(fp,"\ndefine macro Value(Int) replace_vars_in_MAML(Value(Int) i, List(MAML3) vs) = i."); + print(fp,"\ndefine macro Value(Bool) replace_vars_in_MAML(Value(Bool) i, List(MAML3) vs) = i."); + print(fp,"\ndefine macro Value(String) replace_vars_in_MAML(Value(String) i, List(MAML3) vs) = i.\n"); + print(fp,"\ndefine macro Value(Int) replace_vars_in_MAML(Value(Int) i, List(MAML2) vs) = i."); + print(fp,"\ndefine macro Value(Bool) replace_vars_in_MAML(Value(Bool) i, List(MAML2) vs) = i."); + print(fp,"\ndefine macro Value(String) replace_vars_in_MAML(Value(String) i, List(MAML2) vs) = i.\n"); + dump_replace_vars_in_prim3(fp,"MAML2","MAML3"); + dump_replace_vars_in_prim3(fp,"MAML2","MAML2"); + dump_replace_vars_in_prim3(fp,"MAML2a","MAML3"); + dump_replace_vars_in_prim3_MAML1(fp); + dump_make_parse_prim3(fp); + dump_make_parse_prim3_in_list(fp); + print(fp,"\npublic define List(MAML_Error) extract_errors(MAML3 m)."); + print(fp,"\ndefine macro List(MAML_Error) extract_errors(Value(Int) i) = []."); + print(fp,"\ndefine macro List(MAML_Error) extract_errors(Value(String) i) = []."); + print(fp,"\ndefine macro List(MAML_Error) extract_errors(Value(Bool) i) = [].\n"); + dump_make_extract_errors_prim3(fp,"MAML2"); + dump_make_extract_errors_prim3(fp,"MAML3"); + dump_html_formater(fp); + dump_arity_functions(fp); + print(fp,"\npublic define MAML2 glue_texts(MAML2 m).\n"); + print(fp,"\npublic define MAML2b glue_texts(MAML2b m).\n"); + print(fp,"\ndefine macro Value(Int) glue_texts(Value(Int) i) = i."); + print(fp,"\ndefine macro Value(String) glue_texts(Value(String) i) = i."); + print(fp,"\ndefine macro Value(Bool) glue_texts(Value(Bool) i) = i.\n"); + dump_glue_texts_MAML2(fp); + dump_glue_texts_MAML2b(fp); + dump_map_MAML_Prim3(fp); + dump_map_MAML_Prim1(fp); + dump_map_MAML_Prim3_MAML1(fp); + dump_eval_prim3(fp); + dump_alpha_part_Prim3(fp); + unique + }. + +execute anbexec make_prim2_file +transmit generated/prim2.anubis + + At this point, we have the automatically generated tools. + +public define MAML_Pos + make_pos + ( + LexingTools t, + LexerAux a + ) = + position(path(a),fname(a),line(t)(unique),column(t)(unique),offset(t)(unique)). + + + + *** Replacing variables, etc... in a VText. + +define Text + force_nth + ( + Int i, + List(Text) l + ) = + if l is + { + [ ] then should_not_happen(t("")), + [h . t] then + if i =< 0 + then h + else force_nth(i-1,t) + }. + +define MAML1 + force_nth1 + ( + Int i, + List(MAML1) l + ) = + if l is + { + [ ] then should_not_happen(empty), + [h . t] then + if i =< 0 + then h + else force_nth1(i-1,t) + }. + + + 'replace_vars_etc' is used in 'generated/prim2.anubis'. + +public define Text + replace_vars_etc + ( + String path, + MAML_HTML_Options opts, + VText text, + List(Text) values + ) = + if text is + { + t(s) then t(s), + v(i) then force_nth(i-1,values), + fnsize then t(to_decimal(opts.note_font_size)), + textwidth then t(to_decimal(opts.text_width)), + vt1 + vt2 then replace_vars_etc(path,opts,vt1,values)+replace_vars_etc(path,opts,vt2,values) + }. + + + *** Translating messages to English. + +define String + to_English + ( + LexicalError($T) e + ) = + if e is lex_error(b,t,a) then + to_string(b)+" at line "+t.line(unique). + +public define String + format + ( + MAML_Pos p + ) = + since p is position(path,fname,line,col,off), + (path/fname)+" at "+(line+1)+":"+(col+1)+"["+off+"]". // +1 because we number lines and columns from 0 + // whereas text editors generally number them from 1 + +public define String + to_English + ( + MAML_Error e + ) = + if e is + { + lexical(pos,le) then "Lexical error in '"+format(pos)+"': "+to_English(le), + lexical(pos,le) then "Lexical error in '"+format(pos)+"': "+to_English(le), + missing_end(path,fname) then "Missing $end in '"+(path/fname)+"'", + end_in_operand(pos) then "$end found within an operand in '"+format(pos)+"'", + end_in_list(pos) then "$end found within a list in '"+format(pos)+"'", + unknown_mark(pos,name) then "Unknown mark in '"+format(pos)+"': "+name, + premature_end_of_file(path,fname) then "Premature end of file in '"+(path/fname)+"'", + missing_operand(pos,name) then "Missing operand to "+name+" in '"+format(pos)+"'", + file_not_found(pos,path) then "File '"+path+"' not found in '"+format(pos)+"'.", + cannot_read_file(pos,path) then "Cannot read file '"+path+"' in '"+format(pos)+"'.", + cannot_open_file(path) then "Cannot open file '"+path+"'.", + cannot_create_file(path) then "Cannot create file '"+path+"'.", + cannot_write_file(path) then "Cannot write into file '"+path+"'.", + cannot_execute_latex then "Cannot execute LaTeX", + cannot_execute_dvipng then "Cannot execute dvipng", + png_file_corrupted(path) then "PNG file corrupted: '"+path+"'", + dvipng_error(code) then "dvipng error (return code = "+code+")", + regexpr(pos,ree) then "Error in regular expression: "+to_English(ree)+" in '"+format(pos)+"'", + latex_error(pos,logfname) then "LaTeX error in '"+format(pos)+"' (see log file '"+logfname+"')", + latex_error(code,logfname) then "LaTeX returned the error code "+code+" (see log file '"+logfname+"')", + integer_expected(pos) then "Integer expected in '"+format(pos)+"'", + must_be_a_color(pos,s) then "Operand '"+s+"' is not a valid color in '"+format(pos)+"'", + boolean_expected(pos,s) then "Operand '"+s+"' must be a boolean in '"+format(pos)+"'", + must_be_an_int(pos,s) then "Operand '"+s+"' must be an integer in '"+format(pos)+"'", + must_be_a_nzint(pos,s) then "Operand '"+s+"' must be a non zero integer in '"+format(pos)+"'", + must_be_a_positive_int(pos,s) then "Operand '"+s+"' must be a positive or zero integer in '"+format(pos)+"'", + must_be_a_symbol(pos,s) then "Operand '"+s+"' is not a valid symbol in '"+format(pos)+"'", + string_expected(pos,s) then "In '"+format(pos)+"', a character string was expected instead of '"+s+"'." + invalid_initial_counter_value(pos,v) then "Invalid initial counter value: "+v+" in '"+format(pos)+"'", + unknown_counter(pos,name) then "Unknown counter: '"+name+"' in '"+format(pos)+"'", + unknown_macro_name(pos,s) then "Unknown macro name '"+s+"' in '"+format(pos)+"'", + invalid_number_to_add(pos,v) then "Invalid number '"+v+"' to sadd to counter in '"+format(pos)+"'", + unknown_colorizer(name) then "Unknown colorizer '"+name+"'", + colorizer_already_exists(pos,name) then "In '"+format(pos)+"', colorizer '"+name+"' is already constructed.", + not_a_colorizercall_mode(pos,s) then "In '"+format(pos)+"', '"+s+"' is not a $colorizercall mode.", + unknown_accumulator(pos,name) then "In '"+format(pos)+"', unknown accumulator: '"+name+"'.", + invalid_apply_name(pos,name) then "In '"+format(pos)+"' invalid mark name for $apply: '"+name+"'." + bad_apply_arity(pos,name) then "In '"+format(pos)+"' invalid arity for $apply: '"+name+"'.", + not_a_list(pos,s) then "In '"+format(pos)+"', '"+s+"' should be a list.", + misplaced_right_bracket(pos) then "Misplaced right bracket in '"+format(pos)+"'.", + misplaced_right_par(pos) then "Misplaced right parenthese in '"+format(pos)+"'." + }. + + + + + *** Extracting errors from MAML syntax trees. + +public define String to_string(MAML1 m). +public define String to_string(MAML2 m). +public define String to_string(MAML3 m). + +public define MAML2 + add_errors + ( + List(MAML_Error) l + ) = + if l is + { + [ ] then empty, + [h . t] then error(h) + add_errors(t) + }. + + +define List(MAML_Error) + extract_errors_aux + ( + MAML2 m + ) = + if m is + { + error(me) then [me], + erroneous(me,text) then [me], + empty then [], + false then [], + true then [], + text(value) then [], + variable(id) then [], + list(l,d) then flat(map(extract_errors_aux,l)), + alpha(m1) then extract_errors_aux(m1), + colorize(pos,cname,operand) then extract_errors_aux(operand), // cname is already a string + postpone(pos,t) then [], + prim3(p3) then extract_errors(p3), + m1 + m2 then extract_errors_aux(m1) + extract_errors_aux(m2) + }. + +public define List(MAML_Error) + extract_errors + ( + MAML2 m + ) = + no_doubles(extract_errors_aux(m)). + + +define List(MAML_Error) + extract_errors_aux + ( + MAML3 m + ) = + if m is + { + error(me) then [me], + erroneous(me,m1) then [me], + empty then [], + text(value) then [], + list(l) then flat(map(extract_errors_aux,l)), + postpone(pos,text) then [], + prim3(p3) then extract_errors(p3), + m1 + m2 then extract_errors_aux(m1) + extract_errors_aux(m2) + }. + +public define List(MAML_Error) + extract_errors + ( + MAML3 m + ) = + no_doubles(extract_errors_aux(m)). + + + + + + + *** Formating a MAML syntax tree into a string. + + + + + This is used when an operand of a mark must be seen as a string (for example, the name of a colorizer). + + +public define String to_string (MAML1 m). +public define String to_string (MAML2 m). + + + +define String + to_string_aux // here we have length(d) = length(l)+1 + ( + List($M) l, // l is non empty (and $M is either MAML1 or MAML2) + List(String) d, // d has the same length as l + $M -> String to_string + ) = + if l is + { + [ ] then "", + [l1 . ls] then if d is + { + [ ] then should_not_happen(""), + [d1 . ds] then with rest = to_string_aux(ls,ds,to_string), + to_string(l1)+d1+rest + } + }. + + +define String + to_string + ( + List($M) l, // $M is either MAML1 or MAML2 + List(String) d, // decoration for the list + $M -> String to_string + ) = + if d is + { + [ ] then // no decoration information available + "["+concat(map(to_string,l),",")+"]", + [d1 . ds1] then // decoration is available + // special treatment if l is empty + if l is + { + [ ] then if ds1 is + { + [ ] then should_not_happen(""), + [d2 . _] then + d1+d2 + }, + [_ . _] then + d1+to_string_aux(l,ds1,to_string) + } + }. + + + +public define String + to_string + ( + MAML1 m + ) = + if m is + { + error(me) then red(to_English(me)), + erroneous(me,m1) then to_string(m1), + empty then "", + text(value) then value, + variable(id) then "$"+id, + prim1(p1) then to_string(p1), + list(l,d) then to_string(l,d,to_string), + alpha(m1) then "$alphabetic("+to_string(m1)+")", + colorize(pos,cname,op) then "$colorize("+to_string(cname)+")("+to_string(op)+")", + define(pos,name,ar,val) then "$define("+name+")("+ar+")("+to_string(val)+")", + undefine(pos,name) then "$undefine("+name+")", + _if(pos,test,ift,iff) then "$if("+to_string(test)+")("+to_string(ift)+")("+to_string(iff)+")", + prim3(p3) then to_string(p3), + computed(m2) then to_string(m2), + macro(pos,name,operands) then if operands is + { + [ ] then "$"+name, + [_ . _] then "$"+name+concat(map((MAML1 a) |-> "("+to_string(a)+")", + operands)) + }, + m1 + m2 then to_string(m1) + to_string(m2) + }. + +public define String + to_string_all + ( + MAML2 m + ). + +public define String + to_string_all + ( + MAML1 m + ) = + if m is + { + error(me) then red(to_English(me)), + erroneous(me,m1) then "("+to_string_all(m1)+")", + empty then "", + text(value) then "("+value+")", + variable(id) then "$"+id, + prim1(p1) then "("+to_string(p1)+")", + list(l,d) then "["+concat(map(to_string_all,l),",")+"]", + alpha(m1) then "$alphabetic("+to_string_all(m1)+")", + colorize(pos,cname,op) then "$colorize("+to_string_all(cname)+")("+to_string_all(op)+")", + define(pos,name,ar,val) then "$define("+name+")("+ar+")("+to_string_all(val)+")", + undefine(pos,name) then "$undefine("+name+")", + _if(pos,test,ift,iff) then "$if("+to_string_all(test)+")("+to_string_all(ift)+")("+to_string_all(iff)+")", + prim3(p3) then "("+to_string(p3)+")", + computed(m2) then "("+to_string_all(m2)+")", + macro(pos,name,operands) then if operands is + { + [ ] then "$"+name, + [_ . _] then "$"+name+concat(map((MAML1 a) |-> "("+to_string_all(a)+")", + operands)) + }, + m1 + m2 then to_string_all(m1)+"+"+to_string_all(m2) + }. + +public define String + to_string + ( + MAML2 m + ) = + if m is + { + error(me) then red(to_English(me)), + erroneous(me,m1) then to_string(m1), + empty then "", + false then "$false", + true then "$true", + text(value) then value, + variable(id) then "$"+id, + list(l,d) then to_string(l,d,to_string), + alpha(m1) then "$alphabetic("+to_string(m1)+")", + colorize(pos,cname,op) then "$colorize("+cname+","+to_string(op)+")", + postpone(pos,text) then "$postpone("+to_string(text)+")", + prim3(p3) then to_string(p3,to_string), + m1 + m2 then to_string(m1) + to_string(m2) + }. + +public define String + to_string_all + ( + MAML2 m + ) = + if m is + { + error(me) then red(to_English(me)), + erroneous(me,m1) then to_string_all(m1), + empty then "", + false then "$false", + true then "$true", + text(value) then "("+value+")", + variable(id) then "$"+id, + list(l,d) then "["+concat(map(to_string_all,l),",")+"]", + alpha(m1) then "$alphabetic("+to_string_all(m1)+")", + colorize(pos,cname,op) then "$colorize("+cname+","+to_string_all(op)+")", + postpone(pos,text) then "$postpone("+to_string_all(text)+")", + prim3(p3) then "("+to_string(p3,to_string)+")", + m1 + m2 then to_string_all(m1) +"+"+ to_string_all(m2) + }. + +public define String + to_string + ( + MAML2b m + ) = + if m is + { + error(me) then red(to_English(me)), + erroneous(me,m1) then to_string(m1), + empty then "", + call(name) then "$call("+name+")", + return then "$return", + text(value) then value, + variable(id) then "$"+id, + list(l) then concat(map(to_string,l),"$,"), + colorize(pos,cname,op) then "$colorize("+cname+","+to_string(op)+")", + prim3(p3) then to_string(p3,to_string), + m1 + m2 then to_string(m1) + to_string(m2) + }. + + + + + +public define MAML2 + sum + ( + List(MAML2) l + ) = + if l is + { + [ ] then empty, + [h . t] then h + sum(t) + }. + +public define MAML3 + sum + ( + List(MAML3) l + ) = + if l is + { + [ ] then empty, + [h . t] then h + sum(t) + }. + +public define Text + sum + ( + List(Text) l + ) = + if l is + { + [ ] then t(""), + [h . t] then h + sum(t) + }. + + The replacement function below goes from MAML2 to MAML3. This replacement is used only during + the colorization for replacing $1 in the value of a color rule. + +public define MAML3 + replace_vars_in_MAML + ( + MAML2a body, + List(MAML3) values + ) = + if body is + { + error(me) then error(me), + erroneous(me,m1) then erroneous(me,m1), + empty then empty, + text(tx) then text(tx), + variable(i) then if nth(i-1,values) is + { + failure then should_not_happen(empty), + success(val) then val + }, + list(l) then list(map((MAML2a m1) |-> replace_vars_in_MAML(m1,values),l)), + prim3(p3) then replace_vars_in_prim3(p3,values), + m1 + m2 then replace_vars_in_MAML(m1,values) + replace_vars_in_MAML(m2,values) + }. + + +public define MAML1 + replace_vars_in_MAML + ( + MAML1 m, + List(MAML1) values + ) = + if m is + { + error(me) then m, + erroneous(me,text) then m, + empty then m, + text(value) then m, + variable(id) then force_nth1(id-1,values), + prim1(p1) then replace_vars_in_prim1(p1,values), + list(l,d) then list(map((MAML1 m1) |-> replace_vars_in_MAML(m1,values),l),d), + alpha(m1) then alpha(replace_vars_in_MAML(m1,values)), + colorize(pos,cname,operand) then colorize(pos,cname,replace_vars_in_MAML(operand,values)), + define(pos,name,ar,val) then define(pos,name,ar,replace_vars_in_MAML(val,values)), + undefine(pos,name) then m, + _if(pos,test,ift,iff) then _if(pos,replace_vars_in_MAML(test,values), + replace_vars_in_MAML(ift,values), + replace_vars_in_MAML(iff,values)), + prim3(p3) then replace_vars_in_prim3(p3,values), + computed(m2) then m, + macro(pos,name,operands) then macro(pos,name,map((MAML1 m1) |-> replace_vars_in_MAML(m1,values),operands)), + m1+m2 then replace_vars_in_MAML(m1,values) + replace_vars_in_MAML(m2,values) + }. + +public define MAML2 + replace_vars_in_MAML + ( + MAML2 body, + List(MAML2) values + ) = + //iprint("replace_vars_in_MAML: body = "+to_string_all(body)+"\n"); + if body is + { + error(me) then body, + erroneous(me,m1) then body, + empty then body, + false then body, + true then body, + text(tx) then body, + variable(i) then if nth(i-1,values) is + { + failure then should_not_happen(empty), + success(val) then //iprint("replace_vars_in_MAML: val = "+to_string_all(val)+"\n"); + val + }, + list(l,d) then list(map((MAML2 m2) |-> replace_vars_in_MAML(m2,values),l),d), + alpha(m1) then alpha(replace_vars_in_MAML(m1,values)), + colorize(pos,cn,op) then colorize(pos,cn,replace_vars_in_MAML(op,values)), + postpone(pos,text) then body, + prim3(p3) then replace_vars_in_prim3(p3,values), + m1 + m2 then replace_vars_in_MAML(m1,values) + replace_vars_in_MAML(m2,values) + }. + + + *** Constructing the initial macro tree (containing predefined macros). + + Definition of predefined macros. Notice that $comment cannot be externalized because of + the mode of parsing ('verb') of its operand. + + +define MAML_Pos ipos = position("internal","",0,0,0). + + define List(MacroDef) + predefined_macros + = + [ + macro("error", [maml], empty), // this definition can be superseded by the user + macro("comment", [verb], empty), + macro("red", [maml], prim3(rgb(ipos,text("255,0,0"),variable(1)))), + macro("blue", [maml], prim3(rgb(ipos,text("0,0,255"),variable(1)))), + macro("green", [maml], prim3(rgb(ipos,text("0,255,0"),variable(1)))), + macro("yellow", [maml], prim3(rgb(ipos,"255,255,0",variable(1)))), + macro("grey", [maml], prim3(rgb(ipos,"120,120,120",variable(1)))), + + macro("section", [maml], prim3(sec(ipos,variable(1)))), + macro("subsection", [maml], prim3(subsec(ipos,variable(1)))), + macro("subsubsection", [maml], prim3(subsubsec(ipos,variable(1)))) + ]. + + + An adhoc iteration function used for constructing the initial macro tree. + +define $T + iterate + ( + ($D,$T) -> $T f, + List($D) l, + $T t + ) = + if l is + { + [ ] then t, + [d1 . others] then + iterate(f,others,f(d1,t)) + }. + + public define MacroTree + initial_macro_tree + = + // a function for inserting a single definition + with ins = (MacroDef def, MacroTree t) |-> insert(name(def),[def],t), + iterate(ins,predefined_macros,new_tree(bt24cmp)). + + + *** Counting errors. + + public define One + count_error + ( + Toolbox tbox + ) = + with v = tbox.keep.max_errors_v, + v <- *v + 1. + + public define Bool + too_many_errors + ( + Toolbox tbox + ) = + *(tbox.keep.max_errors_v) =< 0. + + + *** Getting the last definition (if any) of a macro. + +public define Maybe(MacroDef) + get_macro_def + ( + Toolbox tbox, + String macro_name + ) = + if get(macro_name,*(tbox.keep.macro_tree_v)) is + { + failure then failure, + success(l) then if l is + { + [ ] then failure, + [h . _] then success(h) + } + }. + + +public define Maybe(Int) + get_macro_arity + ( + Toolbox tbox, + String macro_name + ) = + if get(macro_name,*(tbox.keep.arity_tree_v)) is + { + failure then failure, + success(l) then if l is + { + [ ] then failure, + [h . _] then success(h) + } + }. + + + *** Dividing a 'Word32' by a 'Float'. + +public define Word32 + Word32 x / Float f + = + if to_Float(x) / f is + { + failure then x, + success(q) then integral_part_to_Word32(q) + }. + + + *** Dividing a 'Float' by an 'Int'. + +public define Float + Float f / Int n + = + if f/to_Float(n) is + { + failure then f, + success(q) then q + }. + +public define Int + Int x / Float f + = + if to_Float(x)/f is + { + failure then x, + success(q) then integral_part(q) + }. + + + *** Printing a message on 'stdout' in case '-verbose' option is set. + +public define macro $T + if_verbose + ( + Toolbox tbox, + String before, // what must be printed before the term is executed + $T term, // the term to be excuted + String after // what must be printed after the term is executed + ) = + with v = verbose:tbox.keep.options, + (if v then iprint(before) else unique); + with result = term, + (if v then iprint(after) else unique); + result. + + + *** Formating a Value(?). + +public define String + to_decimal + ( + Value(Int) v + ) = + since v is value(vh,vp), "$ifhtml("+to_decimal(vh)+")$ifpdf("+to_decimal(vp)+")". + +public define String + to_string + ( + Value(String) v + ) = + since v is value(vh,vp), "$ifhtml("+vh+")$ifpdf("+vp+")". + +define String + format + ( + Bool b + ) = + if b then "$true" else "$false". + +public define String + to_string + ( + Value(Bool) v + ) = + since v is value(vh,vp), "$ifhtml("+format(vh)+")$ifpdf("+format(vp)+")". + +public define String + to_string + ( + Value(CCMode) v + ) = + since v is value(vh,vp), "$ifhtml("+format(vh)+")$ifpdf("+format(vp)+")". + + + + \ No newline at end of file diff --git a/anubis_dev/library/doc_tools/maml4_record.anubis b/anubis_dev/library/doc_tools/maml4_record.anubis new file mode 100644 index 0000000..680c46d --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_record.anubis @@ -0,0 +1,318 @@ + + + MAML4 + + Tools needed by marks requiring an immediate action. + + +transmit maml4_lexers.anubis + + + *** This file defines the following function: + +public define One record_definition (Toolbox tbox, + String name, + Int numargs, + MAML body). +public define One record_colorrule (Toolbox tbox, + String cname, + String regexpr, + MAML body). +public define Result(RegExprError,MAML) make_colorizer (Toolbox tbox, + String name). +public define MAML apply_colorizations (Toolbox tbox, + MAML m, + List(Colorizer) clrzrs). +public define One do_undefine (Toolbox tbox, + String name). + + --- That's all for the public part ! ------------------------------------------------- + + The primitive marks which need to be handled are: + + $colorizer + $colorrule + $define + $input + $output + $undefine + + Other primitive marks don't need anything (at parse time). + + Macros need to be expanded (this is done in the parser). + + Create a constant 'maml' arity. +define List(ParseMode) + cst_maml_arity // for example: 3 |-> [maml,maml,maml] + ( + Int n + ) = + if n =< 0 then [ ] else [maml . cst_maml_arity(n-1)]. + +public define One + record_definition + ( + Toolbox tbox, + String name, + Int numargs, + MAML body + ) = + with v = tbox.keep.macro_tree_v, + v <- update(name,*v,(Maybe(List(MacroDef)) mb_m) |-> if mb_m is + { + failure then success([macro(name,cst_maml_arity(numargs),body)]) + success(l) then success([macro(name,cst_maml_arity(numargs),body) . l]) + }). + + + + + *** Colorizing stuff. + +public define One + record_colorrule + ( + Toolbox tbox, + String cname, + String regexpr, + MAML body + ) = + with v = tbox.keep.colorrules_v, + v <- [rule(cname,regexpr,body) . *v]. + + + Parsing a string to be colorized. + +define MAML + color_parser + ( + One -> LexOut(ColorToken,One) color_lexer + ) = + if color_lexer(unique) is + { + error(e) then empty, + ok(s) then if s is + { + end_of_input then empty, + color(c,tx) then replace_vars_in_MAML(c,[text(tx)]) + color_parser(color_lexer), + text(tx) then text(tx) + color_parser(color_lexer) + } + }. + + + + A colorizer is mainly a function of type 'String -> MAML' transforming a character string into + a 'colorized' MAML tree. The function below creates such a colorizer. It proceeds as follows: + + - it selects all color rules corresponding to the name of the colorizer, + - it creates a fast lexer description using these color rules, adding + two generic lexer items for all those sequences not recognized by the given + regular expressions (since everything in the text to be colorized must be kept), + - it calls 'make_saved_lexer' (from fast_lexer_5.anubis) in order to make the lexer, + - it construct the colorizing function by applying the above 'color_parser' to the + lexer just constructed. + + +define Result(RegExprError,String -> MAML) // the colorizing function + create_colorizer + ( + Toolbox tbox, + String name, // of colorizer + List(ColorRule) rules + ) = + with myrules = map_select((ColorRule r) |-> + if r is rule(n,_,_) then if n = name + then success(r) + else failure, + rules), + // 'reverse' is needed because the order conventions must be the same as in fast_lexer_5.anubis. + ldesc = (List(LexerItem(ColorToken,One)))reverse( + [ + lexer_item(".", return((ByteArray b, LexingTools t, One u) |-> ok(text(to_string(b))))), + lexer_item("([# #r#t]+)|(#n)", return((ByteArray b, LexingTools t, One u) |-> ok(text(to_string(b))))) + . map((ColorRule r) |-> if r is rule(_,re,c) then + lexer_item(re,return((ByteArray b, LexingTools t, One u) |-> ok(color(c,to_string(b))))),myrules) + ] + ), + if if_verbose(tbox,"Making colorizer '"+name+"' ... ",make_saved_lexer(ldesc,end_of_input,'#'),"done\n") is + { + error(e) then error(e), + ok(lexer) then + ok((String text) |-> + with lex = lexer(make_lexing_stream("",text),unique), + color_parser(lex)) + }. + + + + + The function below returns the colorizing function associated to the name of a colorizer. If not + found it returns a function performing no colorisation at all (but preserving the text). + +define String -> MAML + get_colorizer + ( + List(Colorizer) l, + String name + ) = + if l is + { + [ ] then (String s) |-> text(s), + [h . t] then since h is clrzr(n,f), + if n = name + then f + else get_colorizer(t,name) + }. + + + +public define Result(RegExprError,MAML) + make_colorizer + ( + Toolbox tbox, + String name + ) = + if create_colorizer(tbox,name,*(tbox.keep.colorrules_v)) is + { + error(e) then error(e), + ok(f) then + with clrzrs_v = tbox.keep.colorizers_v, + clrzrs_v <- [clrzr(name,f) . *clrzrs_v]; + ok(empty) + }. + + +define MAML colorize(MAML m, String -> MAML do_string). + +define List(MAML) + colorize_operands + ( + Toolbox tbox, + List(Colorizer) clrzrs, + List(MAML) ops, + ) = + map((MAML m1) |-> apply_colorizations(tbox,m1,clrzrs) ,ops). + + + +define MAML + colorize + ( + Toolbox tbox, + List(Colorizer) clrzrs, + MAML m, + String -> MAML do_string // the tool for colorizing strings + ) = + if m is + { + error(me) then m, + erroneous(me,m1) then erroneous(me,colorize(tbox,clrzrs,m1,do_string)), + empty then m, + text(value) then do_string(value), + variable(id) then m, + colorize(cname,text) then colorize(cname,colorize(tbox,clrzrs,text,do_string)), + render(name,operands) then render(name,colorize_operands(tbox,clrzrs,operands)), + render(name,operands) then render(name,colorize_operands(tbox,clrzrs,operands)), + macro(name,operands) then macro(name,map((MAML op) |-> colorize(tbox,clrzrs,op,do_string),operands)), + m1 + m2 then colorize(tbox,clrzrs,m1,do_string) + colorize(tbox,clrzrs,m2,do_string) + }. + + The function below looks for consecutive text("bla") and text("blu") and replaces them by text ("blablu"), + so that the colorizer can recognize a token spanning over several pieces of texts. + +define MAML + glue_texts + ( + MAML m + ) = + if m is + { + error(me) then m, + erroneous(me,m1) then erroneous(me,glue_texts(m1)), + empty then m, + text(value) then m, + variable(id) then m, + colorize(cname,text) then colorize(cname,glue_texts(text)), + render(name,operands) then render(name,map(glue_texts,operands)), + render(name,operands) then render(name,map(glue_texts,operands)), + macro(name,operands) then macro(name,map(glue_texts,operands)), + m1 + m2 then + if m1 is text(t1) + then if m2 is text(t2) + then text(t1+t2) + else if m2 is m2a+m2b + then if m2a is text(t2a) + then glue_texts(text(t1+t2a)+m2b) + else glue_texts(m1)+glue_texts(m2) + else glue_texts(m1)+glue_texts(m2) + else if m1 is m1a+m1b + then if m1b is text(t1b) + then if m2 is text(t2) + then glue_texts(m1a+text(t1b+t2)) + else glue_texts(m1)+glue_texts(m2) + else glue_texts(m1)+glue_texts(m2) + else glue_texts(m1)+glue_texts(m2) + }. + + + The function below is called when the MAML parsing is finished. It looks for colorize(,) + in a MAML tree and replaces them by colorized by the colorizer . The result is again + a MAML tree. + +public define MAML + apply_colorizations_aux + ( + Toolbox tbox, + MAML m, // the MAML tree where colorizations are to be executed + List(Colorizer) clrzrs // the list of all colorizers + ) = + if m is + { + error(me) then m, + erroneous(me,m1) then erroneous(me,apply_colorizations_aux(tbox,m1,clrzrs)), + empty then m, + text(tx) then m, + variable(i) then m, + colorize(cname,txt) then with new_txt = apply_colorizations_aux(tbox,txt,clrzrs), + with do_string = get_colorizer(clrzrs,to_string(cname)), + colorize(tbox,clrzrs,glue_texts(new_txt),do_string), + render(name,args) then render(name,map((MAML m1) |-> apply_colorizations_aux(tbox,m1,clrzrs) ,args)), + render(name,args) then render(name,map((MAML m1) |-> apply_colorizations_aux(tbox,m1,clrzrs) ,args)), + macro(name,args) then macro(name,map((MAML m1) |-> apply_colorizations_aux(tbox,m1,clrzrs) ,args)), + m1 + m2 then apply_colorizations_aux(tbox,m1,clrzrs) + apply_colorizations_aux(tbox,m2,clrzrs) + }. + + +public define MAML + apply_colorizations + ( + Toolbox tbox, + MAML m, // the MAML tree where colorizations are to be executed + List(Colorizer) clrzrs // the list of all colorizers + ) = + apply_colorizations_aux(tbox,check_all_forms(tbox,m),clrzrs). + + + *** Undefine. + + Remove the most recent definition of 'name'. + +public define One + do_undefine + ( + Toolbox tbox, + String name + ) = + with v = tbox.keep.macro_tree_v, + v <- update(name,*v, + (Maybe(List(MacroDef)) mb_defs) |-> if mb_defs is + { + failure then failure, + success(l) then if l is + { + [ ] then failure, + [h . t] then success(t) + } + }). + + \ No newline at end of file diff --git a/anubis_dev/library/doc_tools/maml4_tutorial.maml b/anubis_dev/library/doc_tools/maml4_tutorial.maml new file mode 100644 index 0000000..9071c2b --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_tutorial.maml @@ -0,0 +1,1510 @@ + + + + The MAML4 tutorial + (written in MAML4) + + +$begin +$define(article)(0)() +$define(tocsec)(1)($par$bold($1)$par) +$define(tocsubsubsec)(1)() +$define(subseclayout)(1)($par$big($bold($1))$par$par) +$input(basis.maml) + + +$// A counters for the catalog of marks +$pushcounter(markcount)(0) + +$// an accumulator for displaying a table of all mark names at the +$// beginning of the catalog section +$accumulator(tabmark) + +$define(marklo) $// marl layout + (1) + ($addtocounter(markcount)(1)$par$par$bold($countervalue(sec).$countervalue(markcount). $1)$par$par) + + $// A colorizer for MAML code +$colorrule(maml)(#$#/#/.*)($darkgreen($1)) +$colorrule(maml)((#$[#,#[#]#(#)])|(#$[a-zA-Z#_][0-9a-zA-Z#_]*)|(#$#$))($bold($red($1))) +$colorrule(maml)(#$[0-9]+)($magenta($1)) +$colorrule(maml)([0-9]+)($sienna($1)) +$colorizer(maml) + +$// Some layout macros. +$define(p)(0)($par$par) +$define(title)(1)($center($big($big($bold($1))))) +$define(MAML)(0)($bold($rgb(180,0,0)(M)$rgb(0,120,0)(A)$rgb(80,80,80)(M)$rgb(0,0,220)(L))) +$define(em)(1)($italic($1)) +$define(textcolor)(0)(100,20,20) +$define(mtt)(1)($tt($colorize(maml)($nolist($1)))) +$define(mcode)(1)($code(230,235,220)($colorize(maml)($par$nolist($1)$par$par))) +$define(mcenter)(1)($par$center($colorize(maml)($nolist($1)))$par) +$define(argu)(1)($rgb(0,80,0)($bold($tt(<$1>)))) +$define(LaTeX)(0)($latex(\LaTeX)) +$define(unsafe)(0)($bold($rgb(220,0,0)(unsafe))) +$define(id)(1)($1) +$define(ptext)(1)($rgb(120,40,40)($1)) +$define(fname)(1)($rgb(0,80,50)($tt($1))) + + +$// A system for displaying names of marks on several columns +$pushcounter(col)(0) +$define(advcol)(0)($if($equals($countervalue(col))(3))($setcounter(col)(0)$par)($addtocounter(col)(1))) + +$// Displaying marks in the catalog and accumulating links to them. +$define(mark0)(1)($append(tabmark)($box(20)()$box(120)($ref($1)($mtt($$$1)))$advcol)$label($1)$marklo($red($mtt($$$1)))) +$define(mark1)(2)($append(tabmark)($box(20)()$box(120)($ref($1)($mtt($$$1)))$advcol)$label($1)$marklo($red($mtt($$$1$lpar$argu($2)$rpar)))) +$define(mark2)(3)($append(tabmark)($box(20)()$box(120)($ref($1)($mtt($$$1)))$advcol)$label($1)$marklo($red($mtt($$$1$lpar$argu($2)$rpar$lpar$argu($3)$rpar)))) +$define(mark3)(4)($append(tabmark)($box(20)()$box(120)($ref($1)($mtt($$$1)))$advcol)$label($1)$marklo($red($mtt($$$1$lpar$argu($2)$rpar$lpar$argu($3)$rpar$lpar$argu($4)$rpar)))) +$define(mark4)(5) + ($append(tabmark)($box(20)()$box(120)($ref($1)($mtt($$$1)))$advcol)$label($1)$marklo($red($mtt($$$1$lpar$argu($2)$rpar$lpar$argu($3)$rpar$lpar$argu($4)$rpar$lpar$argu($5)$rpar)))) + + + + + $/////////////////// Here begins the text ////////////////////////// + +$title(The $MAML (version 4) Tutorial) +$title(and Reference) +$par$par$par + +$MAML (the $em(Minimalist Anubis Markup Language)) is an easy to use tool for writing texts. It provides +commands for using different $bold(font) $italic(styles), $big(font $big(sizes)), $red(colors), for making lists, tables, +sectionning units, inserting images +and +hypertext links, automatically making a table of contents, +and most sorts of things which are useful for writting texts which are agreable to read. +It is also able to automatically produce syntactic colorations. The $MAML +compiler produces HTML and PDF output files from a $MAML source text. +This documentation itself was written in $MAML.$p + +Despite its computing capabilities, $MAML is $em(not a programming language). It is a $em(text formating language). +Programming with $MAML is easy provided you write only very short pieces of programs. Making big programs in $MAML +would generate absolutely unreadable source texts (like what happens with $latex(\TeX)). We have managed to present +many (short) examples of $MAML programming in this tutorial, which helps to quickly understand the explanations.$p + +The very first version of $MAML was designed for allowing users on a forum to decorate their messages, and was +very rudimentary. This is +why $MAML was called $em(minimalist). This version 4 is now quite far from being $em(minimalist), but the name $MAML +remains (partly because it's funny when pronounced in French). + +$p +$center($bold(Table of Contents))$par +$tableofcontents + + +$////////////////////////////////////////////////////////////////////////////////: +$section(howto)(How to use $MAML) +$subsection(ascmdlinetool)(As a command line tool) +$MAML can be used as a command line tool. This tool can work to its full power +only if $mtt(pdflatex) and $mtt(dvipng) are installed on +your system. If they are not, you can still use $MAML, but the mark $mtt($$latex) will not work, and you will not be able +to produce a PDF output. See the Anubis library documentation for more precise explanations. +$par +$par +Assuming that the file $mtt(my_file.maml) contains some $MAML source text, +you just have to issue the command: +$mcode(anbexec maml my_file.maml) +and the $MAML compiler will produce a file named $mtt(my_file.maml.html) that you can view with your favorite browser. +$par +$par +This command line tool has several options that you can discover by typing: +$mcode(anbexec maml) +For example, the option $mtt(-pdf) produces a PDF output. +$p + +$subsection(fromyoursource)(From within your Anubis source code) +You may also want to use the $MAML compiler from within your Anubis source code. For example, you may want to use $MAML + on a web site. +In this case, have a look at the Anubis library documentation. +Notice that several $MAML marks are $unsafe for a use on the web. We explain in the library documentation +how to restrict $MAML to safe marks.$p + + +$subsection(aswebuser)(As a web user) +Since $MAML can be used in a web site (powered for example by the Anubis web server), it is possible to allow web users +(those persons visiting the web site) to write $MAML texts within web pages. In this case, the set of available $MAML +marks is restricted for ensuring the security of the web server.$p + + + +$////////////////////////////////////////////////////////////////////////// +$section(syntax)(The $MAML syntax) +$subsection(beginend)($mtt($$begin), $mtt($$end) and special characters) +When it reads a source text, the $MAML compiler ignores everything until the first occurrence of $ref(begin)($mtt($$begin)). After +this $em(mark), the compiler parses and evaluates the text until it finds $ref(end)($mtt($$end)). Then again, it ignores everything +until the next $mtt($$begin), and so on.$p + +Between $mtt($$begin) and $mtt($$end), the compiler considers all characters as neutral (i.e. they represent only +themselves), except the character $mtt($$). This character introduces a so-called $em(mark), which can have so-called +$em(operands). The operands are delimited by pairs of parentheses. + +Within an operand, all characters are considered as pure text, except the following: +$list( + $item the character $mtt($$), + $item the left and right parentheses $mtt($lpar) and $mtt($rpar). They are used for delimiting blocks of text. + $item the left and right square brackets $mtt($[) and $mtt($]). They are used for delimiting lists, and within such + lists, the comma $mtt($,) is used for separating the elements of the list. The comma is otherwise neutral. +) + Of course, the possibility exists of inserting these characters as usual neutral characters. It is enough to prefix + them by a $mtt($$). Hence, for example, $mtt($[) marks the beginning of a list, whereas $mtt($$$[) just represents a + left square bracket.$p + + The figure below sumarizes the above rules. +$mcode( $em($darkgreen(before $$begin everything is ignored)) + + $$begin + + $em($navy(here, outside any operand of mark, only the character $$ is special)) + + $$a_mark(... $em($darkred(here, $bold($$ $( $) $[) and $bold($]) are special)) ...) + (... $[ $em($sienna(and here, the comma also is special)) $] + ... $$another_mark( $em($darkred(here too, $bold($$ $( $) $[) and $bold($]) are special)) ...) ... + (... $$nolist($em($purple(but here, only $bold($$ $() and $bold($)) are special + even if we are within a list, but brackets + must still be balanced))) ...) ) + + $$end + + $em($darkgreen(here again, everything is ignored)) + + $$begin + + $em($navy(and here, it works again as above after the first $$begin)) + $em($black(you can alternate $$begin and $$end any number of times)) + + $em($black(etc... (and an $$end is required for closing each $$begin)))) + + +$subsection(syntaxmark)(Marks) +This character $mtt($$) indicates +that what follows is a $em(mark). The name of the mark (a non empty sequence of characters among +$mtt($black(A...Za...z0...9))) and the underscore $mtt(_) and not beginning by a digit) +immediatly follows the character $mtt($dollar). The operands +of the mark follow this name, and each one must be delimited by a pair of parentheses. For example, if you +want to render some text in dark red, you can write this, where $mtt(rgb) is the name of the mark (this mark takes two operands):$par +$mcenter($mtt($$rgb(120,0,0)(This text is rendered in dark red.))) +which produces this: +$mcenter($rgb(120,0,0)(This text is rendered in dark red.)) + +You shall learn below how to write $em(macros) in $MAML using the mark $ref(define)($mtt($$define)), +so that you can actually simplify the writing of the above. For example the name $MAML itself +is produced by the macro $mtt($$MAML) which is defined as follows: +$mcode($$define(MAML)(0) $$// defining the macro $$MAML taking zero operand + ($$bold($$rgb(180,0,0)(M)$$rgb(0,120,0)(A)$$rgb(80,80,80)(M)$$rgb(0,0,220)(L)))) + +$subsection(linecomments)(Line comments) +Notice that you can put $em(line comments) into your $MAML source texts as follows:$p +$center($mtt($$// blah blah blah ...))$par +The mark $mtt($$//) and what follows until the end of the line are ignored by the compiler (but it keep +the new line charaters). This kind of comment can be +put everywhere, including within operands of marks, between the operands of a mark (as shown above) and between +a mark and its first operand.$p + +$subsection(balanced)(Parentheses must be balanced) +Each mark accepts a fixed number of operands. Since each operand must be delimited by a pair of parentheses +(which are not part of the operand itself), the +parentheses which are part of the operand (if any) must be balanced, otherwise the $MAML parser will not find the closing +parenthese. Nevertheless, you can still include unbalanced parentheses in an operand provided that you write them +$mtt($$lpar) (left parenthese) and $mtt($$rpar) (right parenthese).$p + + +$subsection(marknamedelim)(How mark names are delimited) +Also remark that between any two operands of a mark (and between the mark itself and its first operand), you cannot +write anything else than $em(white) characters (i.e. spaces, line-feeds, carriage-returns and tabulators), and line +comments. For example, +$mcode($$rgb(0,0,255)(My text)) +is equivalent to +$mcode($$rgb (0,0,255) $$// this make a bright blue + (My Text)) +But if you write this: $mtt($$rgb(0,0,255) a (My text)), the compiler will complain that an operand is missing (it +also indicates the path of the file and the line number where this happens). +$par +$par +$em(Remark:) The name of a mark is right delimited by the first character which is not an acceptable character +for such a name. If this character is a space, it is $em(not) discarded (unlike what the $latex(\TeX) compiler +does). Hence for example, +$mtt($$lpar x) (with just one space between $mtt($$lpar) and $mtt(x)) +produces $lpar x (with a space between the parenthese and x), +so that it seems that there is no way to obtain $id($lpar)x (with nothing between the parenthese and x). +Actually, there is a simple trick to +obtain the later. Indeed, it is enough to define an $em(identity) macro as follows: +$mcode($$define(id)(1)($$1)) +and to write $mtt($$id($$lpar)x).$p + + + + +$subsection(definingmarks)(Defining new marks with $mtt($$define)) +We already saw examples of use of $mtt($$define) above. It's now time to give precisions about this possibility to +enrich the language with new marks, which is one of the most powerful tools we have at hand.$p + +The syntax of $mtt($$define) is as follows:$par +$mcenter($mtt($$define($argu(name))($argu(arity))($argu(value)))) +where $argu(name) is the name you want to give to your new mark, $argu(arity) its $em(arity), i.e. the number of +operands it takes, and $argu(value) the value of the mark, which of course depends on the values of it's future operands, which +is the reason why $argu(value) contains so-called $MAML $em(variables) $mtt($$1), $mtt($$2), etc...$p + +Notice that if a macro with the same name $argu(name) is already defined, $mtt($$define) does not destroy this +previous definition of $argu(name). It pushes the new definition on a stack of definitions associated to this name. As a +consequence, when you use $mtt($$undefine($argu(name))), the most recent definition of name is poped off this stack (and +forgotten) and the previous one prevails again. See $ref(undefine)($mtt($$undefine)) for some examples.$p + +When the $MAML compiler encounters a $mtt($$define($argu(name))($argu(arity))($argu(value))), it doesn't evaluate +(i.e. it doesn't $em(compute)) $argu(name) nor $argu(arity). Consequently, these two operands must be written in their +definitive form.$p + +The third operand $argu(value) is only $em(partly evaluated) in the sens that macros are expanded within $argu(value), +but primitive marks are not executed (which is in any case mandatory since operands are not yet known). +This policy has two important consequences: +$list( + $item if $argu(value) contains a call to $argu(name), this call doesn't refer to the macro currently being defined, + but to its previous definition (if any). As a byproduct, this also forbids recursive definitions of macros, so + protecting the $MAML compiler against infinite loops.$p + $item $argu(value) cannot refer to a macro which is not yet defined (there are no forward references in $MAML), so + that the macro always keeps the meaning it has when it is defined, except that the values provided by primitive marks + will be computed only when the macro is used. +) +Nevertheless, you may want, especially if you are defining a customizable style of document for example, to define +macros making use of other macros which can be redefined by the user of your style file. The solution is first of all +to define these other macros conditionally, i.e. as follows: +$mcode($$if($$defined($argu(name)))()($$define($argu(name))(...)(...))) +that is that you provide a $em(default) definition, but only in case your user did not define $argu(name). Of course, this +implies that your user must define $argu(name) $em(before) writing $mtt($$input($argu(your style file))).$p + +$///////////////////////////////////////////////////////////////////////// +$section(style)(Be stylish) +The primitive $MAML marks are rather basic, and should preferably be used for creating macros. +In other words, it's better to first define (using the $mtt($$define) mark) the concepts you will use in your +text, rather than writing them from scratch at each occurrence. In some sens, defining these concepts is the same as +creating your own style. $p + +$subsection(basismaml)(The file $fname(basis.maml)) +Notice that a file $fname(basis.maml) exists in $fname(library/doc_tools) which already contains macros of +common usage. +$p + +$subsection(styleexample)(An example) +It can be the case that some concept of your discourse has to be emphasized in a particular way, and that +you (arbitrarily) chosed to print it +in red. You should not use $mtt($$rgb(255,0,0)(...)) in the text. You should better first give a name (say $mtt(emph)) to +your concept, and define it near the beginning of the text: +$p +$mtt($$define(emph)(1)($$rgb(255,0,0)($$1))) +$p +and write $mtt($$emph(...)) in the text instead of $mtt($$rgb(255,0,0)(...)). +$p +This will structure your text in a useful semantic way, instead of a non significant way, making it easier +to later update. +It also has the advantage that you can later easily change the layout of the text by modifying +only the values in these $mtt($$define). +$p +$subsection(inputstyle)(Inputting a style file) +The $mtt($$input) mark let you $em(input) a $MAML source at any point of another $MAML source. Hence, you should +define your style in a file (say $mtt(mystyle.maml)) and put an $mtt($$input(mystyle.maml)) after the first $mtt($$begin) +of your source file. Notice that the input file also needs to contain a $mtt($$begin) and an $mtt($$end).$p + + + +$/////////////////////////////////////////////////////////////////////////////: +$section(colorize)(Automatic colorization) +$MAML has a simple system for automatic colorization of texts. Within a $MAML source text, +you can define one or several colorizers, and later apply them at will. Actually, by $em(colorization) we mean +something quite general, i.e. not dealing only with colors.$p + +$subsection(createcolorizer)(Creating a colorizer) +In order to create a colorizer, you must: +$list( + $item define one or several $italic(color rules), + $item when done, create the $italic(colorizer). +) +A color rule has the form:$par +$mcenter($mtt($$colorrule($argu(colorizer name))($argu(regular expression))($argu($MAML expression)))) +The $argu(colorizer name) of the colorizer must be an ordinary symbol. The $argu(regular expression) must follow the syntax defined in +$fname(library/lexical_analysis/fast_lexer_5.anubis) (see the Anubis library documentation) and $em(is not evaluated), so +that it must be written in its definitive form. +The $argu($MAML expression) can contain the $MAML $em(variable) +$mtt($$1) which is replaced by the token (i.e. the character string recognized by the regular expression) +to be colorized.$par$par + +Once the color rules are setup, you can create the colorizer as follows:$par +$mcenter($mtt($$colorizer($argu(colorizer name)))) +Then, you can colorize a text:$par +$mcenter($mtt($$colorize($argu(colorizer name))($argu(text)))) + +$subsection(mycolorizer)(A colorizer example) +As an example, consider the following definition of a colorizer, which is used in this tutorial for colorizing +$MAML code: +$mcode( $$// line comments +$$colorrule(maml)(#$$#/#/.*)($$darkgreen($$1)) + $$// mark names (inclusing inhibited characters) +$$colorrule(maml)($black((#$$$[#$,#$[#$]#(#)$])|(#$$$[a-zA-Z#_$]$[0-9a-zA-Z#_$]*)|(#$$#$$))) + ($$bold($$red($$1))) + $$// MAML variables +$$colorrule(maml)($black(#$$$[0-9$]+))($$magenta($$1)) + $$// integers +$$colorrule(maml)($black($[0-9$]+))($$sienna($$1)) + $$// creating the colorizer +$$colorizer(maml)) +There are plenty of examples of use of this colorizer in this tutorial (including the above definition of the +$mtt(maml) colorizer$sp!), so that you can easily check that the result is coherent with the definition.$p + +Notice that we used $mtt($$bold) in the above definition, which is not a color per se. Actually any mark can be used, so +that colorizers can also be used for a purpose having nothing to do with colors.$p + +$subsection(colorizerprecedence)(Primitive marks and colorizers) +You also need to know what happens if the text to be colorized contains $MAML marks. +All macros are expanded before colorization applies, so that macros have no incidence on colorization, but they can be +used within a text to be colorized. $p + +Things are different for primitive marks. Indeed, how do you interpret for example +$p +$center($mtt($$colorize(maml)($black(This is $$rgb(120,0,0)(an example) text.)))) +$par +It should be clear that $tt($$rgb) in this example should +have precedence over $mtt($$colorize), otherwise it would be useless. So, the behavior of $MAML is that it doesn't +apply a colorizer within the operands of primitive marks (it would be nevertheless meaningless in the case of the operand +$tt(120,0,0) of $tt($$rgb)).$p + +As a consequence, the above example gives +$colorize(maml)(This is $rgb(120,0,0)(an example) text.), +not $colorize(maml)(This is an example text.)$p + +Nevertheless, you can still colorize within an operand within a text to be colorized. For example, +$p +$center($mtt($$tt($$colorize(maml)($black($$$$bold($$darkgreen($$$$red(text)))))))) +$par +produces $tt($colorize(maml)($$bold($darkgreen($$red(text))))), whereas +$p +$center($mtt($$tt($$colorize(maml)($black($$$$bold($$darkgreen($$colorize(maml)($$$$red(text))))))))) +$par +produces $tt($colorize(maml)($$bold($darkgreen($colorize(maml)($$red(text)))))).$p + +$subsection(severalcolorizers)(Using several colorizers together) +You can use several colorizers together. Below is another colorizer: +$mcode($$colorrule(funny)([a-e])($$rgb(10,0,130)($$sup($$1))) +$$colorrule(funny)([e-k])($$rgb(150,0,0)($$italic($$1))) +$$colorrule(funny)([l-p])($$rgb(100,100,0)($$big($$big($$1)))) +$$colorrule(funny)([p-z])($$rgb(0,100,100)($$sub($$big($$1)))) +$$colorizer(funny)) +$colorrule(funny)([a-e])($rgb(10,0,130)($sup($1))) +$colorrule(funny)([e-k])($rgb(150,0,0)($italic($1))) +$colorrule(funny)([l-p])($rgb(100,100,0)($big($big($1)))) +$colorrule(funny)([p-z])($rgb(0,100,100)($sub($big($1)))) +$colorizer(funny) +If you write: +$mcode($$tt($$colorize(maml) + ($black($$$$bold(Some text $$colorize(funny)(with a piece of funny text) in it.))))) +you get $tt($colorize(maml)($$bold(Some text $colorize(funny)(with a piece of funny text) in it.)))$p + + +$subsection(colorizercall)(Calling a colorizer from within a colorizer) +Using several colorizers together can also help to solve particular colorizing problems, because the above is not the +whole story about $MAML colorizers. Indeed, we have another primitive mark: +$p +$center($mtt($$colorizercall($argu(mode))($argu(colorizer1))($argu(call))($argu(colorizer2))($argu(return)))) +$par +which allows to $em(call) a colorizer (here $mtt($argu(colorizer2))) from within another colorizer (here $mtt($argu(colorizer1))). +The operands $mtt($argu(call)) and $mtt($argu(return)), which can be any $MAML expressions expanding into regular expressions, are used +as $em(call) and $em(return) instructions. In other words, when $mtt($argu(colorizer1)) encounters something matching the +regular expression $mtt($argu(call)) it calls $mtt($argu(colorizer2)) which will return when it founds something matching the +regular expression $mtt($argu(return)).$p + +The pieces of text matching $mtt($argu(call)) and $mtt($argu(return)) are colorized by $mtt($argu(colorizer1)) or by +$mtt($argu(colorizer2)), depending on the value of $argu(mode). There are four modes: +$list( + $item $mtt(ee) ($em(exclude-exclude)): both $argu(call) and $argu(return) are colorized by $argu(colorizer1), + $item $mtt(ei) ($em(exclude-include)): $argu(call) is colorized $argu(colorizer1) and $argu(return) by $argu(colorizer2), + $item $mtt(ie) ($em(include-exclude)): $argu(call) is colorized $argu(colorizer2) and $argu(return) by $argu(colorizer1), + $item $mtt(ii) ($em(include-include)): both $argu(call) and $argu(return) are colorized by $argu(colorizer2). +) + + +$subsection(colorcallexample)(A colorizer call example) +Consider the case of an Anubis source text, such as: +$ptext($code(255,255,255)($nolist( + + A function for computing the length of a list: + +public define Int + length + ( + List($$T) l + ) = + if l is + { + [ ] then 0, + [h . t] then 1 + length(t) + }. + + Blah blah blah ... + +))) +This example contains a $em(paragraph) defining a function, which is surrounded by so-called $em(off-paragraph +comments). In order to colorize this text we need to be able to detect the beginning and the end of Anubis paragraphs. +This is not possible if we use only color rules as defined by $mtt($$colorrule), but it becomes possible if we also use +$mtt($$colorizercall).$p + +Indeed, we first define two colorizers, say $mtt(off) for off-paragraph comments and $mtt(in) for paragraphs.$p + +In this example, we deliberately chosed to have a head of case of the form $ptext([h . t]) in the conditional, +because it also contains an $em(end dot) (a dot followed by a space or a linefeed) which must not be confused +with the end dot closing the paragraph.$p + +In order to colorize the paragraph itself, we need something like: +$p +$center($mtt($$colorizercall(ii)(off)(#npublic)(in)(#.[# #r#n]))) +$par +However, if we do that, the colorization of the paragraph will end at the end dot which is within the square brackets. +In order to avoid this, we must add another call: +$p +$center($mtt($$colorizercall(ii)(in)(#$[)(in)(#$]))) +$par +(the sharp character, i.e. the escape character for regular expressions, +in front of the square brackets is necessary since square brackets are special characters +in regular expressions). +That way, the colorizer $mtt(in) will call itself when it reads an opening square bracket and return (to itself) when it reads the +corresponding closing square bracket.$p + +However, with these two call rules, the colorization is still not correct because when the opening bracket of $mtt([h . +t]) is seen the colorizer $mtt(in) calls itself, and the second instance of $mtt(in) returns on the end dot so that the +first instance of $mtt(in) returns on the closing bracket, and the $mtt(off) colorizer is active again at this +closing bracket. The solution is to define two distinct $mtt(in) colorizers, as shown below.$par + +$mcode($$colorrule(off)(.)($$darkgreen($$1)) +$$colorrule(in1)(.)($$darkred($$1)) +$$colorrule(in2)(.)($$rgb(0,100,100)($$1)) +$$colorrule(in1)(#npublic[# #r#n]+define)($$tbgc(220,220,0)($$rgb(0,0,100)($$bold($$1)))) +$$colorrule(in1)(#.[# #r#n])($$tbgc(220,220,0)($$rgb(0,0,100)($$bold($$1)))) +$$colorizercall(ii)(off)(#npublic[# #r#n]+define)(in1)(#.[# #r#n]) +$$colorizercall(ii)(in1)(#$[)(in2)(#$]) +$$colorizercall(ii)(in2)(#$[)(in2)(#$]) +$$colorizer(in1) +$$colorizer(in2) +$$colorizer(off)) + + +$colorrule(off)(.)($darkgreen($1)) +$colorrule(in1)(.)($darkred($1)) +$colorrule(in2)(.)($rgb(0,100,100)($1)) +$colorrule(in1)(#npublic[# #r#n]+define)($tbgc(220,220,0)($rgb(0,0,100)($bold($1)))) +$colorrule(in1)(#.[# #r#n])($tbgc(220,220,0)($rgb(0,0,100)($bold($1)))) +$colorizercall(ii)(off)(#npublic[# #r#n]+define)(in1)(#.[# #r#n]) +$colorizercall(ii)(in1)(#[)(in2)(#]) +$colorizercall(ii)(in2)(#[)(in2)(#]) +$colorizer(in1) +$colorizer(in2) +$colorizer(off) +(we put a different color for $mtt(in1) and $mtt(in2) texts for showing where $mtt(in1) calls $mtt(in2) and where $mtt(in2) +returns). +Now, if we write $mtt($$code($$_ivory)($$colorize(off)($argu(the above example text)))), we get: + +$code($_ivory)($colorize(off)($nolist( + + A function for computing the length of a list: + +public define Int + length + ( + List($$T) l + ) = + if l is + { + [ ] then 0, + [h . t] then 1 + length(t) + }. + + Blah blah blah ... + +))) +and more generally, this works for any depth of square brackets nesting.$p + + +$subsection(noncolor)(A non colorizing example.) +As said above, colorizers are more general than just a tool for colorizing text. For example, they can be used, +to some extent, for $em(parsing) a text.$p + +Assume that we have a text which is in CSV (comma separated values) format. Such texts are very common since every +database system is able to export its tables in this format. Below is an example of such a datum. +$mcode($$define(mycsvtable)(0) +(Ford,Max,32,New York +Jackson,Niel,64,Los Angeles +Kennedy,Justin,25,New York +Obama,Barack,55,Washington +Smith,John,24,Baltimore +Trump,Donald,70,New York)) + +$define(mycsvtable)(0) +(Ford,Max,32,New York +Jackson,Niel,64,Los Angeles +Kennedy,Justin,25,New York +Obama,Barack,55,Washington +Smith,John,24,Baltimore +Trump,Donald,70,New York) + + +In this piece of text, the lines of the table are separated by linefeeds and the values in a line are separated by +commas. For simplicity, we assume that the values contain no comma and no linefeed. In a realistic situation, we would +have to enhance our example for handling (for example) commas which are within a pair of parentheses. This kind of +enhancement would require some $mtt($$colorizercall).$p + +We define the following colorizer. +$mcode($$pushcounter(col)(0) +$$pushcounter(line)(0) +$$colorrule(display)(#,)($$addtocounter(col)(1)) +$$colorrule(display)(#n) + ($$addtocounter(line)(1)$$par$$box(40)($$countervalue(line))$$setcounter(col)(0)) +$$colorrule(display)($[^#n#$,$]*)($$if($$equals(2)($$countervalue(col))) + ($$box(40)($$red($$1))) + ($$if($$equals(0)($$countervalue(col))) + ($$box(100)($$bold($$1))) + ($$box(100)($$1)))) +$$colorizer(display)) + +$pushcounter(col)(0) +$pushcounter(line)(0) +$colorrule(display)(#,)($addtocounter(col)(1)) +$colorrule(display)(#n)($addtocounter(line)(1)$par$box(40)($countervalue(line))$setcounter(col)(0)) +$colorrule(display)([^#n#,]*)($if($equals(2)($countervalue(col))) + ($box(40)($red($1)))($if($equals(0)($countervalue(col)))($box(100)($bold($1)))($box(100)($1)))) +$colorizer(display) +If we write +$mcode($$colorize(display)( +$$mycsvtable)) + +we obtain: +$par +$colorize(display)( +$mycsvtable) +$p +Notice that thanks to the counter $mtt(col), we can perform a different treatment on each column. +Also remark that the first line of +the table has a number in front of it because we added a linefeed in front of $mtt($$mycsvtable) within the second operand of +$mtt($$colorize). +$p +Now, we want to get this same text in the form of a list of lines, where each line is itself a list of values. +To this end, we define another $em(colorizer). +$mcode($$accumulator(table) +$$accumulator(line) + $$// without the line below, the commas would appear on the page +$$colorrule(parsecsv)(#$,)() +$$colorrule(parsecsv)(#n)($$append(table)($$content(line))$$accumulator(line)) +$$colorrule(parsecsv)($[^#n#$,$]+)($$append(line)($$1)) +$$colorizer(parsecsv) +$$colorize(parsecsv)($$mycsvtable +)) + +$accumulator(table) +$accumulator(line) +$colorrule(parsecsv)(#,)() +$colorrule(parsecsv)(#n)($append(table)($content(line))$accumulator(line)) +$colorrule(parsecsv)([^#n#,]+)($append(line)($1)) +$colorizer(parsecsv) +$colorize(parsecsv)($mycsvtable +) + +Despite the fact that we wrote $mtt($$colorize), this doesn't produce any output because +the regular expressions cover all cases and the values in the color +rules contain only marks which produce side effects but no output.$p + +So, we expect that the accumulator $mtt(table) contains our list of lists. +To check that, we define: +$mcode($$define(putbox)(1)($$tbgc($$_azure)($$box(75)($$1)) ) +$$define(putpar)(1)($$apply(putbox)($$1)$$par)) + +$define(putbox)(1)($tbgc($_azure)($box(75)($1)) ) +$define(putpar)(1)($apply(putbox)($1)$par) + +and write $mtt($$apply(putpar)($$content(table))), which produces +$p +$apply(putpar)($content(table)) +$par +and $mtt($$apply(putpar)($$transpose($$content(table)))), which produces +$p +$apply(putpar)($transpose($content(table))) +$par +This last manipulation makes even more obvious the fact that we actually got our table in the form of +a list of lists. + + + +$p +$section(tools)(Other tools) +$MAML is $em(not a programming language). It is a $em(document formatting language). Nevertheless, it provides some +programming capabilities, but only those which are (to our opinion) required for the needs of the layout of the +document. Of course, this set of tools could be enlarged in the future.$p + +$subsection(arithmetics)(Elementary arithmetics) +$MAML is able to perform some elementary arithmetic operations on numbers (which are all relative integers). These +operations are: +$list( + $item $box(200)($mtt($$add($argu(m))($argu(n)))) addition of $argu(m) and $argu(n) + $item $box(200)($mtt($$minus($argu(m))($argu(n)))) substraction of $argu(n) from $argu(m) + $item $box(200)($mtt($$opp($argu(m)))) opposite of $argu(m) + $item $box(200)($mtt($$mul($argu(m))($argu(n)))) multiplication of $argu(m) by $argu(n) + $item $box(200)($mtt($$quotient($argu(m))($argu(n)))) quotient of the euclidian division of $argu(m) by $argu(n) + $item $box(200)($mtt($$remainder($argu(m))($argu(n)))) remainder of the euclidian division of $argu(m) by $argu(n) +) +In case of a division by zero, an error message is generated.$p + +$////////////////////////////////////////////////////////////////////////////////// +$subsection(booleans)(Booleans and control) +$MAML provides some rudimentary tools for better controling the $MAML compiler. $MAML recognizes the marks $mtt($$true) and +$mtt($$false) as $em(truth values) (aka. $em(booleans)). Other marks also produce booleans, such as +$mtt($$equals($argu(expr 1))($argu(expr 2))) and $mtt($$defined($argu(macro name))).$p + +These truth values can be used as $argu(test) in:$p +$center($mtt($$if($argu(test))($argu(if true))($argu(if false))))$par +The value of the above mark is $argu(if true) if $argu(test) is true and $argu(if false) otherwise, and of course +only one of $argu(if true) and $argu(if false) is evaluated.$p + +Notice that some logical operators can be defined: +$mcode($$define(and) (2) ($$if($$1)($$2)($$false)) +$$define(or) (2) ($$if($$1)($$true)($$2)) +$$define(neg) (1) ($$if($$1)($$false)($$true)) +$$define(implies) (2) ($$or($$neg($$1))($$2))) + + +$///////////////////////////////////////////////////////////////////////////// +$subsection(counters)(Counters) +$MAML has a notion of $em(counter). You can create a counter with $mtt($$pushcounter($argu(name))($argu(init))), where +$argu(name) is the name of the new counter, and $argu(init) its initial value (which must be a positive, zero or +negative integer).$p + +You can get the value of a counter with $mtt($$countervalue($argu(name))) (giving a character string representing +the value in decimal notation, possibly prefixed by a minus sign). +You can modify the value of a counter with $mtt($$setcounter($argu(name))($argu(value))) and +$mtt($$addtocounter($argu(name))($argu(value))).$p + +You can destroy a counter with $mtt($$popcounter($argu(name))).$p + +Actually, for each counter name, $MAML manages a stack of counters. Consequently, if you create a new counter with the +same name as an already existing counter, the first counter is not destroyed and +becomes visible again when the second counter is destroyed.$p + +As an exemple, consider the following: + + +$mcode($$pushcounter(n)(0) +$$define(ga)(0)($$addtocounter(n)(1)$$countervalue(n))) +$pushcounter(n)(0) +$define(ga)(0)($addtocounter(n)(1)$countervalue(n)) + +If we write: $mtt($$ga $$ga $$ga $$ga $$ga $$ga $$ga $$ga $$ga $$ga $$ga $$ga $$ga), we get:$p +$center ($ga $ga $ga $ga $ga $ga $ga $ga $ga $ga $ga $ga $ga) +Continuing that way, we can write: +$mcode($$pushcounter(n)(25) +$$countervalue(n) +$$popcounter(n) +$$countervalue(n)) +and we get: +$center( +$pushcounter(n)(25) +$countervalue(n) +$popcounter(n) +$countervalue(n)) +(as expected).$p + + +$subsection(lists)(Lists) +$MAML has a notion of $em(list). In order to create a list (say with three elements $mtt(a), $mtt(b) and $mtt(c)), +you can write $mtt($[a$,b$,c$]). If you write this outside any $MAML operand, you get this: +$p +[a,b,c] +$p +In other words, the square brackets and the comma are just seen as ordinary (neutral) characters (and there is no list +at all in this case). On the contrary, if you write $mtt($$red($[a$,b$,c$])), you get this: +$p +$red([a,b,c]) +$p +This is first of all because the square brackets and the comma are recognized as special characters within an operand +(so that we now have an actual list), and because the rendering of a list consists in rendering its element one after the +other without any separator between them. Nevertheless, if we want to render the above list in red with the brackets +and the commas, it is enough to write $mtt($$red($$$[a$$$,b$$$,c$$$])): +$p +$red($[a$,b$,c$]) +$p + +The square brackets and the comma, everywhere they are recognized as special characters $em(eat) the spaces on both +sides. This means that it is equivalent to write $mtt($$red($[a$,b$,c$])) and to write $mtt($$red( $[ a$, b $, c +$] )). However, be careful because an expression such as $mtt($$red($[a$,b$,c$])) is $em(not) a list and triggers +an error if written at a place where a list is required.$p + +List are useful because they can be manipulated by several primitive marks, such as: +$list( + $item $mtt($ref(reverse)($$reverse)($argu(list))) + $item $mtt($ref(sort)($$sort)($argu(list))) + $item $mtt($ref(length)($$length)($argu(list))) + $item $mtt($ref(sublist)($$sublist)($argu(start))($argu(end))($argu(list))) + $item $mtt($ref(apply)($$apply)($argu(mark name))($argu(list))) + $item $mtt($ref(transpose)($$transpose)($argu(list of lists))) +) +How these primitives marks operate is explained in the $ref(catalog)(catalog).$p + +There are circumstances where we want the square brackets and the comma to be considered as ordinary (neutral) +characters. For example, it should be the case for the second operand of +$ref(code)($mtt($$code($argu(color))($argu(computer code)))), and also in some operands of some other primitives. +To simplify the matter and to offer the maximal number of possibilities, primitives such as $mtt($$code) don't care +about that. This is why we propose the primitive $ref(nolist)($mtt($$nolist($argu(text)))) which inhibits the +recognition of the squares brackets and the comma within $argu(text). Hence, $mtt($$code) should be used as follows: +$p +$center($mtt($$code($argu(color))($$nolist($argu(computer code))))) +$par +and you can define a macro for handling this.$p + +As an example, consider the following list of words: +$mcode($$define(cities)(0) + ($[New York$,Paris$,Berlin$,Moscow$,Casablanca$,Cairo$,Athens$,Rio de Janeiro$])) +$define(cities)(0)([New York,Paris,Berlin,Moscow,Casablanca,Cairo,Athens,Rio de Janeiro]) + +We can write: +$mcode($$pushcounter(n)(0) +$$define(number)(1)($$addtocounter(n)(1)$$box(20)($$countervalue(n).)$$1$$par) +$$define(a)(1)($$alphabetic($$1)) +$$center($$apply(number)($$sort($$apply(a)($$cities))))) +which gives this: +$pushcounter(n)(0) +$define(number)(1)($addtocounter(n)(1)$box(20)($countervalue(n).)$1$par) +$define(a)(1)($alphabetic($1)) +$center($apply(number)($sort($apply(a)($cities)))) + +$p + +$/////////////////////////////////////////////////////////////////////////////////////////// +$section(tips)(Tips and tricks) +If your text needs to display some computer code, it can be the case (depending on the programming language) +that this code uses dollar characters. This is the case of Anubis for example, since dollars are used by +type parameters. These dollars can make a problem since the dollar is also the escape character of $MAML.$par$par + +You can of course double the dollars in the computer text examples, but there are situations where we don't want to +do this, or just cannot do this. This is the case for example in the Anubis library, since some files are at the +same time $MAML files (compilable by $MAML), and Anubis file (compilable by $mtt(anubis)). In this case, we cannot +change anything to the text, and in particular, we cannot double the dollars. $par$par + +A solution, assuming for example that there are two type parameters $mtt($$T) and $mtt($$U) in the Anubis text, is to +define two macros: +$mcode($$define(T)(0)($$$$T) +$$define(U)(0)($$$$U)) +so that the $MAML compiler will not be disturbed by these type parameters, which is rendered correctly. +Since this doesn't change anything in the +Anubis text itself (the above $mtt($$define) should be outside any Anubis paragraph), this doesn't change anything from the point +of view of the Anubis compiler. This trick can of course be applied to other programming languages.$p + + +$subsection(commonerrors)(Common errors) +Below are most of the errors the author made himself during the writting of this tutorial. +$list( + + $item Thinking that $mtt($$tbgc($$_red)($$box(100)())) produces a red rectangle of the given width + (with no text at all into it). + This actually produces a white rectangle. In order + to get this red rectangle, you need to write $mtt($$tbgc($$_red)($$box(100)($$sp))) (recall that $mtt($$sp) is + the so-called $em(non breakable space)).$p + + $item Using $mtt($$blahblah) instead of $mtt($$$$blahblah), i.e. forgetting to double the dollar when we want to render a dollar + character (or the contrary).$p + + $item Writing $tt(#$$//.*) instead of $tt(#$$#/#/.*) as a regular expression in order to colorize $MAML line comments. + Of course, the first form $em(is seen) as the beginning of a line comment, and the final result is quite surprising. +) + +$///////////////////////////////////////////////////////////////////////////////// +$section(toolsbasis)(Tools available in $fname(basis.maml)) +This $MAML file provides some tools of common usage. In order to use these tools, you must write +$center($mtt($$input(basis.maml)))$par +after the first $mtt($$begin), but some tools require that you define a macro before this $mtt($$input).$p + +Some of the macros defined in this file can be redefined easily from within your source text. If this is not enough for +your needs, you still have the possibility to use a customized copy of $fname(basis.maml).$p + + +$subsection(colors)(Colors) +The file $fname(basis.maml) provides a small selection of colors in the form of macros taking zero operand. These macros are to be used +within the first operand of $mtt($$rgb), $mtt($$code) and $mtt($$tbgc), i.e. at a place where a color value in the +form $mtt(r,g,b) is expected.$p +$pushcounter(colorcnt)(0) +$define(sc)(2)($box(20)()$box(100)($$_$1)$tbgc($2)($sp$sp$sp$sp$sp$sp$sp$sp$sp$sp)$box(20)()$// +$if($equals(2)($countervalue(colorcnt)))($setcounter(colorcnt)(0)$par)($addtocounter(colorcnt)(1))) + +$sc(azure)($_azure) +$sc(black)($_black) +$sc(blue)($_blue) +$sc(caramel)($_caramel) +$sc(chocolate)($_chocolate) +$sc(cyan)($_cyan) +$sc(darkgreen)($_darkgreen) +$sc(gold)($_gold) +$sc(green)($_green) +$sc(grey)($_grey) +$sc(ivory)($_ivory) +$sc(lavender)($_lavender) +$sc(magenta)($_magenta) +$sc(navy)($_navy) +$sc(orange)($_orange) +$sc(pink)($_pink) +$sc(purple)($_purple) +$sc(red)($_red) +$sc(darkred)($_darkred) +$sc(salmon)($_salmon) +$sc(sienna)($_sienna) +$sc(turquoise)($_turquoise) +$sc(white)($_white) +$sc(yellow)($_yellow) + +$undefine(sc) +$p +The file also provide macros with the same name, but without the leading underscore, +taking one operand for directly colorizing texts. For example $mtt($$red(...)) is +equivalent to $mtt($$rgb($$_red)(...)).$p + +$subsection(stylearticle)(The style $mtt(article)) +This $em(style) provides definitions for the marks $mtt($$section), $mtt($$subsection) and $mtt($$subsubsection) (which +are not primitive marks), and also defines a mark $mtt($$tableofcontents).$p + +$subsubsection(_)(How to use it) +In order to use this style, you must write:$p +$center($mtt($$define(article)(0)()))$par +$em(before) $mtt($$input(basis.maml)), because the style is conditionned by a $mtt($$if($$defined(article))...) +within $fname(basis.maml).$p + +The marks $mtt($$section), $mtt($$subsection) and $mtt($$subsubsection) take two operands. The first one must be a +symbol +which is the symbolic name you want to give to the section (it is used +for generating internal links, but you can also refer to the section with a $ref(ref)($mtt($$ref(...)(...)))). +The second one is the title of the section.$p + +The mark +$mtt($$tableofcontents) produces a table of contents and can be written anywhere because it contains a +$ref(postpone)($mtt($$postpone)), +so that it provides a complete table of contents regardless of its position in your source text.$p + +$subsubsection(_)(Customizing $mtt(article)) +The lines of the table of contents are displayed by the marks $mtt($$tocsec), +$mtt($$tocsubsec) and $mtt($$tocsubsubsec). If you are not satisfied with the layout provided by these marks, you can +define your own versions, provided that you write your definitions $em(before) $mtt($$input(basis.maml)). These marks take only one +operand which is the line to be displayed. For example, you can define:$par +$mcenter($mtt($$define(tocsec)(1)($$par$$bold($$1)$$par))) +This will replace the default definition provided by $fname(basis.maml). This may be useful for example to redefine +$mtt($$tocsubsubsec) if you have +subsubsections in your text and don't want them to appear in the table of contents.$p + +The same is true for the marks $mtt($$seclayout), $mtt($$subseclayout) and $mtt($$subsubseclayout), which define the +layout of the section titles themselves. These marks take one operand which is the title itself.$p + +$subsection(book)(The style $mtt(book)) +This style is the same as article, except that it also has a notion of chapter. Hence, it also defines the mark +$mtt($$chapter($argu(symbolic name))($argu(title))), and you can redefine the marks +$mtt($$tocchap($argu(title))) and $mtt($$chaplayout($argu(title))).$p + + + +$////////////////////////////////////////////////////////////////////////////: +$section(catalog)(The catalog of $MAML marks) +Below is a description of the $postpone($countervalue(markcount)) primitive $MAML marks.$p +$postpone($content(tabmark)) + + + $mark1(accumulator)(name) + This mark creates a $em(variable) named $argu(name) called an $em(accumulator). + The content of an accumulator is always a list, and this list is empty when the accumulator is created. With the mark + $mtt($$append), you can add content to the accumulator. Each use of $mtt($$append) adds an element to end of the list + contained in the accumulator. At any time, you can get the content of the accumulator with $mtt($$content).$p + + An accumulator cannot be destroyed, but it can be reinitialized. Indeed, $mtt($$accumulator($argu(name))) empties the + accumulator if it already exists, and puts the empty list in it. Unlike counters and macros, there is no stack associated to an + accumulator name. For example: + $mcode($$accumulator(acc) +$$append(acc)(A) +$$append(acc)(B) +$$content(acc) +$$par +$$accumulator(acc) +$$append(acc)(C) +$$content(acc)) + produces: + $p + $accumulator(acc) + $append(acc)(A) + $append(acc)(B) + $content(acc) + $par + $accumulator(acc) + $append(acc)(C) + $content(acc) + $p + Accumulators can be used in conjunction with $ref(postpone)($mtt($$postpone)) for constructing + tables of content and indexes. + See also $ref(append)($mtt($$append)) and $ref(content)($mtt($$content)). + + $mark2(addtocounter)(name)(value) + This marks adds $argu(value) to the most recent instance of the counter whose name is $argu(name). + + $mark2(append)(name)(text) + This mark appends $argu(text) at the end of the content of the $ref(accumulator)(accumulator) $argu(name). More + precisely, since the content of an accumulator is a list, the new content of the accumulator is the list obtained + by adding $argu(text) as the last element of this list. + See also $ref(accumulator)($mtt($$accumulator)) and $ref(content)($mtt($$content)). + + $mark2(apply)(name)(list) + This mark applies the macro whose name is $argu(name) to all elements of the list $argu(list). This creates a new list + of the same length. If $argu(list) is not a list, the result is the same as if it was a one element list.$p + + Notice that the first operand is the name of the macro to applied, but $em(without the leading $mtt($$)). In other words, this + operand is not the macro to apply but only its name. The corresponding macro must take just one operand. If not, an + error message is generated.$p + + Furthermore, the macro to be applied must take a unique operand, and notice that $argu(name) cannot be the name of + a primitive mark. It $em(must) be the name of a macro. Hence, if you want to apply a primitive mark, you must first + define an equivalent macro.$p + + As an example, consider the following: + $mcode($$define(mylist)(0)($[a$,b$,c$,d$]) +$$mylist$$par +$$define(a)(1)(<$$red($$1)>) +$$apply(a)($$mylist)) +which produces:$p + +$define(mylist)(0)([a,b,c,d]) +$mylist$par +$define(a)(1)(<$red($1)>) +$apply(a)($mylist) +$p + See also $ref(box)($mtt($$box)) for a more sophisticated example. + + + $mark0(begin) This mark is looked for by $MAML before it parses anything (even within a file refered to by + $mtt($$input)). When $mtt($$begin) is found, $MAML parses the text until it + encounters the mark $mtt($$end). After this mark, $MAML continues ignoring everything until the next $mtt($$begin), + etc... $par$par + + Notice that this mecanism can also be used for inserting a comment: + $mcode($$end + ... your comment ... +$$begin) + + $mark1(big)(text) Prints its operand $argu(text) bigger. This mark can be nested. For example, + $list( + $item $box(200)($mtt($$big(text))) produces $big(text) + $item $box(200)($mtt($$big($$big(text)))) produces $big($big(text)) + $item $box(200)($mtt($$big($$big($$big(text))))) produces $big($big($big(text))) + ) + + + $mark1(bold)(text) The operand is rendered in $bold(bold). + + $mark2(box)(width)(text) This mark puts $argu(text) into an invisible box of width $argu(width). The text is left aligned + within the box. This mark can be used for simulating tabulators. For example, + $mcode($$define(tableline)(4)($$box(50)($$1) $$box(50)($$2) $$box(30)($$red($$3)) $$4 $$par) + +$$tableline(Smith)(John)(24)(Baltimore) +$$tableline(Ford) (Max) (32)(New York)) + produces:$par$par + $define(tableline)(4)($box(50)($1) $box(50)($2) $box(30)($red($3)) $4 $par) + $tableline(Smith)(John)(24)(Baltimore) + $tableline(Ford) (Max) (32)(New York) + $par + + $label(colortableexample) + As an example, here is something more sophisticated. We construct a table similar to the table above, + but we want it to be automatically sorted by the last names (first column) and to be in pajama stripes, + in other words, so that odd numbered lines + are shown on a different background color than even numbered lines. It is clear that the background color + cannot be decided before the list is sorted, so that, after the list is sorted, we have to apply a macro + to each element of the list. This is why we need to use the primitive mark $ref(apply)($mtt($$apply)). + $mcode( $$// we first create a counter that we use as a flag + $$// (taking the values 0 and 1 only) +$$pushcounter(flag)(0) + $$// we define a color depending on the value of the flag + $$// and flipflopping the flag at each use +$$define(linecolor)(0) + ($$if($$equals(0)($$countervalue(flag))) + ($$setcounter(flag)(1)$$_lavender) + ($$setcounter(flag)(0)$$_ivory)) + $$// define the layout of a line of the table, and put an '$$alphabetic' in order + $$// to tell MAML how to sort lines +$$define(tableline)(4) + ($$box(80)($$alphabetic($$1))$$box(80)($$2)$$box(50)($$red($$3))$$box(80)($$4)$$par) + $$// define a macro for putting a backgroud color behind a line +$$define(putbg)(1)($$tbgc($$linecolor)($$1)) + $$// sort the lines and apply this macro to each line +$$center($$apply(putbg)($$sort( +$[$$tableline(Smith)(John)(24)(Baltimore)$, + $$tableline(Ford) (Max) (32)(New York)$, + $$tableline(Jackson)(Niel)(64)(Los Angeles)$, + $$tableline(Kennedy) (Justin) (25)(New York)$, + $$tableline(Trump)(Donald)(70)(New York)$, + $$tableline(Obama) (Barack)(55)(Washington)$] +)))) + + +$pushcounter(flag)(0) +$define(linecolor)(0)($if($equals(0)($countervalue(flag)))($setcounter(flag)(1)$_lavender)($setcounter(flag)(0)$_ivory)) +$define(tableline)(4)($box(80)($alphabetic($1))$box(80)($2)$box(50)($red($3))$box(80)($4)$par) +$define(putbg)(1)($tbgc($linecolor)($1)) +$center($apply(putbg)($sort( +[$tableline(Smith)(John)(24)(Baltimore), + $tableline(Ford) (Max) (32)(New York), + $tableline(Jackson)(Niel)(64)(Los Angeles), + $tableline(Kennedy) (Justin) (25)(New York), + $tableline(Trump)(Donald)(70)(New York), + $tableline(Obama) (Barack)(55)(Washington)]))) +$p +The macro $mtt($$pajamatable) defined in $fname(basis.maml) realises such a table and accepts the data in the form of a +list of lists. + + $mark1(center)(text) This mark horizontally centers the $argu(text) in the page. For example, + $mtt($$center(centered text)) produces:$par + $mcenter(centered text) + + $mark2(code)(background color)(text) This marks is for writing computer code. + The $argu(text) operand is formated using a fixed width + (typewriter) font, spaces and newlines are taken into account, so that the result has essentially the same layout as the + original. Nevertheless, $MAML marks are allowed within $argu(text), but some of them, such as $mtt($$list), + can produce incoherent results. For example, + $par + $mcode($$define(T)(0)($$$$T) $$// so that MAML is not troubled by $$T +$$code($$_lavender)($$nolist($black( +define Int + length + ( + List($$T) l + ) = + if l is + { + [ ] then 0, // the list is empty + [h . t] then 1+length(t) + }.) +$$undefine(T)))) + produces: + $define(T)(0)($$T) + $code($_lavender)($nolist(define Int + length + ( + List($T) l + ) = + if l is + { + [ ] then 0, // the list is empty + [h . t] then 1+length(t) + }.)) + $undefine(T) + (You can also use a $ref(colorize)(colorizer) for colorizing the code.) + $par$par + See also $ref(tt)($mtt($$tt(...))) and $ref(verbatim)($mtt($$verbatim(...))) + + $mark2(colorize)(name)(text) See $ref(colorize)(Automatic colorization). + $mark1(colorizer)(name) See $ref(colorize)(Automatic colorization). + $mark4(colorizercall)(name)(regexpr)(name)(regexpr) See $ref(colorize)(Automatic colorization). + $mark3(colorrule)(name)(regexpr)(text) See $ref(colorize)(Automatic colorization). + + $mark1(content)(name) + The value of this mark is the content of the $ref(accumulator)(accumulator) $argu(name). Recall that this content + is a list. See also $ref(accumulator)($mtt($$accumulator)) and $ref(append)($mtt($$append)). + + $mark1(countervalue)(name) + This mark produces the value of the counter $argu(name) in decimal notation. See $ref(counters)(Counters). + + $mark3(define)(name)(number of operands)(value) + This mark let you define new marks (i.e. $em(macros)). It takes three operands. The first operand $argu(name) + is the name of the new mark. If it is + already in use, the new definition masks the previous one until you use an $ref(undefine)($mtt($$undefine($argu(name)))). + The name must be made only of letters $mtt(A...Z) and $mtt(a...z), decimal digits $mtt(0...9) and + the underscore character, and must + not begin by a digit. The second operand $argu(number of operands) is the number of operands your new mark will accept. + It must + be a positive or zero integer. The last operand $argu(value) is the value of the mark. This is a $MAML text, and it can + contain marks of the form $mtt($$1), $mtt($$2), $mtt($$3), ... (called $MAML $em(variables)) which represent the operands + of the mark, and which will later be replaced by the actual operands when the mark is used in the text.$p + + $mtt($$define) doesn't allow to define recursive macros. Nevertheless, + see $ref(undefine)($mtt($$undefine)) where more explanations are given on the behavior of $mtt($$define). + + + $mark1(defined)(name) + This mark has a boolean value which is $em(true) if a macro is defined with name $argu(name) and $em(false) + otherwise. + + $mark0(end) This mark indicates that the $MAML compiler should stop parsing until the next $mtt($$begin) (or the end + of file). See $ref(begin)($mtt($$begin)). + + $mark2(equals)(expr 1)(expr 2) + This mark has a boolean value which is $em(true) if $argu(expr 1) and $argu(expr 2) are equal. By $em(equal), we + mean identical after $argu(expr 1) and $argu(expr 2) are computed. + + $mark0(false) This mark represents the truth value $em(false). + + $mark3(if)(test)(if true)(if false) + This mark represents $argu(if true) if $argu(test) is true, and $argu(if false) otherwise. Only one of + $argu(if true) and $argu(if false) is evaluated. + + $mark1(ifhtml)(text) The operand $argu(text) is present in the HTML output, but not in the $LaTeX nor in the PDF + output. + + $mark1(ifpdf)(text) The operand $argu(text) is present in the $LaTeX and in the PDF + output, but not in the HTML output. + + $mark2(image)(width)(file path) + This mark inserts an image in the text. The operand $argu(width) is the width the image will have + when displayed (in pixels in the case of HTML, and points in the case of $LaTeX), and $argu(file path) is the path of the file + containing the image. For example, + $mcode($$center($$image($$ifpdf(100)$$ifhtml(200))($$id($$thisfilepath)/cows.jpg))) + produces: + $mcenter($image($ifpdf(100)$ifhtml(200))($id($thisfilepath)/cows.jpg)) + + Remark the presence of $mtt($$id($$thisfilepath)/) before the name of the file (which is here assumed to be + in the same directory as the maml file containing the above expression). The mark $mtt($$thisfilepath) gives + the absolute path of the file it is written into. Also, because we need to glue this path to the name of the image + file, we use the macro $mtt($$id) defined by $mtt($$define(id)(1)($$1)). $p + + At the same time, you remark that the width of the image doesn't need to be given lexically and + can be computed using $MAML marks. + + + $mark1(input)(file name) + This mark let you insert the content of another $MAML file. This other file could for example contain your own $MAML + macros.$par$par + Notice that the input file also needs to have a $mtt($$begin) and an $mtt($$end). + In other words, when told to read another file by + $mtt($$input) the $MAML compiler ignores everything in this other file until it finds a $mtt($$begin). + $par$par + This mark can be $unsafe on the web, except if you filter the operand. See the Anubis library documentation. + + + $mark1(italic)(text) Prints its operand $argu(text) in $italic(italic). + + $mark0(item) Marks the begining of an $em(item) within a $ref(list)($mtt($$list)) + + $mark1(label)(tag) This mark defines a $em(label) in the text, in other words, a position where to jump. + This is to be used in conjunction with $ref(ref)($mtt($$ref)). + + $mark1(latex)(formula) This mark allows to include math formulas to be formated by $LaTeX. + For example, + $mcenter($mcode($$latex($dollar$$\int_0^\infty\frac{dx}{1+x^2}$dollar$dollar))) + is rendered as: + $latex($$\int_0^\infty\frac{dx}{1+x^2}$$) + This mark should not be used for big pieces of $LaTeX + text. It is mainly intended for math formulas, especially for HTML output where the formula is rendered + as a PNG image with transparent background. + $par$par + You can use $mtt($$latex) in the text. The result is correctly aligned with the text. For example,$par + $mcenter($mcode(the polynomial $$latex($$X^2+X+1$dollar) is of degree 2)) + is rendered as: + $mcenter(the polynomial $latex($X^2+X+1$) is of degree 2) + + Unfortunatly, $latex(\TeX) is $unsafe as explained in $tlink(this document)(http://cseweb.ucsd.edu/~hovav/dist/texhack.pdf). + Hence, you should forbid this mark for a web usage, except if you add a filter in order to reject all $LaTeX + commands which don't belong to a given list of safe commands. This list doesn't need to be very long since the + $mtt($$latex) mark is mainly used for inserting math formulas. See the Anubis library documentation to learn how + to install this list of safe $LaTeX commands. + + $mark1(length)(list) + This mark returns the number of elements in its operand which is supposed to be a list. If the operand is not a list, + the result is $mtt(1) if the operand is not empty (i.e. if it contains at least one character), and $mtt(0) if it is + empty. + + $mark1(list)(items) This mark allows to create a list. The operand $argu(items) must be a sequence of $em(items), + i.e. texts which are all prefixed by the mark $ref(item)($mtt($$item)).$par$par + Example: + $mcode($$list( + $$item Boys: $$list( $$item John $$item Max) + $$item Girls: $$list($$item Julie $$item Geraldine $$item Sophia))) + produces: + $list( + $item Boys: $list( $item John $item Max) + $item Girls: $list($item Julie $item Geraldine $item Sophia)) + + $mark0(lpar) This mark inserts a left (opening) parenthese into the text. You must use $mtt($$lpar) and/or + $mtt($$rpar) if you want to introduce unbalanced parentheses within an operand of a mark. + + $mark2(mailto)(address)(text) This marks, which appears as $argu(text), + creates a link which is supposed, in the HTML case, to open your mail agent in order to let you + send an email to the indicated $argu(address). In the PDF case, the $argu(address) is just indicated between parentheses + beside $argu(text). + For example,$par + $mcenter($mtt($$blue($$mailto(XZ32@planet.mars)(the martian)))) produces: + $blue($mailto(XZ32@planet.mars)(the martian))$ifhtml( (you can try it)). + + $mark1(nolist)(text) + This mark inhibits the recognition of the square brackets and the comma as list delimitors within $argu(text). See + $ref(lists)(Lists). + + $mark1(note)(text) This mark produces a footnote containing $argu(text). + In the case of $LaTeX/PDF this is a usual + footnote.$ifpdf($note(Like this one.)) In the case of HTML, this is a popup which appears at the bottom of the browser's window when the mouse + passes over this indication : $ifhtml($note(Here is the note !))$ifpdf(($sup(note))).$ifhtml( Try it !) + + $mark2(nth)(n)(list) + This mark extracts the $argu(n)$sup(th) element of the list $argu(list). It generates an error if this element doesn't + exist. Numbering begins at zero. + + $mark2(output)(file path)(text) This mark does not produce anything in the resulting HTML or PDF files, but outputs + $argu(text) (without any modification) into the file $argu(file path). + $par + $par + $mtt($$output) can be very $unsafe for the web. In any case it is not very useful on the web because web pages offer + other ways of uploading files. So, the best is just to forbid it. + + $mark0(par) This marks generates a line break. You can use several $mtt($$par) in order to make some + vertical space in your text. + $par$par + $em(Warning:) The MAML parser doesn't take newline characters into account (they are just read as spaces). Hence, + using $mtt($$par) is often necessary. You can also define a macro inserting several such newlines. For example: + $mcode($$define(p)(0)($$par$$par)) + + $mark1(popcounter)(name) + This mark destroys the most recent counter whose name is $argu(name). + + $mark1(postpone)(text) + The $MAML text $argu(text) is evaluated only after the entire $MAML source is parsed and evaluated (including the + sources obtained via $mtt($$input)). + On the contrary, everything not within a $mtt($$postpone) is + evaluated at the moment it is parsed. The mark $mtt($$postpone) is typically used in conjunction with $mtt($$accumulator), + $mtt($$append) and $mtt($$content) for creating a table of contents at the beginning of a document. This is how + the table of contents at the beginning of this tutorial was made.$p + + As another easy example, the sentence $em(Below is a description of the $postpone($countervalue(markcount)) + primitive $MAML marks.) that you can find just after the section title $ref(catalog)(The catalog of $MAML marks) contains a + $mtt($$postpone($$countervalue(markcount))) producing the number $postpone($countervalue(markcount)) (where + $mtt(markcount) is the name of the counter used for numbering the marks in this catalog). + + $mark2(pushcounter)(name)(init) + This mark creates a new counter under the name $argu(name), with $argu(init) as its initial value. See + $ref(counters)(Counters). + + $mark2(ref)(tag)(text) + This mark creates an internal hyperlink. When clicked upon, this moves the text + to the position of the $ref(label)($mtt($$label)) (this is a $mtt($$ref) !) with the same tag name. + + $mark1(reverse)(list) + This mark return its operand (assumed to be a list), but in reverse order. If the operand is not a list, an error + message is generated. + + $mark2(rgb)(color)(text) This mark sets the color of characters in $argu(text) to $argu(color), where + $argu(color) has the form of three integers separated by commas, representing the intensities of red, green and blue. + These numbers must be between 0 and 255. For example,$par + $mcenter($mtt($$rgb(255,0,0)(the text))) + produces: + $mcenter($rgb(255,0,0)(the text)) + See also $ref(colors)(the predefined colors). + + $mark0(rpar) This mark inserts a right (closing) parenthese into the text. You must use $mtt($$lpar) and/or + $mtt($$rpar) if you want to introduce unbalanced parentheses within an operand of a mark. + + $mark2(setcounter)(name)(value) + This mark puts the value $argu(value) in the most recent counter whose name is $argu(name). See $ref(counters)(Counters). + + $mark1(sort)(list) + This marks performs a quick sorting of its operand which is supposed to be a list. If the operand is not a list, it is + returned as is.$p + + The sorting is always alphabetic, but it can be relative to any part of the elements in the list. In order to + designate which part of an element of the list must be used for comparison, put the special mark + $mtt($$alphabetic($argu(part))) around this part.$p + + At the rendering stage $mtt($$alphabetic($argu(part))) is just replaced by $mtt($argu(part)). See $ref(box)($mtt($$box)) + for an example. + + $mark0(sp) This mark (space) produces an unbreakable space (translated into $tt( ) in HTML and $tt(~) in $latex(\LaTeX)). + + $mark1(sub)(text) This mark lowers $argu(text) and renders it in a smaller size. For example, $mtt(x$$sub(1)) + produces x$sub(1). + + $mark3(sublist)(start)(end)(list) + The third operand of this mark is supposed to be a list. If it's not a list, an error message is generated.$p + + If it is a list, the result is the sublist beginning at element number $argu(start) (included) and finishing at + element number $argu(end) (not included). Notice that numbering begins at $mtt(0), not $mtt(1). + If the value of $argu(start) or $argu(end) is out of bounds, this value is + replaced by the actual bound which is $mtt(0) for $argu(start) and the length of the list for $argu(end). For example, + + $mcode($$sublist(-3)(4)($nolist([a,b,c,d,e,f,g,h,i,j,k]))$$par +$$sublist(0)(4)($nolist([a,b,c,d,e,f,g,h,i,j,k]))$$par +$$sublist(1)(4)($nolist([a,b,c,d,e,f,g,h,i,j,k]))) + produces:$p + $sublist(-3)(4)([a,b,c,d,e,f,g,h,i,j,k])$par + $sublist(0)(4)([a,b,c,d,e,f,g,h,i,j,k])$par + $sublist(1)(4)([a,b,c,d,e,f,g,h,i,j,k]) + + + + $mark1(sup)(text) This mark raises $argu(text) and renders it in a smaller size. For example, $mtt(x$$sup(1)) + produces x$sup(1). + + $mark2(tbgc)(color)(text) This mark ($em(text background color)) shows $argu(text) over a background of color + $argu(color). For example, $mtt($$tbgc($$_lavender)(Some text.)) + produces: $tbgc($_lavender)(Some text.) + $par$par + This is valuable for short texts. For long texts, $ref(code)($mtt($$code(...))) may be more + appropriate. + + $mark0(thisfilepath) + This marks provides the absolute path of the file it is written into.$p + + $mtt($$thisfilepath) is $unsafe for the web, because it can reveal an absolute path of your web server. You should forbid + it. + + $mark2(tlink)(text)(url) This mark creates an hypertext link targeting the $argu(url), and shown as the clickable + $argu(text) (which can also be an image). For example, + $mcode($$tlink(Visit + $$big($$blue(G)$$red(o)$$yellow(o)$$blue(g)$$green(l)$$red(e))) + (http://www.google.com)) + produces + $tlink(Visit + $big($blue(G)$red(o)$yellow(o)$blue(g)$green(l)$red(e)))(http://www.google.com)$ifhtml( (that + you can click upon)). + + + + $mark1(transpose)(list of lists) + This mark $em(transposes) (somehow as in mathematics) a list of lists considered as a $em(matrix). As an example, + we define: +$mcode($$define(mylist)(0)($[$[a$,b$]$,$[c$,d$,e$]$,$[f$,g$]$]) +$$define(addbox)(1)($$box(16)($$1)) +$$define(separ)(1)($$apply(addbox)($$1)$$par)) + +$define(mylist)(0)([[a,b],[c,d,e],[f,g]]) +$define(addbox)(1)($box(16)($1)) +$define(separ)(1)($apply(addbox)($1)$par) + +Now, if we write $mtt($$apply(separ)($$mylist)), we obtain: +$p +$apply(separ)($mylist) +$par +and if we write $mtt($$apply(separ)($$transpose($$mylist))), we obtain: +$p +$apply(separ)($transpose($mylist)) +$par + + + Notice that if a line of the matrix is shorter than a subsequent line, $mtt($$transpose) automatically inserts $em(empty) + (invisible) elements in the + transposed matrix so that items which are in the same $em(line) in the original matrix are in the same $em(column) in the + transposed matrix.$p + + This is useful (in conjunction with $ref(sublist)($mtt($$sublist))) and some $ref(arithmetics)(arithmetics) + for example for displaying a list of items on several columns, with the first group of elements in the first + column (not the first line), the next group of elements in the second column, and so on. This can be used for example + for automatically producing an index on several columns. This is also used in this tutorial for displaying the list + of all marks on four columns $ref(catalog)(at the beginning of this section).$p + + Below is a simple example. We want to sort a list of words in alphabetic order and to present them on two columns. + $mcode( $$// define a list of words +$$define(words)(0) + ($[We$,want$,to$,sort$,a$,list$,of$,words$,and$, + to$,present$,them$,in$,alphabetic$,order$,on$,two$,columns$])) + +$define(words)(0) + ([We,want,to,sort,a,list,of,words,and,to,present,them,in,alphabetic,order,on,two,columns]) + + We prepare the sorting of the list by applying a $mtt($$box(120)) and a $mtt($$alphabetic) to all elements. + $mcode($$define(a)(1)($$box(120)($$alphabetic($$1))) $$// because $$apply accepts only macros +$$define(sortedwords)(0)($$sort($$apply(a)($$words)))) + +$define(a)(1)($box(120)($alphabetic($1))) +$define(sortedwords)(0)($sort($apply(a)($words))) +so that $mtt($$sortedwords) looks like this: +$p +$sortedwords +$p + Now, we compute the length of this list, divide it by $mtt(2) and add 1 if the remainder is not zero, + so that we can cut our list in two lists + of almost the same length (the first one with possibly one element more than the second one). +$mcode($$define(halflen)(0)($$add($$quotient($$length($$sortedwords))(2)) + ($$if($$equals(0)($$remainder($$length($$sortedwords))(2)))(0)(1))) +$$define(column1)(0)($$sublist(0)($$halflen)($$sortedwords)) +$$define(column2)(0)($$sublist($$halflen)($$length($$sortedwords))($$sortedwords))) + +$define(halflen)(0)($add($quotient($length($sortedwords))(2)) + ($if($equals(0)($remainder($length($sortedwords))(2)))(0)(1))) +$define(column1)(0)($sublist(0)($halflen)($sortedwords)) +$define(column2)(0)($sublist($halflen)($length($sortedwords))($sortedwords)) + +Finally, we can get the wanted result by writing: +$define(putpar)(1)($1$par) +$mcode($$define(putpar)(1)($$1$$par) +$$center($$apply(putpar)($$transpose($[$$column1$,$$column2$])))) + +$center($apply(putpar)($transpose([$column1,$column2]))) +$p + The macro $mtt($$multicolumns($argu(number of columns))($argu(items))) defined in $fname(basis.maml) + is just a more general version of the above. + + + $mark0(true) This mark represents the truth value $em(true). + + $mark1(tt)(text) This mark renders $argu(text) in fixed width (typewriter) font. It is similar to + $ref(code)($mtt($$code(...))), with the difference that $argu(text) is put inline instead of as a separate block. + For example, $mtt($$red($$tt(This)) is $$code(220,220,220)(an) example.) + produces: $red($tt(This)) is $code(220,220,220)(an) example. + $par$par + See also $ref(code)($mtt($$code(...))) and $ref(verbatim)($mtt($$verbatim(...))). + + $mark1(undefine)(name) This mark allows to $em(undefine) a macro previously defined by $ref(define)($mtt($$define)). + Actually, it removes only the last definition of the macro whose name is given, so that the previous definition of + this same mark name (if any) is working again. + If no macro with name $argu(name) exists, nothing happens. $par$par + + Example: + $mcode($$define(emph)(1)($$italic($$1)) +$$emph(text1)$$par +$$define(emph)(2)($$bold($$1):$$red($$2)) +$$emph(text2a)(text2b)$$par +$$undefine(emph) +$$emph(text3)) + produces:$par$par + +$define(emph)(1)($italic($1)) +$emph(text1)$par +$define(emph)(2)($bold($1):$red($2)) +$emph(text2a)(text2b)$par +$undefine(emph) +$emph(text3) + $par$par + As a consequence, a $MAML text can safely be embedded into another $MAML text using $mtt($$input), provided + that you $em(undefine) the macros defined in the embedded text at the end of the embedded text. $p + + As told in $ref(define)($mtt($$define)), $mtt($$define) doesn't allow recursion. However, if a macro with the same + name is already defined, any usage of this macro name in the body of the new definition refers to the previous + definition. For example, + $mcode($$define(bu)(1)($$italic($$1)) +$$bu(Some text.)$$par +$$define(bu)(2)($$rgb(120,0,0)($$bu($$1) $$2)) +$$bu(Text1)(Text2)) produces:$par$par + + + $define(bu)(1)($italic($1)) + $bu(Some text.)$par + $define(bu)(2)($rgb(120,0,0)($bu($1) $2)) + $bu(Text1)(Text2)$par + + + $mark1(verbatim)(text) This marks reproduces its content without any change with two exceptions. + Indeed, $MAML marks within + $argu(text) are not interpreted, except the two marks $mtt($$lpar) and $mtt($$rpar), which allows you + to produce unbalanced parentheses in $argu(text) despite the fact that actual parentheses $em(must) be + balanced in $argu(text). Example: + $par + $mcode($$verbatim(In this ($$italic(text))(), ((parentheses) are) $$rpar$$rpar$$lpar balanced.)) + produces: + $p + $verbatim(In this ($italic(text))(), ((parentheses) are) $rpar$rpar$lpar balanced.) + $p + Nevertheless, colors are applied if $mtt($$verbatim(...)) is within a $mtt($$rgb(...)(...)). Indeed, + $mcode($$rgb(255,0,0)($$verbatim(Red verbatim text))) produces: + $rgb(255,0,0)($verbatim(Red verbatim text)) + On the contrary, $mcode($$colorize(maml)($$verbatim(Red verbatim text))) produces: + $colorize(maml)($verbatim(Red verbatim text)) + because $mtt($$verbatim) is not a macro. + $par + $par + See also $ref(code)($mtt($$code(...))) and $ref(tt)($mtt($$tt(...))). + $p$p + + + +$ifhtml($par$par$par$par$par$par$par$par) + +$end + + diff --git a/anubis_dev/library/doc_tools/maml4_tutorial.maml.html b/anubis_dev/library/doc_tools/maml4_tutorial.maml.html new file mode 100644 index 0000000..113819d --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_tutorial.maml.html @@ -0,0 +1,1631 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
The
M
A
M
L
(version 4) Tutorial
+
and Reference
+


+ +
M
A
M
L
(the Minimalist Anubis Markup Language) is an easy to use tool for writing texts. It provides +commands for using different font styles, font sizes,
colors
, for making lists, tables, +sectionning units, inserting images +and +hypertext links, automatically making a table of contents, +and most sorts of things which are useful for writting texts which are agreable to read. +It is also able to automatically produce syntactic colorations. The
M
A
M
L
+compiler produces HTML and PDF output files from a
M
A
M
L
source text. +This documentation itself was written in
M
A
M
L
.

+ +Despite its computing capabilities,
M
A
M
L
is not a programming language. It is a text formating language. +Programming with
M
A
M
L
is easy provided you write only very short pieces of programs. Making big programs in
M
A
M
L
+would generate absolutely unreadable source texts (like what happens with ). We have managed to present +many (short) examples of
M
A
M
L
programming in this tutorial, which helps to quickly understand the explanations.

+ +The very first version of
M
A
M
L
was designed for allowing users on a forum to decorate their messages, and was +very rudimentary. This is +why
M
A
M
L
was called minimalist. This version 4 is now quite far from being minimalist, but the name
M
A
M
L
+remains (partly because it's funny when pronounced in French). + +

+
Table of Contents

+ + + + +
1. How to use
M
A
M
L


+ +
1.1. As a command line tool

+ +
M
A
M
L
can be used as a command line tool. This tool can work to its full power +only if pdflatex and dvipng are installed on +your system. If they are not, you can still use
M
A
M
L
, but the mark
$latex
will not work, and you will not be able +to produce a PDF output. See the Anubis library documentation for more precise explanations. +
+
+Assuming that the file my_file.maml contains some
M
A
M
L
source text, +you just have to issue the command: +

anbexec maml my_file.maml

+and the
M
A
M
L
compiler will produce a file named my_file.maml.html that you can view with your favorite browser. +
+
+This command line tool has several options that you can discover by typing: +

anbexec maml

+For example, the option -pdf produces a PDF output. +

+ +
1.2. From within your Anubis source code

+ +You may also want to use the
M
A
M
L
compiler from within your Anubis source code. For example, you may want to use
M
A
M
L
+ on a web site. +In this case, have a look at the Anubis library documentation. +Notice that several
M
A
M
L
marks are
unsafe
for a use on the web. We explain in the library documentation +how to restrict
M
A
M
L
to safe marks.

+ + +
1.3. As a web user

+ +Since
M
A
M
L
can be used in a web site (powered for example by the Anubis web server), it is possible to allow web users +(those persons visiting the web site) to write
M
A
M
L
texts within web pages. In this case, the set of available
M
A
M
L
+marks is restricted for ensuring the security of the web server.

+ + + + +
2. The
M
A
M
L
syntax


+ +
2.1.
$begin
,
$end
and special characters


+ +When it reads a source text, the
M
A
M
L
compiler ignores everything until the first occurrence of . After +this mark, the compiler parses and evaluates the text until it finds . Then again, it ignores everything +until the next
$begin
, and so on.

+ +Between
$begin
and
$end
, the compiler considers all characters as neutral (i.e. they represent only +themselves), except the character $. This character introduces a so-called mark, which can have so-called +operands. The operands are delimited by pairs of parentheses. + +Within an operand, all characters are considered as pure text, except the following: +
    +
  • the character $, +
  • the left and right parentheses ( and ). They are used for delimiting blocks of text. +
  • the left and right square brackets [ and ]. They are used for delimiting lists, and within such + lists, the comma , is used for separating the elements of the list. The comma is otherwise neutral. +
+ Of course, the possibility exists of inserting these characters as usual neutral characters. It is enough to prefix + them by a $. Hence, for example, [ marks the beginning of a list, whereas
$[
just represents a + left square bracket.

+ + The figure below sumarizes the above rules. +

before $begin everything is ignored
+ +
$begin
+ +
here, outside any operand of mark, only the character $ is special
+ +
$a_mark
(...
here, $ ( ) [ and ] are special
...) + (... [
and here, the comma also is special
] + ...
$another_mark
(
here too, $ ( ) [ and ] are special
...) ... + (...
$nolist
(
but here, only $ ( and ) are special + even if we are within a list, but brackets + must still be balanced
) ...) ) + +
$end
+ +
here again, everything is ignored
+ +
$begin
+ +
and here, it works again as above after the first $begin
+
you can alternate $begin and $end any number of times
+ +
etc... (and an $end is required for closing each $begin)


+ + +
2.2. Marks

+ +This character $ indicates +that what follows is a mark. The name of the mark (a non empty sequence of characters among +
A...Za...z0...9
) and the underscore _ and not beginning by a digit) +immediatly follows the character $. The operands +of the mark follow this name, and each one must be delimited by a pair of parentheses. For example, if you +want to render some text in dark red, you can write this, where rgb is the name of the mark (this mark takes two operands):
+
$rgb
(
120
,
0
,
0
)(This text is rendered in dark red.)

+which produces this: +
This text is rendered in dark red.

+ +You shall learn below how to write macros in
M
A
M
L
using the mark , +so that you can actually simplify the writing of the above. For example the name
M
A
M
L
itself +is produced by the macro
$MAML
which is defined as follows: +

$define
(MAML)(
0
)
$// defining the macro $MAML taking zero operand
+ (
$bold
(
$rgb
(
180
,
0
,
0
)(M)
$rgb
(
0
,
120
,
0
)(A)
$rgb
(
80
,
80
,
80
)(M)
$rgb
(
0
,
0
,
220
)(L)))

+ +
2.3. Line comments

+ +Notice that you can put line comments into your
M
A
M
L
source texts as follows:

+
$// blah blah blah ...

+The mark
$//
and what follows until the end of the line are ignored by the compiler (but it keep +the new line charaters). This kind of comment can be +put everywhere, including within operands of marks, between the operands of a mark (as shown above) and between +a mark and its first operand.

+ +
2.4. Parentheses must be balanced

+ +Each mark accepts a fixed number of operands. Since each operand must be delimited by a pair of parentheses +(which are not part of the operand itself), the +parentheses which are part of the operand (if any) must be balanced, otherwise the
M
A
M
L
parser will not find the closing +parenthese. Nevertheless, you can still include unbalanced parentheses in an operand provided that you write them +
$lpar
(left parenthese) and
$rpar
(right parenthese).

+ + +
2.5. How mark names are delimited

+ +Also remark that between any two operands of a mark (and between the mark itself and its first operand), you cannot +write anything else than white characters (i.e. spaces, line-feeds, carriage-returns and tabulators), and line +comments. For example, +

$rgb
(
0
,
0
,
255
)(My text)

+is equivalent to +

$rgb
(
0
,
0
,
255
)
$// this make a bright blue
+ (My Text)

+But if you write this:
$rgb
(
0
,
0
,
255
) a (My text)
, the compiler will complain that an operand is missing (it +also indicates the path of the file and the line number where this happens). +
+
+Remark: The name of a mark is right delimited by the first character which is not an acceptable character +for such a name. If this character is a space, it is not discarded (unlike what the compiler +does). Hence for example, +
$lpar
x
(with just one space between
$lpar
and x) +produces ( x (with a space between the parenthese and x), +so that it seems that there is no way to obtain (x (with nothing between the parenthese and x). +Actually, there is a simple trick to +obtain the later. Indeed, it is enough to define an identity macro as follows: +

$define
(id)(
1
)(
$1
)

+and to write
$id
(
$lpar
)x
.

+ + + + +
2.6. Defining new marks with
$define


+ +We already saw examples of use of
$define
above. It's now time to give precisions about this possibility to +enrich the language with new marks, which is one of the most powerful tools we have at hand.

+ +The syntax of
$define
is as follows:
+
$define
(
<name>
)(
<arity>
)(
<value>
)

+where
<name>
is the name you want to give to your new mark,
<arity>
its arity, i.e. the number of +operands it takes, and
<value>
the value of the mark, which of course depends on the values of it's future operands, which +is the reason why
<value>
contains so-called
M
A
M
L
variables
$1
,
$2
, etc...

+ +Notice that if a macro with the same name
<name>
is already defined,
$define
does not destroy this +previous definition of
<name>
. It pushes the new definition on a stack of definitions associated to this name. As a +consequence, when you use
$undefine
(
<name>
)
, the most recent definition of name is poped off this stack (and +forgotten) and the previous one prevails again. See for some examples.

+ +When the
M
A
M
L
compiler encounters a
$define
(
<name>
)(
<arity>
)(
<value>
)
, it doesn't evaluate +(i.e. it doesn't compute)
<name>
nor
<arity>
. Consequently, these two operands must be written in their +definitive form.

+ +The third operand
<value>
is only partly evaluated in the sens that macros are expanded within
<value>
, +but primitive marks are not executed (which is in any case mandatory since operands are not yet known). +This policy has two important consequences: +
    +
  • if
    <value>
    contains a call to
    <name>
    , this call doesn't refer to the macro currently being defined, + but to its previous definition (if any). As a byproduct, this also forbids recursive definitions of macros, so + protecting the
    M
    A
    M
    L
    compiler against infinite loops.

    +
  • <value>
    cannot refer to a macro which is not yet defined (there are no forward references in
    M
    A
    M
    L
    ), so + that the macro always keeps the meaning it has when it is defined, except that the values provided by primitive marks + will be computed only when the macro is used. +
+Nevertheless, you may want, especially if you are defining a customizable style of document for example, to define +macros making use of other macros which can be redefined by the user of your style file. The solution is first of all +to define these other macros conditionally, i.e. as follows: +

$if
(
$defined
(
<name>
))()(
$define
(
<name>
)(...)(...))

+that is that you provide a default definition, but only in case your user did not define
<name>
. Of course, this +implies that your user must define
<name>
before writing
$input
(
<your style file>
)
.

+ + +
3. Be stylish

+ +The primitive
M
A
M
L
marks are rather basic, and should preferably be used for creating macros. +In other words, it's better to first define (using the
$define
mark) the concepts you will use in your +text, rather than writing them from scratch at each occurrence. In some sens, defining these concepts is the same as +creating your own style.

+ +
3.1. The file
basis.maml


+ +Notice that a file
basis.maml
exists in
library/doc_tools
which already contains macros of +common usage. +

+ +
3.2. An example

+ +It can be the case that some concept of your discourse has to be emphasized in a particular way, and that +you (arbitrarily) chosed to print it +in red. You should not use
$rgb
(
255
,
0
,
0
)(...)
in the text. You should better first give a name (say emph) to +your concept, and define it near the beginning of the text: +

+
$define
(emph)(
1
)(
$rgb
(
255
,
0
,
0
)(
$1
))
+

+and write
$emph
(...)
in the text instead of
$rgb
(
255
,
0
,
0
)(...)
. +

+This will structure your text in a useful semantic way, instead of a non significant way, making it easier +to later update. +It also has the advantage that you can later easily change the layout of the text by modifying +only the values in these
$define
. +

+
3.3. Inputting a style file

+ +The
$input
mark let you input a
M
A
M
L
source at any point of another
M
A
M
L
source. Hence, you should +define your style in a file (say mystyle.maml) and put an
$input
(mystyle.maml)
after the first
$begin
+of your source file. Notice that the input file also needs to contain a
$begin
and an
$end
.

+ + + + +
4. Automatic colorization

+ +
M
A
M
L
has a simple system for automatic colorization of texts. Within a
M
A
M
L
source text, +you can define one or several colorizers, and later apply them at will. Actually, by colorization we mean +something quite general, i.e. not dealing only with colors.

+ +
4.1. Creating a colorizer

+ +In order to create a colorizer, you must: +
    +
  • define one or several color rules, +
  • when done, create the colorizer. +
+A color rule has the form:
+
$colorrule
(
<colorizer name>
)(
<regular expression>
)(
<
M
A
M
L
expression>
)

+The
<colorizer name>
of the colorizer must be an ordinary symbol. The
<regular expression>
must follow the syntax defined in +
library/lexical_analysis/fast_lexer_5.anubis
(see the Anubis library documentation) and is not evaluated, so +that it must be written in its definitive form. +The
<
M
A
M
L
expression>
can contain the
M
A
M
L
variable +
$1
which is replaced by the token (i.e. the character string recognized by the regular expression) +to be colorized.

+ +Once the color rules are setup, you can create the colorizer as follows:
+
$colorizer
(
<colorizer name>
)

+Then, you can colorize a text:
+
$colorize
(
<colorizer name>
)(
<text>
)

+ +
4.2. A colorizer example

+ +As an example, consider the following definition of a colorizer, which is used in this tutorial for colorizing +
M
A
M
L
code: +

$// line comments
+
$colorrule
(maml)(#$#/#/.*)(
$darkgreen
(
$1
)) +
$// mark names (inclusing inhibited characters)
+
$colorrule
(maml)(
(#$[#,#[#]#(#)])|(#$[a-zA-Z#_][0-9a-zA-Z#_]*)|(#$#$)
) + (
$bold
(
$red
(
$1
))) +
$// MAML variables
+
$colorrule
(maml)(
#$[0-9]+
)(
$magenta
(
$1
)) +
$// integers
+
$colorrule
(maml)(
[0-9]+
)(
$sienna
(
$1
)) +
$// creating the colorizer
+
$colorizer
(maml)

+There are plenty of examples of use of this colorizer in this tutorial (including the above definition of the +maml colorizer !), so that you can easily check that the result is coherent with the definition.

+ +Notice that we used
$bold
in the above definition, which is not a color per se. Actually any mark can be used, so +that colorizers can also be used for a purpose having nothing to do with colors.

+ +
4.3. Primitive marks and colorizers

+ +You also need to know what happens if the text to be colorized contains
M
A
M
L
marks. +All macros are expanded before colorization applies, so that macros have no incidence on colorization, but they can be +used within a text to be colorized.

+ +Things are different for primitive marks. Indeed, how do you interpret for example +

+
$colorize
(maml)(
This is $rgb(120,0,0)(an example) text.
)
+
+It should be clear that $rgb in this example should +have precedence over
$colorize
, otherwise it would be useless. So, the behavior of
M
A
M
L
is that it doesn't +apply a colorizer within the operands of primitive marks (it would be nevertheless meaningless in the case of the operand +120,0,0 of $rgb).

+ +As a consequence, the above example gives +This is
an example
text., +not This is an example text.

+ +Nevertheless, you can still colorize within an operand within a text to be colorized. For example, +

+
$tt
(
$colorize
(maml)(
$$bold($darkgreen($$red(text)))
))
+
+produces
$bold
(
$red(text)
)
, whereas +

+
$tt
(
$colorize
(maml)(
$$bold($darkgreen($colorize(maml)($$red(text))))
))
+
+produces
$bold
(
$red
(text)
)
.

+ +
4.4. Using several colorizers together

+ +You can use several colorizers together. Below is another colorizer: +

$colorrule
(funny)([a-e])(
$rgb
(
10
,
0
,
130
)(
$sup
(
$1
))) +
$colorrule
(funny)([e-k])(
$rgb
(
150
,
0
,
0
)(
$italic
(
$1
))) +
$colorrule
(funny)([l-p])(
$rgb
(
100
,
100
,
0
)(
$big
(
$big
(
$1
)))) +
$colorrule
(funny)([p-z])(
$rgb
(
0
,
100
,
100
)(
$sub
(
$big
(
$1
)))) +
$colorizer
(funny)

+ + + + + +If you write: +

$tt
(
$colorize
(maml) + (
$$bold(Some text $colorize(funny)(with a piece of funny text) in it.)
))

+you get
$bold
(Some text
w
i
t
h
a
p
i
e
c
e
o
f
f
u
n
n
y
t
e
x
t
in it.)


+ + +
4.5. Calling a colorizer from within a colorizer

+ +Using several colorizers together can also help to solve particular colorizing problems, because the above is not the +whole story about
M
A
M
L
colorizers. Indeed, we have another primitive mark: +

+
$colorizercall
(
<mode>
)(
<colorizer1>
)(
<call>
)(
<colorizer2>
)(
<return>
)
+
+which allows to call a colorizer (here
<colorizer2>
) from within another colorizer (here
<colorizer1>
). +The operands
<call>
and
<return>
, which can be any
M
A
M
L
expressions expanding into regular expressions, are used +as call and return instructions. In other words, when
<colorizer1>
encounters something matching the +regular expression
<call>
it calls
<colorizer2>
which will return when it founds something matching the +regular expression
<return>
.

+ +The pieces of text matching
<call>
and
<return>
are colorized by
<colorizer1>
or by +
<colorizer2>
, depending on the value of
<mode>
. There are four modes: +
    +
  • ee (exclude-exclude): both
    <call>
    and
    <return>
    are colorized by
    <colorizer1>
    , +
  • ei (exclude-include):
    <call>
    is colorized
    <colorizer1>
    and
    <return>
    by
    <colorizer2>
    , +
  • ie (include-exclude):
    <call>
    is colorized
    <colorizer2>
    and
    <return>
    by
    <colorizer1>
    , +
  • ii (include-include): both
    <call>
    and
    <return>
    are colorized by
    <colorizer2>
    . +
+ + +
4.6. A colorizer call example

+ +Consider the case of an Anubis source text, such as: +
+
+   A function for computing the length of a list:
+   
+public define Int
+   length
+   (
+     List($T)   l
+   ) =
+   if l is 
+   {
+     [ ]     then 0, 
+     [h . t] then 1 + length(t)
+   }.
+   
+   Blah blah blah ...
+   
+
+This example contains a paragraph defining a function, which is surrounded by so-called off-paragraph +comments. In order to colorize this text we need to be able to detect the beginning and the end of Anubis paragraphs. +This is not possible if we use only color rules as defined by
$colorrule
, but it becomes possible if we also use +
$colorizercall
.

+ +Indeed, we first define two colorizers, say off for off-paragraph comments and in for paragraphs.

+ +In this example, we deliberately chosed to have a head of case of the form
h . t
in the conditional, +because it also contains an end dot (a dot followed by a space or a linefeed) which must not be confused +with the end dot closing the paragraph.

+ +In order to colorize the paragraph itself, we need something like: +

+
$colorizercall
(ii)(off)(#npublic)(in)(#.[# #r#n])
+
+However, if we do that, the colorization of the paragraph will end at the end dot which is within the square brackets. +In order to avoid this, we must add another call: +

+
$colorizercall
(ii)(in)(#[)(in)(#])
+
+(the sharp character, i.e. the escape character for regular expressions, +in front of the square brackets is necessary since square brackets are special characters +in regular expressions). +That way, the colorizer in will call itself when it reads an opening square bracket and return (to itself) when it reads the +corresponding closing square bracket.

+ +However, with these two call rules, the colorization is still not correct because when the opening bracket of [h . +t] is seen the colorizer in calls itself, and the second instance of in returns on the end dot so that the +first instance of in returns on the closing bracket, and the off colorizer is active again at this +closing bracket. The solution is to define two distinct in colorizers, as shown below.
+ +

$colorrule
(off)(.)(
$darkgreen
(
$1
)) +
$colorrule
(in
1
)(.)(
$darkred
(
$1
)) +
$colorrule
(in
2
)(.)(
$rgb
(
0
,
100
,
100
)(
$1
)) +
$colorrule
(in
1
)(#npublic[# #r#n]+define)(
$tbgc
(
220
,
220
,
0
)(
$rgb
(
0
,
0
,
100
)(
$bold
(
$1
)))) +
$colorrule
(in
1
)(#.[# #r#n])(
$tbgc
(
220
,
220
,
0
)(
$rgb
(
0
,
0
,
100
)(
$bold
(
$1
)))) +
$colorizercall
(ii)(off)(#npublic[# #r#n]+define)(in
1
)(#.[# #r#n]) +
$colorizercall
(ii)(in
1
)(#[)(in
2
)(#]) +
$colorizercall
(ii)(in
2
)(#[)(in
2
)(#]) +
$colorizer
(in
1
) +
$colorizer
(in
2
) +
$colorizer
(off)

+ + + + + + + + + + + + + +(we put a different color for in
1
and in
2
texts for showing where in
1
calls in
2
and where in
2
+returns). +Now, if we write
$code
(
$_ivory
)(
$colorize
(off)(
<the above example text>
))
, we get: + +
+
+   
A
f
u
n
c
t
i
o
n
f
o
r
c
o
m
p
u
t
i
n
g
t
h
e
l
e
n
g
t
h
o
f
a
l
i
s
t
:
+
+public define
I
n
t
+
l
e
n
g
t
h
+
(
+
L
i
s
t
(
$
T
)
l
+
)
=
+
i
f
l
i
s
+
{
+
[
]
t
h
e
n
0
,
+
[
h
.
t
]
t
h
e
n
1
+
l
e
n
g
t
h
(
t
)
+
}
.
+ +
B
l
a
h
b
l
a
h
b
l
a
h
.
.
.
+ +
+and more generally, this works for any depth of square brackets nesting.

+ + +
4.7. A non colorizing example.

+ +As said above, colorizers are more general than just a tool for colorizing text. For example, they can be used, +to some extent, for parsing a text.

+ +Assume that we have a text which is in CSV (comma separated values) format. Such texts are very common since every +database system is able to export its tables in this format. Below is an example of such a datum. +

$define
(mycsvtable)(
0
) +(Ford,Max,
32
,New York +Jackson,Niel,
64
,Los Angeles +Kennedy,Justin,
25
,New York +Obama,Barack,
55
,Washington +Smith,John,
24
,Baltimore +Trump,Donald,
70
,New York)

+ + + + +In this piece of text, the lines of the table are separated by linefeeds and the values in a line are separated by +commas. For simplicity, we assume that the values contain no comma and no linefeed. In a realistic situation, we would +have to enhance our example for handling (for example) commas which are within a pair of parentheses. This kind of +enhancement would require some
$colorizercall
.

+ +We define the following colorizer. +

$pushcounter
(col)(
0
) +
$pushcounter
(line)(
0
) +
$colorrule
(display)(#,)(
$addtocounter
(col)(
1
)) +
$colorrule
(display)(#n) + (
$addtocounter
(line)(
1
)
$par
$box
(
40
)(
$countervalue
(line))
$setcounter
(col)(
0
)) +
$colorrule
(display)([^#n#,]*)(
$if
(
$equals
(
2
)(
$countervalue
(col))) + (
$box
(
40
)(
$red
(
$1
))) + (
$if
(
$equals
(
0
)(
$countervalue
(col))) + (
$box
(
100
)(
$bold
(
$1
))) + (
$box
(
100
)(
$1
)))) +
$colorizer
(display)

+ + + + + + + +If we write +

$colorize
(display)( +
$mycsvtable
)

+ +we obtain: +
+
1
Ford
Max
32
New York

2
Jackson
Niel
64
Los Angeles

3
Kennedy
Justin
25
New York

4
Obama
Barack
55
Washington

5
Smith
John
24
Baltimore

6
Trump
Donald
70
New York
+

+Notice that thanks to the counter col, we can perform a different treatment on each column. +Also remark that the first line of +the table has a number in front of it because we added a linefeed in front of
$mycsvtable
within the second operand of +
$colorize
. +

+Now, we want to get this same text in the form of a list of lines, where each line is itself a list of values. +To this end, we define another colorizer. +

$accumulator
(table) +
$accumulator
(line) +
$// without the line below, the commas would appear on the page
+
$colorrule
(parsecsv)(#,)() +
$colorrule
(parsecsv)(#n)(
$append
(table)(
$content
(line))
$accumulator
(line)) +
$colorrule
(parsecsv)([^#n#,]+)(
$append
(line)(
$1
)) +
$colorizer
(parsecsv) +
$colorize
(parsecsv)(
$mycsvtable
+)

+ + + + + + + + + +Despite the fact that we wrote
$colorize
, this doesn't produce any output because +the regular expressions cover all cases and the values in the color +rules contain only marks which produce side effects but no output.

+ +So, we expect that the accumulator table contains our list of lists. +To check that, we define: +

$define
(putbox)(
1
)(
$tbgc
(
$_azure
)(
$box
(
75
)(
$1
)) ) +
$define
(putpar)(
1
)(
$apply
(putbox)(
$1
)
$par
)

+ + + + +and write
$apply
(putpar)(
$content
(table))
, which produces +

+
Ford
Max
32
New York

Jackson
Niel
64
Los Angeles

Kennedy
Justin
25
New York

Obama
Barack
55
Washington

Smith
John
24
Baltimore

Trump
Donald
70
New York

+
+and
$apply
(putpar)(
$transpose
(
$content
(table)))
, which produces +

+
Ford
Jackson
Kennedy
Obama
Smith
Trump

Max
Niel
Justin
Barack
John
Donald

32
64
25
55
24
70

New York
Los Angeles
New York
Washington
Baltimore
New York

+
+This last manipulation makes even more obvious the fact that we actually got our table in the form of +a list of lists. + + + +

+
5. Other tools

+ +
M
A
M
L
is not a programming language. It is a document formatting language. Nevertheless, it provides some +programming capabilities, but only those which are (to our opinion) required for the needs of the layout of the +document. Of course, this set of tools could be enlarged in the future.

+ +
5.1. Elementary arithmetics

+ +
M
A
M
L
is able to perform some elementary arithmetic operations on numbers (which are all relative integers). These +operations are: +
    +
  • $add
    (
    <m>
    )(
    <n>
    )
    addition of
    <m>
    and
    <n>
    +
  • $minus
    (
    <m>
    )(
    <n>
    )
    substraction of
    <n>
    from 
    <m>
    +
  • $opp
    (
    <m>
    )
    opposite of
    <m>
    +
  • $mul
    (
    <m>
    )(
    <n>
    )
    multiplication of
    <m>
    by
    <n>
    +
  • $quotient
    (
    <m>
    )(
    <n>
    )
    quotient of the euclidian division of
    <m>
    by
    <n>
    +
  • $remainder
    (
    <m>
    )(
    <n>
    )
    remainder of the euclidian division of
    <m>
    by
    <n>
    +
+In case of a division by zero, an error message is generated.

+ + +
5.2. Booleans and control

+ +
M
A
M
L
provides some rudimentary tools for better controling the
M
A
M
L
compiler.
M
A
M
L
recognizes the marks
$true
and +
$false
as truth values (aka. booleans). Other marks also produce booleans, such as +
$equals
(
<expr 1>
)(
<expr 2>
)
and
$defined
(
<macro name>
)
.

+ +These truth values can be used as
<test>
in:

+
$if
(
<test>
)(
<if true>
)(
<if false>
)

+The value of the above mark is
<if true>
if
<test>
is true and
<if false>
otherwise, and of course +only one of
<if true>
and
<if false>
is evaluated.

+ +Notice that some logical operators can be defined: +

$define
(and) (
2
) (
$if
(
$1
)(
$2
)(
$false
)) +
$define
(or) (
2
) (
$if
(
$1
)(
$true
)(
$2
)) +
$define
(neg) (
1
) (
$if
(
$1
)(
$false
)(
$true
)) +
$define
(implies) (
2
) (
$or
(
$neg
(
$1
))(
$2
))

+ + + +
5.3. Counters

+ +
M
A
M
L
has a notion of counter. You can create a counter with
$pushcounter
(
<name>
)(
<init>
)
, where +
<name>
is the name of the new counter, and
<init>
its initial value (which must be a positive, zero or +negative integer).

+ +You can get the value of a counter with
$countervalue
(
<name>
)
(giving a character string representing +the value in decimal notation, possibly prefixed by a minus sign). +You can modify the value of a counter with
$setcounter
(
<name>
)(
<value>
)
and +
$addtocounter
(
<name>
)(
<value>
)
.

+ +You can destroy a counter with
$popcounter
(
<name>
)
.

+ +Actually, for each counter name,
M
A
M
L
manages a stack of counters. Consequently, if you create a new counter with the +same name as an already existing counter, the first counter is not destroyed and +becomes visible again when the second counter is destroyed.

+ +As an exemple, consider the following: + + +

$pushcounter
(n)(
0
) +
$define
(ga)(
0
)(
$addtocounter
(n)(
1
)
$countervalue
(n))

+ + + +If we write:
$ga
$ga
$ga
$ga
$ga
$ga
$ga
$ga
$ga
$ga
$ga
$ga
$ga
, we get:

+
1 2 3 4 5 6 7 8 9 10 11 12 13
+Continuing that way, we can write: +

$pushcounter
(n)(
25
) +
$countervalue
(n) +
$popcounter
(n) +
$countervalue
(n)

+and we get: +
+ +25 + +13
+(as expected).

+ + +
5.4. Lists

+ +
M
A
M
L
has a notion of list. In order to create a list (say with three elements a, b and c), +you can write [a,b,c]. If you write this outside any
M
A
M
L
operand, you get this: +

+[a,b,c] +

+In other words, the square brackets and the comma are just seen as ordinary (neutral) characters (and there is no list +at all in this case). On the contrary, if you write
$red
([a,b,c])
, you get this: +

+
abc
+

+This is first of all because the square brackets and the comma are recognized as special characters within an operand +(so that we now have an actual list), and because the rendering of a list consists in rendering its element one after the +other without any separator between them. Nevertheless, if we want to render the above list in red with the brackets +and the commas, it is enough to write
$red
(
$[
a
$,
b
$,
c
$]
)
: +

+
[a,b,c]
+

+ +The square brackets and the comma, everywhere they are recognized as special characters eat the spaces on both +sides. This means that it is equivalent to write
$red
([a,b,c])
and to write
$red
( [ a, b , c +] )
. However, be careful because an expression such as
$red
([a,b,c])
is not a list and triggers +an error if written at a place where a list is required.

+ +List are useful because they can be manipulated by several primitive marks, such as: + +How these primitives marks operate is explained in the .

+ +There are circumstances where we want the square brackets and the comma to be considered as ordinary (neutral) +characters. For example, it should be the case for the second operand of +, and also in some operands of some other primitives. +To simplify the matter and to offer the maximal number of possibilities, primitives such as
$code
don't care +about that. This is why we propose the primitive which inhibits the +recognition of the squares brackets and the comma within
<text>
. Hence,
$code
should be used as follows: +

+
$code
(
<color>
)(
$nolist
(
<computer code>
))
+
+and you can define a macro for handling this.

+ +As an example, consider the following list of words: +

$define
(cities)(
0
) + ([New York,Paris,Berlin,Moscow,Casablanca,Cairo,Athens,Rio de Janeiro])

+ + +We can write: +

$pushcounter
(n)(
0
) +
$define
(number)(
1
)(
$addtocounter
(n)(
1
)
$box
(
20
)(
$countervalue
(n).)
$1
$par
) +
$define
(a)(
1
)(
$alphabetic
(
$1
)) +
$center
(
$apply
(number)(
$sort
(
$apply
(a)(
$cities
))))

+which gives this: + + + +
1.
Athens
2.
Berlin
3.
Cairo
4.
Casablanca
5.
Moscow
6.
New York
7.
Paris
8.
Rio de Janeiro
+ +

+ + +
6. Tips and tricks

+ +If your text needs to display some computer code, it can be the case (depending on the programming language) +that this code uses dollar characters. This is the case of Anubis for example, since dollars are used by +type parameters. These dollars can make a problem since the dollar is also the escape character of
M
A
M
L
.

+ +You can of course double the dollars in the computer text examples, but there are situations where we don't want to +do this, or just cannot do this. This is the case for example in the Anubis library, since some files are at the +same time
M
A
M
L
files (compilable by
M
A
M
L
), and Anubis file (compilable by anubis). In this case, we cannot +change anything to the text, and in particular, we cannot double the dollars.

+ +A solution, assuming for example that there are two type parameters
$T
and
$U
in the Anubis text, is to +define two macros: +

$define
(T)(
0
)(
$$
T) +
$define
(U)(
0
)(
$$
U)

+so that the
M
A
M
L
compiler will not be disturbed by these type parameters, which is rendered correctly. +Since this doesn't change anything in the +Anubis text itself (the above
$define
should be outside any Anubis paragraph), this doesn't change anything from the point +of view of the Anubis compiler. This trick can of course be applied to other programming languages.

+ + +
6.1. Common errors

+ +Below are most of the errors the author made himself during the writting of this tutorial. +
    + +
  • Thinking that
    $tbgc
    (
    $_red
    )(
    $box
    (
    100
    )())
    produces a red rectangle of the given width + (with no text at all into it). + This actually produces a white rectangle. In order + to get this red rectangle, you need to write
    $tbgc
    (
    $_red
    )(
    $box
    (
    100
    )(
    $sp
    ))
    (recall that
    $sp
    is + the so-called non breakable space).

    + +
  • Using
    $blahblah
    instead of
    $$
    blahblah
    , i.e. forgetting to double the dollar when we want to render a dollar + character (or the contrary).

    + +
  • Writing #$//.* instead of #$#/#/.* as a regular expression in order to colorize
    M
    A
    M
    L
    line comments. + Of course, the first form is seen as the beginning of a line comment, and the final result is quite surprising. +
+ + +
7. Tools available in
basis.maml


+ +This
M
A
M
L
file provides some tools of common usage. In order to use these tools, you must write +
$input
(basis.maml)

+after the first
$begin
, but some tools require that you define a macro before this
$input
.

+ +Some of the macros defined in this file can be redefined easily from within your source text. If this is not enough for +your needs, you still have the possibility to use a customized copy of
basis.maml
.

+ + +
7.1. Colors

+ +The file
basis.maml
provides a small selection of colors in the form of macros taking zero operand. These macros are to be used +within the first operand of
$rgb
,
$code
and
$tbgc
, i.e. at a place where a color value in the +form r,g,b is expected.

+ + + +
$_azure
          
+ +
$_black
          
+ +
$_blue
          
+
+
$_caramel
          
+ +
$_chocolate
          
+ +
$_cyan
          
+
+
$_darkgreen
          
+ +
$_gold
          
+ +
$_green
          
+
+
$_grey
          
+ +
$_ivory
          
+ +
$_lavender
          
+
+
$_magenta
          
+ +
$_navy
          
+ +
$_orange
          
+
+
$_pink
          
+ +
$_purple
          
+ +
$_red
          
+
+
$_darkred
          
+ +
$_salmon
          
+ +
$_sienna
          
+
+
$_turquoise
          
+ +
$_white
          
+ +
$_yellow
          
+
+ + +

+The file also provide macros with the same name, but without the leading underscore, +taking one operand for directly colorizing texts. For example
$red
(...)
is +equivalent to
$rgb
(
$_red
)(...)
.

+ +
7.2. The style article

+ +This style provides definitions for the marks
$section
,
$subsection
and
$subsubsection
(which +are not primitive marks), and also defines a mark
$tableofcontents
.

+ +
7.2.1. How to use it
+ +In order to use this style, you must write:

+
$define
(article)(
0
)()

+before
$input
(basis.maml)
, because the style is conditionned by a
$if
(
$defined
(article))...
+within
basis.maml
.

+ +The marks
$section
,
$subsection
and
$subsubsection
take two operands. The first one must be a +symbol +which is the symbolic name you want to give to the section (it is used +for generating internal links, but you can also refer to the section with a ). +The second one is the title of the section.

+ +The mark +
$tableofcontents
produces a table of contents and can be written anywhere because it contains a +, +so that it provides a complete table of contents regardless of its position in your source text.

+ +
7.2.2. Customizing article
+ +The lines of the table of contents are displayed by the marks
$tocsec
, +
$tocsubsec
and
$tocsubsubsec
. If you are not satisfied with the layout provided by these marks, you can +define your own versions, provided that you write your definitions before
$input
(basis.maml)
. These marks take only one +operand which is the line to be displayed. For example, you can define:
+
$define
(tocsec)(
1
)(
$par
$bold
(
$1
)
$par
)

+This will replace the default definition provided by
basis.maml
. This may be useful for example to redefine +
$tocsubsubsec
if you have +subsubsections in your text and don't want them to appear in the table of contents.

+ +The same is true for the marks
$seclayout
,
$subseclayout
and
$subsubseclayout
, which define the +layout of the section titles themselves. These marks take one operand which is the title itself.

+ +
7.3. The style book

+ +This style is the same as article, except that it also has a notion of chapter. Hence, it also defines the mark +
$chapter
(
<symbolic name>
)(
<title>
)
, and you can redefine the marks +
$tocchap
(
<title>
)
and
$chaplayout
(
<title>
)
.

+ + + + +
8. The catalog of
M
A
M
L
marks


+ +Below is a description of the 60 primitive
M
A
M
L
marks.

+















+ + +

8.1.
$accumulator
(
<name>
)


+ This mark creates a variable named
<name>
called an accumulator. + The content of an accumulator is always a list, and this list is empty when the accumulator is created. With the mark +
$append
, you can add content to the accumulator. Each use of
$append
adds an element to end of the list + contained in the accumulator. At any time, you can get the content of the accumulator with
$content
.

+ + An accumulator cannot be destroyed, but it can be reinitialized. Indeed,
$accumulator
(
<name>
)
empties the + accumulator if it already exists, and puts the empty list in it. Unlike counters and macros, there is no stack associated to an + accumulator name. For example: +

$accumulator
(acc) +
$append
(acc)(A) +
$append
(acc)(B) +
$content
(acc) +
$par
+
$accumulator
(acc) +
$append
(acc)(C) +
$content
(acc)

+ produces: +

+ + + + AB +
+ + + C +

+ Accumulators can be used in conjunction with for constructing + tables of content and indexes. + See also and . + +

8.2.
$addtocounter
(
<name>
)(
<value>
)


+ This marks adds
<value>
to the most recent instance of the counter whose name is
<name>
. + +

8.3.
$append
(
<name>
)(
<text>
)


+ This mark appends
<text>
at the end of the content of the
<name>
. More + precisely, since the content of an accumulator is a list, the new content of the accumulator is the list obtained + by adding
<text>
as the last element of this list. + See also and . + +

8.4.
$apply
(
<name>
)(
<list>
)


+ This mark applies the macro whose name is
<name>
to all elements of the list
<list>
. This creates a new list + of the same length. If
<list>
is not a list, the result is the same as if it was a one element list.

+ + Notice that the first operand is the name of the macro to applied, but without the leading $. In other words, this + operand is not the macro to apply but only its name. The corresponding macro must take just one operand. If not, an + error message is generated.

+ + Furthermore, the macro to be applied must take a unique operand, and notice that
<name>
cannot be the name of + a primitive mark. It must be the name of a macro. Hence, if you want to apply a primitive mark, you must first + define an equivalent macro.

+ + As an example, consider the following: +

$define
(mylist)(
0
)([a,b,c,d]) +
$mylist
$par
+
$define
(a)(
1
)(<
$red
(
$1
)>) +
$apply
(a)(
$mylist
)

+which produces:

+ + +abcd
+ +<
a
><
b
><
c
><
d
> +

+ See also for a more sophisticated example. + + +

8.5.
$begin


This mark is looked for by
M
A
M
L
before it parses anything (even within a file refered to by +
$input
). When
$begin
is found,
M
A
M
L
parses the text until it + encounters the mark
$end
. After this mark,
M
A
M
L
continues ignoring everything until the next
$begin
, + etc...

+ + Notice that this mecanism can also be used for inserting a comment: +

$end
+ ... your comment ... +
$begin


+ +

8.6.
$big
(
<text>
)


Prints its operand
<text>
bigger. This mark can be nested. For example, +
    +
  • $big
    (text)
    produces text +
  • $big
    (
    $big
    (text))
    produces text +
  • $big
    (
    $big
    (
    $big
    (text)))
    produces text +
+ + +

8.7.
$bold
(
<text>
)


The operand is rendered in bold. + +

8.8.
$box
(
<width>
)(
<text>
)


This mark puts
<text>
into an invisible box of width
<width>
. The text is left aligned + within the box. This mark can be used for simulating tabulators. For example, +

$define
(tableline)(
4
)(
$box
(
50
)(
$1
)
$box
(
50
)(
$2
)
$box
(
30
)(
$red
(
$3
))
$4
$par
) + +
$tableline
(Smith)(John)(
24
)(Baltimore) +
$tableline
(Ford) (Max) (
32
)(New York)

+ produces:

+ +
Smith
John
24
Baltimore
+
Ford
Max
32
New York
+
+ + + As an example, here is something more sophisticated. We construct a table similar to the table above, + but we want it to be automatically sorted by the last names (first column) and to be in pajama stripes, + in other words, so that odd numbered lines + are shown on a different background color than even numbered lines. It is clear that the background color + cannot be decided before the list is sorted, so that, after the list is sorted, we have to apply a macro + to each element of the list. This is why we need to use the primitive mark . +

$// we first create a counter that we use as a flag
+
$// (taking the values 0 and 1 only)
+
$pushcounter
(flag)(
0
) +
$// we define a color depending on the value of the flag
+
$// and flipflopping the flag at each use
+
$define
(linecolor)(
0
) + (
$if
(
$equals
(
0
)(
$countervalue
(flag))) + (
$setcounter
(flag)(
1
)
$_lavender
) + (
$setcounter
(flag)(
0
)
$_ivory
)) +
$// define the layout of a line of the table, and put an '$alphabetic' in order
+
$// to tell MAML how to sort lines
+
$define
(tableline)(
4
) + (
$box
(
80
)(
$alphabetic
(
$1
))
$box
(
80
)(
$2
)
$box
(
50
)(
$red
(
$3
))
$box
(
80
)(
$4
)
$par
) +
$// define a macro for putting a backgroud color behind a line
+
$define
(putbg)(
1
)(
$tbgc
(
$linecolor
)(
$1
)) +
$// sort the lines and apply this macro to each line
+
$center
(
$apply
(putbg)(
$sort
( +[
$tableline
(Smith)(John)(
24
)(Baltimore), +
$tableline
(Ford) (Max) (
32
)(New York), +
$tableline
(Jackson)(Niel)(
64
)(Los Angeles), +
$tableline
(Kennedy) (Justin) (
25
)(New York), +
$tableline
(Trump)(Donald)(
70
)(New York), +
$tableline
(Obama) (Barack)(
55
)(Washington)] +)))

+ + + + + + +
Ford
Max
32
New York

Jackson
Niel
64
Los Angeles

Kennedy
Justin
25
New York

Obama
Barack
55
Washington

Smith
John
24
Baltimore

Trump
Donald
70
New York

+

+The macro
$pajamatable
defined in
basis.maml
realises such a table and accepts the data in the form of a +list of lists. + +

8.9.
$center
(
<text>
)


This mark horizontally centers the
<text>
in the page. For example, +
$center
(centered text)
produces:
+
centered text

+ +

8.10.
$code
(
<background color>
)(
<text>
)


This marks is for writing computer code. + The
<text>
operand is formated using a fixed width + (typewriter) font, spaces and newlines are taken into account, so that the result has essentially the same layout as the + original. Nevertheless,
M
A
M
L
marks are allowed within
<text>
, but some of them, such as
$list
, + can produce incoherent results. For example, +
+

$define
(T)(
0
)(
$$
T)
$// so that MAML is not troubled by $T
+
$code
(
$_lavender
)(
$nolist
(
+define Int + length + ( + List($T) l + ) = + if l is + { + [ ] then 0, // the list is empty + [h . t] then 1+length(t) + }.
+
$undefine
(T)))

+ produces: + +
define Int
+  length
+  (
+    List($T) l
+  ) =
+  if l is 
+  {
+    [ ]      then 0,  // the list is empty
+    [h . t]  then 1+length(t)    
+  }.
+ + (You can also use a for colorizing the code.) +

+ See also and + +

8.11.
$colorize
(
<name>
)(
<text>
)


See . +

8.12.
$colorizer
(
<name>
)


See . +

8.13.
$colorizercall
(
<name>
)(
<regexpr>
)(
<name>
)(
<regexpr>
)


See . +

8.14.
$colorrule
(
<name>
)(
<regexpr>
)(
<text>
)


See . + +

8.15.
$content
(
<name>
)


+ The value of this mark is the content of the
<name>
. Recall that this content + is a list. See also and . + +

8.16.
$countervalue
(
<name>
)


+ This mark produces the value of the counter
<name>
in decimal notation. See . + +

8.17.
$define
(
<name>
)(
<number of operands>
)(
<value>
)


+ This mark let you define new marks (i.e. macros). It takes three operands. The first operand
<name>
+ is the name of the new mark. If it is + already in use, the new definition masks the previous one until you use an . + The name must be made only of letters A...Z and a...z, decimal digits
0
...
9
and + the underscore character, and must + not begin by a digit. The second operand
<number of operands>
is the number of operands your new mark will accept. + It must + be a positive or zero integer. The last operand
<value>
is the value of the mark. This is a
M
A
M
L
text, and it can + contain marks of the form
$1
,
$2
,
$3
, ... (called
M
A
M
L
variables) which represent the operands + of the mark, and which will later be replaced by the actual operands when the mark is used in the text.

+ +
$define
doesn't allow to define recursive macros. Nevertheless, + see where more explanations are given on the behavior of
$define
. + + +

8.18.
$defined
(
<name>
)


+ This mark has a boolean value which is true if a macro is defined with name
<name>
and false + otherwise. + +

8.19.
$end


This mark indicates that the
M
A
M
L
compiler should stop parsing until the next
$begin
(or the end + of file). See . + +

8.20.
$equals
(
<expr 1>
)(
<expr 2>
)


+ This mark has a boolean value which is true if
<expr 1>
and
<expr 2>
are equal. By equal, we + mean identical after
<expr 1>
and
<expr 2>
are computed. + +

8.21.
$false


This mark represents the truth value false. + +

8.22.
$if
(
<test>
)(
<if true>
)(
<if false>
)


+ This mark represents
<if true>
if
<test>
is true, and
<if false>
otherwise. Only one of +
<if true>
and
<if false>
is evaluated. + +

8.23.
$ifhtml
(
<text>
)


The operand
<text>
is present in the HTML output, but not in the nor in the PDF + output. + +

8.24.
$ifpdf
(
<text>
)


The operand
<text>
is present in the and in the PDF + output, but not in the HTML output. + +

8.25.
$image
(
<width>
)(
<file path>
)


+ This mark inserts an image in the text. The operand
<width>
is the width the image will have + when displayed (in pixels in the case of HTML, and points in the case of ), and
<file path>
is the path of the file + containing the image. For example, +

$center
(
$image
(
$ifpdf
(
100
)
$ifhtml
(
200
))(
$id
(
$thisfilepath
)/cows.jpg))

+ produces: +

+ + Remark the presence of
$id
(
$thisfilepath
)/
before the name of the file (which is here assumed to be + in the same directory as the maml file containing the above expression). The mark
$thisfilepath
gives + the absolute path of the file it is written into. Also, because we need to glue this path to the name of the image + file, we use the macro
$id
defined by
$define
(id)(
1
)(
$1
)
.

+ + At the same time, you remark that the width of the image doesn't need to be given lexically and + can be computed using
M
A
M
L
marks. + + +

8.26.
$input
(
<file name>
)


+ This mark let you insert the content of another
M
A
M
L
file. This other file could for example contain your own
M
A
M
L
+ macros.

+ Notice that the input file also needs to have a
$begin
and an
$end
. + In other words, when told to read another file by +
$input
the
M
A
M
L
compiler ignores everything in this other file until it finds a
$begin
. +

+ This mark can be
unsafe
on the web, except if you filter the operand. See the Anubis library documentation. + + +

8.27.
$italic
(
<text>
)


Prints its operand
<text>
in italic. + +

8.28.
$item


Marks the begining of an item within a + +

8.29.
$label
(
<tag>
)


This mark defines a label in the text, in other words, a position where to jump. + This is to be used in conjunction with . + +

8.30.
$latex
(
<formula>
)


This mark allows to include math formulas to be formated by . + For example, +

$latex
(
$$
\int_
0
^\infty\frac{dx}{
1
+x^
2
}
$$
)


+ is rendered as: +

+ This mark should not be used for big pieces of + text. It is mainly intended for math formulas, especially for HTML output where the formula is rendered + as a PNG image with transparent background. +

+ You can use
$latex
in the text. The result is correctly aligned with the text. For example,
+

the polynomial
$latex
(
$X
^
2
+X+
1
$)
is of degree
2



+ is rendered as: +
the polynomial is of degree
2

+ + Unfortunatly, is
unsafe
as explained in this document. + Hence, you should forbid this mark for a web usage, except if you add a filter in order to reject all + commands which don't belong to a given list of safe commands. This list doesn't need to be very long since the +
$latex
mark is mainly used for inserting math formulas. See the Anubis library documentation to learn how + to install this list of safe commands. + +

8.31.
$length
(
<list>
)


+ This mark returns the number of elements in its operand which is supposed to be a list. If the operand is not a list, + the result is
1
if the operand is not empty (i.e. if it contains at least one character), and
0
if it is + empty. + +

8.32.
$list
(
<items>
)


This mark allows to create a list. The operand
<items>
must be a sequence of items, + i.e. texts which are all prefixed by the mark .

+ Example: +

$list
( +
$item
Boys:
$list
(
$item
John
$item
Max) +
$item
Girls:
$list
(
$item
Julie
$item
Geraldine
$item
Sophia))

+ produces: +
    +
  • Boys:
    • John
    • Max
    +
  • Girls:
    • Julie
    • Geraldine
    • Sophia
+ +

8.33.
$lpar


This mark inserts a left (opening) parenthese into the text. You must use
$lpar
and/or +
$rpar
if you want to introduce unbalanced parentheses within an operand of a mark. + +

8.34.
$mailto
(
<address>
)(
<text>
)


This marks, which appears as
<text>
, + creates a link which is supposed, in the HTML case, to open your mail agent in order to let you + send an email to the indicated
<address>
. In the PDF case, the
<address>
is just indicated between parentheses + beside
<text>
. + For example,
+
$blue
(
$mailto
(XZ
32
@planet.mars)(the martian))

produces: + (you can try it). + +

8.35.
$nolist
(
<text>
)


+ This mark inhibits the recognition of the square brackets and the comma as list delimitors within
<text>
. See + . + +

8.36.
$note
(
<text>
)


This mark produces a footnote containing
<text>
. + In the case of /PDF this is a usual + footnote. In the case of HTML, this is a popup which appears at the bottom of the browser's window when the mouse + passes over this indication : . Try it ! + +

8.37.
$nth
(
<n>
)(
<list>
)


+ This mark extracts the
<n>
th element of the list
<list>
. It generates an error if this element doesn't + exist. Numbering begins at zero. + +

8.38.
$output
(
<file path>
)(
<text>
)


This mark does not produce anything in the resulting HTML or PDF files, but outputs +
<text>
(without any modification) into the file
<file path>
. +
+
+
$output
can be very
unsafe
for the web. In any case it is not very useful on the web because web pages offer + other ways of uploading files. So, the best is just to forbid it. + +

8.39.
$par


This marks generates a line break. You can use several
$par
in order to make some + vertical space in your text. +

+ Warning: The MAML parser doesn't take newline characters into account (they are just read as spaces). Hence, + using
$par
is often necessary. You can also define a macro inserting several such newlines. For example: +

$define
(p)(
0
)(
$par
$par
)

+ +

8.40.
$popcounter
(
<name>
)


+ This mark destroys the most recent counter whose name is
<name>
. + +

8.41.
$postpone
(
<text>
)


+ The
M
A
M
L
text
<text>
is evaluated only after the entire
M
A
M
L
source is parsed and evaluated (including the + sources obtained via
$input
). + On the contrary, everything not within a
$postpone
is + evaluated at the moment it is parsed. The mark
$postpone
is typically used in conjunction with
$accumulator
, +
$append
and
$content
for creating a table of contents at the beginning of a document. This is how + the table of contents at the beginning of this tutorial was made.

+ + As another easy example, the sentence Below is a description of the 60 + primitive
M
A
M
L
marks.
that you can find just after the section title contains a +
$postpone
(
$countervalue
(markcount))
producing the number 60 (where + markcount is the name of the counter used for numbering the marks in this catalog). + +

8.42.
$pushcounter
(
<name>
)(
<init>
)


+ This mark creates a new counter under the name
<name>
, with
<init>
as its initial value. See + . + +

8.43.
$ref
(
<tag>
)(
<text>
)


+ This mark creates an internal hyperlink. When clicked upon, this moves the text + to the position of the (this is a
$ref
!) with the same tag name. + +

8.44.
$reverse
(
<list>
)


+ This mark return its operand (assumed to be a list), but in reverse order. If the operand is not a list, an error + message is generated. + +

8.45.
$rgb
(
<color>
)(
<text>
)


This mark sets the color of characters in
<text>
to
<color>
, where +
<color>
has the form of three integers separated by commas, representing the intensities of red, green and blue. + These numbers must be between 0 and 255. For example,
+
$rgb
(
255
,
0
,
0
)(the text)

+ produces: +
the text

+ See also . + +

8.46.
$rpar


This mark inserts a right (closing) parenthese into the text. You must use
$lpar
and/or +
$rpar
if you want to introduce unbalanced parentheses within an operand of a mark. + +

8.47.
$setcounter
(
<name>
)(
<value>
)


+ This mark puts the value
<value>
in the most recent counter whose name is
<name>
. See . + +

8.48.
$sort
(
<list>
)


+ This marks performs a quick sorting of its operand which is supposed to be a list. If the operand is not a list, it is + returned as is.

+ + The sorting is always alphabetic, but it can be relative to any part of the elements in the list. In order to + designate which part of an element of the list must be used for comparison, put the special mark +
$alphabetic
(
<part>
)
around this part.

+ + At the rendering stage
$alphabetic
(
<part>
)
is just replaced by
<part>
. See + for an example. + +

8.49.
$sp


This mark (space) produces an unbreakable space (translated into &nbsp; in HTML and ~ in ). + +

8.50.
$sub
(
<text>
)


This mark lowers
<text>
and renders it in a smaller size. For example, x
$sub
(
1
)
+ produces x1. + +

8.51.
$sublist
(
<start>
)(
<end>
)(
<list>
)


+ The third operand of this mark is supposed to be a list. If it's not a list, an error message is generated.

+ + If it is a list, the result is the sublist beginning at element number
<start>
(included) and finishing at + element number
<end>
(not included). Notice that numbering begins at
0
, not
1
. + If the value of
<start>
or
<end>
is out of bounds, this value is + replaced by the actual bound which is
0
for
<start>
and the length of the list for
<end>
. For example, + +

$sublist
(-
3
)(
4
)([a,b,c,d,e,f,g,h,i,j,k])
$par
+
$sublist
(
0
)(
4
)([a,b,c,d,e,f,g,h,i,j,k])
$par
+
$sublist
(
1
)(
4
)([a,b,c,d,e,f,g,h,i,j,k])

+ produces:

+ abcd
+ abcd
+ bcd + + + +

8.52.
$sup
(
<text>
)


This mark raises
<text>
and renders it in a smaller size. For example, x
$sup
(
1
)
+ produces x1. + +

8.53.
$tbgc
(
<color>
)(
<text>
)


This mark (text background color) shows
<text>
over a background of color +
<color>
. For example,
$tbgc
(
$_lavender
)(Some text.)
+ produces:
Some text.
+

+ This is valuable for short texts. For long texts, may be more + appropriate. + +

8.54.
$thisfilepath


+ This marks provides the absolute path of the file it is written into.

+ +
$thisfilepath
is
unsafe
for the web, because it can reveal an absolute path of your web server. You should forbid + it. + +

8.55.
$tlink
(
<text>
)(
<url>
)


This mark creates an hypertext link targeting the
<url>
, and shown as the clickable +
<text>
(which can also be an image). For example, +

$tlink
(Visit +
$big
(
$blue
(G)
$red
(o)
$yellow
(o)
$blue
(g)
$green
(l)
$red
(e))) + (http://www.google.com)

+ produces + Visit +
G
o
o
g
l
e
(that + you can click upon). + + + +

8.56.
$transpose
(
<list of lists>
)


+ This mark transposes (somehow as in mathematics) a list of lists considered as a matrix. As an example, + we define: +

$define
(mylist)(
0
)([[a,b],[c,d,e],[f,g]]) +
$define
(addbox)(
1
)(
$box
(
16
)(
$1
)) +
$define
(separ)(
1
)(
$apply
(addbox)(
$1
)
$par
)

+ + + + + +Now, if we write
$apply
(separ)(
$mylist
)
, we obtain: +

+
a
b

c
d
e

f
g

+
+and if we write
$apply
(separ)(
$transpose
(
$mylist
))
, we obtain: +

+
a
c
f

b
d
g

e

+
+ + + Notice that if a line of the matrix is shorter than a subsequent line,
$transpose
automatically inserts empty + (invisible) elements in the + transposed matrix so that items which are in the same line in the original matrix are in the same column in the + transposed matrix.

+ + This is useful (in conjunction with ) and some + for example for displaying a list of items on several columns, with the first group of elements in the first + column (not the first line), the next group of elements in the second column, and so on. This can be used for example + for automatically producing an index on several columns. This is also used in this tutorial for displaying the list + of all marks on four columns .

+ + Below is a simple example. We want to sort a list of words in alphabetic order and to present them on two columns. +

$// define a list of words
+
$define
(words)(
0
) + ([We,want,to,sort,a,list,of,words,and, + to,present,them,in,alphabetic,order,on,two,columns])

+ + + + We prepare the sorting of the list by applying a
$box
(
120
)
and a
$alphabetic
to all elements. +

$define
(a)(
1
)(
$box
(
120
)(
$alphabetic
(
$1
)))
$// because $apply accepts only macros
+
$define
(sortedwords)(
0
)(
$sort
(
$apply
(a)(
$words
)))

+ + + +so that
$sortedwords
looks like this: +

+
a
alphabetic
and
columns
in
list
of
on
order
present
sort
them
to
to
two
want
We
words
+

+ Now, we compute the length of this list, divide it by
2
and add 1 if the remainder is not zero, + so that we can cut our list in two lists + of almost the same length (the first one with possibly one element more than the second one). +

$define
(halflen)(
0
)(
$add
(
$quotient
(
$length
(
$sortedwords
))(
2
)) + (
$if
(
$equals
(
0
)(
$remainder
(
$length
(
$sortedwords
))(
2
)))(
0
)(
1
))) +
$define
(column
1
)(
0
)(
$sublist
(
0
)(
$halflen
)(
$sortedwords
)) +
$define
(column
2
)(
0
)(
$sublist
(
$halflen
)(
$length
(
$sortedwords
))(
$sortedwords
))

+ + + + + +Finally, we can get the wanted result by writing: + +

$define
(putpar)(
1
)(
$1
$par
) +
$center
(
$apply
(putpar)(
$transpose
([
$column1
,
$column2
])))

+ +
a
present

alphabetic
sort

and
them

columns
to

in
to

list
two

of
want

on
We

order
words

+

+ The macro
$multicolumns
(
<number of columns>
)(
<items>
)
defined in
basis.maml
+ is just a more general version of the above. + + +

8.57.
$true


This mark represents the truth value true. + +

8.58.
$tt
(
<text>
)


This mark renders
<text>
in fixed width (typewriter) font. It is similar to + , with the difference that
<text>
is put inline instead of as a separate block. + For example,
$red
(
$tt
(This)) is
$code
(
220
,
220
,
220
)(an) example.
+ produces:
This
is
an
example. +

+ See also and . + +

8.59.
$undefine
(
<name>
)


This mark allows to undefine a macro previously defined by . + Actually, it removes only the last definition of the macro whose name is given, so that the previous definition of + this same mark name (if any) is working again. + If no macro with name
<name>
exists, nothing happens.

+ + Example: +

$define
(emph)(
1
)(
$italic
(
$1
)) +
$emph
(text
1
)
$par
+
$define
(emph)(
2
)(
$bold
(
$1
):
$red
(
$2
)) +
$emph
(text
2
a)(text
2
b)
$par
+
$undefine
(emph) +
$emph
(text
3
)

+ produces:

+ + +text1
+ +text2a:
text2b

+ +text3 +

+ As a consequence, a
M
A
M
L
text can safely be embedded into another
M
A
M
L
text using
$input
, provided + that you undefine the macros defined in the embedded text at the end of the embedded text.

+ + As told in ,
$define
doesn't allow recursion. However, if a macro with the same + name is already defined, any usage of this macro name in the body of the new definition refers to the previous + definition. For example, +

$define
(bu)(
1
)(
$italic
(
$1
)) +
$bu
(Some text.)
$par
+
$define
(bu)(
2
)(
$rgb
(
120
,
0
,
0
)(
$bu
(
$1
)
$2
)) +
$bu
(Text
1
)(Text
2
)

produces:

+ + + + Some text.
+ +
Text1 Text2

+ + +

8.60.
$verbatim
(
<text>
)


This marks reproduces its content without any change with two exceptions. + Indeed,
M
A
M
L
marks within +
<text>
are not interpreted, except the two marks
$lpar
and
$rpar
, which allows you + to produce unbalanced parentheses in
<text>
despite the fact that actual parentheses must be + balanced in
<text>
. Example: +
+

$verbatim
(In this (
$italic
(text))(), ((parentheses) are)
$rpar
$rpar
$lpar
balanced.)

+ produces: +

+ In this ($italic(text))(), ((parentheses) are) ))( balanced. +

+ Nevertheless, colors are applied if
$verbatim
(...)
is within a
$rgb
(...)(...)
. Indeed, +

$rgb
(
255
,
0
,
0
)(
$verbatim
(Red verbatim text))

produces: +
Red verbatim text
+ On the contrary,

$colorize
(maml)(
$verbatim
(Red verbatim text))

produces: + Red verbatim text + because
$verbatim
is not a macro. +
+
+ See also and . +



+ + + +







+ +
\ No newline at end of file diff --git a/anubis_dev/library/doc_tools/maml4_types.anubis b/anubis_dev/library/doc_tools/maml4_types.anubis new file mode 100644 index 0000000..bb07668 --- /dev/null +++ b/anubis_dev/library/doc_tools/maml4_types.anubis @@ -0,0 +1,958 @@ + + MAML 4 + + Most commonly used types. + + +transmit maml4_interface.anubis + + + *** Lexing modes. + + Depending on where we are in the source text, we use a different lexer + +public type LexMode: + skip, // skipping until the next $begin (or the end of file) + out, // parsing between $begin and $end + blank, // skipping until the next expected mark operand + in, // parsing MAML operands + verb. // parsing verbatim operands + + + *** Parsing modes. + + Some operands are parsed as MAML trees, but must have a certain 'form' after macros are expanded. + These 'forms' are formalized by: + +public type MustBe: + any, // can be anything + bool, // MAML boolean + color, // must be a color + ccmode, // colorizercall mode (ee, ei, ie or ii) + int, // must be an integer + pint, // must be a positive (or 0) integer + nzint, // must be a non zero integer (positive or negative) + string, // must be a character string (i.e must be free of MAML marks) + symbol. // must be a symbol + + How to parse an operand. + +public type ParseMode: + maml, // MAML mode producing any MAML tree + maml(MustBe), // MAML mode, but must produce the specified form. + verb. // verbatim mode + + + An 'arity' is a list of parse modes. Each primitive mark has an arity with a parse mode for each operand. + +public type alias Arity = List(ParseMode). + + *** Pure text. + + A replacement type for 'String' which avoids concatenations. + +public type Text: + t(String), + Text + Text. + + Convenience macros: +public define macro Text Text text + String s = text + t(s). +public define macro Text String s + Text text = t(s) + text. + + + *** Text with variables. + + The same one, but including the possibility to insert variables and some special + stuff into the text. These extra elements are treated by 'replace_vars_etc' (see maml4_private.anubis). + +public type VText: + t(String), // ordinary text + v(Int), // variable + fnsize, // to be replaced by the font size for footnotes + textwidth, // to be replaced by the width of text + VText+VText. // two consecutive pieces of VText + + Convenience macros: +public define macro VText VText text + String s = text + t(s). +public define macro VText String s + VText text = t(s) + text. + + + + *** Generating some types. + + In this section, a piece of program for automatically generating some type definitions. + + Decription of primitive marks. + + Recall that the MAML compiler works as follows: + + parse eval colorize html + --------> ------> ----------> --------> HTML + | latex + `-----------> LaTeX + + 'eval' is executed after each top level mark (together with its operands) is parsed. + 'colorize' is executed after the whole text is parsed and evaluated. + + We dispatch primitive marks into several categories: + - category 1: those which desappear after 'eval' (example: $addtocounter) + - category 2: special category for $colorize + - category 3: those which survive after 'colorize' (example: $rgb) + + 'Stackable' marks are those which must be push onto a stack during parsing, because we need to + know if we are currently within one of their operands. For example $latex doesn't produce a PNG + image if it is within $ifpdf. Also $latex produces a different MAML1 datum if it is within $note + (and not within $ifpdf), so as to adjust a reduction factor for PNG images. + +public type Stackable: + stack, // mark symbol (of type 'URenderPrim') must be pushed onto parser's stack + nostack. // mark symbol must not be pushed onto parser's stack + + +public type PrimMark1: + primitive1 (String name, + Stackable stackable, + Arity arity, + Maybe(String) prerender). + + Convenience functions: +define PrimMark1 primitive1(String name, Arity a) = primitive1(name,nostack,a,failure). +define PrimMark1 primitive1(String name, String prerender) = primitive1(name,nostack,[],success(prerender)). + + Primitive marks of category 1 are of two sorts: + 1a they produce an effect and return 'empty' + 1b they produce not effect and return an non empty item + +public define List(PrimMark1) + primitives1a + = + [ // effect producing primitives + // all the primitives below desappear after 'eval' + primitive1("accumulator", [maml(symbol)]), + primitive1("addtocounter", [maml(symbol),maml(int)]), + primitive1("append", [maml(symbol),maml]), + primitive1("colorizer", [maml(symbol)]), + primitive1("colorizercall", [maml(ccmode),maml(symbol),verb,maml(symbol),verb]), + primitive1("colorrule", [maml(symbol),verb,maml]), + primitive1("output", [maml(string),verb]), + primitive1("popcounter", [maml(symbol)]), + primitive1("pushcounter", [maml(symbol),maml(int)]), + primitive1("setcounter", [maml(symbol),maml(int)]) + ]. + +public define List(PrimMark1) + primitives1b + = + [ + // no effect produced by these + // all the primitives below desappear after 'eval' + primitive1("add", [maml(int),maml(int)]), + primitive1("apply", [maml(symbol),maml]), + primitive1("content", [maml(symbol)]), + primitive1("countervalue", [maml(symbol)]), + primitive1("defined", [maml(symbol)]), + primitive1("dollar", "$"), + primitive1("equals", [maml,maml]), + primitive1("false", []), + primitive1("input", [maml(string)]), + primitive1("latex", [verb]), + primitive1("length", [maml]), + primitive1("lpar", "("), + primitive1("minus", [maml(int),maml(int)]), + primitive1("mul", [maml(int),maml(int)]), + primitive1("nolist", [maml]), + primitive1("opp", [maml(int)]), + primitive1("postpone", [maml]), + primitive1("quotient", [maml(int),maml(nzint)]), + primitive1("remainder", [maml(int),maml(nzint)]), + primitive1("reverse", [maml]), + primitive1("rpar", ")"), + primitive1("sort", [maml]), + primitive1("sublist", [maml(int),maml(int),maml]), + primitive1("thisfilepath", []), + primitive1("transpose", [maml]), + primitive1("true", []), + primitive1("verbatim", [verb]) + ]. + + +public define List(PrimMark1) + primitives1 = primitives1a + primitives1b. + + +public type PrimMark3: + primitive3 (String name, // name of mark + Stackable stackable, // see just above + Arity arity, // how to parse each operand + VText html_code, // how to produce HTML code + VText latex_code). // how to produce LaTeX code + + + Convenience function: +public define PrimMark3 primitive3 (String name, Arity arity, VText html_code, VText latex_code) = + primitive3(name,nostack,arity,html_code,latex_code). + + +public define List(PrimMark3) + primitives3 + = + [ + primitive3("big", [maml], + ""+v(1)+"", + "{\larger "+v(1)+"}"), + primitive3("bold", [maml], + ""+v(1)+"", + "{\bf "+v(1)+"}"), + primitive3("box", [maml(int),maml], + "
"+v(2)+"
", + "\\makebox["+v(1)+"px][l]{"+v(2)+"}"), + primitive3("center", [maml], + "
"+ + v(1)+"
", + "\\begin{center}"+v(1)+"\\end{center}"), + primitive3("code", stack, [maml(color),maml], + "
"+v(2)+"
", + "\n\n{\\tt\\begin{tabularx}{\\textwidth}{>{\\columncolor[rgb]{"+v(1)+ + "}}X}{}"+v(2)+"\\hfill{}\\end{tabularx}}\n\n"), + primitive3("displaylatex", [verb,verb,maml(int),maml(int),maml(int)], + "

", + "{}"+v(1)+"{}"), + primitive3("ifhtml", [maml], + v(1), + t("")), + primitive3("ifpdf", stack, [maml], + t(""), + v(1)), + primitive3("image", [maml(int),maml(string)], + "", + "{\\includegraphics[width="+v(1)+"pt]{"+v(2)+"}}"), + primitive3("inlinelatex", [ + verb, // original LaTeX text (to be copied into the LaTeX output + verb, // path of PNG image + maml(int), // width of PNG image + maml(int), // height of PNG image + maml(int) // number of pixels the PNG image must be shifted down + ], + "", + "{}"+v(1)+"{}"), + primitive3("italic", [maml], + ""+v(1)+"", + "{\\it{}"+v(1)+"}"), + primitive3("item", [], + t("
  • "), + t("\\item ")), + primitive3("label", [maml(symbol)], + "", + "\\label{"+v(1)+"}"), + primitive3("list", [maml], + "
      "+v(1)+"
    ", + "\\begin{liste}"+v(1)+"\\end{liste}"), + primitive3("mailto", [maml(string),maml], + ""+v(2)+"", + "{"+v(2)+"} ({\\verb+"+v(1)+"+})"), + primitive3("note", stack, [maml], + "
    (note) +
    "+ + v(1)+"
    ", + "{\\rm(\\footnote{"+v(1)+"})}"), + primitive3("par", [], + t("
    "), + t("\\rule{1mm}{0mm}\n\n")), + primitive3("ref", [maml(symbol),maml], + ""+v(2)+"", + v(2)+" (page \\pageref{"+v(1)+"})"), + primitive3("rgb", [maml(color),maml], + "
    "+v(2)+"
    ", + "{\\color[rgb]{"+v(1)+"}"+v(2)+"}"), + primitive3("sp", [], + t(" "), + t("~")), + primitive3("sub", [maml], + ""+v(1)+"", + "{\\raisebox{-3pt}{\smaller{}"+v(1)+"}}"), + primitive3("sup", [maml], + ""+v(1)+"", + "{\\raisebox{3pt}{\smaller{}"+v(1)+"}}"), + primitive3("tbgc", [maml(color),maml], + "
    "+ + v(2)+"
    ", + "{\\definecolor{bgcol}{rgb}{"+v(1)+"}\\colorbox{bgcol}{"+v(2)+"}}"), + primitive3("tlink", [maml,maml(string)], + ""+v(1)+"", + v(1)+" ({\\tt{}"+v(2)+"})"), + primitive3("tt", [maml], + "" + +v(1)+"", + "{\\tt{"+v(1)+"}}"), + primitive3("verbatim", [verb], + "
    "+v(1)+"

    ", + "\\begin{verbatim}"+v(1)+"\\end{verbatim}") + ]. + + + + + Making the file 'generated/prim1.anubis': + +read tools/basis.anubis + +define One + dump_PrimName_type + ( + WStream fp + ) = + print(fp,"\npublic type PrimName:\n"); + print(fp,concat(map((PrimMark1 p) |-> " _"+name(p),primitives1),",\n")); + print(fp,",\n"); + print(fp,concat(map((PrimMark3 p) |-> " "+name(p),primitives3),",\n")); + print(fp,".\n"). + +define One + dump_prim_types + ( + WStream fp + ) = + print(fp,"\npublic type Prim1:\n"); + print(fp,concat(map((PrimMark1 m) |-> " _"+name(m)+"(MAML_Pos)",primitives1),",\n")); + print(fp,".\n"); + print(fp,"\npublic type Prim3:\n"); + print(fp,concat(map((PrimMark3 m) |-> " "+name(m)+"(MAML_Pos)",primitives3),",\n")); + print(fp,".\n"). + + +define One + dump_MAML_Prim1_type + ( + WStream fp + ) = + print(fp,"\npublic type MAML_Prim1:\n"); + print(fp,concat(map((PrimMark1 m) |-> if m is primitive1(name,_,arity,_) then + " _"+name+(if arity is + { + [ ] then "(MAML_Pos)", + [_ . _] then "(MAML_Pos,"+concat(map((ParseMode mod) |-> if mod is + { + maml then "MAML1", + maml(_) then "MAML1", + verb then "MAML1" + }, + arity),",")+")" + }), + primitives1),",\n")); + print(fp,".\n"). + + +define One + dump_MAML_Prim3_type + ( + WStream fp + ) = + print(fp,"\npublic type MAML_Prim3($M):\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is primitive3(name,_,arity,_,_) then + " "+name+(if arity is + { + [ ] then "(MAML_Pos)", + [_ . _] then "(MAML_Pos,"+concat(map((ParseMode mod) |-> if mod is + { + maml then "$M", + maml(mb) then if mb is + { + any then "$M", + bool then "Value(Bool)", + color then "Value(String)", + ccmode then "Value(CCMode)", + int then "Value(Int)", + pint then "Value(Int)", + nzint then "Value(Int)", + string then "Value(String)", + symbol then "Value(String)" + }, + verb then "Value(String)" + }, arity),",")+")" + }), + primitives3),",\n")); + print(fp,".\n"). + + +define One + dump_MAML_Prim3_MAML1_type + ( + WStream fp + ) = + print(fp,"\npublic type MAML_Prim3_MAML1:\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is primitive3(name,_,arity,_,_) then + " "+name+(if arity is + { + [ ] then "(MAML_Pos)", + [_ . _] then "(MAML_Pos,"+concat(map((ParseMode mod) |-> "MAML1", + arity),",")+")" + }), + primitives3),",\n")); + print(fp,".\n"). + + + *** Padding a string (used for generating 'generated/prim*.anubis'). + +public define String + padn + ( + String s + ) = + with n = (Int)30, + with l = length(s), if l > n then s else s+constant_string(n-l,' '). + + + +public define String + stdvars_no_par + ( + Arity ar, + String -> String decorate, + String sep + ) = + if ar is [] then "" else + concat(map_iterate((Int n, ParseMode mod) |-> decorate("_"+n), ar, 0, (Int n) |-> n+1),sep). + +public define String + stdvars + ( + Arity ar, + String -> String decorate, + String sep + ) = + "("+stdvars_no_par(ar,decorate,sep)+")". + +public define String + stdvars_no_par + ( + Arity ar, + (String,ParseMode) -> String decorate, + String sep + ) = + if ar is [] then "" else + concat(map_iterate((Int n, ParseMode mod) |-> decorate("_"+n,mod), ar, 0, (Int n) |-> n+1),sep). + +public define String + stdvars + ( + Arity ar, + (String,ParseMode) -> String decorate, + String sep + ) = + "("+stdvars_no_par(ar,decorate,sep)+")". + + + +define One + dump_to_string_Prim3_MAML1 + ( + WStream fp + ) = + print(fp,"\npublic define String to_string(MAML_Prim3_MAML1 p) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is primitive3(name,_,arity,_,_) then + " "+padn(name+"(_,"+stdvars_no_par(arity,(String v) |-> v,",")+")")+" then \"$"+name+ + stdvars(arity,(String v) |-> "\"+to_string("+v+")+\"",")(")+"\"", + primitives3), + ",\n")); + print(fp," }.\n"). + +define One + dump_to_string_MAML_Prim3 + ( + WStream fp + ) = + print(fp,"\npublic define String to_string(MAML_Prim3($T) p, $T -> String to_str) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> if m is primitive3(name,_,arity,_,_) then + " "+padn(name+"(_,"+ + stdvars_no_par(arity,(String v) |-> v,",")+")")+" then \"$"+name+ + stdvars(arity,(String v, ParseMode mod) |-> "\"+"+ + (if mod is + { + maml then "to_str", + maml(mb) then if mb is + { + any then "to_str", + bool then "format", + color then "to_string", // 'to_string' is required even for strings, + ccmode then "format", // because they are actually of type Value(String) + int then "to_decimal", + pint then "to_decimal", + nzint then "to_decimal", + string then "to_string", + symbol then "to_string" + }, + verb then "to_string" + })+ + "("+v+")+\"",")(")+"\"", + primitives3), + ",\n")); + print(fp," }.\n"). + +define One + dump_to_string_Prim1 + ( + WStream fp + ) = + print(fp,"\npublic define String to_string(MAML_Prim1 p) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark1 m) |-> if m is primitive1(name,_,arity,_) then + " _"+padn(name+ + "(_,"+stdvars_no_par(arity,(String v) |-> v,",")+")")+" then \"$" + +(if name = "dollar" then "" else (name+ + stdvars(arity,(String v) |-> "\"+to_string("+v+")+\"",")(")))+"\"", + primitives1), + ",\n")); + print(fp," }.\n"). + + +define One + dump_1_to_PrimName + ( + WStream fp + ) = + print(fp,"\npublic define PrimName to_PrimName(MAML_Prim1 p) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark1 m) |-> since m is primitive1(name,_,arity,_), + " _"+padn(name+stdvars([maml . arity],(String v) |-> v,","))+" then _"+name + ,primitives1),",\n")); + print(fp,"\n }.\n"). + +define One + dump_3_to_PrimName + ( + WStream fp + ) = + print(fp,"\npublic define PrimName to_PrimName(MAML_Prim3($M) p) =\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark3 m) |-> since m is primitive3(name,_,arity,_,_), + " "+padn(name+stdvars([maml . arity],(String v) |-> v,","))+" then "+name + ,primitives3),",\n")); + print(fp,"\n }.\n"). + + +define One + dump_is_category_1a + ( + WStream fp + ) = + print(fp,"\npublic define Bool is_category_1a(Prim1 p)=\n"); + print(fp," if p is\n"); + print(fp," {\n"); + print(fp,concat(map((PrimMark1 m) |-> since m is primitive1(name,_,_,_), + " _"+padn(name+"(_)")+" then true", + primitives1a),",\n")); + print(fp,",\n"); + print(fp,concat(map((PrimMark1 m) |-> since m is primitive1(name,_,_,_), + " _"+padn(name+"(_)")+" then false", + primitives1b),",\n")); + print(fp," }.\n"). + +global define One + make_prim1_file + ( + List(String) _ + ) = + forget(make_directory("generated",default_directory_mode)); + if file("generated/prim1.anubis",new) is + { + failure then print("Cannot create file 'generated/prim1.anubis'\n"), + success(filep) then with fp = (WStream)weaken(filep), + + print(fp,"\n\n This file was automatically generated from within ../maml4_types.anubis\n"); + print(fp," by 'make_prim1_file'.\n"); + print(fp,"\nread ../maml4_interface.anubis\n"); + print(fp,"\npublic type MAML1:..."); + print(fp,"\npublic type MAML2:..."); + print(fp,"\npublic type CCMode:..."); + print(fp,"\npublic type Value($T):...\n"); + print(fp,"\npublic define String to_decimal(Value(Int) v)."); + print(fp,"\npublic define String to_string(Value(String) v)."); + print(fp,"\npublic define String to_string(Value(Bool) v)."); + print(fp,"\npublic define String to_string(Value(CCMode) v)."); + print(fp,"\npublic define String to_string(MAML1 m).\n"); + print(fp,"\n The reason why the alternative names below have an\n underscore is that 'if' is a keyword in Anubis.\n"); + dump_PrimName_type(fp); + dump_prim_types(fp); + dump_MAML_Prim1_type(fp); + dump_MAML_Prim3_type(fp); + dump_MAML_Prim3_MAML1_type(fp); + dump_is_category_1a(fp); + dump_1_to_PrimName(fp); + dump_3_to_PrimName(fp); + dump_to_string_Prim1(fp); + dump_to_string_Prim3_MAML1(fp); + dump_to_string_MAML_Prim3(fp); + unique + }. + + +execute anbexec make_prim1_file +transmit generated/prim1.anubis + + At this point, the types 'Prim1', 'Prim2' and 'Prim3' are defined. + +public type alias Stack = List(PrimName). // type of stack for the parser + + + *** Handling two values, one for HTML, the other one for PDF. + + This happens because of $ifhtml and $ifpdf. + +public type Value($T): + value($T for_html, // the value for HTML output + $T for_pdf). // the value for PDF output. + + +public type CCMode: + ee, // exclude-exclude + ei, // exclude-include + ie, // etc... + ii. + +public type CCMode1: + e, // exclude + i. // include + + + + + *** Types of tokens. + + Types of tokens for all MAML lexers. + +public type SkipToken: + end_of_input, + begin. // $begin + +public type OutToken: + end_of_input, + end, // i.e. $end (which is not the end of the input) + // primitives + prim1 (Prim1 name), + colorize (MAML_Pos pos), + define (MAML_Pos pos), + undefine (MAML_Pos pos), + _if (MAML_Pos pos), + prim3 (Prim3 name), + // ordinary text + text (String value), + // names of macros + macro (MAML_Pos pos, + String name). + +public type BlankToken: + end_of_input, + lpar. + + +public type InToken: + end_of_input, + end, + lpar, + rpar, + lbrk (String d), // d is the original token with whites on both sides of the bracket + rbrk (String d), + comma (String d), + prim1 (Prim1 name), + alpha (MAML_Pos pos), + colorize (MAML_Pos pos), + define (MAML_Pos pos), + undefine (MAML_Pos pos), + _if (MAML_Pos pos), + prim3 (Prim3 name), + text (String value), + macro (MAML_Pos pos, + String name), + variable (Int id). + +public type VerbToken: + end_of_input, + lpar, + rpar, + dollar, + text (String content). + + + + + *** Token types for cheking 'forms' of expanded MAML trees. + +public type ColorValueToken: // used for parsing colors: r,g,b + end_of_input, + int (Int), + comma. + +public type SymbolToken: + end_of_input, + symbol. + + + + *** The types of MAML syntax trees. + + MAML1 = what comes out of the parser + MAML2 = what comes out of the evaluator (prim1s and macros desappear) + MAML2a (colorize desappears) + MAML3 = what comes out of the colorizer (variables desappear) + +public type MAML2:... + +public type MAML1: + error (MAML_Error me), + erroneous (MAML_Error me, + MAML1 text), // erroneous text with the corresponding error + empty, + text (String value), // text not containing any mark + variable (Int id), // $1, $2, ... + prim1 (MAML_Prim1 p1), + list (List(MAML1) l, + List(String) deco), + alpha (MAML1 m), // used for sorting + colorize (MAML_Pos pos, + MAML1 cname, + MAML1 operand), + define (MAML_Pos pos, + String name, + Int arity, + MAML1 value), + undefine (MAML_Pos pos, + String name), + _if (MAML_Pos pos, + MAML1 test, + MAML1 iftrue, + MAML1 iffalse), + prim3 (MAML_Prim3_MAML1 p3), + computed (MAML2 cpted), // already computed object + macro (MAML_Pos pos, + String name, // user defined macro + List(MAML1) operands), + MAML1 + MAML1. // two consecutives pieces of MAML text + +public type MAML2: + error (MAML_Error me), + erroneous (MAML_Error me, + MAML1 text), // erroneous text with the corresponding error + empty, + false, // false and true desappear quickly (see 'maml4_eval.anubis') + true, + text (String value), // text not containing any mark + variable (Int id), // $1, $2, ... + list (List(MAML2) l, + List(String) deco), + alpha (MAML2 m), // used for sorting + colorize (MAML_Pos pos, + String cname, + MAML2 operand), + postpone (MAML_Pos pos, + MAML1 text), + prim3 (MAML_Prim3(MAML2) p3), + MAML2 + MAML2. // two consecutives pieces of MAML text + +public type MAML2b: + error (MAML_Error me), + erroneous (MAML_Error me, + MAML1 text), // erroneous text with the corresponding error + empty, + call (String cname), + return, + text (String value), // text not containing any mark + variable (Int id), // $1, $2, ... + list (List(MAML2b) l), + colorize (MAML_Pos pos, + String cname, + MAML2b operand), + prim3 (MAML_Prim3(MAML2b) p3), + MAML2b + MAML2b. // two consecutives pieces of MAML text + +public type MAML2a: + error (MAML_Error me), + erroneous (MAML_Error me, + MAML1 text), // erroneous text with the corresponding error + empty, + text (String value), // text not containing any mark + variable (Int id), // $1, $2, ... + list (List(MAML2a) l), + prim3 (MAML_Prim3(MAML2a) p3), + MAML2a + MAML2a. // two consecutives pieces of MAML text + +public type MAML3: + error (MAML_Error me), + erroneous (MAML_Error me, + MAML1 text), // erroneous text with the corresponding error + empty, + text (String value), // text not containing any mark + list (List(MAML3) l), + postpone (MAML_Pos pos, + MAML1 text), + prim3 (MAML_Prim3(MAML3) p3), + MAML3 + MAML3. // two consecutives pieces of MAML text + +public define MAML1 to_MAML1 (MAML2 m). +public define MAML1 to_MAML1 (MAML2a m). +public define MAML1 to_MAML1 (MAML3 m). + + + + public define MAML2 erroneous(MAML_Error e, MAML2 m). + + *** Colorizing. + +public type ColorRule: + rule (String colorizer_name, + String regular_expression, + MAML1 value). // an expression containing a $1 to be replaced by the token read + +public type ColorCall: + colorcall (CCMode mode, + String colorizer1_name, + String call, // regular expression + String colorizer2_name, + String return). + + public type Colorizer: + clrzr (String name, // of colorizer + String -> MAML2b handle_calls, // parser for handling calls + String -> MAML3 colorize). // parser for colorizing strings (see maml4_colorize.anubis) + + + + *** Tokens as they are returned by colorizer's lexers. + + +public type ColorToken: + end_of_input, + color (MAML1 value, // the MAML expression containing a $1 to be replaced + String text), // the token recognized by a user's regular expression + text (String text). // all parts of the text to be colorized which are not recognized + // by user's regular expressions. (see 'create_colorizer' in + // maml4_colorize.anubis) + +public type ColorCallToken: + end_of_input, + call (CCMode1 mode, + String cname, + String token), + return (CCMode1 mode, + String token), + text (String text). + +public type alias CallLexer = One -> Result(LexicalError(One),ColorCallToken). +public type alias CallLexerTree = TreeKV(String,LexingStream -> CallLexer). +public type alias ColorLexer = One -> Result(LexicalError(One),ColorToken). +public type alias ColorLexerTree = TreeKV(String,LexingStream -> ColorLexer). + + + *** The 'macro definitions B-tree'. + + Recorded definition of a macro. + +public type MacroDef: + macro (String name, // name of macro + List(ParseMode) arity, // here all operands are parsed as MAML text + // so that only the length of this list matters + MAML1 body). // body of definition of macro + + The 'macro tree' associates to each macro the list (stack) of its definitions (not a single definition, + so that when a macro is '$undefined', the previous definition prevails). + +public type alias MacroTree = TreeKV(String, // name of macro + List(MacroDef)). // stack of its definitions + + The same one but which contains only the arities. +public type alias ArityTree = TreeKV(String, + List(Int)). + + + *** Counters. + + The use can create a counters. Each counter has a name and an initial value. A counter is created by: + + $pushcounter()() + + The must be a symbol and the must be a (possibly negative) integer. The value of a counter + can be read by: + + $countervalue() + + + The value of a counter can be changed using: + + $addtocounter()() + $setcounter()() + + A counter can be destroyed using: + + $popcounter() + + Actually, for each there is a stack of counters, so that $pushcounter can be used several times with + the sane . At each $popcounter(), the most recent counter with that name is detroyed so that the previous + one then prevails. + + +public type alias CounterTree = TreeKV(String,List(Int)). +public type alias AccumulatorTree = TreeKV(String,List(MAML2)). + + + + + + *** Parsing toolbox. + + A toolbox is used for parsing. + + When we encounter an '$input', we must construct a new toolbox. However, part of the current toolbox + must be kept because it is independent of the file currently parsed. This part is formalized as: + +public type alias SpecLex($Token) = (LexingStream,One) -> One -> LexOut($Token,One). + +public type ToolboxKeep: + toolboxkeep( + // user's options: + List(MAML_Option) options, + // lists of user defined stuff + Var(MacroTree) macro_tree_v, + Var(ArityTree) arity_tree_v, + Var(List(ColorRule)) colorrules_v, + Var(List(ColorCall)) colorcall_v, + Var(CallLexerTree) call_lexer_tree_v, + Var(ColorLexerTree) color_lexer_tree_v, + Var(CounterTree) counter_tree_v, + Var(AccumulatorTree) accumulator_tree_v, + Var(Int) max_errors_v, // counting errors + MAML_HTML_Options html_options // used to compute the 'reduction factor' for PNG images + // (see 'parse_latex' in maml4_parser.anubis) + ). + + + The complete toolbox: + +public type Toolbox: + toolbox ( + String file_path, // absolute path of file currently parsed + String file_name, // name of file currently parsed + LexingStream ls, // lexing stream (allows to recover of positions in text) + One -> LexOut(SkipToken,One) skip_lex, // lexer for skipping until next $begin + One -> LexOut(OutToken,LexerAux) out_lex, // lexer for parsing between $begin and $end (but outside operands) + One -> LexOut(BlankToken,One) blank_lex, // lexer for skipping until expected operand + One -> LexOut(InToken,LexerAux) in_lex, // lexer for parsing MAML operands + One -> LexOut(VerbToken,One) verb_lex, // lexer for parsing verbatim operands + ToolboxKeep keep // part of toolbox to be kept over $inputs + ). + + + + \ No newline at end of file diff --git a/anubis_dev/library/doc_tools/png/fNScTnBA4MH-qH_w0pRfArXeeKE8.png b/anubis_dev/library/doc_tools/png/fNScTnBA4MH-qH_w0pRfArXeeKE8.png new file mode 100644 index 0000000..7473396 Binary files /dev/null and b/anubis_dev/library/doc_tools/png/fNScTnBA4MH-qH_w0pRfArXeeKE8.png differ diff --git a/anubis_dev/library/doc_tools/png/foAbejNaCwiT0Jzk31KqV0gRWsOY.png b/anubis_dev/library/doc_tools/png/foAbejNaCwiT0Jzk31KqV0gRWsOY.png new file mode 100644 index 0000000..b134a41 Binary files /dev/null and b/anubis_dev/library/doc_tools/png/foAbejNaCwiT0Jzk31KqV0gRWsOY.png differ diff --git a/anubis_dev/library/doc_tools/png/fq22PnfBrYNx2fPr8NQyxy5tdO_A.png b/anubis_dev/library/doc_tools/png/fq22PnfBrYNx2fPr8NQyxy5tdO_A.png new file mode 100644 index 0000000..f2aef2c Binary files /dev/null and b/anubis_dev/library/doc_tools/png/fq22PnfBrYNx2fPr8NQyxy5tdO_A.png differ diff --git a/anubis_dev/library/doc_tools/png/fyKx7xRolFAoYjXkjs4VdbNyRjAQ.png b/anubis_dev/library/doc_tools/png/fyKx7xRolFAoYjXkjs4VdbNyRjAQ.png new file mode 100644 index 0000000..957c021 Binary files /dev/null and b/anubis_dev/library/doc_tools/png/fyKx7xRolFAoYjXkjs4VdbNyRjAQ.png differ diff --git a/anubis_dev/library/doc_tools/png/tNScTnBA4MH-qH_w0pRfArXeeKE8.png b/anubis_dev/library/doc_tools/png/tNScTnBA4MH-qH_w0pRfArXeeKE8.png new file mode 100644 index 0000000..2829be3 Binary files /dev/null and b/anubis_dev/library/doc_tools/png/tNScTnBA4MH-qH_w0pRfArXeeKE8.png differ diff --git a/anubis_dev/library/doc_tools/png/toAbejNaCwiT0Jzk31KqV0gRWsOY.png b/anubis_dev/library/doc_tools/png/toAbejNaCwiT0Jzk31KqV0gRWsOY.png new file mode 100644 index 0000000..7407302 Binary files /dev/null and b/anubis_dev/library/doc_tools/png/toAbejNaCwiT0Jzk31KqV0gRWsOY.png differ diff --git a/anubis_dev/library/doc_tools/png/tyKx7xRolFAoYjXkjs4VdbNyRjAQ.png b/anubis_dev/library/doc_tools/png/tyKx7xRolFAoYjXkjs4VdbNyRjAQ.png new file mode 100644 index 0000000..889f566 Binary files /dev/null and b/anubis_dev/library/doc_tools/png/tyKx7xRolFAoYjXkjs4VdbNyRjAQ.png differ -- libgit2 0.21.4