lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Jan 9, 2008 5:22 AM, Javier Guerra Giraldez <javier@guerrag.com> wrote:

> Scala does a very decent job of using such approaches for XML, [...]

after a (very) quick glance, it seems very similar to E4X; enhancing the
syntax of the language to make XML a new type, and using field-like accessors
for the XML nodes.

can be an interesting project; but the only obvious advantage seems to remove
the quotes around XML constants... how often do you need XML constants in the
code?

My personal feeling is that syntax for XML constants is not important, and actually not worth it. But you can introduce one if you think that's important. What's important is structural pattern matching (see below).
 
the other posibility that i see is using metalua's pattern match to handle xml
itself.  but wouldn't that be at compile time? can metalua match at runtime?

Yes, that's the whole point: your matching statement is compiled into some equivalent code, harder to read for you but intelligible to the VM. Consider this sample:

match foo with
| { tag='Alpha', x, "some_string", y } -> f1(x+y)
| { a, ... } if a>10 -> f2(a)
end

The first case matches if foo is:
- a table;
- with a tag field containing 'Alpha';
- and exactly 3 array-part children;
- and whose 2nd child must be equal to the constant string "some_string".
If the pattern matches, x will be set to the value of the 1st child, and y to the value of the 3rd one. This will allow to use these children's values in the corresponding block "f1(x+y)". All of this complex test is expressed by the pattern "{ tag = 'Alpha', x, 'some_string', y }".

The second case checks that foo is a table, has at least one array-part element, calls the first one 'a', and checks that a>10.

The first pattern to match is selected, and the corresponding block of code is executed. The code above is therefore equivalent to this:

if type(foo) == "table" and #foo==3 and foo.tag=='Alpha' and foo[2] == "some_string" then
   local x, y = foo[1], foo[3]
   f1 (x+y)
elseif type(foo)=="table" and #foo>=1  then
   local a=foo[1]
   if a>10 then
      f2(a)
   end
end

(In reality, it's compiled into something equivalent, slightly faster and much less readable, but you're but supposed to look at compiled code. There's a "-a" option in the metalua compiler that prints the compiled code as an AST, if you really want to know).

If you compare the match...with version and the compiled one, I believe the interest of the first syntax is quite obvious. And that's with pretty simple pattern, and only two cases. Imagine how readable a bigger program such a this one would be, without pattern matching: http://repo.or.cz/w/metalua.git?a=blob;f=src/lib/walk.mlua ("`Foo{ bar }" is syntax sugar for "{ tag='Foo', bar }". It's extremely handy to represent deeply nested trees, such as routinely manipulated in XML. And it works for values as well as for patterns).
 
also, you mention that there's no point in replacing LuaExpat; does that mean
that metalua's pattern matching can 'match' patterns in the parsed structure
and not only on strings?  that sounds promising, but somewhat removed from
metalua's original purpose as a compiler extension.

Pattern matching in metalua matches structures, *not* strings. Lua's regular expressions are a good fit for 80% of string pattern matching needs, and for the remaining cases, lpeg works really great. I see no way nor need to seriously improve on these with metalua (although I'm always eager to read diverging opinions).

-- Fabien