Skip to content

Commit

Permalink
Sandbox run 01.2024, fixes for Fatal cases (10) (#2309)
Browse files Browse the repository at this point in the history
* process Dimension height param for \parbox

* guard and warn against limitations of multirow binding

* allow more recursion for parameter reads; guard double-loading on \xyoption

* guard revertScript from inner Tokens

* avoid expl3 loading confusion, base lipsum.sty on xparse.sty

* add quotemeta guard for literal regex matches in listings

* guard against realizeXMNode coming back with a non-libxml result

* ensure import.sty works with ZIP inputs, by consulting the sourcedirectory param

* math-aware ulem macros (todo: add XMWrap class to contents)

* flatten Token list in revertScript; thanks @brucemiller
  • Loading branch information
dginev authored Feb 7, 2024
1 parent 2f82c5f commit 5fd5c5b
Show file tree
Hide file tree
Showing 13 changed files with 66 additions and 36 deletions.
6 changes: 3 additions & 3 deletions lib/LaTeXML/Core/Alignment.pm
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ use LaTeXML::Common::XML;
use LaTeXML::Common::Dimension;
use LaTeXML::Core::Alignment::Template;
use List::Util qw(max sum);
use base qw(LaTeXML::Core::Whatsit);
use base qw(Exporter);
use base qw(LaTeXML::Core::Whatsit);
use base qw(Exporter);
our @EXPORT = (qw(
&ReadAlignmentTemplate &MatrixTemplate));

Expand Down Expand Up @@ -1407,7 +1407,7 @@ sub summarize_alignment {

__END__
=pod
=pod
=head1 NAME
Expand Down
1 change: 1 addition & 0 deletions lib/LaTeXML/Core/Definition/Constructor.pm
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ sub getNumArgs {
# Digest the constructor; This should occur in the Stomach to create a Whatsit.
# The whatsit which will be further processed to create the document.
sub invoke {
no warnings 'recursion';
my ($self, $stomach) = @_;
# Call any `Before' code.
my $_tracing = $STATE->lookupValue('TRACING') || 0;
Expand Down
2 changes: 1 addition & 1 deletion lib/LaTeXML/Core/Parameter.pm
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ sub read {
# Hmmm, seem to still need it...
if ($$self{semiverbatim}) { # Open coded setupCatcodes
$STATE->beginSemiverbatim(@{ $$self{semiverbatim} }); }

no warnings 'recursion';
my $value = &{ $$self{reader} }($gullet, @{ $$self{extra} || [] });
$value = $value->neutralize(@{ $$self{semiverbatim} }) if $$self{semiverbatim} && (ref $value)
&& $value->can('neutralize');
Expand Down
3 changes: 3 additions & 0 deletions lib/LaTeXML/Core/Parameters.pm
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ sub revertArguments {
return @tokens; }

sub readArguments {
no warnings 'recursion';
my ($self, $gullet, $fordefn) = @_;
my @args = ();
my ($p, $v);
return map { $p = $_; $v = $p && $p->read($gullet, $fordefn); ($$p{novalue} ? () : $v); } @$self; }

sub readArgumentsAndDigest {
no warnings 'recursion';
my ($self, $stomach, $fordefn) = @_;
my @args = ();
my $gullet = $stomach->getGullet;
Expand All @@ -77,6 +79,7 @@ sub reparseArgument {
my ($self, $gullet, $tokens) = @_;
if (defined $tokens) {
return $gullet->readingFromMouth(LaTeXML::Core::Mouth->new(), sub { # start with empty mouth
no warnings 'recursion';
my ($gulletx) = @_;
$gulletx->unread($tokens); # but put back tokens to be read
my @values = $self->readArguments($gulletx);
Expand Down
6 changes: 5 additions & 1 deletion lib/LaTeXML/MathParser.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1008,7 +1008,11 @@ sub is_genuinely_unparsed {
if (!$node->getAttribute('idref')) {
return 1; }
else {
return is_genuinely_unparsed(realizeXMNode($node), $document); } }
my $real_node = realizeXMNode($node);
# Note that some parses fail with an ARRAY ref [ltx:Error,...]
# so realizeXMNode may fail!
return 1 if (ref $real_node) !~ /^XML::LibXML/;
return is_genuinely_unparsed($real_node, $document); } }
elsif ($tag eq 'ltx:XMDual') {
my ($content, $presentation) = element_nodes($node);
return is_genuinely_unparsed($content, $document); }
Expand Down
4 changes: 2 additions & 2 deletions lib/LaTeXML/Package/LaTeX.pool.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -4919,8 +4919,8 @@ EOL

Let('\lx@parboxnewline', '\lx@newline'); # Obsolete, but in case still used
# NOTE: There are 2 extra arguments (See LaTeX Companion, p.866)
# for height and inner-pos. We're ignoring them, for now, though.
DefConstructor('\parbox[] OptionalUndigested OptionalUndigested {Dimension} VBoxContents', sub {
# for height and inner-pos. We're ignoring inner-pos, for now, though.
DefConstructor('\parbox[] [Dimension] OptionalUndigested {Dimension} VBoxContents', sub {
my ($document, $attachment, $b, $c, $width, $body, %props) = @_;
insertBlock($document, $body,
width => $width,
Expand Down
8 changes: 5 additions & 3 deletions lib/LaTeXML/Package/TeX.pool.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ DefParameterType('BalancedParen', sub {
# in order to correctly deal with catcodes.
# BEWARE: This is NOT a shorthand for a simple digested {}!
DefParameterType('Digested', sub {
no warnings 'recursion';
my ($gullet) = @_;
$gullet->skipSpaces;
my $ismath = $STATE->lookupValue('IN_MATH');
Expand Down Expand Up @@ -4443,11 +4444,12 @@ DefPrimitiveI(T_SUB, undef, sub { scriptHandler($_[0], 'SUBSCRIPT'); });
# at the least they're ugly; in some applications they affect "round trip" processing.
# OTOH, direct use of \@@POSTSUPERSCRIPT, etal, MAY need to have extra braces around them.
# So, when reverting, we're going to a bit of extra trouble to make sure we have ONE set
# of braces, but no extras!! [Worry about lists of lists...]
# of braces, but no extras!!
sub revertScript {
my ($script) = @_;
my @tokens = $script->revert;
my @t = @tokens;
# We need to handle lists of lists, see arXiv:2210.11051
my @tokens = Tokens($script->revert)->unlist;
my @t = @tokens;
my $l;
if ($t[0]->defined_as(T_BEGIN)) {
$l++; shift(@t); }
Expand Down
3 changes: 2 additions & 1 deletion lib/LaTeXML/Package/import.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ use LaTeXML::Util::Pathname;
DefPrimitive('\lx@set@path OptionalMatch:* {}', sub {
my ($stomach, $star, $path) = @_;
$path = ToString(Expand($path));
if (!pathname_is_absolute($path)) {
$path = pathname_absolute($path, LookupValue('SOURCEDIRECTORY')); }
if ($star) { # * omits TEXINPUTS!
AssignValue(SEARCHPATHS => [pathname_canonical($path)]); }
else {
Expand All @@ -46,4 +48,3 @@ Let('\subinputfrom', '\subimport');

#======================================================================
1;

2 changes: 1 addition & 1 deletion lib/LaTeXML/Package/lipsum.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ use strict;
use warnings;
use LaTeXML::Package;

LoadPool('expl3');
RequirePackage('xparse');
InputDefinitions('lipsum', type => 'sty', noltxml => 1);
1;
12 changes: 5 additions & 7 deletions lib/LaTeXML/Package/listings.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -1286,13 +1286,11 @@ sub lstProcess {
grep { $$delimiters{$_}{escape} } sort keys %$delimiters);
local $LaTeXML::QUOTED_RE = "\\\\\\\\"; # start w/ backslashed backslash?
local $LaTeXML::SPACE = (lstGetBoolean('showspaces') ? T_CS('\@lst@visible@space') : T_CS(" "));
local $LaTeXML::CASE_SENSITIVE = lstGetBoolean('sensitive');
# Don't these need \Q,\E?
# local $LaTeXML::LITERATE_RE = join('|', map { "\\Q" . $$_[0] . "\\E"; } @$literate);
local $LaTeXML::LITERATE_RE = join('|', map { $$_[0]; } @$literate);
local $LaTeXML::LITERATE_INNER_RE = join('|', map { $$_[0]; } grep { !$$_[2]; } @$literate);
if (!$LaTeXML::CASE_SENSITIVE) { # Clunky, inefficient, but until we know, we don't know
foreach my $word (keys %$words) { # Modify in place (they'll get rebuilt if/when needed)
local $LaTeXML::CASE_SENSITIVE = lstGetBoolean('sensitive');
local $LaTeXML::LITERATE_RE = join('|', map { quotemeta($$_[0]); } @$literate);
local $LaTeXML::LITERATE_INNER_RE = join('|', map { quotemeta($$_[0]); } grep { !$$_[2]; } @$literate);
if (!$LaTeXML::CASE_SENSITIVE) { # Clunky, inefficient, but until we know, we don't know
foreach my $word (keys %$words) { # Modify in place (they'll get rebuilt if/when needed)
$$words{ uc($word) } = $$words{$word}; } }

# === Start processing
Expand Down
15 changes: 13 additions & 2 deletions lib/LaTeXML/Package/multirow.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,22 @@ use warnings;
use LaTeXML::Package;

DefPrimitive('\multirowsetup', undef);
DefPrimitive('\multirow[]{Number}[Number]{}[Dimension]{}', sub {
DefPrimitive('\multirow[]{Float}[Number]{}[Dimension]{}', sub {
my ($stomach, $attachment, $nrows, $bigstruts, $width, $fixup, $content) = @_;
if (my $alignment = LookupValue('Alignment')) {
my $colspec = $alignment->currentColumn;
$$colspec{rowspan} = $nrows->valueOf;
my $rowspan = $nrows->valueOf;
if ($rowspan < 0) {
# Example from arXiv:2210.15835
# \multirow{-8.2}{*}{\includegraphics[width=0.398\linewidth]{figures/NoPredict0msDelayRef}}
Warn("unsupported", "multirow", $stomach,
"Negative row sizes for \\multirow are not yet supported.");
$rowspan = 1; }
elsif ($rowspan != int($rowspan)) {
Warn("unsupported", "multirow", $stomach,
"Fractional row sizes for \\multirow are not yet supported.");
$rowspan = int($rowspan); }
$$colspec{rowspan} = $rowspan;
$$colspec{vattach} = translateAttachment($attachment) if $attachment;
}
Digest(Tokens(T_CS('\hbox'), T_BEGIN, T_CS('\multirowsetup'), $content->unlist, T_END)); });
Expand Down
30 changes: 16 additions & 14 deletions lib/LaTeXML/Package/ulem.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,22 @@ use LaTeXML::Package;
RequireResource('ltx-ulem.css');

#======================================================================
DefConstructor('\uline{}',
"<ltx:text class='ltx_ulem_uline'>#1</ltx:text>");
DefConstructor('\uuline{}',
"<ltx:text class='ltx_ulem_uuline'>#1</ltx:text>");
DefConstructor('\uwave{}',
"<ltx:text class='ltx_ulem_uwave'>#1</ltx:text>");
DefConstructor('\sout{}',
"<ltx:text class='ltx_ulem_sout'>#1</ltx:text>");
DefConstructor('\xout{}',
"<ltx:text class='ltx_ulem_xout'>#1</ltx:text>");
DefConstructor('\dashuline{}',
"<ltx:text class='ltx_ulem_dashuline'>#1</ltx:text>");
DefConstructor('\dotuline{}',
"<ltx:text class='ltx_ulem_dotuline'>#1</ltx:text>");
# TODO: We still need to propagate the XMWrap class to the inner argument,
# not yet implemented in MathParser?
DefConstructor('\uline{}', "?#isMath(<ltx:XMWrap class='ltx_ulem_uline'>#1</ltx:XMWrap>)"
. "(<ltx:text class='ltx_ulem_uline'>#1</ltx:text>)");
DefConstructor('\uuline{}', "?#isMath(<ltx:XMWrap class='ltx_ulem_uuline'>#1</ltx:XMWrap>)"
. "(<ltx:text class='ltx_ulem_uuline'>#1</ltx:text>)");
DefConstructor('\uwave{}', "?#isMath(<ltx:XMWrap class='ltx_ulem_uwave'>#1</ltx:XMWrap>)"
. "(<ltx:text class='ltx_ulem_uwave'>#1</ltx:text>)");
DefConstructor('\sout{}', "?#isMath(<ltx:XMWrap class='ltx_ulem_sout'>#1</ltx:XMWrap>)"
. "(<ltx:text class='ltx_ulem_sout'>#1</ltx:text>)");
DefConstructor('\xout{}', "?#isMath(<ltx:XMWrap class='ltx_ulem_xout'>#1</ltx:XMWrap>)"
. "(<ltx:text class='ltx_ulem_xout'>#1</ltx:text>)");
DefConstructor('\dashuline{}', "?#isMath(<ltx:XMWrap class='ltx_ulem_dashuline'>#1</ltx:XMWrap>)"
. "(<ltx:text class='ltx_ulem_dashuline'>#1</ltx:text>)");
DefConstructor('\dotuline{}', "?#isMath(<ltx:XMWrap class='ltx_ulem_dotuline'>#1</ltx:XMWrap>)"
. "(<ltx:text class='ltx_ulem_dotuline'>#1</ltx:text>)");

DefMacro('\normalem', '');
#======================================================================
Expand Down
10 changes: 9 additions & 1 deletion lib/LaTeXML/Package/xy.tex.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,15 @@ DefMacro('\xyoption{}', sub {
elsif ($xy_unsupported{$option}) {
Warn('xy', 'unsupported', $gullet,
"The xy extension/feature $option_s may not be supported"); }
return Tokens(T_CS('\lx@xy@xyoption@orig'), T_BEGIN, $option, T_END); });
my $cache_key = "loaded_xyoption_$option_s";
if (LookupValue($cache_key)) {
Info('xy', 'ignored', "xyoption $option_s was requested twice, not reloading");
return ();
} else {
Note("loading xyoption $option_s.");
AssignValue($cache_key, 1, 'global');
return Tokens(T_CS('\lx@xy@xyoption@orig'), T_BEGIN, $option, T_END); }
}, locked => 1);

# Redefine so we get more tracable/debugable info
DefPrimitive('\xywarning@{}', sub { Info('xy', 'warning', $_[0], ToString($_[1])); });
Expand Down

0 comments on commit 5fd5c5b

Please sign in to comment.