. "$BST_LIB" require perl libparse-yapp-perl/present # BST-TIMEOUT: 600 # # Measured, not guessed: this suite's own `==BST-SUITE` line reported elapsed=91s # on an unloaded host (2026-08-22, first verifying boot, 64 cases). 600 is ~6.6x # that, which is the headroom the packager README asks for -- the bound has to # hold on the host's worst day, not its median one. Without a marker the runner # would apply its 60 s default and this suite would trip on every run. # # Parse::Yapp 1.21 (meta-oe recipes-devtools/perl/libparse-yapp-perl_1.21.bb) -- # an LALR(1) parser generator that reads a yacc-style grammar and emits a # self-contained Perl parser module. Sixteenth Perl module on this image under # BRINTOS-999, and the second whose acceptance criterion actually RUNS: it is # pure Perl, so BRINTOS-881 -- the -Uusedl -Uuseshrplib arm that stops every XS # module here -- does not apply. # # THIS SUITE'S PASS CRITERION IS THE DISTRIBUTION'S OWN t/, NOT A HAND-WRITTEN # BATTERY -- the ticket's own wording. The port therefore installs the suite # (libparse-yapp-perl-ptest, from ptest-perl enabled for this recipe alone) and # section 5 runs `prove -r t/` over it. # # WHAT THE TICKET EXPECTED, AND WHAT IS ACTUALLY TRUE HERE. The ticket says the # t/ cases "generate parsers from bundled grammars and run them over sample # input, which makes the suite file-in / output-out and byte-comparable against # the x86-64 reference". The first half is exactly right. The second half is # NOT, and it is the one measurement in this port that changed a design: # # THE GENERATED PARSER MODULE IS NOT BYTE-STABLE, ON ANY HOST. Parse::Yapp # serialises its LALR tables by walking perl hashes, so the emitted .pm text # follows perl's per-process hash order. Five generations of the SAME grammar # by the SAME interpreter on x86-64 gave five different md5s # (a780bc85/87b20239/82ac882f/cb0680cb/2ca0fdab, measured 2026-08-22), as did # three runs at pinned PERL_HASH_SEED with PERL_PERTURB_KEYS=2. So an # md5-of-the-.pm case would have been red on every boot for a reason that has # nothing to do with wasm32 -- a false red pointed at the platform. # # What IS byte-comparable, and is what section 4 asserts, is the generated # parser's OUTPUT over sample input. Same 13 lines on target and on x86-64, # character for character. That is the ticket's intent with the invariant it # actually has. # # EVERY REFERENCE BELOW WAS MEASURED, NOT READ OFF THE TARBALL. The control is # the same 1.21 tree built and run on x86-64 (perl 5.38.2), driven exactly as the # sections below drive it: `prove -r t/` gives `All tests successful.`, Files=3, # Tests=33, Result: PASS in ~1 s (0.29 s CPU). # # Five layers: # 1. filesystem facts -- what the port SHIPS, asserted before anything starts # perl, so they hold on a boot where the interpreter cannot load a module. # 2. the harness the criterion names. # 3. can perl load the module on this boot, classified on the diagnostic. # 4. the generator END TO END: grammar in, parser out, parser run over sample # input, output compared against the x86-64 reference. Both the happy path # and the two refusal paths (conflict report, malformed grammar). # 5. the criterion: prove -r t/ over the installed suite. # perl prints a four-line locale-warning preamble on EVERY invocation on this # image, on stderr. Sections 3-5 capture 2>&1 (they must: a prove that died has # said so on stderr), so without this strip every red would report "Setting # locale failed" in the 100-char detail field -- the wrong diagnosis in the one # place a later reader attributes by. Same strip as 36-libdev-checklib-perl.test. _yapp_clean() { printf '%s\n' "$1" | awk '/^perl: warning/ { skip=1; next } /^[ \t]/ && skip { next } { skip=0; print }' } V=$(ls -d /usr/lib/perl5/vendor_perl/* 2>/dev/null | head -1) CORE=$(ls -d /usr/lib/perl5/5.* 2>/dev/null | head -1) PT=/usr/lib/libparse-yapp-perl/ptest # ------------------------- 1. what the port SHIPS: filesystem facts ---------- # The VERSION dir, not the arch dir: Parse::Yapp is pure Perl, so cpan installs # it to vendor_perl// and NOT to the vendor_perl//-linux/ that # 36-libdbi-perl.test globs for its XS module. Verified against the built .deb, # not assumed: the package ships # ./usr/lib/perl5/vendor_perl/5.38.4/Parse/Yapp.pm and six modules beside it. check libparse-yapp-perl/vendor-dir test -n "$V" check libparse-yapp-perl/module-installed test -f "$V/Parse/Yapp.pm" # The whole closure, each named. Loading Parse::Yapp pulls all six at compile # time, so a package that shipped only the front module would fail in section 3 # with a diagnostic naming whichever one perl reached first -- which is not the # same finding as "the package is incomplete", and only these cases can say so. for mod in Driver Grammar Lalr Options Output Parse; do check "libparse-yapp-perl/module-$mod" test -f "$V/Parse/Yapp/$mod.pm" done # The generator itself -- the package's one program, and what section 4 drives. check libparse-yapp-perl/bin-installed test -x /usr/bin/yapp # The recipe's do_install:append rewrites that script's shebang to # `#!/usr/bin/env perl`. Asserted because a recipe that stopped doing it would # ship a script with the build host's interpreter path baked in -- which nothing # else here would notice, and which makes /usr/bin/yapp unrunnable on target # while every module case above still passes. check_eq libparse-yapp-perl/bin-shebang "#!/usr/bin/env perl" \ "$(head -1 /usr/bin/yapp 2>/dev/null)" # ...and the interpreter that shebang defers to has to be resolvable. `env` is # coreutils', not this port's, but a `yapp` whose shebang cannot resolve is # indistinguishable in section 4 from a `yapp` that is broken. check libparse-yapp-perl/env-resolves-perl test -x /usr/bin/perl # THE INSTALLED SUITE -- the deliverable the ticket's criterion runs on. It is # NOT in the upstream recipe: meta-oe inherits `cpan` only, so this layer's # bbappend adds `inherit ptest-perl` AND `PTEST_ENABLED = "1"` (both are needed; # the class deletes its own task without the flag). These cases are what says # the pair took effect. check libparse-yapp-perl/ptest-dir test -d "$PT/t" check libparse-yapp-perl/ptest-runptest test -f "$PT/run-ptest" for t in base calc stress; do check "libparse-yapp-perl/ptest-$t" test -f "$PT/t/$t.t" done # 3 -- the whole of the distribution's t/. This recipe removes none of them, so # the count is the tarball's and a recipe that started pruning reds here. The # x86-64 control ran exactly these 3. check_eq libparse-yapp-perl/ptest-count 3 "$(ls "$PT"/t/*.t 2>/dev/null | wc -l | tr -d ' ')" # ------------------- 2. the harness the criterion names ---------------------- # `prove` reached this image under libdbi-perl (perl-misc + perl-module-app-prove) # and WORKS only because libdev-checklib-perl added the 43 perl-module-tap-* # splits. Asserted as ordinary reds, not as a `require`: their absence is a # regression to report, not a reason to skip this port's criterion. check libparse-yapp-perl/prove-installed test -x /usr/bin/prove check libparse-yapp-perl/prove-lib test -f "$CORE/App/Prove.pm" # ------------------ 3. can perl LOAD this module on this boot? --------------- # Pure Perl, so BRINTOS-881 does not apply and no .so is wanted. A clean import # is the expected -- and the only passing -- outcome. Failure is classified on # the diagnostic so a red says WHOSE defect it is rather than quoting 100 # characters of transcript. pout=$(perl -e ' eval { require Parse::Yapp }; my $e = $@; if (!$e) { printf "YAPP-LOADED %s\n", ($Parse::Yapp::VERSION // "undef") } else { print "YAPP-FAILED: $e\n" }' 2>&1) prc=$? pdiag=$(_yapp_clean "$pout"); [ -n "$pdiag" ] || pdiag=$pout case "$pdiag" in *YAPP-LOADED*) bst_ok libparse-yapp-perl/import-load ;; *) case "$pdiag" in *"Can't locate Parse/Yapp.pm"*) why="OURS -- libparse-yapp-perl is not on this image, or did not install into \@INC" ;; *"Can't locate"*) why="OURS -- a module in Parse::Yapp's closure is missing from this image; read the name in the diagnostic" ;; *mremap_chunk*|*munmap_chunk*|*"corrupted size"*|*"corrupted double-linked list"*|\ *"double free or corruption"*|*"free(): "*|*"malloc(): "*|*"realloc(): "*) # The pattern set is WIDE on purpose and was widened by measurement under # BRINTOS-1011: glibc has a dozen spellings for one abort, and missing # one turns an attributed red into a false alarm in the single field a # later reader attributes by. why="linux-in-the-browser#154 -- perl aborts in glibc's allocator while compiling a module" ;; *) if [ "$prc" = 134 ]; then why="unclassified SIGABRT -- rc=134 with no allocator diagnostic; probably #154 with a spelling this guard has not seen, but not asserted as one" else why="unclassified -- neither a clean import, a missing-module diagnostic, nor #154's allocator abort" fi ;; esac bst_notok libparse-yapp-perl/import-load "rc=$prc $(_bst_1line "$pdiag") -- $why" ;; esac # The version the front module reports. Pinned exactly: it is a property of the # tarball, it is what the -V banner in section 4 must agree with, and a mismatch # between the two is how a half-installed upgrade shows itself. check_eq libparse-yapp-perl/version "YAPP-LOADED 1.21" "$(_yapp_clean "$pout" | tail -1)" # The module compiled WHOLE, not just as far as its first statement. These five # methods are the whole of the public interface `yapp` drives, and they are # resolved through @ISA (Parse::Yapp inherits Parse::Yapp::Output), so this also # asserts the inheritance chain the six files above build. api=$(perl -e ' eval { require Parse::Yapp }; print "API"; print " ", (Parse::Yapp->can($_) ? $_ : "-") for qw(new Output Warnings ShowDfa Conflicts); print " ISA=@Parse::Yapp::ISA\n"' 2>&1 | tail -1) check_eq libparse-yapp-perl/api-compiled \ "API new Output Warnings ShowDfa Conflicts ISA=Parse::Yapp::Output" "$api" # ------------------ 4. THE GENERATOR, END TO END ----------------------------- # The rootfs is read-only at browser runtime and yapp WRITES its output beside # its input, so everything here happens in a writable staging dir. `cd` is never # run at the top level -- brintos/linux#73 makes a failed top-level chdir kill # the whole file -- only inside command substitutions, which fork first. WD=${TMPDIR:-/tmp}/bst-libparse-yapp-perl.$$ mkdir -p "$WD" cp "$BST_DATA/yapp-calc.yp" "$BST_DATA/yapp-calc.in" \ "$BST_DATA/yapp-amb.yp" "$BST_DATA/yapp-bad.yp" "$WD/" 2>/dev/null check libparse-yapp-perl/payload-staged test -f "$WD/yapp-calc.yp" # 4a. GRAMMAR IN, PARSER OUT. yapp reads yapp-calc.yp -- an integer calculator # exercising %right/%left precedence, %prec on unary minus, right-associative # '^', assignment through YYData, YYError on division by zero, and error # recovery -- and writes a parser module. gen=$(cd "$WD" && yapp -m BstCalc -o BstCalc.pm yapp-calc.yp 2>&1); grc=$? gen=$(_yapp_clean "$gen") if [ "$grc" = 0 ]; then bst_ok libparse-yapp-perl/generate else bst_notok libparse-yapp-perl/generate "rc=$grc $(_bst_1line "$gen")"; fi check libparse-yapp-perl/generated-file test -s "$WD/BstCalc.pm" # The generated module is perl, and has to compile as perl. Asserted before it # is RUN so that a syntax-level defect in the emitted text reds here, by name, # instead of surfacing as a wrong answer below. comp=$(cd "$WD" && perl -c BstCalc.pm 2>&1); crc=$? comp=$(_yapp_clean "$comp") case "$comp" in *"syntax OK"*) bst_ok libparse-yapp-perl/generated-compiles ;; *) bst_notok libparse-yapp-perl/generated-compiles "rc=$crc $(_bst_1line "$comp")" ;; esac # 4b. PARSER RUN, OUTPUT COMPARED. This is the ticket's "file-in / output-out # and byte-comparable against the x86-64 reference", with the invariant the # generator actually has (see the header: the .pm TEXT is not stable, its # behaviour is). The 13 lines below are the x86-64 control's stdout verbatim, # '|'-joined so one case can assert the whole transcript. REF="R 7|R 9|R 512|R 1|R 5|R 25|R 2.5|R DIVZERO|R ERR|R SYNTAX|R ERR|R 89|R DONE" run=$(cd "$WD" && perl BstCalc.pm yapp-calc.in 2>&1); rrc=$? run=$(_yapp_clean "$run") runline=$(printf '%s\n' "$run" | tr '\n' '|' | sed 's/|$//') check_eq libparse-yapp-perl/parser-output "$REF" "$runline" check_eq libparse-yapp-perl/parser-rc 0 "$rrc" # The individual values, named. Without these the case above is one red carrying # a 100-char diff and the reader cannot tell an arithmetic fault from a # precedence fault from a parser that never started. # # What calc-mul-binds-tighter does and does NOT establish, measured rather than # assumed: deleting `%left '*' '/'` from the grammar changes NOTHING here. With # no declared precedence yapp reports the conflict and resolves it by shifting, # which for `1+2*3` is the same tree, so all 13 lines are byte-identical. These # cases assert the parser's ANSWERS, which is the deliverable; they are not a # test of the %left declaration itself. The mutation that does move them is # associativity -- `%right '^'` to `%left` turns 2^3^2 from 512 into 64, and # calc-pow-right-assoc reds alone with `want:'R 512' got:'R 64'`. n=0 for want in "R 7" "R 9" "R 512" "R 1" "R 5" "R 25" "R 2.5" "R DIVZERO" "R ERR" "R SYNTAX" "R ERR" "R 89" "R DONE"; do n=$((n + 1)) got=$(printf '%s\n' "$run" | sed -n "${n}p") case "$n" in 1) id=mul-binds-tighter ;; 2) id=parens ;; 3) id=pow-right-assoc ;; 4) id=unary-minus-prec ;; 5) id=assign ;; 6) id=var-lookup ;; 7) id=division ;; 8) id=yyerror-divzero ;; 9) id=recover-divzero ;; 10) id=syntax-error ;; 11) id=recover-syntax ;; 12) id=sub-left-assoc ;; *) id=footer-reached ;; esac check_eq "libparse-yapp-perl/calc-$id" "$want" "$got" done # 4c. TWO INDEPENDENT GENERATIONS AGREE. The parser TEXT differs between them -- # measured on x86-64, five md5s from five runs, because Parse::Yapp emits its # tables in perl hash order -- so this asserts the property that IS invariant: # two parsers generated from one grammar behave identically. It is also the case # that would catch a table serialisation genuinely corrupted on this arm, which # an md5 comparison could not distinguish from the ordering noise. gen2=$(cd "$WD" && yapp -m BstCalc -o Twice.pm yapp-calc.yp 2>&1); g2rc=$? run2=$(cd "$WD" && perl Twice.pm yapp-calc.in 2>&1) run2line=$(_yapp_clean "$run2" | tr '\n' '|' | sed 's/|$//') if [ "$g2rc" = 0 ]; then check_eq libparse-yapp-perl/regenerate-agrees "$runline" "$run2line" else bst_notok libparse-yapp-perl/regenerate-agrees "second generation failed rc=$g2rc $(_bst_1line "$(_yapp_clean "$gen2")")" fi # 4d. STANDALONE (-s) INLINES THE DRIVER. A standalone parser carries # Parse::Yapp::Driver's code inside it and must run with nothing of Parse::Yapp # on @INC -- which is the mode anyone shipping a generated parser uses. Driven # with PERL5LIB emptied and @INC pruned of the vendor dir, so a parser that # secretly still needs the installed module reds here rather than passing on the # module that happens to sit beside it. sgen=$(cd "$WD" && yapp -s -m BstCalc -o Sa.pm yapp-calc.yp 2>&1); sgrc=$? if [ "$sgrc" = 0 ]; then bst_ok libparse-yapp-perl/standalone-generate else bst_notok libparse-yapp-perl/standalone-generate "rc=$sgrc $(_bst_1line "$(_yapp_clean "$sgen")")"; fi # NOTE the absence of a `$0 = ...` here, which is the obvious way to make the # parser's own usage message read nicely. It was written that way first and the # case went red on the first verifying boot with `Can't set $0 with prctl(): # Function not implemented` -- a defect in this control, not in the port: # prctl(2) is unwired on wasm32 (brintos/linux#29) and perl's $0 setter croaks # rather than degrading. Nothing in Parse::Yapp assigns $0, so the right fix was # to stop the control doing it; the finding went onto #29 as a reproducer. sarun=$(cd "$WD" && PERL5LIB= perl -e ' @INC = grep { !m{/vendor_perl/} } @INC; do "./Sa.pm"; die $@ if $@;' -- yapp-calc.in 2>&1) saline=$(_yapp_clean "$sarun" | tr '\n' '|' | sed 's/|$//') check_eq libparse-yapp-perl/standalone-output "$REF" "$saline" # 4e. CONFLICT DETECTION. An unparenthesised `E: E '+' E` is one shift/reduce # conflict; yapp must SAY so and must still emit a parser (it resolves by # shifting). -v additionally writes .output -- named after the GRAMMAR, # not after -o, which is worth pinning because it is the surprising half. amb=$(cd "$WD" && yapp -v -m Amb -o Amb.pm yapp-amb.yp 2>&1); arc=$? amb=$(_yapp_clean "$amb") check_eq libparse-yapp-perl/conflict-rc 0 "$arc" case "$amb" in *"1 shift/reduce conflict"*) bst_ok libparse-yapp-perl/conflict-reported ;; *) bst_notok libparse-yapp-perl/conflict-reported "$(_bst_1line "$amb")" ;; esac check libparse-yapp-perl/conflict-listing test -s "$WD/yapp-amb.output" check libparse-yapp-perl/conflict-still-emits test -s "$WD/Amb.pm" # 4f. THE REFUSAL PATH. A grammar that does not parse must produce a diagnostic, # a non-zero exit, and NO output file. The last of the three is the one that # matters: a generator that writes a truncated parser on a failed parse is worse # than one that writes nothing, and only this case can tell them apart. bad=$(cd "$WD" && yapp -m Bad -o Bad.pm yapp-bad.yp 2>&1); brc=$? bad=$(_yapp_clean "$bad") check_eq libparse-yapp-perl/badgrammar-rc 255 "$brc" case "$bad" in *"*Fatal* Errors detected"*) bst_ok libparse-yapp-perl/badgrammar-diagnostic ;; *) bst_notok libparse-yapp-perl/badgrammar-diagnostic "$(_bst_1line "$bad")" ;; esac check libparse-yapp-perl/badgrammar-no-output test ! -f "$WD/Bad.pm" # 4g. THE BANNER. -V is the one invocation that needs no grammar, and it is the # cheapest statement that the installed /usr/bin/yapp is this version rather # than something left on the image by an earlier port. check_out libparse-yapp-perl/banner "This is Parse::Yapp version 1.21." yapp -V # ------------------------- 5. THE CRITERION: prove -r t/ --------------------- # Run from a WRITABLE COPY, not in place: the deployed rootfs is read-only at # browser runtime. Cheap here (3 files) and it removes a whole class of false # red. PW=$WD/ptest mkdir -p "$PW" && cp -r "$PT/t" "$PW/t" 2>/dev/null check libparse-yapp-perl/suite-staged test -f "$PW/t/base.t" # THE HARNESS ITSELF, BEFORE THE CRITERION THAT RIDES ON IT. `prove` resolving # and parsing is not the same as `prove` running: TAP::Harness names its five # collaborators as bare strings and loads them at run time, so poky's # use-scanning RDEPENDS generator never saw them and an image can carry a # /usr/bin/prove that dies on first invocation. Asserted on a trivial # self-contained test so a broken harness reds HERE, by name, instead of turning # the cases below into an unreadable heap. A .t file is a PROGRAM prove executes, # not a TAP transcript it reads -- so the smoke file is perl that PRINTS the # plan, not the plan itself. cat > "$PW/smoke.t" <<'SMOKE' print "1..1\nok 1 - smoke\n"; SMOKE smoke=$(cd "$PW" && prove smoke.t 2>&1); srn=$? smoke=$(_yapp_clean "$smoke") case "$smoke" in *"Result: PASS"*) bst_ok libparse-yapp-perl/prove-smoke ;; *) bst_notok libparse-yapp-perl/prove-smoke \ "rc=$srn prove cannot run a 1-line passing test -- $(_bst_1line "$smoke")" ;; esac rm -f "$PW/smoke.t" out=$(cd "$PW" && prove -r t/ 2>&1); rc=$? out=$(_yapp_clean "$out") # `Result: PASS` is prove's own verdict over the whole run and is the ticket's # "reporting zero failures" verbatim; the exit status is asserted beside it # because a harness that died before printing a verdict leaves neither. The red # carries its ATTRIBUTION rather than just the transcript. case "$out" in *"Result: PASS"*) bst_ok libparse-yapp-perl/prove-result ;; *) if printf '%s\n' "$out" | grep -q '^panic: magic_killbackrefs'; then why="linux-in-the-browser#93 -- perl's magic_killbackrefs use-after-free in global destruction; the identical tree is Result: PASS on x86-64" elif printf '%s\n' "$out" | grep -q '^panic: '; then why="a perl interpreter panic that is NOT #93's magic_killbackrefs -- read perl-no-panic's detail" else why="no interpreter panic -- this is a genuine test failure and is THIS PORT'S to answer" fi bst_notok libparse-yapp-perl/prove-result "rc=$rc $(_bst_1line "$out") -- $why" ;; esac check_eq libparse-yapp-perl/prove-rc 0 "$rc" case "$out" in *"All tests successful."*) bst_ok libparse-yapp-perl/prove-all-successful ;; *) bst_notok libparse-yapp-perl/prove-all-successful "$(_bst_1line "$out")" ;; esac # The file count is pinned EXACTLY -- it is a property of the package, already # asserted on the rootfs in section 1, and a harness that silently ran fewer # files is the failure a green verdict cannot show. files=$(printf '%s\n' "$out" | sed -n 's/^Files=\([0-9]*\),.*/\1/p' | tail -1) check_eq libparse-yapp-perl/prove-files 3 "$files" # The assertion count is bounded from BELOW, not pinned. 33 is what the x86-64 # control ran (8 + 15 + 10); none of the three files skips anything on this arm, # so a lower number means a file died part-way and prove still counted it. # Bounding from below rather than pinning keeps a future 1.22 with an extra case # from reading as a regression. tests=$(printf '%s\n' "$out" | sed -n 's/^Files=[0-9]*, Tests=\([0-9]*\),.*/\1/p' | tail -1) case "$tests" in ''|*[!0-9]*) bst_notok libparse-yapp-perl/prove-tests "no Tests= total in prove's summary -- $(_bst_1line "$out")" ;; *) if [ "$tests" -ge 33 ]; then bst_ok libparse-yapp-perl/prove-tests else bst_notok libparse-yapp-perl/prove-tests "Tests=$tests, want >= 33 (x86-64 control ran 33)"; fi ;; esac # THE THREE FILES, PINNED BY NAME. A skip and a pass are both green to prove, so # without this a regression that turned all three into skips would still report # Result: PASS -- the exact false green the criterion is meant to exclude. None # of the three can legitimately skip here: all are self-contained, needing only # Parse::Yapp on @INC. for t in base calc stress; do line=$(printf '%s\n' "$out" | grep -m1 "^t/$t\.t ") case "$line" in '') bst_notok "libparse-yapp-perl/ran-$t" "t/$t.t has no line in prove's transcript -- it did not run at all" ;; *skipped*) bst_notok "libparse-yapp-perl/ran-$t" "t/$t.t skipped; it is self-contained and must run -- $(_bst_1line "$line")" ;; *ok*) bst_ok "libparse-yapp-perl/ran-$t" ;; *) bst_notok "libparse-yapp-perl/ran-$t" "$(_bst_1line "$line")" ;; esac done # WHICH FILES FAILED, BY NAME. Without this a non-zero prove is one red carrying # 100 characters of transcript, and the file that actually broke is whichever one # happened to print first. prove's Test Summary Report names each on a line of # the form `t/.t (Wstat: ...)`, so the names are recoverable and belong in # the report rather than in a later reader's guess. bad=$(printf '%s\n' "$out" | sed -n 's/^\(t\/[A-Za-z0-9_.-]*\.t\) *(Wstat:.*/\1/p' | sort | tr '\n' ' ') if [ -z "$bad" ]; then bst_ok libparse-yapp-perl/prove-failing-files else bst_notok libparse-yapp-perl/prove-failing-files "failing files: $bad"; fi # A perl INTERPRETER PANIC is not a test failure and must not be reported as one. # perl prints `panic: ` from its own guts when an internal invariant # breaks; on this arm that is a platform fact about perl-on-wasm32, not a # statement about Parse::Yapp. Named separately so it is attributable instead of # being buried in whichever red quoted the transcript first. pan=$(printf '%s\n' "$out" | grep -m1 '^panic: ') if [ -n "$pan" ]; then case "$pan" in *magic_killbackrefs*) pwhy="linux-in-the-browser#93 -- the magic_killbackrefs use-after-free this arm already carries a warnings.pm workaround for" ;; *) pwhy="an interpreter panic #93 does not cover -- unattributed, and worth a brintos.io issue" ;; esac bst_notok libparse-yapp-perl/perl-no-panic "$(_bst_1line "$pan") -- $pwhy" else bst_ok libparse-yapp-perl/perl-no-panic fi rm -rf "$WD"