Skip to content

Commit

Permalink
More optimization (#2149)
Browse files Browse the repository at this point in the history
* For Core processing objects, avoid OOPS method dispatch internally for non-polymorphic methods

* Guarantee that expandables (Expandable,Conditional) invoke always returns Tokens; take advantage of that in Gullet; uniform use of isExpandable method, not property

* Fix bad definition of \pdfname,\pdftrailer

* slightly more efficient (if slightly awkward) parsing of numbers, dimensions, etc

* New ->equivalent() tests whether  is equal or \let to  (more efficient than Equals when appropriate); Use it in tight loops in Gullet and TeX.pool; move optimized CSName parsing to ->readCSName; faster \expandafter accomodates chains of \expandafter

* Introduce a Deprecated warning for obsolete functions; Deprecate readInternal(Integer|Dimension|Glue|MuGlue)

* Define (and use) ->defined_as(), rather than ->equivalent()

* Whoops, getting ahead of myself

* SHEESH
  • Loading branch information
brucemiller authored Jul 13, 2023
1 parent 4757b39 commit 43610f7
Show file tree
Hide file tree
Showing 13 changed files with 663 additions and 598 deletions.
9 changes: 8 additions & 1 deletion lib/LaTeXML/Common/Error.pm
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ our @EXPORT = (
# Progress Spinner
qw(&ProgressSpinup &ProgressSpindown &ProgressStep),
# Debugging messages
qw(&DebuggableFeature &Debug &CheckDebuggable),
qw(&DebuggableFeature &Debug &CheckDebuggable &Deprecated),
# Colored-logging related functions
qw(&colorizeString),
# stateless message generation
Expand Down Expand Up @@ -486,6 +486,13 @@ sub CheckDebuggable {
print STDERR _freshline(\*STDERR), "Known debugging features: " . join(', ', sort keys %LaTeXML::Debuggable) . "\n"; }
return; }

sub Deprecated {
my ($key, $version, $message) = @_;
return if $STATE && $STATE->lookupMapping('DEPRECATIONS_WARNED', $key);
Warn('deprecated', $key, undef, "$key is deprecated (as of $version)", $message);
$STATE->assignMapping('DEPRECATIONS_WARNED', $key => 1) if $STATE;
return; }

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Handlers for perl's die & warn
# We'll try to decode some common errors to make them more usable
Expand Down
17 changes: 10 additions & 7 deletions lib/LaTeXML/Core/Definition/Conditional.pm
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@ sub new {
my ($class, $cs, $parameters, $test, %traits) = @_;
my $source = $STATE->getStomach->getGullet->getMouth;
return bless { cs => $cs, parameters => $parameters, test => $test,
locator => $source->getLocator,
isExpandable => 1,
locator => $source->getLocator,
%traits }, $class; }

sub isExpandable {
return 1; }

sub getTest {
my ($self) = @_;
return $$self{test}; }

# This MUST return Tokens() or undef. (NOT a Token)
sub invoke {
my ($self, $gullet) = @_;
# A real conditional must have condition_type set
Expand Down Expand Up @@ -132,17 +135,17 @@ sub skipConditionalBody {
shift(@$stack); } # then DO pop that conditional's frame; it's DONE!
elsif (!--$level) { # If no more nesting, we're done.
shift(@$stack); # Done with this frame
return $t; } } # AND Return the finishing token.
return TokensI($t); } } # AND Return the finishing token.
elsif ($level > 1) { } # Ignore \else,\or nested in the body.
elsif (($cond_type eq 'or') && (++$n_ors == $nskips)) {
return $t; }
return TokensI($t); }
elsif (($cond_type eq 'else') && $nskips
# Found \else and we're looking for one?
# Make sure this \else is NOT for a nested \if that is part of the test clause!
&& ($$stack[0] eq $LaTeXML::IFFRAME)) {
# No need to actually call elseHandler, but note that we've seen an \else!
$$stack[0]{elses} = 1;
return $t; } } # } #}
return TokensI($t); } } # } #}
Error('expected', '\fi', $gullet, "Missing \\fi or \\else, conditional fell off end",
"Conditional started at " . ToString($start));
return; }
Expand All @@ -156,7 +159,7 @@ sub invoke_else {
. " since we seem not to be in a conditional");
return; }
elsif ($$stack[0]{parsing}) { # Defer expanding the \else if we're still parsing the test
return Tokens(T_CS('\relax'), $LaTeXML::CURRENT_TOKEN); }
return TokensI(T_CS('\relax'), $LaTeXML::CURRENT_TOKEN); }
elsif ($$stack[0]{elses}) { # Already seen an \else's at this level?
Error('unexpected', $LaTeXML::CURRENT_TOKEN, $gullet,
"Extra " . Stringify($LaTeXML::CURRENT_TOKEN),
Expand All @@ -180,7 +183,7 @@ sub invoke_fi {
. " since we seem not to be in a conditional");
return; }
elsif ($$stack[0]{parsing}) { # Defer expanding the \else if we're still parsing the test
return Tokens(T_CS('\relax'), $LaTeXML::CURRENT_TOKEN); }
return TokensI(T_CS('\relax'), $LaTeXML::CURRENT_TOKEN); }
else { # "expand" by removing the stack entry for this level
local $LaTeXML::IFFRAME = $$stack[0];
$STATE->shiftValue('if_stack'); # Done with this frame
Expand Down
47 changes: 28 additions & 19 deletions lib/LaTeXML/Core/Definition/Expandable.pm
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,27 @@ use base qw(LaTeXML::Core::Definition);

sub new {
my ($class, $cs, $parameters, $expansion, %traits) = @_;
$expansion = Tokens($expansion) if ref $expansion eq 'LaTeXML::Core::Token';
my $source = $STATE->getStomach->getGullet->getMouth;
if (ref $expansion eq 'LaTeXML::Core::Tokens') {
my $type = ref $expansion;
# expansion must end up Tokens or CODE
if (!$type) {
$expansion = TokenizeInternal($expansion)->packParameters; }
elsif ($type eq 'LaTeXML::Core::Token') {
$expansion = TokensI($expansion); }
elsif ($type eq 'LaTeXML::Core::Tokens') {
Fatal('misdefined', $cs, $source, "Expansion of '" . ToString($cs) . "' has unbalanced {}",
"Expansion is " . ToString($expansion)) unless $expansion->isBalanced;
$expansion = $expansion->packParameters unless $traits{nopackParameters}; }
elsif (!ref $expansion) {
$expansion = TokenizeInternal($expansion)->packParameters; }

elsif ($type ne 'CODE') {
Error('misdefined', $cs, $source,
"Expansion of '" . ToString($cs) . "' cannot be of type '$type'");
$expansion = TokensI(); }
return bless { cs => $cs, parameters => $parameters, expansion => $expansion,
locator => $source->getLocator,
isProtected => $traits{protected} || $STATE->getPrefix('protected'),
isOuter => $traits{outer} || $STATE->getPrefix('outer'),
isLong => $traits{long} || $STATE->getPrefix('long'),
isExpandable => 1,
locator => $source->getLocator,
isProtected => $traits{protected} || $STATE->getPrefix('protected'),
isOuter => $traits{outer} || $STATE->getPrefix('outer'),
isLong => $traits{long} || $STATE->getPrefix('long'),
hasCCARG => (($type ne 'CODE') && (grep { $$_[1] == CC_ARG; } $expansion->unlist) ? 1 : 0),
%traits }, $class; }

sub isExpandable {
Expand All @@ -49,6 +55,7 @@ sub getExpansion {
return $$self{expansion}; }

# Expand the expandable control sequence. This should be carried out by the Gullet.
# This MUST return Tokens() or undef. (NOT a Token)
sub invoke {
no warnings 'recursion';
my ($self, $gullet, $onceonly) = @_;
Expand Down Expand Up @@ -80,20 +87,22 @@ sub invoke {
Error('recursion', $$self{cs}, $gullet,
"Token " . Stringify($$self{cs}) . " expands into itself!",
"defining as empty");
$expansion = Tokens(); } }
$expansion = TokensI(); } }
$result = $expansion; }
else {
my @args = $parms->readArguments($gullet, $self);
# for "real" macros, make sure all args are Tokens
my $r;
my @targs = map { ($_ && ($r = ref $_)
&& (($r eq 'LaTeXML::Core::Token') || ($r eq 'LaTeXML::Core::Tokens'))
? $_ : Tokens(Revert($_))); } @args;
if ($$self{hasCCARG}) { # Do we actually need to substitute the args in?
my $r; # Make sure they are actually Tokens!
@args = map { ($_ && ($r = ref $_)
&& (($r eq 'LaTeXML::Core::Token') || ($r eq 'LaTeXML::Core::Tokens'))
? $_ : Tokens(Revert($_))); } @args;
$result = $expansion->substituteParameters(@args); }
else {
$result = $expansion; }
if ($tracing) { # More involved...
Debug($self->tracingCSName . ' ->' . tracetoString($expansion));
Debug($self->tracingArgs(@targs)) if @args; }
$result = $expansion->substituteParameters(@targs); }
# Getting exclusive requires dubious Gullet support!
Debug($self->tracingArgs(@args)) if @args; } }
# Getting exclusive profiling requires dubious Gullet support!
$result = Tokens($result, T_MARKER($profiled)) if $profiled;
return $result; }

Expand Down
Loading

0 comments on commit 43610f7

Please sign in to comment.