NAME
Positron::Expression - a simple language for template parameters
VERSION
version v0.1.3
SYNOPSIS
use Positron::Expression;
my $env = Positron::Environment->new({ key => 'value' });
my $value = Positron::Expression::evaluate($string, $env);
DESCRIPTION
A simple expression language for templating constructs. The main function, evaluate
, takes an expression as a string and a Positron::Environment object, and evaluates the two. The result is a scalar value.
GRAMMAR
The grammar is basically built up of the following rules. The exact grammar is available as a package variable $Positron::Expression::grammar
; this is a string which could be fed to Parse::RecDescent starting at the token expression
.
However, the Parse::RecDescent path has been replaced with a version using plain regular expressions, so the string is no longer the direct definition of the grammar.
Whitespace
Whitespace is generally allowed between individual parts of the grammar.
Literals
4 , -3.8 , "A string" , 'another string' , `a third string`
The grammar allows for literal strings and numbers. Numbers are integers or floating point numbers. Notations with exponents or with different bases are not supported. Negative numbers are possible.
Strings are delimited by double quotes, single quotes, or backticks. Strings cannot contain their own delimiters; with three delimiters to choose from, though, this should cover most use cases.
Variable lookups
a , key0 , ListValues , flag_not_possible
A single, non-deliminated word is looked up in the environment; that value is returned. This may be undef
if the environment does not contain such a key.
Words follow the rules for identifiers in most C-like languages (and Perl), in that they may start with a letter or an underscore, and contain only letters or underscores. Currently, only ASCII letters are supported; this will hopefully change in the future.
Function calls
a() , b(0) , find_file("./root", filename)
Functions are looked up in the environment, like variables. They obey the same rules for identifiers, and are expected to return an anonymous function (a sub reference).
This function is then called with the evaluated arguments. In the last example above, filename
is looked up in the environment, and the resulting value passed as the second argument to the function.
All function calls are made in scalar context.
Subselects
Subselects allow you to to select a part of something else, like getting the value for a given key in a hash, or an indexed entry in a list, or call a method on an object etc. In Positron::Expression
, these are denoted with a dot, .
, hence the alternative name "dotted expression". Subselects can be chained.
The following subselects are possible:
Array index
a.0 , b.4.-1 , c.$i
Arrays are indexed by appending an integer to the variable or expression holding the array. Like Perl, indices start with 0, and negative indices count from the back. The form $<expression>
can be used to take any expression that evaluates to an integer as an index.
Hash index
pos.x , server.link.url , authors."Ben Deutsch" , names.$current
Hashes are indexed by appending a key, an identifier or string, to the variable or expression holding the hash. Most keys in practice will fit the form of an identifier as above (letters, digits, underscores). If not, a quoted string can be used. The form $<expression>
can again be used to take any expression that evaluates to a string as the key.
Object attributes
obj.length , task.parent.priority , obj.$attr
Object attributes work just like hash indices above, except they are called on an object and look up that attribute.
(In Perl, this is the same as a method call without parameters.)
Object method calls
img.make_src(320, 240) , abs(int(-4.2))
Method calls work like a mixture between attributes and function calls. The method name is restricted to an actual key, however, and not a free-form string or a $
-expression.
Like functions, methods are called in scalar context.
Nested expressions
hash.(var).length , ports.(resource.server)
Expressions can be nested with parentheses. The var
expression above is equivalent to hash.$var.length
, since var
as an expression is a variable lookup in the environment.
Boolean combinations
a ? !b , if ? then : else , !!empty
The ?
, :
and !
operands stand for "and", "or" and "not", respectively. This terminology, while a bit obscure, is the mirror of Python's a and b or c
ternary operator replacement. In practice, this allows for some common use cases:
Not
The !
operator has a higher precedence than ?
or :
, binding closer. It reverses the "truth" of the expression it precedes.
Note: unlike pure Perl, a reference to an empty array or an empty hash counts as false! In Perl, it would be true because all references are true, barring overloading; only non-reference empty arrays and hashes are false. Positron's use is closer related to the Perl usages of if ( $@list )
than if ( $list )
, and is typically what you mean.
Conditional values: And
only_if ? value , first_cond ? second_cond ? result
The ?
operator is a short-circuiting &&
or and
equivalent. If the left hand side is false, it is returned, otherwise the right hand side is returned. It is chainable, and left associative.
The most common use case is text insertion with a condition which is ''
when false; the right hand text is only inserted if the condition is true.
Defaults: Or
first_try : second_try : third_try
The :
operator is a short-circuiting ||
or or
equivalent. If the left hand side is true, it is returned, otherwise the right hand side is returned. It is chainable, left associative, and has the same precedence as ?
.
The most common use case is to provide a chain of fallback values, selecting the first fitting (i.e. true) one.
Ternary Operator
if ? then : else
Taken together, the ?
and :
operators form the well-known ternary operator: if the left-most term is true, the middle term is chosen; else the right-most term is.
FUNCTIONS
evaluate
my $value = Positron::Expression::evaluate($string, $environment);
Evaluates the expression in $string
with the Positron::Environment $env
. The result is always a scalar value, which may be a plain scalar or a reference. For example, the expression x
with the environment { x => [1] }
will evaluate to a reference to an array with one element.
parse
my $tree = Positron::Expression::parse($string);
Parses the string in the first argument, and returns an abstract parse tree. The exact form of the tree is not important, it is usually a structure made of nested array references. The important part is that it contains no blessed references, only strings, numbers, arrays and hashes (that is, references to those).
This makes it easy to serialize the tree, for distributed caching or persistant storage, if parsing time is critical.
See also reduce
to continue the evaluation.
reduce
my $value = Positron::Expression::reduce($tree, $environment);
The companion of parse
, this function takes an abstract parse tree and returns a scalar value. Essentially,
my $tree = Positron::Expression::parse($string);
my $value = Positron::Expression::reduce($tree, $environment);
is equivalent to
my $value = Positron::Expression::evaluate($string, $environment);
true
In Perl, empty lists and hashes count as false. The only way for Positron::Environment
to contain lists and hashes is as array or hash references. However, these count as true
in Perl, even if they reference an empty array or hash.
To aid decisions in templates, the function true
returns a false value for references to empty arrays or hashes, and a true value for non-empty ones. Other values, such as plain scalars, blessed references, subroutine references or undef
, are returned verbatim. Their truth values are therefore up to Perl (a reference blessed into a package with an overloaded bool
method may still return false, for example).
AUTHOR
Ben Deutsch, <ben at bendeutsch.de>
BUGS
None known so far, though keep in mind that this is alpha software.
Please report any bugs or feature requests to bug-positron at rt.cpan.org
, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Positron. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
SUPPORT
This module is part of the Positron distribution.
You can find documentation for this distribution with the perldoc command.
perldoc Positron
You can also look for information at:
RT: CPAN's request tracker (report bugs here)
AnnoCPAN: Annotated CPAN documentation
CPAN Ratings
Search CPAN
LICENSE AND COPYRIGHT
Copyright 2013 Ben Deutsch. All rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See http://dev.perl.org/licenses/ for more information.