The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

Name

Config::Perl - Perl extension for parsing configuration files written in a subset of Perl and (limited) undumping of data structures (via PPI, not eval)

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, but please make sure to read Data::Undump::PPI for details!

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 license 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.06 of the module. Although this module has a fair number of tests, it still lacks some features (see list below) and there may be bugs lurking. Contributions are welcome!

Interface

This module has a simple OO interface. A new parser is created with Config::Perl->new 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.

Config::Perl->new(debug=>1) turns on debugging.

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 currently 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)

  • dereferencing via the arrow operator (also implicit arrow operator between subscripts)

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 via @{...}, %{...}, 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, including bless (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.