Name

Config::Perl - Perl extension to parse configuration files written in a subset of Perl and (limited) undumping of data structures (safer than eval thanks to parsing via PPI)

Synopsis

use Config::Perl;
my $parser = Config::Perl->new;
my $data = $parser->parse_or_die( \<<' END_CONFIG_FILE' );
  # This is the example configuration file
  $foo = "bar";
  %text = ( test => ["Hello", "World!"] );
  @vals = qw/ x y a /;
END_CONFIG_FILE
print $data->{'$foo'}, "\n";   # prints "bar\n"

# Resulting $data: {
#   '$foo'  => "bar",
#   '%text' => { test => ["Hello", "World!"] },
#   '@vals' => ["x", "y", "a"],
# };

Description

The goal of this module is to support the parsing of a small subset of Perl, primarily in order to parse configuration files written in that subset of Perl. As a side effect, this module can "undump" some data structures written by Data::Dumper and Data::Dump - see Data::Undump::PPI.

The code is parsed via PPI, eliminating the need for Perl's eval. This should provide a higher level of safety* compared to eval (even when making use of a module like Safe).

* Disclaimer: A "higher level of safety" does not mean "perfect safety". This software is distributed without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See also the licence for this software.

This module attempts to provide 100% compatibility with Perl over the subset of Perl it supports. When a Perl feature is not supported by this module, it should complain that the feature is not supported, instead of silently giving a wrong result. If the output of a parse is different from how Perl would evaluate the same string, then that is a bug in this module that should be fixed by correcting the output or adding an error message that the particular feature is unsupported. However, the result of using this module to parse something that is not valid Perl is undefined; it may cause an error, or may fail in some other silent way.

This document describes version 0.02 of the module. Although this module is well-tested and working, it still lacks some features to make it really useful (see list below). Contributions are welcome!

Interface

This module has a simple OO interface. A new parser is created with Config::Perl->new, which currently does not take any arguments, and documents are parsed with either the method parse_or_die or parse_or_undef.

my $parser = Config::Perl->new;
my $out1 = $parser->parse_or_undef(\' $foo = "bar"; ');
warn "parse failed: ".$parser->errstr unless defined $out1;
my $out2 = $parser->parse_or_die('filename.pl');

The arguments and return values of these two methods are (almost) the same: They each take exactly one argument, which is either a filename, or a reference to a string containing the code to be parsed (this is the same as PPI::Document's new method).

The methods differ in that, as the names imply, parse_or_die will die on errors, while parse_or_undef will return undef; the error message is then accessible via the errstr method.

For a successful parse, the return value of each function is a hashref representing the "symbol table" of the parsed document. This "symbol table" hash is similar to, but not the same as, Perl's symbol table. The hash includes a key for every variable declared or assigned to in the document, the key is the name of the variable including its sigil. If the document ends with a plain value or list that is not part of an assignment, that value is saved in the "symbol table" hash with the key "_" (a single underscore).

For example, the string "$foo=123; $bar=456;" will return the data structure { '$foo'=>123, '$bar'=>456 }, and the string "('foo','bar')" will return the data structure { _=>["foo","bar"] }.

Note that documents are currently always parsed in list context. For example, this means that a document like "@foo = ("a","b","c"); @foo" will return the array's elements ("a","b","c") instead of the item count (3). This also means that the special hash element "_" will currently always be an arrayref.

What is currently supported

  • plain scalars, arrays, hashes, lists

  • arrayrefs and hashrefs constructed via [] and {} resp.

  • declarations - only our, also my on the outermost level (document) where it is treated exactly like our; not supported are lexical my inside blocks, local or state

  • assignments (except the return value of assignments is not yet implemented)

  • simple array and hash subscripts (e.g. $x[1], $x[$y], $x{z}, $x{"$y"})

  • very simple variable interpolations in strings (currently only "hello$world" or "foo${bar}quz") and some escape sequences (e.g. "\x00")

  • do blocks (contents limited to the supported features listed here)

What is not supported (yet)

I hope to achieve a balance where this module is useful, without becoming too much of a re-implementation of Perl. I've labeled these items with "wishlist", "maybe", and "no", depending on whether I currently feel that I'd like to support this feature in a later version, I'd consider supporting this feature if the need arises, or I currently don't think the feature should be implemented.

  • lexical variables (my) (wishlist)

  • taking references via \ and dereferencing (@{...}, %{...}, etc.) (wishlist)

  • return values of assignments (e.g. $foo = do { $bar = "quz" }) (maybe)

  • operators other than assignment (maybe; supporting a subset, like concatenation, is wishlist)

  • conditionals, like for example a very simple if ($^O eq 'linux') { ... } (maybe)

  • any functions (mostly this is "no"; supporting a very small subset of functions, e.g. push, is "maybe")

  • anything that can't be resolved via a static parse (including subs, many regexps, etc.) (no)

  • Note this list is not complete.

Author, Copyright, and License

Copyright (c) 2015 Hauke Daempfling (haukex@zero-g.net).

This library is free software; you can redistribute it and/or modify it under the same terms as Perl 5 itself.

For more information see the Perl Artistic License, which should have been distributed with your copy of Perl. Try the command "perldoc perlartistic" or see http://perldoc.perl.org/perlartistic.html.