Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 134 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,45 @@ PerlPP: Perl preprocessor
Translates **Text+Perl** to **Text**.
It can be used for any kind of text templating, e.g. code generation.
No external modules are required, just a single file.
Requires Perl 5.10+.

Usage: perl perlpp.pl [options] [filename]
Options:
-o, --output filename Output to the file instead of STDOUT.
-s, --set name=value Set $S{name}=value in the generated code.
The hash %S always exists, but is empty
if you haven't specified any -s options.
-e, --eval expression Evaluate the expression(s) before any Perl code.
-d, --debug Don't evaluate Perl code, just write it to STDERR.
-h, --help Usage help.
PerlPP runs in two passes: it generates a Perl script from your input, and then
it runs the generated script. If you see `error at (eval ##)`
(for some number `##`), it means there was an error in the generated script.

Syntax
------
Usage
-----

Syntax is a bit similar to PHP.
Perl code has to be included between `<?` and `?>` tags.
There are several modes, indicated by the opening tag:
Usage: perl perlpp.pl [options] [filename]
Options:
-o, --output filename Output to the file instead of STDOUT.
-D, --define name=value Set $D{name}=value in the generated
code. The hash %D always exists, but
is empty if you haven't specified any
-D options.
Also substitutes _name_ with _value_
in the output file.
_value_ is optional and defaults to
true.
-e, --eval statement Evaluate the statement(s) before any
Perl code of the input files.
-E, --debug Don't evaluate Perl code, just write
it to STDERR.
-s, --set name=value As -D, but gneerates into %S and does
not substitute in the text body.
-h, --help Usage help.

In a **-D** command, the `value` must be a valid Perl value, e.g., `"foo"`
for a string. This may require you to escape quotes in the **-D** argument,
depending on your shell. E.g., if `-D foo="bar"` doesn't work, try
`-D 'foo="bar"'` (with single quotes around the whole `name=value` part).

Syntax of the input file
------------------------

The syntax is a bit similar to PHP.
Perl code is included between `<?` and `?>` tags.
There are several modes, indicated by the character after the `<?`:

<? code mode: Perl code is between the tags.
<?= echo mode: prints a Perl expression
Expand All @@ -41,6 +63,19 @@ produces the result:

<?x this tag is passed as is ?> because "x" is not a valid mode

The Generated Script
--------------------

The generated script:

- is in its own package, named based on the input filename
- `use`s `5.010`, `strict`, and `warnings`
- provides constants `true` (=`!!1`) and `false` (=`!!0`) (with `use constant`)
- Declares `my %D` and initializes `%D` based on any **-D** options you provide

Other than that, everything in the script comes from your input file(s).
Use the **-E** option to see the generated script.

Examples
--------

Expand Down Expand Up @@ -108,27 +143,43 @@ So `<?/ ... ?>` is effectively a shorthand for `<? print "\n"; ... ?>`.
Commands
--------

### Include

<?:include file.p ?>
<?:include "long file name.p" ?>

or `<?:include "long file name.p" ?>` (keep a whitespace between `"` and `?>`, explained further).
Includes source code of another PerlPP file into this position.
Note that this file can be any PerlPP input, so you can also use this to
include plain text files or other literal files.
When using the long form, make sure there is whitespace between the trailing
`"` and the closing tag `?>`, as explained below under "Capturing."

### Prefix

<?:prefix foo bar ?>

Replaces word prefixes in the following output.
In this case words like `fooSomeWord` will become `barSomeWord`.

### Macro

<?:macro some_perl_code; ?>

will run `some_perl_code;` at the time of script generation. Whatever output
the perl code produces will be included verbatim in the script output.
This can be used to dynamically select which files you want to include,
using
using the provided `Include()` function. For example:

<?:macro my $fn="some_name"; Include $fn; ?>

has the same effect as

<?:include some_name ?>

but `$fn` can be determined programmatically. Note that it is not currently
possible to select the filename to `Include` based on defines set with **-D**,
since those do not take effect until the script has been generated.

Capturing
---------

Expand All @@ -137,16 +188,16 @@ Sometimes it is great to get (capture) source text into a Perl string.
"?> start of capturing
<?" end of capturing

For example
There must be no whitespace between the `"` and the `?>` or `<?`. For example:

<? print "?>That's cool<?" . "?>, really.<?"; ?>

is the same as

<? print 'That\'s cool' . ', really.'; ?>

Captured strings are properly escaped, and can be sequenced like in this example.
Moreover, they can be nested!
Captured strings are properly escaped, and can be sequenced like in
this example. Moreover, they can be nested!

<?
sub ABC {
Expand All @@ -160,30 +211,77 @@ Moreover, they can be nested!
<? ABC(); ?>
<?" ); ?>

Printed characters from the second `ABC()` call are attached to the string `'alphabet '`,
so the result will be
Printed characters from the second `ABC()` call are attached to the
string `'alphabet '`, so the result will be

abcdefghijklmnopqrstuvwxyz
ALPHABET
ABCDEFGHIJKLMNOPQRSTUVWXYZ

Capturing works in all modes: code, echo, or command mode.

Custom Preprocessors
--------------------
C Preprocessor Emulation
------------------------

It's possible to create your own pre/post-processors with `PerlPP::AddPreprocessor` and `PerlPP::AddPostprocessor`.
This feature is used in [BigBenBox](https://github.com/d-ash/BigBenBox) for generating code in the C programming language.
The **-D** switch defines elements of `%D`. If you do not specify a
value, the value `true` (a constant in the generated script) will be used.
The following commands work mostly analogously to their C preprocessor
counterparts.

Future
------
- `<?:define NAME ?>`
- `<?:undef NAME ?>`
- `<?:ifdef NAME ?>`
- `<?:else ?>`
- `<?:endif ?>`
- `<?:if NAME CONDITION ?>`
- `<?:elsif NAME CONDITION ?>` (`elif` and `elseif` are synonyms)

For example:

<?:ifdef NAME ?>
foo
<?:endif ?>

is the same as the more verbose script:

<? if(defined($D{NAME})) { ?>
foo
<? } ?>

### If and Elsif

Tests with `<?:if NAME ... ?>` and `<?:elsif NAME ... ?>` have two restrictions:

- If `$D{NAME}` does not exist, the test will be `false` regardless
of the condition `...`.
- The `...` must be a valid Perl expression when
`$D{NAME}` is added to the beginning, with no
parentheses around it.

For example, `<?:if FOO eq "something" ?>` (note the whitespace before `?>`!)
will work fine. However, if you want to test `(FOO+1)*3`, you will need
to use the full Perl code.

Other Features
--------------

### Custom Preprocessors

It's possible to create your own pre/post-processors in a `<?:macro ?>` block
using `PerlPP::AddPreprocessor` and `PerlPP::AddPostprocessor`.
This feature is used in [BigBenBox](https://github.com/d-ash/BigBenBox) for
generating code in the C programming language.

### Future

Suggestions are welcome.

Highlighting
------------
Highlighting in your editor
---------------------------

### Vim

To make PerlPP insets highlighted in Vim, add this to *~/.vimrc*
To make highlight PerlPP insets in Vim, add this to *~/.vimrc*

autocmd colorscheme * hi PerlPP ctermbg=darkgrey ctermfg=lightgreen

Expand All @@ -193,3 +291,9 @@ and create corresponding *~/.vim/after/syntax/FILETYPE.vim*

FILETYPE can be determined with `:set ft?`

## Copyright

Distributed under the MIT license --- see
[LICENSE.txt](LICENSE.txt) for details.
By Andrey Shubin (d-ash at Github) and Chris White (cxw42 at Github).

Loading