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...