NAME
Language::Expr - Simple minilanguage for use in expression
VERSION
version 0.14
SYNOPSIS
use 5.010;
use Language::Expr;
my $le = Language::Expr->new;
# evaluate expressions
say $le->eval('1 + 2*3 + [4, 5][-1]'); # 12
say $le->eval(q("i" . " love " .
{lang=>"perl", food=>"rujak"}["lang"])); # "i love perl"
# convert Expr to Perl
use Language::Expr::Compiler::Perl;
my $perl = Language::Expr::Compiler::Perl->new;
say $perl->perl('1 ^^ 2'); # "(1 xor 2)"
# convert Expr to JavaScript
use Language::Expr::Compiler::JS;
my $js = Language::Expr::Compiler::JS->new;
say $js->js('1 . 2'); # "'' + 1 + 2"
# use variables & functions in expression (interpreted mode)
$le->interpreted(1);
$le->var('a' => 3, 'b' => 4);
$le->func(pyth => sub { ($_[0]**2 + $_[1]**2)**0.5 });
say $le->eval('pyth($a, $b)'); # 5
# use variables & functions in expression (compiled mode, by default the Perl
# compiler translates variables and function call as-is and runs it in
# Language::Expr::Compiler::Perl namespace, but you can customize this)
$le->interpreted(0);
package Language::Expr::Compiler::Perl;
sub pyth { ($_[0]**2 + $_[1]**2)**0.5 }
our $a = 3;
our $b = 4;
package main;
say $le->compiler->perl('pyth($a, $b)'); # "pyth($a, $b)"
say $le->eval('pyth($a, $b)'); # 5
# tell compiler to use My namespace, translate 'func()' to 'My::func()' and
# '$var' to '$My::var'
package My;
sub pyth { sprintf("%.03f", ($_[0]**2 + $_[1]**2)**0.5) }
our $a = 3;
our $b = 4;
package main;
$le->compiler->hook_var (sub { '$My::'.$_[0] });
$le->compiler->hook_func(sub { 'My::'.shift."(".join(", ", @_).")" });
say $le->compiler->perl('pyth($a, $b)'); # "My::pyth($My::a, $My::b)"
say $le->eval('pyth($a, $b)'); # "5.000"
# enumerate variables
use Data::Dump;
dd $le->enum_vars('$a*$a + sqr($b)'); # ['a', 'b']
DESCRIPTION
Language::Expr defines a simple, Perl-like expression minilanguage. It supports mathematical and string operators, arrays, hashes, variables, and functions. See Language::Expr::Manual::Syntax for description of the language syntax.
The language is very simple. The parser is just around 120 lines long.
This distribution consists of the language parser (Language::Expr::Parser), some interpreters (Language::Expr::Interpreter::*), and some compilers (Language::Expr::Compiler::*).
ATTRIBUTES
interpreted => BOOL
Whether to use the interpreter. By default is 0 (use the compiler, which means Language::Expr expression will be compiled to Perl code first before executed).
interpreter => OBJ
The Language::Expr::Interpreter::Default instance.
compiler => OBJ
The Language::Expr::Compiler::Perl instance.
varenumer => OBJ
The Language::Expr::Interpreter::VarEnumer instance.
METHODS
new()
Construct a new Language::Expr object.
var(NAME => VALUE, ...)
Define variables.
func(NAME => CODEREF, ...)
Define functions. Dies if function is defined multiple times.
eval(STR) => RESULT
Evaluate expression in STR and return the result. Will die if there is a parsing or runtime error. By default it uses the compiler unless you set interpreted
to 1.
enum_vars(STR) => ARRAYREF
Enumerate variables mentioned in expression STR. Return empty arrayref if no variables are mentioned.
FAQ
Why yet another simplistic (restricted, etc) language? Why not just Perl?
When first adding expression support to Data::Schema (now Data::Sah), I want a language that is simple enough so I can easily convert it to Perl, PHP, JavaScript, and others. I do not need a fully-fledged programming language. In fact, Expr is not even Turing-complete, it does not support assignment or loops. Nor does it allow function definition (though it allows anonymous function in grep/map/usort). Instead, I just need some basic stuffs like mathematical/string/logical operators, arrays, hashes, functions, map/grep/usort. This language will mostly be used inside templates and schemas.
Why don't you use Language::Farnsworth, or Math::Expression, or Math::Expression::Evaluator, or $FOO?
I need several compilers and interpreters (some even with different semantics), so that it's easier to start with a simple parser of my own. And of course there is personal preference of language syntax.
I want different syntax for (variables, foo operator, etc)!
Create your own language :-) Fork this distribution and start modifying the Language::Expr::Parser module.
The parser is too slow!
I personally am not having problem with compile performance. In fact, Regexp::Grammmars should be much faster than Parse::RecDescent. If you need faster parsing speed you can take a look at reimplementing the parser using Parse::Yapp, Parse::Eyapp, etc.
If you are having performance runtime problem, try switching from using the interpreter to using one of the available compilers.
How to show details of errors in expression?
This is a TODO item.
How to convert Expr expression into Perl code?
See Language::Expr::Compiler::Perl.
How to convert Expr expression into JavaScript code?
See Language::Expr::Compiler::JS.
BUGS
Due to possible bugs in Perl's RE engine or Regexp::Grammars or my grammar, some syntax errors will cause further parsing to fail.
SEE ALSO
Syntax reference: Language::Expr::Manual::Syntax
Modules that are using Language::Expr: Data::Sah, Data::Template::Expr (not yet released).
Other related modules: Math::Expression, Math::Expression::Evaluator, Language::Farnsworth
AUTHOR
Steven Haryanto <stevenharyanto@gmail.com>
COPYRIGHT AND LICENSE
This software is copyright (c) 2011 by Steven Haryanto.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.