Bigtop
view release on metacpan or search on metacpan
lib/Bigtop/Parser.pm view on Meta::CPAN
are also sequence blocks, but they are deprecated and never allowed statements.
Further, the various literals are blocks in the grammar (they have block
idents and can have defined keywords), but they don't have brace delimiters.
Instead, they have a single backquoted string.
=item is_valid_keyword
Call this as a class method, passing it a type of keyword and a word that
might be a valid keyword of that type.
Returns true if the keyword is valid, false otherwise.
=item get_valid_keywords
Call this as a class method passing it the type of keywords you want.
Returns a list of all registered keywords, of the requested type, in
string sorted order.
The two preceding methogs are really for internal use in the grammar.
=back
=head2 METHODS which work on the AST
There are quite a few other methods not documented here (shame on me).
Most of those support tentmaker manipulations of the tree, but there
are also some convenience accessors.
=over 4
=item walk_postorder
Walks the AST for you, calling you back when it's time to build something.
The most common skeleton for gen_Backend is:
use Bigtop;
use Bigtop::Backend;
sub gen_Backend {
my $class = shift;
my $build_dir = shift;
my $tree = shift;
# walk the tree
my $something = $tree->walk_postoder( 'output_something' );
my $something_str = join '', @{ $something };
# write the file
Bigtop::write_file( $build_dir, $something_string );
}
This walks the tree from the root. The walking is postorder meaning that
all children are visited before the current node. Each walk_postorder
returns an array reference (which is why we have to join the result
in the above skeleton). After the children have been visited, the
callback (C<output_something> in the example) is called with their output
array reference. You can also pass an additional scalar (which is usually
a hash reference) to walk_postorder. It will be passed along to all
the child walk_postorders and to the callbacks.
With this module walking the tree, all you must do is provide the appropriate
callbacks. Put one at each level of the tree that interests you.
For example, if you are generating SQL, you need to put callbacks in
at least the following packages:
table_block
table_element_block
field_statement
This does require some knowledge of the tree. Please consult bigtop.grammar,
in the lib/Bigtop subdirectory of Bigtop's build directory,
for the possible packages (or grep for package on this file).
There are also several chapters of the Gantry book devoted to explaining
how to use the AST to build backends.
The callbacks are called as methods on the current tree node. They receive
the output array reference from their children and the data scalar that
was passed to walk_postorder (if one was passed in the top level call).
So, a typical callback method might look like this:
sub output_something {
my $self = shift;
my $child_output = shift;
my $data = shift;
...
return [ $output ];
}
Remember that they must return an array reference. If you need something
fancy, you might do this:
return [ [ type1_output => $toutput, type2_output => $other_out ] ];
Then the parent package's callback will receive that and must tease
apart the the two types. Note that I have nested arrays here. This prevents
two children from overwriting each other's output if you are ever tempted
to try saving the return list directly to a hash (think recursion).
(walk_postorder also passes the current node to each child after the
data scalar. This is the child's parent, which is really only useful
during parent building inside the grammar. The parent comes
after the data scalar in both walk_postorder and in the callback.
Most backends will just peek in $self->{__PARENT__} which is gauranteed
to have the parent once the grammar finishes with the AST.)
=item set_parent
This method is the callback used by the grammar to make sure that all nodes
know who their daddy is. You shouldn't call it, but looking at it shows
what the simplest callback might look like. Note that there is only one
of these and it lives in the application_ancestor package, which is not
one of the packages defined in the grammar. But, this module makes
sure that all the grammar defined packages inherit from it.
=item build_lookup_hash
This method builds the lookup hash you can use to find data about other
parts of the tree, without walking to it.
The AST actually has three keys: configuration, application, and lookup.
The first two are built in the normal way from the input file. They
are genuine ASTs in their own right. The lookup key is not. It does
not preserve order. But it does make it easier to retrieve things.
For example, suppose that you are in the method_body package attempting
to verify that requested fields for this method are defined in the
table for this controller. You could walk the tree, but the lookup hash
makes it easier:
unless (
defined $tree->{lookup}{tables}{$table_name}{fields}{$field_name}
) {
die "No such column $field_name\n";
}
The easiest way to know what is available is to dump the lookup hash.
But the pattern is basically this. At the top level there are fixed keywords
for the app level block types: tables, sequences, controllers. The next
level is the name of a block. Under that, there is a fixed keyword for
each subblock type, etc.
=back
=head2 METHODS for use in walk_postorder callbacks
=over 4
=item dumpme
Use this method instead of directly calling Data::Dumper::Dump.
While you could dump $self, that's rather messy. The problem is the parent
nodes. Their presence means a simple dump will always show the whole app
AST. This method carefully removes the parent, dumps the node, and restores
the parent, reducing clutter and leaving everything in tact. The closer
to a leaf you get, the better it works.
=item get_appname
Call this on the full AST. It returns the name of the application.
=item get_config
Call this on the full AST. It returns the config subtree.
=item get_controller_name
Call this, from the method_body package, on the AST node ($self in the
callback). Returns the name of the controller for this method. This
is useful for error reporting.
=item get_method_name
Call this, from the method_body package, on the AST node ($self in the
callback). Returns the name of this method. Useful for error reporting.
=item get_name
While this should work everywhere, it doesn't. Some packages have it.
If yours does, call it. Otherwise peek in $self->{__NAME__}. But,
remember that not everything has a name.
=item get_table_name
Call this, from the method_body package, on the AST node ($self in the
callback). Returns the name of the table this controller controls.
Useful for error reporting.
=back
=head2 METHODS used internally
=over 4
=item import
You probably don't need to call this. But, if you do, pass it a list
of backends to import like this:
use Bigtop::Parser qw( Type=Backend=template.tt );
This will load Bigtop::Type::Backend and tell it to use template.tt.
You can accomplish the same thing by directly calling import as a class
method:
( run in 2.051 seconds using v1.01-cache-2.11-cpan-140bd7fdf52 )