Myll - A New Web-language
Introduction
Myll is a language that can be used to dynamically generate web pages.
It compares to other languages such as ASP/PHP/ColdFusion. However, Myll
does currently not have any interface for database connection.
The first embryo was JHTML by Magnus Axelsson who just
wanted to generate web-pages offline from a template using some kind
of macros. His implementation was an exercise in emacs lisp using too
many lines of code I thought so I wrote mine in perl.
The perl implementation is essentially
15 lines of code.
The initial reason for extending the language was to enable the
creation of a display language front-end to the LysKOM project, replacing
the JySKom server.
Myll - a short description of the language.
Myll: The in-place Macro Substitution Language
For simplicity Myll is implemented using Perl, building on a strong
and efficient text processing language. The source of the interpreter
is small compared to its abilities. External Procedures/Functions are
all implemented either in the language itself or in Perl.
A typical page is "just a function call" -- for example:
http://skiff.cwi.nl:7289/?%5bpage-text+4711%5d
or unencoded:
http://skiff.cwi.nl:7289/?[page-text 4711]
As can be seen from the example a link is just a macro-call. This call
contains all needed parameters. On the server side, the macros are
interpreted/expanded incrementially until pure HTML is output.
A function call is merely an arbitrary text in which substitutions
are made upon:
http://skiff.cwi.nl:7289/?The product of 42 and 4711 is[* 42 4711]!
Which gives the result:
The product of 42 and 4711 is 197862!
How to interface Perl-functions
An External Perl Function (EPF) is interfaced by making sure
that it returns an appropriate string, and possibly performing
side-effects. However, side-effects should be avoided whenever
possible, since the language does not have an explicit evalutation
order.
Perl-interface for some normal aritmetic functions:
[perl +] { $a+$b; } [/perl]
[perl -] { $a-$b; } [/perl]
[perl *] { $a*$b; } [/perl]
[perl /] { $a/$b; } [/perl]
[perl eq] { $a==$b; } [/perl]
[perl gt] { $a>$b; } [/perl]
[perl gte] { $a>=$b; } [/perl]
|
Macros are written like follows
[macro lt A B] [gte B A] [/macro]
[macro lte A B] [gt B A] [/macro]
[macro fac 0] 1 [/macro]
[macro fac N] [* N [fac [- N 1]]] [/macro]
[macro map F] [/macro]
[macro map F O R] [F O][map F R] [/macro]
[macro hyper L T] <a href="L">T</a> [/macro]
|
As can be seen from above a rudimentary pattern matching can
be performed. Mainly on the number of arguments, but also on
all of the arguments ([fac 0]), altogether, in most cases
avoiding having an if-operator.
Pattern
Explicit patterns can be used to parse the input to a function/macro.
It can be seen that the normal space-delimited argument list is just
a shorthand for a regular-expression that splits on whitespaces.
These two definitions are equivalent:
[macro foo %1 %2 %3]
%1-%2-%3
[/macro]
[pattern name (\S+)\s+(\S+)\s+(.*)]
%1-%2-%3
[/pattern]
|
The pattern construct allows for a more explict matching, especially it can be used
for parsing data. Here we parse the unix date, extracting it's components.
[macro td-list L][map [func E][td E][/func] L][/macro]
[macro td-row L][row [td-list L]][/macro]
[pattern parse-unix-date (\S+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\S+)\s+(\d+)]
[table
[td-row Weekday %1]
[td-row Day %3]
[td-row Year %6]
[td-row Month %2]
[td-row Time %4:%5:%6]
[td-row Zone %7]]
[/pattern]
[parse-unix-date Mon Dec 6 14:45:09 CET 1999]
|
Giving:
Weekday | Mon |
Day | 6 |
Year | 09 |
Month | Dec |
Time | 14:45:09 |
Zone | CET |
Evaluation - concept
The language might at a first sight look as if it was just lisp
but with other kinds of brackets. In a way that's partly true.
But, it is something even more strange than lisp. It does
not have an explicit evaluation order -- requiring programs not
to rely on side-effects and in a sence it only gives the guarantees
given by a purely functional language -- that the order
of evaluation or substitution is of no or little importance.
Consider the following program:
[macro PRINT TXT] <li>TXT</li> {/macro]
<ul>
[map PRINT One Two Three Four Five]
</ul>
|
The [map]-call might be expanded in many different ways,
however, the end-result is always the same:
Circular Sequence
[PRINT One][map Two Three Four Five]
[PRINT One][PRINT Two][map Three Four Five]
[PRINT One][PRINT Two][PRINT Three][map Four Five]
[PRINT One][PRINT Two][PRINT Three][PRINT Four][map Five]
[PRINT One][PRINT Two][PRINT Three][PRINT Four][PRINT Five]
<li>One</li><li>Two</li><li>Three</li><li>Four</li><li>Five</li>
|
or Left-Eager
[PRINT One][map Two Three Four Five]
<li>One</li>[PRINT Two][map Three Four Five]
<li>One</li><li>Two</li>[PRINT Three][map Four Five]
<li>One</li><li>Two</li><li>Three</li><li>Four</li>[map Five]
<li>One</li><li>Two</li><li>Three</li><li>Four</li><li>Five</li>
|
or Circular
[PRINT One][map Two Three Four Five]
[PRINT One][PRINT Two][map Three Four Five]
[PRINT One][PRINT Two][PRINT Three][map Four Five]
[PRINT One][PRINT Two][PRINT Three][PRINT Four][map Five]
[PRINT One][PRINT Two][PRINT Three][PRINT Four][PRINT Five]
[PRINT One][PRINT Two][PRINT Three][PRINT Four][PRINT Five]
<li>One</li>[PRINT Two][PRINT Three][PRINT Four][PRINT Five]
<li>One</li><li>Two</li>[PRINT Three][PRINT Four][PRINT Five]
<li>One</li><li>Two</li><li>Three</li><li>Four</li>[PRINT Five]
<li>One</li><li>Two</li><li>Three</li><li>Four</li><li>Five</li>
|
Example: LysKOM - show a text
The following macro displays a text from the LysKOM database,
it uses an extension module for interfacing with the LysKOM database system --
essentially the "comm.perl" module from JySKom plus some simple
interfacing code.
Notice that a "continuation" is made using the macro hyper
which expands into a link, with the result that the function call
is only executed.
[perl kom-name] { &get_name($a); } [/perl]
[perl text-author] { &get_author_of_text($a); } [/perl]
[perl text-comments] { join(" ", &get_comments_of_text($a)); } [/perl]
[perl text-comments-to] { join(" ", &get_text_comment_to($a)); } [/perl]
[perl text-lines] { &get_text_lines($a); } [/perl]
[perl text-subject] { &get_subject($a); } [/perl]
[perl text-text] { &kom_get_text($a,2); } [/perl]
[perl text-words]{$_=&kom_get_text($a,2);s/\n/ /g;$_;}[/perl]
[perl text-date] { local($_, $_, $d, $_) = &kom_get_text_stat($a); return $d;} [/perl]
[perl text-marks] { &get_text_marks($a); } [/perl]
[perl text-chars] { &get_text_chars($a); } [/perl]
[perl text-ccs] { join(" ", &get_ccs_of_text($a)); } [/perl]
[perl text-receivers] { join(" ", &get_recpt_of_text($a)); } [/perl]
[perl text-footnotes] { join(" ", &get_footnotes_of_text($a)); } [/perl]
[perl conf-presentation]{ &get_presentation($a); } [/perl]
[perl conf-unread-count]{ &get_count_unread_fast($a, $b); } [/perl]
[macro page-text TNO]
[begin-html HyKom Test - show-text TNO]
[show-text TNO]
[end-html]
[/macro]
[macro link-text TNO]
[hyper /?[quote page-text TNO] TNO] [/macro]
[macro show-text TNO]
<br>
[link-text TNO] [text-date TNO] / [text-lines TNO] / [link-author TNO] <br>
[map [func N]Mottagare: [link-name N]<br>[/func] [text-receivers TNO]]
[map [func N]Kommentar till text av [link-author N]<br>[/func] [text-comments-to TNO]]
Ă„rende: [text-subject TNO]
----------------------------------------------------------------------
<pre>[text-text TNO]</pre>
([link-text TNO])------------------------------------------------
<br>
[map [func C]Kommentar i [link-text C] av [link-author C]<br>[/func]
[text-comments TNO]]
[/macro]
|
More to come...