• Subject: Lua pattern matching for the poor
• Date: Mon, 20 Mar 2006 16:40:02 +0300

```Hi all!

While playing with language, I've came to following implementation of

Example:

match {
{
function() return true_if_matched end;
function(optional_match_results) do_something() end
};
{
function() return true_if_matched_2 end;
function(optional_match_results) do_something_else() end
};
{
function() return true end;
function(optional_match_results) default_case() end
};
}

To get rid of limitation for unified predicate interface, match
construction assumes predicates work with some upvalues.

While this approach brings considerable syntax and (possibly)
performance overhead, I think it still can be useful in some cases...

With best regards,
Alexander.

--  TODO: This whole thing looks quite performance-hungry.
--  T is table filled with pairs of nullary match-predicates and
result generators,
--  accepting table of return values from match-predicates:
--  t = { {function() ... end, function() ... end} }
--  Matches first valid pattern.
match = function(t)
local res;
for _, v in t do
res = { v[1]() }
if res[1] then return v[2](res) end
end

return assert(false, "No match")()
end

--  Some utility functions
inv = function(v) --  invariant
return function() return v end
end

default = inv(true);

append_to_iter = function(val, iter)
local iter_fn
iter_fn  = function() iter_fn = iter; return val end
return function()
return iter_fn();
end
end

--  Silly example:
my_gfind = function(s, pat)
local m = string.gfind(s, pat)
return m(), m
end

--  Some macroses would help greatly to reduce syntax overhead.
classificate = function(str)
--  Not using inv() for first two cases to delay potentially
performance-hungry evaluation.
return match {
{
function() return my_gfind(str, "%d+") end;
function(m) return "numbers", append_to_iter(m[1], m[2]) end
};
{
function() return my_gfind(str, "%a+") end;
function(m) return "letters", append_to_iter(m[1], m[2]) end
};
{ default; inv(nil) };
}
end

print_classification = function(str)
local r = { classificate(str) }

--  Conventional if would do here :)
match {
{
inv(r[1] ~= nil);
function()
print("type: ", r[1], "\nvalues:");
for val in r[2] do
print(val);
end
end
};
{ default; function() print("type:", "unclassified") end };
}
end

print_classification("this matches numbers 1 and 2");
print_classification("this matches words");
print_classification(")(\$&*#@(\$*&#\$"); -- No match.

```