Subject: | Incorrect treatment of optional subrules in RecDescent grammars |
Date: | Sun, 20 Jul 2008 00:41:05 -0600 |
To: | bug-SQL-Translator [...] rt.cpan.org |
From: | "Arren Lex" <arrenlex [...] gmail.com> |
I was reading your code to help me get familiar with using
Parse::RecDescent with sql-like languages and I found statements like
these:
create : CREATE UNIQUE(?) /(index|key)/i index_name /on/i table_name
'(' field_name(s /,/) ')' "$delimiter"
{
@table_comments = ();
push @{ $tables{ $item{'table_name'} }{'indices'} },
{
name => $item[4],
type => $item[2] ? 'unique' : 'normal',
fields => $item[8],
}
;
}
(This is from the Translator ::Parser::MySQL, there is a
similar\identical statement in ::Access as well, and probably others).
In the "type =>" line, you consider $item[2] (the result of the
optional UNIQUE(?) subrule) to be a boolean value, but it isn't.
According to the Parse::RecDescent main documentation:
Since a repeated subrule may match many instances of the subrule
itself, the value associated with it is not a simple scalar, but
rather a reference to a list of scalars, each of which is the value
associated with one of the individual subrule matches.
So, in fact, $item[2] will be an array reference. If UNIQUE(?) didn't
match anything, it will be a reference to an empty array (my own
testing confirms this). However, array references will evaluate to
true, meaning that $item[2] ? 'unique' : 'normal' will ALWAYS return
'unique'.