Skip to content

Add support for \expandafter, \noexpand, \edef, \let, and \long#2122

Merged
ylemkimon merged 39 commits intomasterfrom
expandafter
Mar 11, 2020
Merged

Add support for \expandafter, \noexpand, \edef, \let, and \long#2122
ylemkimon merged 39 commits intomasterfrom
expandafter

Conversation

@ylemkimon
Copy link
Member

@ylemkimon ylemkimon commented Oct 12, 2019

I'm surprised that they are fairly simple to implement! Fixes #1413.

@codecov-io
Copy link

codecov-io commented Oct 12, 2019

Codecov Report

Merging #2122 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #2122   +/-   ##
=======================================
  Coverage   94.77%   94.77%           
=======================================
  Files          83       83           
  Lines        5358     5358           
  Branches      939      939           
=======================================
  Hits         5078     5078           
  Misses        257      257           
  Partials       23       23
Flag Coverage Δ
#screenshotter 88.45% <ø> (ø) ⬆️
#test 88.55% <ø> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7eb2815...c0307bc. Read the comment docs.

@ylemkimon ylemkimon changed the title Add support for \expandafter Add support for \expandafter, \noexpand, and \edef Oct 12, 2019
@ylemkimon ylemkimon changed the title Add support for \expandafter, \noexpand, and \edef Add support for \expandafter, \noexpand, \edef, and \long Oct 12, 2019
@ylemkimon ylemkimon changed the title Add support for \expandafter, \noexpand, \edef, and \long Add support for \expandafter, \noexpand, \edef, \let, and \long Oct 13, 2019
@ylemkimon ylemkimon changed the title Add support for \expandafter, \noexpand, \edef, \let, and \long [WIP]Add support for \expandafter, \noexpand, \edef, \let, and \long Oct 14, 2019
@ylemkimon ylemkimon changed the title [WIP]Add support for \expandafter, \noexpand, \edef, \let, and \long Add support for \expandafter, \noexpand, \edef, \let, and \long Oct 19, 2019
@ylemkimon
Copy link
Member Author

This is ready for review.

@k4b7
Copy link
Member

k4b7 commented Dec 2, 2019

Since this depends on #2138, maybe set the base of this PR to be internal instead of `master.

Copy link
Member

@k4b7 k4b7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. I'm familiar with these commands so most of my comments are questions. 😅 It would be good to have someone with more LaTeX knowledge review if possible. I do think that introducing some named constants for the different noexpand values would improve readability.

`\gdef` and `\global\def` macros will persist between math expressions.
`\gdef`, `\xdef`, `\global\def`, `\global\edef`, `\global\let`, and `\global\futurelet` will persist between math expressions.

KaTeX has no `\par`, so all macros are long by default and `\long` will be ignored.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL about \long and \par.

src/Token.js Outdated
Comment on lines +23 to +26
export class Token {
text: string;
loc: ?SourceLocation;
noexpand: ?number; /* 1: treat as \relax, 2: pass to the parser */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having constants for these would make the code clearer.

Comment on lines +52 to +55
// <assignment> -> <non-macro assignment>|<macro assignment>
// <non-macro assignment> -> <simple assignment>|\global<non-macro assignment>
// <macro assignment> -> <definition>|<prefix><macro assignment>
// <prefix> -> \global|\long|\outer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this mean?

Copy link
Member Author

@ylemkimon ylemkimon Feb 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the (formal) grammar of TeX from the TeXbook

Comment on lines +58 to +61
names: [
"\\global", "\\long",
"\\\\globallong", // can’t be entered directly
],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are \global and \long grouped together?

Copy link
Member Author

@ylemkimon ylemkimon Feb 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They work in the same manner as a prefix to the macro assignment.

Comment on lines +40 to +41
// if macro is undefined at this moment, set noexpand to 2
// and unexpandable to not expand it later and pass to the parser
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to handle a case like \let\foo=\bar \def\bar{hello, world} \foo where the value of the let is defined after the let?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to handle cases where non-macros are overwritten after \let, e.g., \let\foo=\frac \def\frac{123} \foo12.

Comment on lines +2988 to +2989
expect`\noexpand\foo y`.toParseLike("y",
new Settings({macros: {"\\foo": "x"}}));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the \foo is ignored in this case. Is that correct?

Comment on lines +3179 to +3182
expect`\def\foo{a}\xdef\bar{\foo}\def\foo{}\bar`.toParseLike`a`;
expect`\def\foo{a}\xdef\bar{\def\noexpand\foo{}}\foo\bar\foo`.toParseLike`a`;
expect`\def\foo{a}\xdef\bar{\expandafter\foo\noexpand\foo}\def\foo{b}\bar`
.toParseLike`ab`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the first one, but the second two are a bit mind warping.

Comment on lines +3211 to +3212
expect`\global\global\def\foo{}\foo`.toParseLike``;
expect`\global\long\def\foo{}\foo`.toParseLike``;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like multiple global/long commands in a row are the same as having a single one of those commands, is that right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Comment on lines +3266 to +3269
expect`\let\foo=\frac\def\frac{}\foo12`.toParseLike`\frac12`;
expect`\def\foo{1}\let\bar\foo\def\foo{2}\bar`.toParseLike`1`;
expect`\let\foo=\kern\edef\bar{\foo1em}\let\kern=\relax\bar`.toParseLike`\kern1em`;
expect`\let\foo{\frac\foo1}{2}`.toParseLike`\frac{1}{2}`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize the = was optional when using \let. In the first one it looks like \frac is being redefined, but the result doesn't include this redefinition. I think it would be useful to have comments for some of these tests to help people that aren't as familiar with the interections between let and def.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add comments on test cases.

Comment on lines +580 to +581
"input": "\\\\def\\\\bold{\\\\bgroup\\\\bf\\\\let\\\\next= }\\\\bold{a}",
"lastIndex": 40
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's nice seeing the input here. It makes reviewing snapshot tests easier.

Copy link
Member

@k4b7 k4b7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The comments were very helpful. Thank you!

Comment on lines +26 to +27
noexpand: ?boolean; // don't expand the token
treatAsRelax: ?boolean; // used in \noexpand
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is any combination of these valid?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible in theory, but there is no use yet.

@ylemkimon ylemkimon merged commit 9917d1c into master Mar 11, 2020
@ylemkimon ylemkimon deleted the expandafter branch July 11, 2020 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

support \let

3 participants