aboutsummaryrefslogtreecommitdiff
path: root/ListParser.pm
diff options
context:
space:
mode:
authorDavid Phillips <david@sighup.nz>2018-09-16 23:42:35 +1200
committerDavid Phillips <david@sighup.nz>2018-09-17 00:01:48 +1200
commit5331e8ef6cdb9163e3ec6ee85491b7b286f4cbdc (patch)
tree034e3ffcd6f0f450ba2d6ee51ba54ac3feced716 /ListParser.pm
parent0352e7d89441abc913d69ce6cff551872edc1fe9 (diff)
downloadidalius-5331e8ef6cdb9163e3ec6ee85491b7b286f4cbdc.tar.xz
Overhaul config parsing
* makes plugin config more private: The config file now uses sections denoted with [Plugin::Foo] where plugin- private config can be stored. Plugins are now passed the usual, as well as a hashref for their own config section. They are also passed the config section of the core, i.e. those config options not appearing in an explicit section. Generally, these are used for bot-global options, so should be accessible to all plugins, but plugin-specific config shall be hidden * tries to improve parsing of hash-like strings and arrays The previous mechanism of using regex to pull out possible tokens was only ever meant to be temporary, and caused problems with escaping or encapsulation inside strings. I have made steps on hash parsing to allow tokens inside strings. Both array and hash parsing still to provide an escape character to escape the item separator (,)
Diffstat (limited to 'ListParser.pm')
-rw-r--r--ListParser.pm107
1 files changed, 107 insertions, 0 deletions
diff --git a/ListParser.pm b/ListParser.pm
new file mode 100644
index 0000000..9e3e511
--- /dev/null
+++ b/ListParser.pm
@@ -0,0 +1,107 @@
+package ListParser;
+
+sub parse_mapping {
+ my ($input) = @_;
+ my $key, $value;
+ my $i = 0;
+ my $string_start, $string_end;
+ $string_start = $string_end = undef;
+
+ # Are we currently lexing inside a string literal?
+ my $is_string = 0;
+
+ # Currently parsing key or value?
+ my $is_key = 1;
+
+ while ($i < length($input)) {
+ my $c = substr($input, $i, 1);
+ my $lookahead = substr($input, $i+1, 1);
+
+ if ($is_string and $c eq "'") {
+ $is_string = 0;
+ $string_end = $i;
+ if (not $is_key) {
+ $value = substr($input, $string_start, $string_end - $string_start);
+ }
+ $i++;
+ next;
+ }
+ if (not $is_string) {
+ if ($c =~ /\s/) {
+ # allow whitespace
+ } elsif ($c eq "'") {
+ return ("Key/value must consist of single string", undef, undef) if defined $string_end;
+ $is_string = 1;
+ $string_start = $i + 1;
+ } elsif ($c eq "=") {
+ return ("Expected > after =, got $lookahead", undef, undef) unless $lookahead eq ">";
+ return ("Unexpected '=>'.", undef, undef) unless $is_key;
+ $i++;
+
+ $key = substr($input, $string_start, $string_end - $string_start);
+ $string_start = $string_end = undef;
+ $is_key = 0;
+ } else {
+ return ("Unexpected $c", undef, undef);
+ }
+ }
+ $i++;
+ }
+
+ return (undef, $key, $value);
+}
+
+sub parse_list {
+ my ($input, $is_hash) = @_;
+ my $c_start = $is_hash ? "{" : "[";
+ my $c_end = $is_hash ? "}" : "]";
+ my %h_res;
+ my @a_res;
+ my $i = 0;
+
+ # Index of the start of the current item
+ my $item_i = 0;
+
+ # Level of nested lists, 1 being the minimum
+ my $nest = 1;
+
+ return ("Error: expected $c_start", undef) unless substr($input, $i, 1) eq $c_start;
+
+ $i++;
+ $item_i = $i;
+
+ while ($nest != 0 && $i < length($input)) {
+ my $c = substr($input, $i, 1);
+
+ if ($c eq $c_start) {
+ $nest++;
+ } elsif ($c eq $c_end) {
+ $nest--;
+ }
+
+ if (($nest == 1 and $c eq ",") || ($nest == 0 and $c eq $c_end)) {
+ my $item = substr($input, $item_i, $i - $item_i);
+ $item =~ s/^\s+|\s+$//g;
+ if ($is_hash) {
+ # FIXME should we die on duplicate keys or no?
+ my ($error, $key, $value) = parse_mapping($item);
+ die $error if $error;
+ $h_res{$key} = $value;
+ } else {
+ push @a_res, $item;
+ }
+ $item_i = $i+1;
+ }
+ $i++;
+ }
+
+ return ("Error: expected $c_end, got end of line", undef) unless $nest == 0;
+
+ if ($i != length($input)) {
+ return ("Error: unexpected item in the bagging area (after '$c_end')", undef);
+ }
+
+ return (undef, %h_res) if $is_hash;
+ return (undef, @a_res);
+}
+1;