NAME
treebuild - command-line interface to Lang::Tree::Builder
SYNOPSIS
$ treebuild [-o <dir>] [-p <prefix>] [-l <lang>] [<config>]
treebuild takes a configuration file, either from standard input or from the command line, and generates a set of classes from it. It is intended to make it easy to generate a large set of interrelated classes. My specific requirement when writing it was to have it create all the classes I would need to be able to construct abstract syntax trees.
Although billed as a command line interface to Lang::Tree::Builder, you probably won't need to use the Lang::Tree::Builder API directly as it does nothing that this script can't tell it to do.
The generated classes are made useful by two features. Firstly an api is also generated which provides shorthands for the class constructors. Secondly the generated classes all support the Visitor pattern, and a base visitor class and/or interface is also generated as a convenience.
Options
-o dir-
Generate classes under
dir. A common use of this would be-o lib. -p prefix-
Prepend the literal
prefixto all generated class names. For example given a config containingClassA,ClassBetc, a prefix of-p Foo::would produce output classesFoo::ClassAetc, wheras-p Foowould produceFooClassAetc. Even if you're generating classes for a language other than Perl, you still need to use the Perl-style::separator for namespace components. -l lang-
Generate classes for a language other than Perl. Currently supported values for
langare:- Perl
- PHP
To add support for other languages, look in the distribution for
lib/Tree/Builder/Templates, create a new directory named after the target language in there, copy the templates fromlib/Tree/Builder/Templates/Perlinto it, and edit them appropriately. You may also need to add functionality tolib/Tree/Builder/Class.pmto support your templates. If you do add methods there, you should add them toLang::Tree::Builder::Argstoo. Don't forget when you've finished to add the new language to the list of supported languages here!See Template::Manual for details of the
Template::Toolkitused to process the templates.
Format of the config file
The config file is free-form. Whitespace (including newlines) is not significant except to separate tokens. Comments run from a hash (#) to the end of the line. Each entry in the file has the same general form, best explained with some examples:
# a comment
abstract Expr()
abstract Expr Bool()
Expr Op::Plus(Expr left,
Expr right)
Expr Op::Minus(Expr left,
Expr right)
Expr Op::Times(Expr left,
Expr right)
Expr Op::Divide(Expr left,
Expr right)
Expr Op::And(Expr, Expr)
Expr Number(scalar value)
ExprList(Expr, ExprList)
ExprList EmptyExprList()
The above is saying:
abstract Expr()-
there is an abstract class called
Expr abstract Expr Bool()-
there is an abstract class called
Boolthat inherits fromExpr. Expr Op::Plus(Expr left, Expr right)-
there is a concrete class called
Op::Plusthat inherits fromExpr, and its constructor takes anExprcalledleftand anExprcalledrightas arguments. Expr Op::Minus(Expr left, Expr right)Expr Op::Times(Expr left, Expr right)Expr Op::Divide(Expr left, Expr right)-
more of the same.
Expr Op::And(Expr, Expr)-
there is a concrete class called
Op::Andthat inherits fromExpr, and its constructor takes two unnamedExpras arguments. Expr Number(scalar value)-
there is a concrete class called
Numberwhich inherits fromExprand its constructor takes a simple scalar calledvalueas argument. ExprList(Expr, ExprList)-
there is a concrete class called
ExprListwhose constructor takes anExprand anotherExprListas argument. ExprList EmptyExprList()-
there is a concrete class called
EmptyExprListwhich is anExprListand its constructor takes no arguments.
Output Files
Assume the above config exists in a file called example.tb, and that the following command is run:
$ treebuild -o ./test -p Foo:: -l Perl example.tb
This will create the directory ./test, and inside there will create the following files:
Foo/Expr.pm-
Code implementing an abstract
Foo::Exprclass (because the config declaredExprto be abstract). Being abstract, this class has only anew()method, and that willdieif ever it is called. Foo/Bool.pm-
Code implementing an abstract
Foo::Boolclass which inherits fromExpr. It also has a poisonednew()method. Foo/Op/Plus.pmFoo/Op/Minus.pmFoo/Op/Times.pmFoo/Op/Divide.pm-
Code implementing a
Foo::Op::Plusclass, aFoo::Op::Minusclass, etc. Each of these classes are declared to inherit fromFoo::Expr. They each have anew()method that accepts two arguments. Both arguments tonew()are required to inherit fromFoo::Expr. These arguments correspond to the(Expr left, Expr right)components of the config. Each of the generated classes also provides two accessor methods:getLeft()andgetRight()for retrieving the values, and anaccept()method which supports the visitor pattern, see below. Foo/Op/And.pm-
Code implementing a
Foo::Op::Andclass. In this case, because the config did not name the arguments to the constructor but only the types, the fields will be named after the types of the arguments. Also, because these names are not unique, they will be suffixed by an incrementing number. Therefore the accessor methods will be calledgetExpr1()andgetExpr2(). In other respects it is the same as theFoo::Op::Timesclass and its siblings. Foo/Number.pm-
Code implementing a
Foo::Numberclass. As specified in the config, it inherits fromExprand its constructor accepts a single simple scalar value (not a reference). It provides a singlegetValue()accessor (because the config stated(scalar value), and anaccept()method. Foo/ExprList.pm-
Code implementing a
Foo::ExprListclass. The class in this case does not inherit fromFoo::Expr. Itsnew()method accepts anotherFoo::ExprListand aFoo::Expras argument, and it has accessor methodsgetExprList()andgetExpr(). As usual it also has anaccept()method (more on that later). Foo/EmptyExprList.pmclass.-
Code implementing a
Foo::EmptyExprListclass. This class is defined to inherit fromFoo:ExprListand its constructor takes no arguments. Likewise it has no accessor methods, but still provides anaccept()method. Foo/API.pm-
Code implementing a
Foo::APIclass. This class performs a couple of functions. Firstly it includes (withuse) all of the other classes generated so is a useful one-stop-shop for ensuring they are all loaded (well actually it doesn't botheruse-ing the abstract classes, on the assumption that a concrete class will have loaded them). The second job it does is to provide a shorthand for each of the concrete classes constructors. In the case of our example, it will create subroutinesPlus(),Minus(),Times(),Divide(),And(),Number(),ExprList()andEmptyExprList(). It puts all of these on its@EXPORT_OKlist and makes them available via the shorthand:allimport tag. That means you can write things like:use Foo::API qw(:all); my $exprlist = ExprList(Plus(Number(2), Times(Number(3), Number(4))), ExprList(Number(5), EmptyExprList()));rather than the much more verbose:
use Foo::API; my $exprlist = Foo::ExprList->new( Foo::Op::Plus->new( Foo::Number->new(2), Foo::Op::Times->new( Foo::Number->new(3), Foo::Number->new(4) ) ), Foo::ExprList->new( Foo::Number->new(5), Foo::EmptyExprList->new() ) ); Foo/Visitor.pm-
Code implementing a
Foo::Visitorclass. As noted above, each of the concrete classes defined in the config will have anaccept()method. Thataccept()method takes a$visitoras argument and calls a specific method on it, passing itself as argument. For example theaccept()method ofFoo::Op::Pluswill look something like:sub accept { my ($self, $visitor) = @_; $visitor->visitPlus($self); }Similarily the
ExprList'saccept()will callvisitExprList($self), etc.The
Foo::Visitorclass generated here provides default implementations for all of these methods. It also provides a defaultcombinemethod that aggregates the results. It is intended that you inherit from this and override whatever you need to.
Some effort has been made to generate extensive inline pod documentation for all generated classes, in some ways better than the documentation for the generator! I suggest copying the above config and running treebuild on it, as in the example, then running perldoc on the generated files.
AUTHOR
Bill Hails <me@billhails.net>
SEE ALSO
Lang::Tree::Builder::Args, Lang::Tree::Builder::Class, Lang::Tree::Builder::Data, Lang::Tree::Builder::Parser, Lang::Tree::Builder::Scalar, Lang::Tree::Builder::Tokenizer and last but not least Lang::Tree::Builder itself.