in reply to parse lisp style config

package MyPairList; use strict; use warnings; use feature 'state'; use Data::Dumper; use List::Util qw(all none); use Exporter 'import'; our @EXPORT = qw(pair_list_parse); sub pair_list_parse { my $string = shift; sub get_tokens { my $string = shift; my @tokens = $string =~ /([()]|[^()\s]+)/g; } my @tokens = get_tokens $string; sub parse_list { state @tokens = @_; my @list; while (my $token = shift @tokens) { if ($token eq '(') { push @list, parse_list(); } elsif ($token eq ')') { return \@list; } else { push @list, $token; } } return \@list; } my $list = parse_list @tokens; sub parse_nested_list { my ($list) = @_; my %hash; if (none {ref $_} @$list) { if (@$list == 1) { return $list->[0]; } elsif (@$list == 2) { return { $list->[0] => $list->[1] }; } else { return $list } } elsif (all {ref $_} @$list) { return [ map { parse_nested_list($_) } @$list ]; } else { my ($key, $ref, @remain) = @$list; die 'wrong key ', Dumper $key if ref $key; die 'wrong value ', Dumper $ref unless ref $ref; die 'redundant value', Dumper \@remain if @remain; $hash{$key} = parse_nested_list($ref); } return \%hash; } return parse_nested_list($list) } 1;
I finish a little script, partly achieve my goal, firstly parsed to a nested list, then parsed to pairs or arrays.use '( (a) (b))' to represent list which avoid ambiguity. list is ok, and it keep order. Iterate list first, because it can not get deep value only be chained hash ref.A little example as below.
(config( (a A) (b B) ((good) (bad)) (d e f) (a (a1 (a2 A))) ) )
parsed to
$VAR1 = [ { 'config' => [ { 'a' => 'A' }, { 'b' => 'B' }, [ 'good', 'bad' ], [ 'd', 'e', 'f' ], { 'a' => { 'a1' => { 'a2' => 'A' } } } ] } ];
Like perl do, the parse result is normally what people mean

Replies are listed 'Best First'.
Re^2: parse lisp style config
by choroba (Cardinal) on Nov 28, 2024 at 10:20 UTC
    It seems the code uses nested named subs. Named subs don't nest in Perl as they do in some other languages. Try to avoid nesting named subs.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      > seems the code uses nested named subs.

      I was baffled at first, but you're right, the OP wasn't using proper indentation.

      Worth noting that "newer" Perl versions have lexical subs via my sub name {...} constructs.

      See perlsub#Lexical-Subroutines

      Personally I'm still stuck to my $code_ref = sub {...} approaches.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery

      nested subs provide some more abstraction ability, I use it always, and I need it, as long as perl still respect scope rule. Though I did not know on which case it can break bad.
        It can break bad exactly because of scope. The variables declared in the outer sub are not properly shared to the inner subs (or rather, they are shared only in the first run).
        #!/usr/bin/perl use strict; use warnings; sub outer { my ($x) = @_; sub inner { return $x + 1 } return inner() } print outer(12), "\n"; # 13 print outer(42), "\n"; # 13 !!

        Also, you'll get a warning:

        Variable "$x" will not stay shared at 1.pl line 9.

        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

        nnested subs provide some more abstraction ability

        Not in Perl.

        Whether nested or not, the following two snippets are equivalent:[1]

        sub foo { ... }
        BEGIN { *foo = sub { ... }; }

        As such,

        • Inner sub aren't scoped to outer sub.
        • It misleadingly appears the inner sub is scoped to the outer sub when they're not.
        • The inner sub can't use lexicals of the outer sub.
        • If the inner sub attempts to use lexicals of the outer sub, you get very weird and useless behaviour.
        • If the inner sub attempts to use lexicals of the outer sub, you get a warning.

        As you can see, you gain no abstraction or other benefits. Everything about it is bad.

        That said, none of this applies to lexical inner subs. This is fine:

        sub outer { ... my sub inner { ... } ... }

        1. Exception: The first has a name attached to the sub itself, while the second doesn't. This difference will affect croak and strack traces. I could have used Sub::Util's set_subname to correct this, but loading the module would introduce a new difference.