⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 optreecheck.pm

📁 source of perl for linux application,
💻 PM
📖 第 1 页 / 共 3 页
字号:
       'expect_nt-nonthreaded'	=> '',       'expect-threaded'	=> '',       );#######sub getCmdLine {	# import assistant    # offer help    print(qq{\n$0 accepts args to update these state-vars:	     turn on a flag by typing its name,	     select a value from list by typing name=val.\n    },	  mydumper(\%gOpts))	if grep /help/, @ARGV;    # replace values for each key !! MUST MARK UP %gOpts    foreach my $opt (keys %gOpts) {	# scan ARGV for known params	if (ref $gOpts{$opt} eq 'ARRAY') {	    # $opt is a One-Of construct	    # replace with valid selection from the list	    # uhh this WORKS. but it's inscrutable	    # grep s/$opt=(\w+)/grep {$_ eq $1} @ARGV and $gOpts{$opt}=$1/e, @ARGV;	    my $tval;  # temp	    if (grep s/$opt=(\w+)/$tval=$1/e, @ARGV) {		# check val before accepting		my @allowed = @{$gOpts{$opt}};		if (grep { $_ eq $tval } @allowed) {		    $gOpts{$opt} = $tval;		}		else {die "invalid value: '$tval' for $opt\n"}	    }	    # take 1st val as default	    $gOpts{$opt} = ${$gOpts{$opt}}[0]		if ref $gOpts{$opt} eq 'ARRAY';        }        else { # handle scalars	    # if 'opt' is present, true	    $gOpts{$opt} = (grep /^$opt/, @ARGV) ? 1 : 0;	    # override with 'foo' if 'opt=foo' appears	    grep s/$opt=(.*)/$gOpts{$opt}=$1/e, @ARGV;	}     }    print("$0 heres current state:\n", mydumper(\%gOpts))	if $gOpts{help} or $gOpts{dump};    exit if $gOpts{help};}# the above arg-handling cruft should be replaced by a Getopt call############################### the API (1 function)sub checkOptree {    my $tc = newTestCases(@_);	# ctor    my ($rendering);    print "checkOptree args: ",mydumper($tc) if $tc->{dump};    SKIP: {	skip("$tc->{skip} $tc->{name}", 1) if $tc->{skip};	return runSelftest($tc) if $gOpts{selftest};	$tc->getRendering();	# get the actual output	$tc->checkErrs();	local $Level = $Level + 2;      TODO:	foreach my $want (@{$modes{$gOpts{testmode}}}) {	    local $TODO = $tc->{todo} if $tc->{todo};	    $tc->{cross} = $msgs{"$want-$thrstat"};	    $tc->mkCheckRex($want);	    $tc->mylike();	}    }    return;}sub newTestCases {    # make test objects (currently 1) from args (passed to checkOptree)    my $tc = bless { @_ }, __PACKAGE__	or die "test cases are hashes";    $tc->label();    # cpy globals into each test    foreach my $k (keys %gOpts) {	if ($gOpts{$k}) {	    $tc->{$k} = $gOpts{$k} unless defined $tc->{$k};	}    }    # transform errs to self-hash for efficient set-math    if ($tc->{errs}) {	if (not ref $tc->{errs}) {	    $tc->{errs} = { $tc->{errs} => 1};	}	elsif (ref $tc->{errs} eq 'ARRAY') {	    my %errs;	    @errs{@{$tc->{errs}}} = (1) x @{$tc->{errs}};	    $tc->{errs} = \%errs;	}	elsif (ref $tc->{errs} eq 'Regexp') {	    warn "regexp err matching not yet implemented";	}    }    return $tc;}sub label {    # may help get/keep test output consistent    my ($tc) = @_;    return $tc->{name} if $tc->{name};    my $buf = (ref $tc->{bcopts}) 	? join(',', @{$tc->{bcopts}}) : $tc->{bcopts};    foreach (qw( note prog code )) {	$buf .= " $_: $tc->{$_}" if $tc->{$_} and not ref $tc->{$_};    }    return $tc->{name} = $buf;}################## render and its helperssub getRendering {    my $tc = shift;    fail("getRendering: code or prog is required")	unless $tc->{code} or $tc->{prog};    my @opts = get_bcopts($tc);    my $rendering = ''; # suppress "Use of uninitialized value in open"    my @errs;		# collect errs via     if ($tc->{prog}) {	$rendering = runperl( switches => ['-w',join(',',"-MO=Concise",@opts)],			      prog => $tc->{prog}, stderr => 1,			      ); # verbose => 1);    } else {	my $code = $tc->{code};	unless (ref $code eq 'CODE') {	    # treat as source, and wrap into subref 	    #  in caller's package ( to test arg-fixup, comment next line)	    my $pkg = '{ package '.caller(1) .';';	    {		no strict;		no warnings;		$code = eval "$pkg sub { $code } }";	    }	    # return errors	    if ($@) { chomp $@; push @errs, $@ }	}	# set walk-output b4 compiling, which writes 'announce' line	walk_output(\$rendering);	my $opwalker = B::Concise::compile(@opts, $code);	die "bad BC::compile retval" unless ref $opwalker eq 'CODE';      B::Concise::reset_sequence();	$opwalker->();	# kludge error into rendering if its empty.	$rendering = $@ if $@ and ! $rendering;    }    # separate banner, other stuff whose printing order isnt guaranteed    if ($tc->{strip}) {	$rendering =~ s/(B::Concise::compile.*?\n)//;	print "stripped from rendering <$1>\n" if $1 and $tc->{stripv};	#while ($rendering =~ s/^(.*?(-e) line \d+\.)\n//g) {	while ($rendering =~ s/^(.*?(-e|\(eval \d+\).*?) line \d+\.)\n//g) {	    print "stripped <$1> $2\n" if $tc->{stripv};	    push @errs, $1;	}	$rendering =~ s/-e syntax OK\n//;	$rendering =~ s/-e had compilation errors\.\n//;    }    $tc->{got}	   = $rendering;    $tc->{goterrs} = \@errs if @errs;    return $rendering, @errs;}sub get_bcopts {    # collect concise passthru-options if any    my ($tc) = shift;    my @opts = ();    if ($tc->{bcopts}) {	@opts = (ref $tc->{bcopts} eq 'ARRAY')	    ? @{$tc->{bcopts}} : ($tc->{bcopts});    }    return @opts;}sub checkErrs {    # check rendering errs against expected errors, reduce and report    my $tc = shift;    # check for agreement, by hash (order less important)    my (%goterrs, @got);    $tc->{goterrs} ||= [];    @goterrs{@{$tc->{goterrs}}} = (1) x scalar @{$tc->{goterrs}};        foreach my $k (keys %{$tc->{errs}}) {	if (@got = grep /^$k$/, keys %goterrs) {	    delete $tc->{errs}{$k};	    delete $goterrs{$_} foreach @got;	}    }    $tc->{goterrs} = \%goterrs;    # relook at altered    if (%{$tc->{errs}} or %{$tc->{goterrs}}) {	$tc->diag_or_fail();    }    fail("FORCED: $tc->{name}:\n") if $gOpts{fail}; # silly ?}sub diag_or_fail {    # help checkErrs    my $tc = shift;    my @lines;    push @lines, "got unexpected:", sort keys %{$tc->{goterrs}} if %{$tc->{goterrs}};    push @lines, "missed expected:", sort keys %{$tc->{errs}}   if %{$tc->{errs}};    if (@lines) {	unshift @lines, $tc->{name};	my $report = join("\n", @lines);	if    ($gOpts{report} eq 'diag')	{ _diag ($report) }	elsif ($gOpts{report} eq 'fail')	{ fail  ($report) }	else					{ print ($report) }	next unless $gOpts{errcont}; # skip block    }}=head1 mkCheckRex ($tc)It selects the correct golden-sample from the test-case object, andconverts it into a Regexp which should match against the originalgolden-sample (used in selftest, see below), and on the renderingsobtained by applying the code on the perl being tested.The selection is driven by platform mostly, but also by test-mode,which rather complicates the code.  This is worsened by the potentialneed to make platform specific conversions on the reftext.but is otherwise as strict as possible.  For example, it should *not*match when opcode flags change, or when optimizations convert an op toan ex-op.=head2 match criteriaThe selected golden-sample is massaged to eliminate various matchirrelevancies.  This is done so that the tests dont fail just becauseyou added a line to the top of the test file.  (Recall that therenderings contain the program's line numbers).  Similar cleanups aredone on "strings", hex-constants, etc.The need to massage is reflected in the 2 golden-sample approach ofthe test-cases; we want the match to be as rigorous as possible, andthats easier to achieve when matching against 1 input than 2.Opcode arguments (text within braces) are disregarded for matchingpurposes.  This loses some info in 'add[t5]', but greatly simplifiesmatching 'nextstate(main 22 (eval 10):1)'.  Besides, we are testingfor regressions, not for complete accuracy.The regex is anchored by default, but can be suppressed with'noanchors', allowing 1-liner tests to succeed if opcode is found.=cut# needless complexity due to 'too much info' from B::Concise v.60my $announce = 'B::Concise::compile\(CODE\(0x[0-9a-f]+\)\)';;sub mkCheckRex {    # converts expected text into Regexp which should match against    # unaltered version.  also adjusts threaded => non-threaded    my ($tc, $want) = @_;    eval "no re 'debug'";    my $str = $tc->{expect} || $tc->{expect_nt};	# standard bias    $str = $tc->{$want} if $want && $tc->{$want};	# stated pref    die("no '$want' golden-sample found: $tc->{name}") unless $str;    $str =~ s/^\# //mg;	# ease cut-paste testcase authoring    if ($] < 5.009) {	# add 5.8 private flags, which bleadperl (5.9.1) doesn't have/use/render	# works because it adds no wildcards, which are butchered below..        $str =~ s|(mapstart l?K\*?)|$1/2|mg;        $str =~ s|(grepstart l?K\*?)|$1/2|msg;        $str =~ s|(mapwhile.*? l?K)|$1/1|msg;	$str =~ s|(grepwhile.*? l?K)|$1/1|msg;    }    $tc->{wantstr} = $str;    # make targ args wild    $str =~ s/\[t\d+\]/[t\\d+]/msg;    # escape bracing, etc.. manual \Q (doesnt escape '+')    $str =~ s/([\[\]()*.\$\@\#\|{}])/\\$1/msg;    # $str =~ s/(?<!\\)([\[\]\(\)*.\$\@\#\|{}])/\\$1/msg;    # treat dbstate like nextstate (no in-debugger false reports)    # Note also that there may be 1 level of () nexting, if there's an eval    # Seems easiest to explicitly match the eval, rather than trying to parse    # for full balancing and then substitute .*?    # In which case, we can continue to match for the eval in the rexexp built    # from the golden result.    $str =~ s!(?:next|db)state	      \\\(			# opening literal ( (backslash escaped)	      [^()]*?			# not ()	      (\\\(eval\ \d+\\\)	# maybe /eval \d+/ in ()	       [^()]*?			# which might be followed by something	      )?	      \\\)			# closing literal )	     !'(?:next|db)state\\([^()]*?' .	      ($1 && '\\(eval \\d+\\)[^()]*')	# Match the eval if present	      . '\\)'!msgxe;    # widened for -terse mode    $str =~ s/(?:next|db)state/(?:next|db)state/msg;    if (!$using_open && $tc->{strip_open_hints}) {      $str =~ s[(			# capture		 \(\?:next\|db\)state	# the regexp matching next/db state		 .*			# all sorts of things follow it		 v			# The opening v		)		(?:(:>,<,%,\\{)		# hints when open.pm is in force		   |(:>,<,%))		# (two variations)		(\ ->[0-9a-z]+)?		$	       ]	[$1 . ($2 && ':{') . $4]xegm;	# change to the hints without open.pm    }    if ($] < 5.009) {	# 5.8.x doesn't provide the hints in the OP, which means that	# B::Concise doesn't show the symbolic hints. So strip all the	# symbolic hints from the golden results.	$str =~ s[(			# capture		   \(\?:next\|db\)state	# the regexp matching next/db state		   .*			# all sorts of things follow it		  v			# The opening v		  )		  :(?:\\[{*]		# \{ or \*		      |[^,\\])		# or other symbols on their own		    (?:,		     (?:\\[{*]			|[^,\\])		      )*		# maybe some more joined with commas		(\ ->[0-9a-z]+)?		$	       ]	[$1$2]xgm;			# change to the hints without flags    }    # don't care about:    $str =~ s/:-?\d+,-?\d+/:-?\\d+,-?\\d+/msg;		# FAKE line numbers    $str =~ s/match\\\(.*?\\\)/match\(.*?\)/msg;	# match args

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -