> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/latex/pl/artykuly-szczegolowe/09-an-introduction-to-luatex-part-2-understanding-directlua.md).

# Wprowadzenie do LuaTeX (część 2): zrozumieć \directlua

## Celem tego artykułu

W pierwszej części tego artykułu, [Wprowadzenie do LuaTeX-a (część 1): Czym jest — i co sprawia, że jest tak inny?](/latex/pl/artykuly-szczegolowe/07-an-introduction-to-luatex-part-1-what-is-it-and-what-makes-it-so-different.md), pokrótce omówiliśmy LuaTeX jako niezwykle wszechstronny silnik TeX-a: zaawansowany, programowalny system składu, który oferuje szeroki zakres narzędzi do tworzenia rozwiązań inżynierii dokumentów i produkcji.

W tym końcowym odcinku przyjrzymy się z bliska najważniejszemu elementowi zestawu narzędzi LuaTeX-a: `\directlua` poleceniu, które stanowi „bramę” do programistycznej kontroli składu LuaTeX-a za pomocą języka skryptowego Lua.

Jednak pełne wykorzystanie LuaTeX-a za pomocą `\directlua` wymaga pewnej wiedzy wstępnej na temat kilku zagadnień TeX-a: tokenów TeX-a, list tokenów oraz mechanizmu rozwijania. Celem tego artykułu jest zbadanie i wyjaśnienie tych podstawowych pojęć TeX-a: zestawienie procesów związanych z TeX-em stojących za `\directlua` aby zrozumieć, jak to działa, i stworzyć podstawy do budowania własnych rozwiązań składu z użyciem LuaTeX-a.

Niniejszy artykuł zawiera liczne krótkie przykłady, aby zilustrować i wyjaśnić kluczowe aspekty `\directlua`jego zachowania, celowo unikając nadmiernie złożonego kodu na rzecz krótkich fragmentów kodu. W razie potrzeby przykłady używają podstawowego (surowego/czystego) TeX-a — choć większość osób używa i preferuje LaTeX (makra), podstawowe polecenia TeX-a mają tę zaletę, że są proste.

## Wprowadzenie do Lua w LuaTeX-ie

[Lua](https://www.lua.org/about.html) to język skryptowy, którego [kod źródłowy](https://www.lua.org/download.html) jest wysoce przenośny i łatwy do osadzenia w aplikacjach programowych, umożliwiając twórcom wprowadzanie możliwości skryptowych do swoich programów. Lua został osadzony w [wielu aplikacjach](https://en.wikipedia.org/wiki/List_of_applications_using_Lua) i jest popularnym wyborem w branży gier komputerowych — być może najsłynniejszym przykładem jest [World of Warcraft](https://wowwiki.fandom.com/wiki/Lua_functions).

LuaTeX, jak sama nazwa wskazuje, jest silnikiem TeX-a, który osadza język skryptowy Lua, dając użytkownikom możliwość sterowania zachowaniem składu LuaTeX-a poprzez umieszczanie w dokumentach programów Lua (skryptów). Oprócz bezpośredniej kontroli LuaTeX-a użytkownicy mogą wykorzystywać Lua wyłącznie jako bardzo wydajny język programowania do wykonywania zadań, które mogłyby być niezwykle trudne do osiągnięcia za pomocą języka TeX — który, uczciwie mówiąc, jest wyzwaniem do nauczenia się i opanowania. Dzięki dodaniu i integracji Lua LuaTeX staje się bardzo wszechstronnym i potężnym silnikiem TeX-a, który bezpośrednio obsługuje dwa języki programowania.

### Używanie Lua i TeX-a w dokumencie: wprowadź \directlua

Lua i TeX to dwa *bardzo różne* języki programowania: Lua jest znacznie bliższy temu, co większość ludzi uważa za język programowania, ale TeX, ze swoimi kodami kategorii, tokenami, makrami i mechanizmem rozwijania, jest bardzo odległy od doświadczeń/oczekiwań większości ludzi dotyczących języka, w którym pisze się programy. Jednak, jak pokazała historia, język TeX przetrwał, ponieważ dobrze sprawdza się w tym, do czego został zaprojektowany: sterowaniu składem, nawet jeśli jego sposób działania jest nieco tajemniczy.

Aby sprostać wyzwaniu mieszania języków Lua i TeX w jednym dokumencie TeX-a, twórcy LuaTeX-a wprowadzili nowe polecenie o nazwie `\directlua` które jest drogą do korzystania z Lua — zarówno jako samodzielnego języka programowania, jak i do sterowania zachowaniem składu LuaTeX-a.

Ta `\directlua` polecenie pozwala użytkownikom osadzać kod Lua w ich dokumentach TeX; ten kod jest następnie przekazywany do wbudowanego interpretatora języka Lua w LuaTeX. Jednakże, `\directlua` umożliwia również *łączyć* kod Lua i (La)TeX razem, w tym samym `\directlua` poleceniu — choć wprowadza to dodatkowe komplikacje wynikające z fundamentalnych różnic między językami programowania opartymi na Lua i TeX. Kluczowym wyzwaniem przy używaniu połączenia kodu (La)TeX i Lua jest zapewnienie, że te dwa języki współistnieją pokojowo i nie wchodzą sobie „w drogę”.

`\directlua` najlepiej nadaje się do użycia z krótszymi fragmentami kodu Lua w dokumencie, ale w razie potrzeby można go używać także z bardziej rozbudowanymi programami Lua. Zazwyczaj bardziej obszerne programy Lua oraz biblioteki kodu Lua są zapisywane w plikach zewnętrznych, które można wczytywać, używając funkcji Lua `dofile()` funkcji w ramach `\directlua` polecenia. Z punktu widzenia przetwarzania TeX-a istotną zaletą używania zewnętrznych plików z kodem Lua jest uniknięcie komplikacji wynikających z mechanizmu kodów kategorii TeX-a — zagadnienia w pełni omówionego w tym artykule.

### Bardziej formalny opis \directlua

Ta [Podręcznik referencyjny LuaTeX](http://www.pragma-ade.com/general/manuals/luatex.pdf) opisuje `\directlua` następująco (nieco zmodyfikowane):

> Aby połączyć kod Lua z wejściem TeX, potrzebnych jest kilka nowych prymitywów. Prymityw `\directlua` służy do natychmiastowego wykonywania kodu Lua. Podstawowa składnia to `\directlua{⟨code⟩}`. Pakiet `⟨code⟩` jest rozwijany w całości, a następnie przekazywany do interpretera Lua. Po odczytaniu i zastosowaniu rozwijania do `⟨code⟩`, wynikowa lista tokenów jest konwertowana na ciąg znaków tak, jakby została wyświetlona za pomocą `\the\toks`.

Oczywiście jest to technicznie poprawne, ale być może nie tak łatwe do zrozumienia bez pewnej wiedzy o niższego poziomu procesach TeX-a — takich jak tokeny i rozwijanie.

## Zrozumienie \directlua: Jakie tematy omówimy?

W tym artykule przyjrzymy się bliżej kilku kluczowym zagadnieniom wprowadzającym i przedstawimy szereg przykładów mających pokazać, jak `\directlua` działa i gdzie (lub dlaczego) trzeba zachować ostrożność, łącząc TeX i Lua w swoim `⟨code⟩`.

Omówimy następujące zagadnienia na tyle szczegółowo, aby stworzyć podstawy do zrozumienia `\directlua` i jego „wstępnego przetwarzania” kodu używanego w jego obrębie:

* kody kategorii i tokeny TeX-a: konwertowanie tekstu na tokeny i tokenów na tekst;
* proces rozwijania TeX-a (i zapobieganie rozwijaniu);
* sekwencje ucieczki/mechanizmy Lua dla znaków i ciągów znaków;
* używanie komentarzy w stylu Lua;
* krótkie wprowadzenie do API Lua w LuaTeX-ie.

Jeśli rozumiesz, jak silniki TeX-a tworzą i używają tokenów, oraz nabierzesz świadomości mechanizmu rozwijania TeX-a, będziesz mieć podstawy niezbędne do odblokowania niezwykłej wszechstronności `\directlua` polecenie.

## Podstawy: od tekstu do tokenów i od tokenów do tekstu

Overleaf opublikował kilka artykułów dogłębnie omawiających tokeny TeX-a i powiązane pojęcia, więc nie będziemy tu powtarzać całego tego materiału; zamiast tego zarysujemy te obszary/zagadnienia istotne dla rozwijania lepszego zrozumienia `\directlua`.

Oto lista wcześniej opublikowanych artykułów, które mogą być interesujące:

* [Czym jest token TeX-a?](/latex/pl/artykuly-szczegolowe/53-what-is-a-tex-token.md)
* [Czym jest lista tokenów TeX-a?](/latex/pl/artykuly-szczegolowe/54-what-is-a-tex-token-list.md)
* [Jak działa \expandafter: Wprowadzenie do tokenów TeX-a](/latex/pl/artykuly-szczegolowe/19-how-does-expandafter-work-an-introduction-to-tex-tokens.md)
* [Sześcioodcinkowa seria: Jak naprawdę działają makra TeX-a?](/latex/pl/wiecej-tematow/01-a-six-part-series-how-do-tex-macros-actually-work.md)

### Zrozumienie tokenów znaków

Każdy znak, który silnik TeX-a może odczytać z pliku tekstowego, jest reprezentowany przez dwie wartości liczbowe:

* jego *kod znaku* (wartość ASCII lub dziś punkt kodowy Unicode);
* druga, z perspektywy TeX-a, wartość zwana jego *kodem kategorii*.

Czytelnicy, którzy chcieliby dowiedzieć się więcej o kodach kategorii, mogą być zainteresowani przeczytaniem tego wprowadzenia opublikowanego przez Overleaf: [Więc od czego zaczynamy? Od kodów kategorii](/latex/pl/wiecej-tematow/19-how-tex-macros-actually-work-part-1.md#so2c-where-do-we-start3f-with-category-codes).

Na przykład, jeśli silnik TeX-a wczytuje znak `Skopiowany` miałby dostęp do dwóch informacji: `Skopiowany`kod znaku (65) oraz jego kod kategorii (zwykle 11). Gdy TeX wczyta ten znak `Skopiowany`, jego kod kategorii nie zostanie zmieniony, ale makra użytkownika mogą wprowadzać zmiany kodu kategorii, które mogą wpłynąć na wszelkie *kolejne* znaku `Skopiowany` które *nie został jeszcze odczytany* przez TeX. W konsekwencji TeX musi zapisać, że *ten* znaku `Skopiowany`, *właśnie odczytany*, ma kod kategorii 11. W tym celu TeX używa pary liczb całkowitych (65,11), aby obliczyć inną wartość całkowitą, którą nazywa *tokenem znaku*. Obliczając tę wartość tokenu, która jest przekazywana do wewnętrznego przetwarzania TeX-a, ten konkretny `Skopiowany` i jego kod kategorii są *powiązane*; w efekcie ten token znaku *enkapsuluje* dane, które TeX musi znać o tym znaku, aby użyć ich w późniejszych działaniach składu głębiej wewnątrz silnika TeX-a.

#### Jak obliczane są tokeny znaków?

Po pierwsze, trzeba pamiętać, że silniki TeX-a używają kodu kategorii 13 do tworzenia tak zwanych *znaków aktywnych*: każdy znak z kodem kategorii 13 zachowuje się jak mini-makro; w konsekwencji, jak zobaczymy poniżej, tokeny dla znaków aktywnych są obliczane inaczej niż dla zwykłych znaków z innymi kodami kategorii, takimi jak 10, 11 lub 12.

Dla *nieaktywne* znaki:

* starsze silniki 8-bitowe (TeX Knutha, e-TeX, pdfTeX) obliczają tokeny znaków dla *nieaktywne* znaków, używając

$$\text{(non-active) character token} = (256 \times \text{category code}) + (\text{ASCII character code})$$

* w przypadku LuaTeX-a, który musi obsługiwać wartości znaków Unicode, obliczenia dla *nieaktywne* znaków są podobne, ale dają znacznie większe wartości całkowite:

$$\text{(non-active) character token} = (2^{21} \times \text{category code}) + (\text{Unicode value})$$

Wracając do wcześniejszego przykładu litery A z kodem kategorii 11, LuaTeX obliczyłby wartość tokenu znaku równą $$2^{21} \times 11 + 65 = 23068737$$. Po obliczeniu ta wartość tokenu znaku *wiąże* ten konkretny znak A z wartością kodu kategorii 11. Makra użytkownika mogą zmienić kod kategorii dla każdego kolejnego znaku A, ale kod kategorii tego znaku został ustalony przez przekształcenie go w token do użycia podczas przechodzenia przez wewnętrzne mechanizmy LuaTeX-a. LuaTeX zachował, czyli enkapsulował, zamierzone znaczenie tego znaku ustalone w chwili jego odczytania.

Silniki TeX-a używają łącznie [16 różnych kodów kategorii](/latex/pl/wiecej-tematow/43-table-of-tex-category-codes.md) i *dowolny* z tych kodów kategorii można przypisać za pomocą `\catcode` polecenia, *dowolny* znaku, który silnik TeX-a jest w stanie odczytać. Zmiany kodów kategorii służą do zmiany sposobu, w jaki silniki TeX-a przetwarzają określone znaki wejściowe, pozwalając użytkownikom TeX-a pisać makra, które generują specjalne rezultaty lub zachowania składu.

**Znaki aktywne**

Jak wspomniano, silniki TeX-a używają kodu kategorii 13, aby przypisać znakowi „specjalne znaczenie”, czyniąc go tak zwanym *znakiem aktywnym* który zachowuje się jak mini-makro: nie jest wymagany żaden wiodący `\` znak, odosobniony znak, ze względu na swój kod kategorii, wystarcza, aby wywołać jego zachowanie podobne do makra.

Ponieważ znak aktywny działa jak mini-makro, nie jest on przekształcany w *tokenem znaku* lecz w drugi (całkowitoliczbowy) typ tokenu zwany *tokenem polecenia*. Są one obliczane następująco:

* w starszych silnikach 8-bitowych (TeX Knutha, e-TeX, pdfTeX) tokeny dla znaków aktywnych są obliczane według:

1. oblicz wartość pośrednią zwaną $$\text{curcs}$$ (**cur**rent **c**ontrol **s**equence) gdzie $$\text{curcs} = \text{character code} + 1$$3. oblicz wartość tokenu polecenia, gdzie $$\text{active character token} = \text{curcs} + \text{4095}$$

* w przypadku LuaTeX-a obliczenia są nieco bardziej złożone, ponieważ musi on obsługiwać pełny zakres znaków Unicode, z których każdy może zostać uaktywniony:

1. oblicz pośrednią wartość całkowitą $$\text{curcs}$$ stosując tak zwaną *funkcję hash* do wartości punktu kodowego Unicode znaku aktywnego wyrażonej w UTF-8: $$\text{curcs}=\texttt{hashfunction}\text{(UTF-8 text for Unicode value of active character)}$$3. oblicz wartość całkowitą tokenu: $$\text{active character token} = \text{curcs} + 2^{29} - 1$$

**Przykłady**

* Silniki 8-bitowe: obliczanie tokenu dla znaku aktywnego `~` (kod znaku 126) daje wynik $$\text{curcs} = 126 + 1 = 127$$, dając wartość tokenu równą $$4095 + 127 = 4222$$.
* LuaTeX: obliczanie tokenu dla znaku aktywnego `~` daje wynik $$\text{curcs}=3186$$ dając wartość tokenu równą $$3186 + 2^{29} - 1 = 536874097$$. Tokeny LuaTeX-a używają znacznie większych wartości całkowitych!

### Zrozumienie tokenów poleceń

Oprócz przetwarzania *pojedynczych* znaków silniki TeX-a mogą oczywiście przetwarzać *sekwencje* znaków zwane *polecenia* (lub, mówiąc dokładniej, *sekwencje sterujące*). Z tradycji `\` znak jest używany do sygnalizowania początku polecenia, ale to jedynie konwencja — w rzeczywistości zamiast niego można użyć dowolnego znaku z kodem kategorii 0 (znak ucieczki).

Silniki TeX-a rozpoznają dwa typy poleceń, znane jako *słowa sterujące* i *symbole sterujące*:

* **słowa sterujące**: polecenia zbudowane z jednego lub większej liczby znaków mających kod kategorii 11;
* **symbole sterujące**: polecenia jednopostaciowe, w których kod kategorii tego znaku *nie jest* 11: takie jak `\$`, `\#` lub `\\`.

**Uwaga**: Prymitywy TeX-a `\chardef`, `\mathchardef`, `\countdef`, `\dimendef`, `\skipdef`, `\muskipdef` i `\toksdef` są również używane do definiowania sekwencji sterujących, jednak w przeciwieństwie do zwykłych definicji makr wynikowe sekwencje sterujące (słowa sterujące lub symbole sterujące) *nie są rozwijalne*— omówimy je bardziej szczegółowo poniżej.

#### Jak obliczane są tokeny poleceń?

Podobnie jak w przypadku znaków aktywnych, silniki TeX-a używają drugiego typu całkowitoliczbowej wartości tokenu do reprezentowania poleceń: *tokeny poleceń*— pamiętajmy, że znaki aktywne również generują tokeny poleceń, ponieważ zachowują się jak mini-makra.

Obliczenia używane przez silniki 8-bitowe do tworzenia liczb całkowitych tokenów poleceń można znaleźć w tym [artykule Overleaf](/latex/pl/artykuly-szczegolowe/19-how-does-expandafter-work-an-introduction-to-tex-tokens.md#how-tex-calculates-token-values). Tutaj podsumujemy kluczowe kroki obliczania tokenów poleceń w LuaTeX-ie — które są nieco inne, ponieważ LuaTeX musi przetwarzać wartości kodów znaków Unicode, które mogą być znacznie większe niż wartości 8-bitowe; jednak obliczenia LuaTeX-a podążają za tymi samymi ogólnymi zasadami, których używały starsze silniki 8-bitowe.

Po wykryciu nadchodzącego polecenia silniki TeX-a, w tym LuaTeX, ignorują wiodący `\` znak: nie jest on używany w obliczeniach wartości tokenu polecenia, lecz jedynie działa jako „przełącznik”, informując silnik TeX-a, że musi przetworzyć polecenie. Wartość tokenu polecenia jest obliczana na podstawie sekwencji (jednego lub większej liczby) znaków obecnych w nazwie polecenia — LuaTeX oblicza tokeny poleceń dla symboli sterujących i słów sterujących za pomocą tego samego algorytmu:

1. oblicz pośrednią wartość całkowitą $$\text{curcs}$$ stosując tak zwaną [funkcję hash](https://en.wikipedia.org/wiki/Hash_function) do łańcucha znaków Unicode UTF-8 zawartego w nazwie polecenia: $$\text{curcs}=\texttt{hashfunction}\text{(Unicode UTF-8 string of characters in command name)}$$3. oblicz wartość tokenu polecenia, gdzie $$\text{command token} = \text{curcs} + 2^{29} - 1$$

**Przykłady**

* dla `\\` polecenia (symbol sterujący), LuaTeX oblicza $$\text{curcs}=94$$, otrzymując wartość tokenu dla `\\` o wartości $$94 + 2^{29} - 1 = 536871005$$.
* dla `\vskip` dla prymitywnego polecenia (słowa sterującego) LuaTeX oblicza $$\text{curcs}=3560$$, otrzymując wartość tokenu dla `\vskip` o wartości $$3560 + 2^{29} -1 = 536874471$$.
* dla zdefiniowanego przez użytkownika makra `\mynewmacro` (słowo sterujące) LuaTeX oblicza $$\text{curcs} = 2971$$, otrzymując wartość tokenu dla `\mynewmacro` o wartości $$2971 + 2^{29} -1 = 536873882$$.

Po utworzeniu tokeny mogą być przechowywane do późniejszego użycia w tak zwanych *listach tokenów* lub mogą być natychmiast przekazane do dalszego przetwarzania wewnątrz silnika TeX-a. Używanie wartości całkowitych do reprezentowania tokenów nie tylko działa na wszystkich typach platform obliczeniowych/systemów operacyjnych, ale jest także bardzo wydajnym sposobem przechowywania/przetwarzania danych przez TeX.

### Jak silnik TeX-a identyfikuje typ tokenu (polecenie lub znak)

Mając daną określoną całkowitą wartość tokenu, $$T$$, silnik TeX-a może łatwo ustalić, czy $$T$$ reprezentuje polecenie czy znak, sprawdzając, czy $$T$$ przekracza pewną $$\text{threshold value}$$— to $$\text{threshold value}$$ zależy od silnika TeX-a. Jeśli $$T \geq \text{threshold value}$$ to $$T$$ jest tokenem polecenia, w przeciwnym razie $$T$$ jest tokenem znaku. Wartość graniczna $$\text{threshold value}$$ to $$4095$$ dla silników 8-bitowych oraz $$2^{29}-1$$ (536 870 911) dla LuaTeX-a. Knuth zaprojektował metody używane we wzorach obliczania tokenów tak, aby jego silnik TeX-a, oraz wszystkie późniejsze silniki oparte na jego kodzie/architekturze, mogły szybko i łatwo testować wartości tokenów.

## Tokeny można rozłożyć na części (i ponownie przekształcić w tekst)

Tokeny (liczby całkowite) są mechanizmem, za pomocą którego silnik TeX-a „enkapsuluje” wszystko, co musi zapisać o elemencie wejścia (znaku lub poleceniu). Jednak czasami silnik TeX-a musi odwrócić proces tokenizacji — aby dowiedzieć się, co zostało pierwotnie odczytane, by utworzyć tę wartość tokenu — pojedynczy znak lub sekwencję jednego lub większej liczby znaków tworzących nazwę polecenia:

* **dla tokenów znaków**: Każdy token znaku można podzielić na dwa składniki: kod znaku oraz odpowiadający mu kod kategorii przypisany do tego znaku *w momencie, gdy został pierwotnie odczytany*. Jak wszystkie silniki TeX-a, LuaTeX nie zmieni tego pierwotnego przypisania kodu kategorii, lecz wykorzysta je podczas dalszych wewnętrznych czynności przetwarzania.
* **dla tokenów poleceń:** Są one nieco bardziej szczegółowe, ale jeśli przyjrzeć się obliczaniu tokenów poleceń w LuaTeX-ie, w tym tokenów dla znaków aktywnych, widać, że podążają one za pewnym wzorcem: $$\text{command token} = \text{curcs} + 2^{29} -1$$

gdzie $$\text{curcs}$$ jest obliczana zgodnie z typem tworzonego tokenu polecenia: znak aktywny, symbol sterujący lub słowo sterujące. Zmienna $$\text{curcs}$$ jest *skrajnie* ważnym elementem wewnętrznych operacji silnika TeX-a: mając dowolną całkowitą wartość tokenu polecenia, LuaTeX może bardzo łatwo wyodrębnić wartość $$\text{curcs}$$ z tego tokenu polecenia za pomocą $$\text{curcs} = \text{token value} - (2^{29} -1)$$.

### Dlaczego $$\text{curcs}$$ jest to tak ważne?

Wewnętrzna zmienna TeX-a $$\text{curcs}$$ (**cur**rent **c**ontrol **s**sekwencja) jest niezwykle ważnym składnikiem wewnętrznych „pod maską” działań silnika TeX-a. Chociaż nie będziesz i nie możesz używać jej ani uzyskać do niej bezpośredniego dostępu w swoim kodzie, $$\text{curcs}$$ odgrywa kluczową rolę, ponieważ silniki TeX-a używają bieżącej wartości $$\text{curcs}$$ jako indeksu w wewnętrznych tabelach, które przechowują dane o każdym poleceniu obecnie znanym silnikowi. Tabele te przechowują informacje o bieżącym znaczeniu polecenia: co ono robi lub reprezentuje, a ponadto zapisują sekwencję znaków pierwotnie użytych do obliczenia tej $$\text{curcs}$$ wartości. Wyodrębniając wartość $$\text{curcs}$$ z tokenu polecenia, silnik TeX-a jest w stanie określić nazwę, czyli czytelny dla człowieka tekst, odpowiadający dowolnemu tokenowi (polecenia), co umożliwia mu wykonywanie konwersji token-na-tekst, które są kluczowym aspektem `\directlua`jego działania.

### Przekształcanie tokenów całkowitoliczbowych z powrotem w znaki lub sekwencje znaków (nazwy poleceń)

Widzieliśmy, że silniki TeX-a konwertują znaki wejściowe lub sekwencje znaków na całkowite wartości tokenów, ale zdarzają się sytuacje, w których silnik TeX-a musi *odwrócić* ten proces — aby wypisać czytelny dla człowieka tekst pierwotnie użyty do utworzenia tych całkowitych wartości tokenów; na przykład:

* zapisywanie komunikatów o błędach lub ostrzeżeń na ekran albo `.log` plik;
* wyprowadzanie kodu TeX/LaTeX do pliku tekstowego za pomocą `\write` polecenie;
* przy konwertowaniu sekwencji tokenów na tekst w `\directlua` (jak wkrótce zobaczymy!)

#### Konwertowanie tokenów znaków na tekst

Jak wspomniano, tokeny dla znaków nieaktywnych są obliczane z użyciem kodu kategorii i kodu znaku wejściowego (wartości Unicode). LuaTeX używa wzoru:

$$\text{character token} = (2^{21} \times \text{category code}) + (\text{Unicode value})$$

Prostym zadaniem programistycznym jest rozdzielenie liczby całkowitej $$\text{character token}$$ wartości, aby uzyskać jej składowy kod znaku ($$\text{Unicode value}$$) $$\text{category code}$$.

#### Konwertowanie tokenów poleceń na tekst

Wszystkie silniki TeX-a przechowują nazwę (sekwencję znaków) każdego polecenia, które „znają”: niezależnie od tego, czy polecenie jest makrem zdefiniowanym przez użytkownika, czy wbudowanym prymitywem — przechowywanie nazw poleceń prymitywnych następuje podczas uruchamiania silnika TeX, na długo przed rozpoczęciem przetwarzania kodu. W przypadku poleceń zdefiniowanych przez użytkownika (makr), nazwa tego makra (bez wiodącego `\`) jest przechowywana jako część procesów definiowania makr wewnątrz silników TeX-a.

Gdy silnik TeX-a musi uzyskać dostęp do czytelnego dla człowieka tekstu, z którego pierwotnie obliczono całkowitą wartość tokenu polecenia, najpierw ustali $$\text{curcs}$$ wartość dla tego tokenu; w LuaTeX-ie, $$\text{curcs} = \text{token} - (2^{29} -1$$). Używając wartości $$\text{curcs}$$ wyodrębnionej z tokenu polecenia silnik TeX-a może uzyskać dostęp do wewnętrznej struktury danych zwanej *pulą łańcuchów* aby określić sekwencję czytelnych dla człowieka znaków pierwotnie użytych do obliczenia tej konkretnej wartości dla $$\text{curcs}$$ i w konsekwencji odpowiadającego jej tokenu polecenia.

Jak zobaczymy, te czynności przetwarzania tokenów — przekształcanie sekwencji znaków w całkowite wartości tokenów i przekształcanie całkowitych wartości tokenów z powrotem w sekwencje znaków („detokenizacja”) — są *fundamentalnymi mechanizmami* używanymi wewnątrz `\directlua`.

## Listy tokenów

Gdy silnik TeX-a odczytuje wejście, generuje tokeny znaków i poleceń (oraz je przetwarza), może napotkać pewne polecenia, które instruują silnik, aby (tymczasowo) przestał przekazywać tokeny dalej do dalszego przetwarzania, a zamiast tego odłożył je do późniejszego użycia. Najczęstszym przykładem jest definiowanie makra za pomocą jednego z poleceń definiowania makr `\def`, `\edef`, `\gdef` lub `\xdef`— polecenia LaTeX-a, takie jak `\newcommand` są makrami, które zapewniają dodatkową funkcjonalność zbudowaną wokół niskopoziomowych prymitywów, które ostatecznie wykonują właściwy proces definiowania makra. Makro można uznać za nazwę nadaną określonej liście przechowywanych tokenów: liście tokenów.

Silniki TeX-a czynią *rozległy* użytek z list tokenów, zwłaszcza [tymczasowych list wyłącznie wewnętrznych](/latex/pl/artykuly-szczegolowe/21-how-does-expandafter-work-tex-uses-temporary-token-lists.md) używanych do celów wewnętrznego przetwarzania. Każdy silnik TeX-a udostępnia także polecenia na poziomie użytkownika do tworzenia list tokenów, które są odkładane na czas, gdy użytkownik lub sam silnik TeX-a ich potrzebuje. Liczba poleceń tworzenia list tokenów (wbudowanych prymitywów) różni się w zależności od silnika TeX-a, ale wszystkie mają wspólny minimalny zestaw podstawowy obsługiwany przez każdy silnik, `\toks` prymityw.

W praktyce lista tokenów to po prostu przechowywana sekwencja wartości całkowitych:

* wejście jest odczytywane w celu wygenerowania (obliczenia) poszczególnych tokenów reprezentujących znak lub polecenie;
* każdy token jest następnie odkładany, zachowując kolejność, w jakiej tokeny zostały wygenerowane z wejścia.

Silniki TeX-a przechowują listy tokenów, używając struktury danych zwanej [listą połączoną](https://en.wikipedia.org/wiki/Linked_list) (jednokierunkową). Czytelnicy, którzy chcieliby dowiedzieć się więcej o listach tokenów, są zaproszeni do przeczytania artykułu Overleaf [Czym jest lista tokenów TeX-a?](/latex/pl/artykuly-szczegolowe/54-what-is-a-tex-token-list.md) który posługuje się analogią, aby zbudować pojęcia/idee stojące za listą tokenów. Dogłębne omówienie list tokenów TeX-a oraz tego, jak są one używane w przetwarzaniu makr, można znaleźć w serii artykułów Overleaf [Jak naprawdę działają makra TeX-a?](/latex/pl/wiecej-tematow/01-a-six-part-series-how-do-tex-macros-actually-work.md)

#### Lista tokenów w formie graficznej

Poniższa grafika pokazuje listę tokenów wygenerowaną przez LuaTeX wraz z odpowiadającymi wartościami tokenów utworzonymi z następującego wejścia

`Hi, \TeX! \hskip 5bp`

Na przykład, jeśli zdefiniujemy `\mymacro` jako `\def\mymacro{Hi, \TeX! \hskip 5bp}` definicja `\mymacro` byłaby przechowywana w pamięci przy użyciu takiej listy tokenów:

![](/files/fe9dc9b42f4b5eb1a4aee273d0a8349f0e45f887)

Lista tokenów jest sekwencją połączonych elementów zwanych *węzłów*, nazwą nadaną małemu fragmentowi pamięci LuaTeX-a przydzielonemu do przechowywania każdego elementu listy (jak pojedyncze ogniwa w łańcuchu). Każdy węzeł zawiera całkowitą wartość tokenu oraz adres pamięci *następnego* węzła w łańcuchu, tworząc strukturę danych zwaną [listą połączoną](https://en.wikipedia.org/wiki/Linked_list). Ostatni węzeł wskazuje koniec listy za pomocą specjalnej „wartości null” dla następnego węzła — ponieważ takiego nie ma.

**Uwagi:**

* Dla wygody podaliśmy adres każdego pojedynczego węzła, ale w praktyce te dane nie są przechowywane wewnątrz węzłów listy tokenów; przechowywany jest tylko adres *następnym węzłem* jest potrzebny do budowy list tokenów silnika TeX-a.
* Druga kolumna na grafice zatytułowanej „Co oznacza każdy token” pokazuje serię szarych pól zawierających informacje o tokenie zawartym w każdym węźle: są one wyłącznie informacyjne i *nie* nie stanowią części rzeczywistych danych przechowywanych w liście tokenów.

Oto tabela wartości tokenów zawartych w przedstawionej powyżej liście tokenów:

|                       |                      |                                                                            |                    |
| --------------------- | -------------------- | -------------------------------------------------------------------------- | ------------------ |
| **Element wejściowy** | **Typ wejścia**      | <p><strong>Kod kategorii</strong><br><br><strong>(jeśli znak)</strong></p> | **Wartość tokenu** |
| H                     | znaku                | 11                                                                         | 23068744           |
| i                     | znaku                | 11                                                                         | 23068777           |
| ,                     | znaku                | 12                                                                         | 25165868           |
|                       | znaku                | 10                                                                         | 20971552           |
| \TeX                  | polecenie (makro)    |                                                                            | 536871539          |
| !                     | znaku                | 12                                                                         | 25165857           |
|                       | znaku                | 10                                                                         | 20971552           |
| \hskip                | polecenie (prymityw) |                                                                            | 536874247          |
| 5                     | znaku                | 12                                                                         | 25165877           |
| b                     | znaku                | 11                                                                         | 23068770           |
| s                     | znaku                | 11                                                                         | 23068784           |

**Uwaga:** Nasz oryginalny tekst wejściowy ma po `\hskip` poleceniu, ale w liście tokenów nie ma tokenu reprezentującego ten znak. Ten znak został wchłonięty przez proces skanowania (odczytu) wejścia w LuaTeX-ie, ponieważ został użyty do zakończenia wyszukiwania przez LuaTeX znaków składających się na `\hskip` polecenie.

## Jak naprawdę działa \directlua

Teraz, gdy zbadaliśmy tokeny, listy tokenów i zamianę tokenów na tekst, kolejnym wyzwaniem jest zrozumienie koncepcji tokenu w silniku TeX *rozwijanie*.

Jak wspomniano, `\directlua{⟨code⟩}` można poprosić o przetworzenie `⟨code⟩` który zawiera zarówno kod Lua, jak i TeX/LaTeX, ale wbudowany interpreter języka Lua w LuaTeX nie rozumie TeX-a ani LaTeX-a: jak więc może to działać? Jak to możliwe, że `⟨code⟩` może zawierać instrukcje TeX/LaTeX, nie wprowadzając przy tym całkowitego zamieszania w interpreterze Lua komendami, których nie rozumie? Na przykład poniższa `\directlua` komenda używa wyłącznie makr TeX-a, ale działa:

```
\def\aa{tex}
\def\bb{.}
\def\cc{print}
\def\dd{("Hello")}
\directlua{
   \aa\bb\cc\dd
}
```

Ten `\directlua` komenda skutkuje składem w LuaTeX `Witaj` ale dlaczego i jak to działa, skoro język Lua nie rozumie makr TeX-a?

Odpowiedź zawarta jest we wcześniejszym opisie, który zapożyczyliśmy z [Podręcznik referencyjny LuaTeX](http://www.pragma-ade.com/general/manuals/luatex.pdf) ale możemy uznać, że `\directlua{⟨code⟩}` działa tak, że LuaTeX początkowo „wstępnie przetwarza” `⟨code⟩` zanim cokolwiek zostanie przekazane do interpretatora Lua. Charakter tego „wstępnego przetwarzania” — czyli to, co naprawdę oznacza, i jakie ma konsekwencje dla twojego `⟨code⟩`—to kolejny temat, który omówimy, aby pomóc czytelnikom zainteresowanym wykorzystaniem mocy i elastyczności `\directlua`.

### Jak LuaTeX przetwarza \directlua: pierwsze spojrzenie

Aby rozbudować nasze rozumienie `\directlua`działań „wstępnego przetwarzania” `⟨code⟩` możemy zacząć od poniższego uproszczonego diagramu, który daje przegląd tego, co się dzieje.  `\directlua{⟨code⟩}` dostarczony do

![](/files/905f21774f633fad274bda562fd4f7eae4a9eb54)

jest najpierw zamieniany na tokeny za pomocą procesów i obliczeń omówionych powyżej; ta sekwencja tokenów jest przechowywana w liście tokenów. Gdy ta lista tokenów zostanie zbudowana, każdy token w tej liście jest zamieniany z powrotem na jego tekstową reprezentację: tekst wytworzony przez każdy token — token znakowy lub token komendy — jest łączony (konkatenowany), aby utworzyć pojedynczy ciąg kodu przekazywany do interpretatora Lua w celu wykonania. *rozwijanie tokenów*. Każdy token powstały z tekstu w twoim `⟨code⟩` jest poddawany rodzajowi „inspekcji”, w której LuaTeX stosuje test, aby sprawdzić, czy dany token reprezentuje komendę należącą do podzbioru znanego jako *komendy rozwijalne*. Jeśli tak jest, LuaTeX odfiltrowuje tę komendę przez *usunięcie* usuwanie jej z twojego `⟨code⟩` i *zastępując ją* wynikami procesu, który silniki TeX-a nazywają *rozwijanie tokenów*.

### Jak LuaTeX przetwarza \directlua: drugie spojrzenie (na rozwijanie)

Mechanizm rozwijania TeX-a jest podstawowym elementem wszystkich silników składu opartych na TeX-u, ponieważ ostatecznie każdy z nich wywodzi się z oryginalnego kodu źródłowego i projektu TeX-a Knutha (lub jest na nich oparty). Jednak pojęcie rozwijania jest trudne do wyjaśnienia zwięzłym, a jednocześnie przystępnym językiem, ponieważ w praktyce rozwijanie jest terminem „parasolowym”, używanym do opisania pojedynczego procesu — ale takiego, który daje szeroki zakres wyników. Te zróżnicowane rezultaty są konsekwencją dość eklektycznego zestawu komend, do których można zastosować rozwijanie, więc można przyjąć, że każda komenda rozwijalna ma pewne „zachowanie podczas rozwijania”.

Jako *pierwsze przybliżenie* do zrozumienia rozwijania możemy powiedzieć, że rozwijanie tokenu (komendy) oznacza *usunięcie* usunięcie tej komendy (tokenu) z bieżącego wejścia TeX-a i *zastąpienie* zastąpienie jej sekwencją tokenów, które wynikają z wykonania tej konkretnej komendy rozwijalnej — zastąpienie oryginalnego tokenu wynikami/konsekwencjami jego rozwinięcia *zachowania*. Jednak ta początkowa „definicja” rozwijania — w kategoriach generowania nowych tokenów do odczytu przez TeX-a — nie jest całkowicie poprawna dla wszystkich komend rozwijalnych, ale jako punkt wyjścia jest wystarczająco dobra.

Żeby podać prosty przykład: prymityw TeX-a `\jobname` jest komendą rozwijalną i jej *rozwijanie* jest sekwencją tokenów znakowych reprezentujących nazwę głównego pliku wejściowego TeX-a. Jeśli TeX zdecyduje się rozwinąć `\jobname` komenda (token) jest *usuwana* z bieżącego źródła wejścia TeX-a i *zastępowana* sekwencją tokenów znakowych, którą generuje — po czym TeX odczytuje/przetwarza ją dalej.

W obrębie `\directlua`, po przetworzeniu (usunięciu) tokenu rozwijalnego i zastąpieniu go nowymi tokenami, LuaTeX będzie dalej odczytywać te nowe tokeny, które właśnie wstawił na ich miejsce — ale niektóre z tych nowych tokenów również mogą być rozwijalne. Ponieważ `\directlua` wykonuje tak zwane *pełne rozwijanie*, LuaTeX będzie odczytywał te nowe tokeny i, raz jeszcze, przechodził przez proces rozwijania, aby rozwinąć (usunąć) wszystkie nowe (rozwijalne) tokeny — ten proces rozwijania trwa, dopóki nie pozostanie żaden token rozwijalny. Istnieją jednak dwa ważne wyjątki od tej zasady „ciągłego rozwijania”, o których obu omówimy poniżej:

* używając konstruktu `\the\toks`;
* celowe zapobieganie (wstrzymanie) rozwijaniu jednego lub większej liczby wybranych tokenów.

Jak wspomniano, nasza robocza definicja (pierwsze przybliżenie) rozumienia rozwijania nie obejmuje pełnego zakresu zachowań podczas rozwijania wykazywanych przez podzbiór komend rozwijalnych. Na przykład niektóre komendy rozwijalne nie generują tokenów w sposób, w jaki `\jobname` to robi, ale mogą:

* „filtrować” tokeny z wejścia: komendy warunkowe silnika TeX (`\if`, `\ifcat`, `\ifnum`, `\ifdim`, `\ifodd`, `\ifvmode`, …) są rozwijalne. Ich zachowanie podczas rozwijania jest rodzajem „filtrowania tokenów” — warunkowe mogą być używane w `\directlua`.
* „mieszać” tokeny w wejściu: [`\expandafter` polecenie](/latex/pl/artykuly-szczegolowe/03-a-six-part-article-series-on-expandafter-tex-tokens-and-expansion.md) jest rozwijalny i zmienia kolejność, w jakiej dwa tokeny są rozwijane.
* zapobiegać rozwijaniu: komendy rozwijalne `\noexpand` i `\unexpanded` wstrzymują rozwijanie tokenów komend w wejściu.
* zamieniać ciągi znaków w wejściu na tokeny komend: `\csname … \endcsname.`
* zamieniać wewnętrzne wielkości na sekwencję tokenów znakowych: `\number` i `\the` są komendami rozwijalnymi, które generują sekwencję tokenów znakowych reprezentujących wartość wewnętrznej wielkości.
* zamieniać tokeny komend na tokeny znakowe: `\string` i `\detokenize` są komendami rozwijalnymi, które zamieniają swoje argumenty na sekwencję tokenów znakowych z kodem kategorii 12. Zauważ, że `\detokenize` różni się od `\string`: `\detokenize` może przetwarzać wiele tokenów i wprowadza znak spacji, o kodzie kategorii 10, po przetworzeniu tokenów komend utworzonych z *słowa sterujące*. W praktyce `\detokenize` dodaje końcowy znak spacji po nazwie komendy — kilka przykładów zobaczymy później w artykule.

#### Doprecyzowanie naszej „definicji” rozwijania

Możemy teraz uogólnić naszą definicję, mówiąc, że rozwijanie komendy (tokenu) obejmuje *usunięcie* tej komendy (tokenu) z bieżącego źródła wejścia TeX-a i *zastępując ją* zastąpienie jej wynikiem *operacji tokenowej* wykonanej przez tę komendę. W istocie proces rozwijania powoduje, że komenda rozwijalna wykonuje jakiś rodzaj „operacji” na tokenach w bieżącym wejściu TeX-a, która wpływa na liczbę tokenów albo na zachowanie tokenów, które TeX będzie później odczytywał — dokładna natura tej „operacji” zależy od tego, która komenda jest rozwijana. Wszystkie makra i znaki aktywne są rozwijalne, ale tylko niewielka liczba wbudowanych komend silnika TeX (prymitywów) jest klasyfikowana jako rozwijalna — lista komend rozwijalnych zależy od używanego silnika TeX.

Każdy nowy silnik TeX dziedziczy prymitywne komendy wbudowane u swoich poprzedników — silników TeX wcześniejszych generacji, z których został wywiedziony — a niektóre z tych odziedziczonych prymitywów będą rozwijalne. Oczywiście nowy silnik TeX może zdecydować, że nie zaimplementuje niektórych komend prymitywnych zawartych we wcześniejszych silnikach, albo zmodyfikuje ich zachowanie, aby dopasować je do potrzeb nowego silnika. Ponadto nowe silniki TeX zwykle implementują dodatkowe prymitywy, aby zapewnić obsługę własnej rozszerzonej funkcjonalności — niektóre z nich również mogą być rozwijalne. W konsekwencji liczba dostępnych dla Ciebie komend rozwijalnych będzie się różnić w zależności od używanego silnika TeX — LuaTeX ma ich całkiem sporo.

Kolejną trudnością w wyjaśnianiu/rozumieniu rozwijania, a być może prawdziwym wyzwaniem, jest dokładne wiedzieć *kiedy* silnik TeX rzeczywiście wykona, albo nie wykona, procesu rozwijania. To duży i złożony temat, ponieważ rozwijanie jest głęboko wbudowane w wewnętrzne działanie silników TeX: nie mamy miejsca, aby omawiać to szczegółowo poza użyciem rozwijania w `\directlua`.

### Jak LuaTeX przetwarza \directlua: ostatnie spojrzenie

Poniższy diagram podsumowuje `\directlua` działania wstępnego przetwarzania, które zachodzą wewnątrz samego silnika LuaTeX. Na tym diagramie pokazujemy także dwie niskopoziomowe (wewnętrzne) funkcje LuaTeX, które faktycznie wykonują tę pracę: `scan_toks()` i `tokenlist_to_cstring()`. Funkcje te są napisane w języku C i znajdują się głęboko wewnątrz wykonywalnego oprogramowania LuaTeX: są częścią wewnętrznego mechanizmu LuaTeX, a nie *bezpośrednie* dostępne dla twojego kodu TeX/LaTeX.

![](/files/4276c0e177453214a7b2d5abd340faad40e72e0a)

Poniższy opis `\directlua ⟨code⟩`skracając, opisuje powyższy diagram.

1. Sekwencja znaków w twoim ⟨code⟩ jest przetwarzana przez `scan_toks()`. Jej celem jest odczytanie twojego ⟨code⟩ znak po znaku w celu wygenerowania tokenów znakowych i tokenów komend. Ponieważ tworzy tokeny, kod kategorii przypisany do każdego znaku w ⟨code⟩ w chwili jego odczytu jest niezwykle ważny.
2. Podczas `scan_toks()`przetwarzania (generowania) tokenów każda komenda rozwijalna (token) jest rozwijana *chyba że* powstrzymane za pomocą komend takich jak `\protected` (definicje makr), `\noexpand`, `\unexpanded` itd. Znaki aktywne (kod kategorii 13) są również rozwijane (chyba że im się to uniemożliwi).
3. Strumień tokenów utworzony przez `scan_toks()` jest budowany w jedną długą listę tokenów — tokeny obecne na tej liście obejmują te powstałe w wyniku zastosowania rozwijania do komend rozwijalnych (takich jak makra) obecnych w twoim `⟨code⟩`. Zwróć też uwagę, że `scan_toks()` *nie* uruchamiają lub powodują wykonanie każdego tokenu reprezentującego komendę nierozwijalną: takie tokeny nierozwijalne są po prostu przepuszczane dalej, aby zostać włączone do budowanej listy tokenów.
4. Gdy lista tokenów zostanie ukończona i cała aktywność rozwijania się zakończy, ta lista tokenów jest przetwarzana przez inną funkcję o nazwie `tokenlist_to_cstring()` która zamienia każdy token z końcowej listy tokenów z powrotem na jego tekstową reprezentację. Generuje to ciąg tekstu, który jest kodem Lua przekazywanym do interpretatora Lua. Aby wykonanie powiodło się, ten ciąg musi zawierać poprawny składniowo kod Lua.
5. Przetwarzanie tego kodu przez Lua odbywa się w dwóch krokach:
6. Wbudowany interpreter Lua w LuaTeX analizuje i „kompiluje” kod Lua wygenerowany w poprzednich krokach. Jeśli ta analiza/kompilacja się nie powiedzie, interpreter Lua wygeneruje błędy (takie jak błędy składni) — błędy te mogą spowodować niepowodzenie uruchomienia LuaTeX, chyba że zdecydowałeś się użyć `--interaction=nonstopmode` w wierszu poleceń.
7. Jeśli analiza/kompilacja zakończy się powodzeniem, interpreter Lua wykonuje kod skompilowany w kroku (5a).

W istocie funkcja `scan_toks()` stanowi rdzeń działań wstępnego przetwarzania LuaTeX: jej głównym zadaniem jest rozwinięcie wszystkich rozwijalnych komend TeX/LaTeX zawartych w tekście twojego `⟨code⟩` i skonstruowanie z wszystkiego, co przetworzyła, listy tokenów. Znowu podkreślmy, że `scan_toks()` *nie wykonuje nierozwijalnych komend* (tokenów): po prostu *przechowuje* te tokeny na tworzonej liście tokenów. Po zakończeniu ta lista tokenów jest następnie zamieniana *z powrotem na reprezentację tekstową* przez `tokenlist_to_cstring()`—lista tokenów jest koncepcją wyłącznie TeX-ową, całkowicie obcą interpreterowi Lua, stąd potrzeba zamiany jej na tekst, który staje się kodem Lua do przekazania interpreterowi Lua.

## Rozwijanie jako „interfejs” języka programowania

Możesz myśleć o `\directlua`procesie rozwijania LuaTeX jako mechanizmie lub interfejsie służącym do przekazywania danych/informacji z „Świata TeX-a” do „Świata Lua”: dostarczając metodę, dzięki której język TeX może przekazywać dane do języka Lua. Na przykład kod TeX, taki jak `\number\count75` może być użyty do przeniesienia wartości „Świata TeX-a” zapisanej w rejestrze licznikowym 75 do zmiennej całkowitej x w „Świecie Lua”:

```
\count75=1564 % Dane istniejące w "Świecie TeX-a"
\directlua{
   local x=\number\count75 \space % Przeniesienie danych TeX-a do "Świata Lua"
   tex.print("x= "..x)
   local y = (2*x-65)/5
   tex.print(" oraz y = "..y)
}
```

To generuje kod Lua

```
 local x=1564 tex.print("x= "..x) local y = (2*x-65)/5 tex.print(" oraz y = "..y)
```

**Uwaga**: Dodaliśmy `<space>\space` po `\number\count75` aby zapewnić zachowanie znaku spacji między `1564` i `tex.print`—to nie jest tu ściśle konieczne, ponieważ Lua i tak poprawnie przeanalizowałby kod, gdybyśmy to pominęli. Znak spacji bezpośrednio po `\count75` jest pochłaniany podczas procesu, którego silniki TeX używają do wyszukiwania wartości liczbowych — tutaj wartości przekazywanej do `\count`. Znak spacji po `75` służy do zakończenia wyszukiwania ciągu cyfr przez LuaTeX `75` i jest pochłaniany z wejścia. Makra `\space` rozwija się, aby dostarczyć znak spacji potrzebny do oddzielenia tekstu `1564` i `tex.print`.

Używając powyższego kodu LuaTeX złoży

`x= 1564 oraz y = 612.6`

Tutaj mechanizm „przekazywania danych” jest realizowany przez `\number`: komendę rozwijalną, która w tym przypadku poleca TeX-owi pobrać wartość zapisaną w `\count` rejestrze `75` i na podstawie tej wartości (`1546`) wygenerować serię tokenów znakowych, po jednym tokenie znakowym dla każdej cyfry, co daje sekwencję tokenów dla cyfr `1`, `5`, `6` i `4`. Te 4 tokeny znakowe są włączane do głównej listy tokenów budowanej przez `\directlua` i następnie zamieniane z powrotem na ich tekstową reprezentację, gdy lista tokenów jest zamieniana na tekst. Niewątpliwie jest to bardzo okrężna droga: od `\count75` wartości rejestru zapisanej wewnątrz LuaTeX do cyfr przeznaczonych dla kodu Lua, ale ostatecznie działa.

**WSKAZÓWKA:** Jeśli chcesz sprawdzić wyniki działań rozwijania w LuaTeX, możesz napisać kod taki jak ten:

```
\directlua{
   local foo=[[local x=\number\count75
   tex.print("x= "..x)
   local y = (2*x-65)/5
   tex.print(" oraz y = "..y)]]
   print(foo)
}
```

W tym przykładzie używamy metody długich nawiasów, aby utworzyć zmienną łańcuchową `foo` której celem jest przechowanie łańcucha kodu Lua wygenerowanego z rozwinięcia wszystkiego pomiędzy `[[` i `]]`. Ten łańcuch jest wypisywany na konsolę za pośrednictwem wywołania funkcji Lua `print(foo)`.

W Overleaf możesz zobaczyć podobne wyniki, zapisując zawartość `foo` do `.log` pliku za pomocą funkcji LuaTeX w Lua `texio.write()`:

```
\directlua{
   local foo=[[local x=\number\count75
   tex.print("x= "..x)
   local y = (2*x-65)/5
   tex.print(" oraz y = "..y)]]
   texio.write(foo)
}
```

## Tokeny na liście tokenów \directlua: tokeny nierozwijalne i tokeny nierozwinięte

Zauważyliśmy, że `\directlua{⟨code⟩}` wykonuje *pełne rozwijanie* twojego `⟨code⟩`: usuwa i rozwija wszystkie komendy rozwijalne, aż pozostaną tylko tokeny nierozwijalne. Sekwencja tokenów utworzona przez `\directlua`przetwarzania (w funkcji `scan_toks()` są łączone w celu utworzenia listy tokenów, której poszczególne tokeny zostaną zamienione z powrotem na tekst, aby przekazać je do Lua.

Nie odnieśliśmy jednak jeszcze do końcowej części tej historii, ponieważ musimy rozważyć dwie „klasy” tokenów komend, które mogą przedostać się do listy tokenów budowanej w `\directlua`: będziemy nazywać je *tokenami komend skrótowych* i *nierozwinięte* tokeny:

* **tokenami komend skrótowych**: Ten typ tokenu komendy powstaje z ciągów sterujących zdefiniowanych przy użyciu jednego z prymitywów TeX-a `\chardef`, `\mathchardef`, `\countdef`, `\dimendef`, `\skipdef`, `\muskipdef` i `\toksdef`. Te komendy prymitywne służą do definiowania ciągów sterujących reprezentujących wartość liczbową — wynikowe ciągi sterujące są *nie* rozwijalne.
* **tokeny nierozwinięte**: Ten typ tokenu powstaje z komend, które normalnie zostałyby rozwinięte, ale `\directlua` otrzymał jedno z poniższych poleceń:
* zostały wyraźnie poinstruowane *nie* aby je rozwijać; na przykład wstrzymywanie rozwijania przez komendy `\noexpand` lub `\unexpanded`—już wkrótce wyjaśnimy, jak to się robi;
* wstrzyknięte tokeny przez przetworzenie sekwencji `\the\toks` (więcej na ten temat poniżej).

### Dwie „grupy” tokenów na liście tokenów \directlua

Na podstawie naszych rozważań możemy powiedzieć, że tokeny zawarte w liście tokenów budowanej podczas pierwszego etapu `\directlua`wstępnego przetwarzania LuaTeX (w funkcji `scan_toks()` mieszczą się w dwóch grupach:

1. *z natury nierozwijalne* tokeny

* każdy token reprezentujący nieaktywny *znaku*;
* każdy token reprezentujący nierozwijalny *prymityw* *polecenie*;
* każdy token reprezentujący *skrótową komendę* (te nie są rozwijalne, zob. poniżej).

3. *nierozwinięte* tokeny:

* każdy token reprezentujący komendę rozwijalną, której rozwinięcie zostało *wstrzymane* (lub uniknięte) podczas `\directlua`wstępnego przetwarzania LuaTeX.

#### Tokeny skrótowych komend: tworzenie komend nierozwijalnych

Jak zauważono, silniki TeX udostępniają zestaw prymitywów (wbudowanych komend), które mogą być używane do konstruowania *nierozwijalnych* ciągów sterujących (oznaczonych tutaj jako `⟨command⟩`). Te prymitywy przyjmują postać:

* `\chardef ⟨command⟩ = ⟨numeric value⟩`
* `\mathchardef ⟨command⟩ = ⟨numeric value⟩`
* `\countdef ⟨command⟩ = ⟨numeric value⟩`
* `\dimendef ⟨command⟩ = ⟨numeric value⟩`
* `\skipdef ⟨command⟩ = ⟨numeric value⟩`
* `\muskipdef ⟨command⟩ = ⟨numeric value⟩`
* `\toksdef ⟨command⟩ = ⟨numeric value⟩`

gdzie `⟨numeric value⟩` jest pewną wartością całkowitą odpowiednią dla danej komendy.

Tutaj krótko omówimy użycie `\chardef` aby pokazać kluczową cechę tych prymitywów — tworzenie `⟨command⟩` ciągu sterującego ``\chardef\mydollar=`\$`` do utworzenia ciągu sterującego `\mydollar` i użyć go do składu `$`:

`Zapłaciłem \mydollar30.`

To zostanie złożone jako `Zapłaciłem $30.` Ciąg sterujący `\mydollar` utworzony przez `\chardef` nie jest rozwijalny, jak możemy zobaczyć na następującym przykładzie:

```
\chardef\mydollar=`\$
\directlua{
   local x =[[Zapłaciłem \mydollar30.]]
   texio.write(x)
}
```

Co daje następujący tekst w `.log` pliku

`Zapłaciłem \mydollar 30.`

To pokazuje `\mydollar` została *nie* rozwinięte podczas `\directlua`wstępnego przetwarzania LuaTeX. Spacja pojawiająca się po `\mydollar` jest dodawana, gdy token komendy jest zamieniany na swoją reprezentację tekstową.

Gdy używasz `\chardef` do tworzenia ciągu sterującego, wewnętrzna klasyfikacja tego ciągu sterującego (komendy) przez TeX powoduje, że staje się on *nierozwijalnych* co jest zachowaniem bardzo różnym od ciągów sterujących zdefiniowanych przez jedną z komend definicji makr: \def, \edef, \gdef lub \xdef. Jak zauważono powyżej, podczas procesu konstruowania swojej listy tokenów `\directlua` sprawdza każdy przychodzący token komendy, aby ocenić rozwijalność. Jeśli token komendy nie jest rozwijalny, przechodzi on bezpośrednio do listy tokenów, a jego tekstowa reprezentacja pojawi się później ponownie w łańcuchu kodu Lua wynikającym z zamiany tokenów w liście tokenów z powrotem na ich tekstową formę.

**Krótka uwaga o plain TeX kontra LaTeX**

Historycznie rzecz biorąc, oryginalny plain TeX Knutha definiował powszechnie używane symbole sterujące `\%`, `\&`, `\#` i `\$` używając `\chardef`—nie używając jednej ze standardowych komend definicji makr `\def`, `\edef`, `\gdef` lub `\xdef`. Na przykład:

```
   \chardef\#=`\#
   \chardef\$=`\$
   \chardef\%=`\%
   \chardef\&=`\&
```

Dziwna `` `\ `` składnia jest metodą TeX-a na uzyskanie numerycznej wartości kodu znaku. W starym modelu plain TeX te symbole sterujące nie są rozwijalne (z powodu `\chardef`) ale LaTeX (lub pakiety) mogą je redefiniować jako *makr* aby zapewnić rozszerzoną funkcjonalność — to uczyniłoby je rozwijalnymi, więc warto mieć tego świadomość.

**Jak wpływa to na \directlua?**

Porównajmy wynik poniższego kodu uruchomionego w plain TeX i LaTeX. Dla uproszczenia zapiszemy wyniki do `.log` pliku, używając funkcji LuaTeX Lua API `texio.write()`.

```
\directlua{
   local x=[[\$150 za produkt "\#1"---o 20\%! więcej niż u konkurenta, Widget \& Co.]]
   texio.write(x)
}
```

Uruchomienie tego kodu z użyciem **plain TeX** daje następujący wynik w `.log` pliku, pokazując rezultat wszystkich rozwinięć:

```
\$150 za produkt "\#1"---o 20\%! więcej niż u konkurenta, Widget \& Co.
```

Wyraźnie w plain TeX żaden z symboli sterujących`\$`, `\#`, `\%` lub `\&` nie został rozwinięty — ponieważ wszystkie zostały utworzone przy użyciu `\chardef`.

Uruchomienie tego kodu z użyciem **LaTeX** dokumentu:

```
\documentclass{article}
\begin{document}
   \directlua{local x=[[\$150 za produkt "\#1"---o 20\%! więcej niż u konkurenta, Widget \& Co.]] texio.write(x)}
\end{document}
```

daje następujący wynik w `.log` pliku

```
\protect \TU\textdollar 150 za produkt "\#1"---o 20\%! więcej niż u konkurenta, Widget \& Co.
```

Wyraźnie, uruchomienie LaTeX daje wynik inny niż plain TeX, ponieważ w LaTeX komenda `\$` została rozwinięta, co wskazuje, że jest makrem.

**Uwaga:** Zarówno w plain TeX, jak i w LaTeX `\directlua` nie przetworzył w pełni żadnego z symboli sterujących `\%`, `\&`, `\#` i `\$` w celu wygenerowania odpowiedniego znaku. Podczas procesu rozwijania wykonywanego przez `\directlua` tokeny reprezentujące te symbole sterujące — albo, w przypadku LaTeX, ich rozwinięcie — przechodzą bezpośrednio do głównej listy tokenów budowanej w danym momencie.

**Uwaga:** Symbole sterujące są tworzone z pojedynczego znaku niebędącego w kodzie kategorii 11, takiego jak `\#`. Gdy token reprezentujący symbol sterujący jest zamieniany z powrotem na jego reprezentację tekstową, silniki TeX nie wstawiają po tym tekście znaku spacji. To specjalne traktowanie symboli sterujących jest wbudowaną regułą działania silników TeX.

### Tokeny nierozwinięte: wstrzymywanie rozwijania

`\directlua`wstępne przetwarzanie jest jednym przykładem, w którym silnik TeX wykonuje rozwijanie, ale możesz chcieć *zapobiec* aby rozwijanie było zastosowane do jednego lub więcej tokenów, które w przeciwnym razie zostałyby rozwinięte. Dla innego przykładu, LuaTeX (i wszystkie silniki TeX) wykonują proces rozwijania, podobny do tego w `\directlua`, gdy przetwarzają `\write` polecenia:

`\write file-number {⟨material⟩}`

\write nakazuje silnikowi TeX wypisać `⟨material⟩`—często zawierającą polecenia TeX/LaTeX—do pliku tekstowego (`file-number`); wszelkie rozwijalne polecenia wewnątrz `⟨material⟩` zostaną, o ile nie zostanie to zablokowane, rozwinięte przed `⟨material⟩` zapisaniem do tego pliku.

Jak można się spodziewać, silniki TeX udostępniają polecenia do tłumienia lub kontrolowania rozwijania:

* `\noexpand⟨token⟩`: zapobiega rozwinięciu pojedynczego `⟨token⟩`;
* `\unexpanded{⟨material⟩}`: zapobiega rozwinięciu wszystkich rozwijalnych poleceń (tokenów) w `⟨material⟩`. To w istocie wielotokenowa wersja `\noexpand`;
* `\protected`: prefiks dodawany do definicji makr, który zapobiega rozwinięciu tego makra w pewnych okolicznościach (takich jak podczas `\directlua`, `\write` lub `\edef`).

Mimo nazw sugerujących co innego, zarówno `\noexpand` i `\unexpanded` jesteś *komendy rozwijalne* i stanowią dobre przykłady postrzegania procesu rozwijania w silniku TeX jako wykonywania „operacji na tokenach”: tutaj operacją jest zapobieżenie rozwinięciu jednego lub więcej kolejnych tokenów (poleceń). Ponieważ `\noexpand` i `\unexpanded` oba są rozwijalnymi poleceniami, są usuwane i przetwarzane (wykonywane) podczas `\directlua`wstępnego przetwarzania, gdy konstruuje listę tokenów z twojego `⟨code⟩`.

#### \noexpand ⟨token⟩

`\noexpand ⟨token⟩` zapobiega rozwinięciu pojedynczego `⟨token⟩`. `\noexpand` w obrębie `\directlua` zostanie rozwinięty (usunięty z wejścia) i zastąpiony wynikami jego „zachowania rozwijającego”. Wynikiem rozwinięcia `\noexpand` jest utworzenie specjalnego (ukrytego) `⟨marker token⟩` który jest umieszczany przed oryginalnym `⟨token⟩` którego rozwinięcie ma zostać stłumione: ten `⟨marker token⟩` działa jak znacznik mówiący „nie rozwijaj następnego tokenu”. Ponieważ `\directlua` wykonuje pełne rozwinięcie, ponownie przetworzy wszelkie tokeny wynikające z „zachowania rozwijającego” rozwijalnego polecenia. W konsekwencji, gdy rozwinięcie `\noexpand ⟨token⟩` zostanie zakończone, LuaTeX wraca, aby odczytać wyniki i widzi sekwencję dwóch tokenów `⟨marker token⟩⟨token⟩` co powoduje, że oryginalny `⟨token⟩` przechodzi niezmieniony, bez rozwinięcia, do listy tokenów konstruowanej przez `\directlua`.

**Przykład**

Jeśli zapiszemy

```
\directlua{
   local x= "\TeX"
}
```

stronie `\TeX` makro zostaje rozwinięte do swoich składowych tokenów, co w plain TeX da następujący tekst przekazany do Lua (uwaga: Lua nie może przetworzyć tego kodu; to tylko przykład pokazujący ten proces):

`local x = "T\kern -.1667em\lower .5ex\hbox {E}\kern -.125emX"`

Jeśli *stłumimy* rozwinięcie `\TeX` makra za pomocą `\noexpand`

`\directlua{local x= "\noexpand\TeX"}`

otrzymujemy następujący kod Lua (ponownie, Lua nie może uruchomić tego kodu; to po prostu przykład pokazujący `\noexpand`):

`local x= "\TeX "`

Dzięki `\noexpand`, `\directlua` nie zostanie rozwinięte `\TeX` lecz po prostu pozwoli wartości tokenu reprezentującej `\TeX` polecenie przejść bez zmian do listy tokenów budowanej podczas pierwszego etapu `\directlua`wstępnego przetwarzania LuaTeX.

**Uwaga:** Znak spacji pojawiający się po `\TeX` jest wprowadzany przez późniejszą konwersję w LuaTeX `\TeX` wartości tokenu całkowitego z powrotem do jego reprezentacji tekstowej (w `tokenlist_to_cstring()` funkcji).

#### \unexpanded{⟨material⟩}

`\unexpanded` jest rozwijalnym poleceniem, które tłumi rozwinięcie wszystkich tokenów utworzonych z `⟨material⟩`. Jak zauważyliśmy, gdy silnik TeX wykonuje rozwijanie, każde rozwijalne polecenie jest *usuwana* usuwane z wejścia i *zastępowana* zastępowane wynikami swojego „zachowania rozwijającego”; co to właściwie oznacza dla `\unexpanded`? Zwykle podczas *pełne rozwijanie*, gdy proces rozwijania dla danego polecenia zostanie zakończony, silnik TeX przechodzi do odczytu/przetwarzania wszelkich tokenów wynikających z „zachowania rozwijającego” tego polecenia — musi dalej rozwijać wszelkie tokeny, które zostały wytworzone. Jednak `\unexpanded` *omija* wszelkie dalsze rozwijanie: oto, jak to robi.

Wewnątrz silnika TeX polecenie `\unexpanded` najpierw konwertuje znaki i polecenia w `⟨material⟩` do tymczasowej listy tokenów złożonej z *nierozwinięte* tokenów. Gdy wszystkie tokeny zostaną utworzone i zapisane w tej tymczasowej liście tokenów, `\unexpanded` polecenie powoduje, że `\directlua` na *pomija* powrót do ich odczytu i przetwarzania — mimo że \directlua wykonuje pełne rozwinięcie. Zamiast tego te *nierozwinięte* tokeny przechodzą bezpośrednio i zostają włączone do głównej listy tokenów budowanej przez `\directlua` (w `scan_toks()` funkcji). W ten sposób wszystko w `⟨material⟩` jest konwertowane do tokenów, a proces rozwijania jest pomijany dla tego zestawu tokenów. Działanie `\unexpanded{⟨material⟩}` jest podobne do użycia `\the\toks`, o czym mowa poniżej.

**Przykład**

`\unexpanded` daje wyniki w sposób podobny do `\noexpand` z wyjątkiem tego, że może zapobiegać rozwinięciu wielu tokenów; oto przykład:

```
\directlua{
   local x = "\unexpanded{\foo\bar\foobar}. But Lua can't process this code!"
}
```

co daje następujący tekst jako kod dla Lua:

`local x = "\foo \bar \foobar . But Lua can't process this code!"`

**Uwaga**: Po każdej nazwie polecenia znajdują się znaki spacji. To znowu jest konsekwencja późniejszej konwersji przez LuaTeX nierozwiniętych tokenów `\foo`, `\bar` i `\foobar` z powrotem na tekst w `tokenlist_to_cstring()` funkcji.

#### definicje makr \protected

Ta `\protected` polecenie jest prefiksem stosowanym do definicji makra, aby zapobiec rozwinięciu tego makra, gdy TeX buduje rozwiniętą listę tokenów, taką jak lista tokenów zbudowana przez `\directlua`wstępnego przetwarzania LuaTeX.

**Przykład**

Załóżmy, że definiujesz następujące makra z użyciem i bez użycia `\protected` prefiksu:

```
\def\macroA{"This unprotected macro contains a string"}
\protected\def\macroB{"This protected macro also contains a string"}
```

Jeśli użyjesz operatora konkatenacji łańcuchów Lua (`..`) do zapisania

```
\directlua{
   local x=\macroA..\macroB
}
```

`\directlua`wstępne przetwarzanie dałoby następujący kod do przekazania do Lua:

`local x="This unprotected macro contains a string"..\macroB`

`\macroA` nie jest zdefiniowane przy użyciu `\protected` więc zostaje rozwinięte, produkując pierwszą część łańcucha do konkatenacji, ale `\macroB` jest zdefiniowane przy użyciu `\protected` więc nie zostało rozwinięte.

Podczas wstępnego przetwarzania funkcja `scan_toks()` w LuaTeX utworzyła token dla `\macroA`, rozpoznała, że jest to zwykłe rozwijalne polecenie, i rozwinęła je: to rozwinięcie daje sekwencję tokenów znakowych, po jednym tokenie znakowym na każdy znak w `"This unprotected macro contains a string"`. Każdy token znakowy jest przekazywany dalej i dodawany do budowanej listy tokenów.

Gdy `scan_toks()` tworzy token dla `\macroB` zauważa, że to polecenie zostało zdefiniowane jako `\protected` i nie rozwija go: token reprezentujący `\macroB` przechodzi niezmieniony (nierozwinięty) do budowanej listy tokenów. Gdy ta lista tokenów zostanie zbudowana, następnym etapem wstępnego przetwarzania, w `tokenlist_to_cstring()` funkcji, jest konwersja wszystkich tokenów w liście tokenów z powrotem do ich reprezentacji tekstowej. Nierozwinięty token reprezentujący `\macroB` zostaje wykryty i przekonwertowany do swojej reprezentacji tekstowej, co daje tekst `\macroB` pojawiający się w kodzie przeznaczonym dla Lua. Zauważ, że Lua nie może w rzeczywistości skleić `"This unprotected macro contains a string"..\macroB` aby utworzyć końcowy łańcuch, ponieważ `\macroB` nie ma znaczenia w składni Lua, co skutkuje błędem `unexpected symbol near '\'`.

**Ciekawostki**: Pakiet `\protected` polecenie zostało wprowadzone przez $$\varepsilon\text{-}\mathrm{\TeX}$$, pierwsze ważne rozszerzenie oryginalnego oprogramowania TeX autorstwa Knutha, i jest obsługiwane przez wszystkie silniki TeX, których rodowód kodu obejmuje $$\varepsilon\text{-}\mathrm{\TeX}$$.

### Nierozwinięte tokeny: użycie \the\toks w \directlua

Życie w programowaniu nie byłoby takie samo bez tych „wyjątków”, z którymi trzeba sobie radzić, a użycie `\the` w połączeniu z `\toks` w `\directlua` jest jednym z takich wyjątków.

#### Krótki wstęp do \toks

Prymityw TeX-a `\toks` nakazuje silnikowi TeX zapisać pewne tokeny do późniejszego użycia: zamiast być przekazywane do dalszego przetwarzania, te tokeny są odkładane na bok i przechowywane w lokalizacji pamięci określonej za pomocą *rejestru tokenów*. Na przykład możemy polecić silnikowi TeX utworzyć pewne tokeny i zapisać je w lokalizacji rejestru tokenów `100` używając

`\toks100={Hi, \TeX! \hskip 5bp}`

Tutaj TeX używa rejestru tokenów `100` aby uzyskać dostęp do znanej lokalizacji w swojej pamięci: obszaru przechowywania przeznaczonego do trzymania list tokenów.

Tokeny reprezentujące wszystko pomiędzy `{` i `}` są tworzone, *ale nie są rozwijane*, i łączone w listę tokenów — podobnie do listy tokenów, którą omówiliśmy wcześniej w tym artykule. Aby ponownie użyć tych tokenów, napisalibyśmy `\the\toks100` w którym `\the` (rozwijalne polecenie) nakazuje TeX-owi pobrać zapisane tokeny i wstawić je w miejscu, w którym napisałeś `\the\toks100`. Innym sposobem myślenia o tym jest `\the\toks` sprawia, że TeX wstawia pewne tokeny w to miejsce.

Ta `\toks` polecenie *nie rozwija* żadnego z tokenów, które ma utworzyć i zapisać: po prostu konwertuje znaki i polecenia pomiędzy `{` i `}` na tokeny i je przechowuje.

#### Powrót do \directlua

W dyskusji o rozwijaniu zauważyliśmy `\directlua{⟨code⟩}` wykonuje *pełne rozwijanie* o wartości `⟨code⟩`: usuwanie wszystkich rozwijalnych poleceń i zastępowanie ich wynikiem ich „zachowania rozwijającego” — kontynuując *dalsze rozwijanie* wszelkich tokenów powstałych w wyniku początkowego rozwinięcia rozwijalnego polecenia.

`\the` jest rozwijalnym poleceniem, więc `\directlua` zostanie ono rozwinięte; jednak gdy `\the` jest używane w połączeniu z `\toks` w obrębie `\directlua`, jak w `\the\toks⟨token register⟩`, wstawione tokeny są *nie rozwijane dalej*. Rozwinięcie `\the\toks⟨token register⟩` wstrzykuje sekwencję *nierozwinięte* tokenów, zapisanych w `⟨token register⟩`, bezpośrednio do listy tokenów konstruowanej przez `\directlua`: to zachowanie omija zwykły proces pełnego rozwijania. W praktyce te tokeny przechodzą dalej, *nierozwinięte*aby zostać włączone do głównej listy tokenów budowanej przez `\directlua`—ten proces przepuszczania nierozwiniętych tokenów działa podobnie do `\unexpanded`, jak omówiono wcześniej.

**Przykład**

Załóżmy, że zdefiniujemy makro `\mymacro` jako `\def\mymacro{\TeX}`. Zawiera tylko jeden token dla `\TeX` polecenia (które jest makrem): więc mamy rozwijalne polecenie `\mymacro` które zawiera inne makro `\TeX`, które również jest rozwijalne.

Poniższy kod spowoduje, że Lua spróbuje utworzyć zmienną tekstową `x`:

```
\def\mymacro{\TeX}
\directlua{
   local x="\mymacro"
}
```

Wewnątrz \\`directlua`, token dla `\mymacro` zostaje rozwinięty, ale daje to inny rozwijalny token, `\TeX`który jest dalej rozwijany. W plain TeX te rozwinięcia dają następujący tekst przekazany do Lua:

`local x = "T\kern -.1667em\lower .5ex\hbox {E}\kern -.125emX"`

Ten kod próbuje zdefiniować łańcuch zawierający tekst reprezentujący rozwiniętą wersję `\TeX` makra. Jeśli spróbujesz uruchomić ten przykład, Lua spróbuje skonstruować ten łańcuch, ale się nie powiedzie, generując błąd:

`invalid escape sequence near ' "T\k'.`

Później w tym artykule przyjrzymy się znaczeniu „invalid escape sequence”.

Porównajmy teraz użycie `\mymacro` z umieszczeniem `\TeX` tokenu wewnątrz listy tokenów wygenerowanej przez `\toks` polecenia:

```
\toks100={\TeX}
\directlua{
   local x="\the\toks100"
}
```

przetwarzanie LuaTeX `\directlua` wygeneruje ten łańcuch tekstowy dla Lua:

`local x = "\TeX "`

Znak spacji po `\TeX` jest generowany przez proces konwersji poleceń i tokenów na tekst w LuaTeX.

**Ale zauważ**: Pakiet `\TeX` makro zostało *nie* rozwinięte do swoich składowych tokenów. `\the\toks100` spowodowało wstawienie tokenów przechowywanych w rejestrze 100, ale to wszystko: one są *nie* nie rozwijane dalej i zostają włączone do głównej listy tokenów budowanej przez `\directlua` (wewnątrz funkcji `scan_toks()`). Umieszczanie tokenów w liście tokenów utworzonej przez `\toks` to kolejny sposób zapobiegania rozwijaniu tokenów.

Jeśli uruchomimy ten przykład, on również zwróci błąd:

`invalid escape sequence near ' "\T'.`

Lua-owe sekwencje ucieczki omówimy później w artykule.

## Inne polecenia/techniki używane w rozwijaniu

W tej sekcji przyjrzymy się dodatkowym poleceniom/metodom TeX, które mogą być przydatne w sytuacjach, gdy stosowane jest rozwijanie (na przykład w `\directlua`).

### \string ⟨token⟩

`\string` jest rozwijalnym poleceniem, które konwertuje ⟨token⟩ na sekwencję tokenów znakowych, z których każdy ma kategorię kodu 12.

Na przykład, `\string\TeX` wygenerowałoby sekwencję 4 tokenów znakowych `\`, `T`, `e` i `X` gdzie każdemu znakowi przypisana jest kategoria kodu 12 (w tym początkowemu `\` znakowi).

Jeśli zapiszemy

```
\directlua{
   local x="I will use \string\newcommand"
   print(x)
}
```

stronie `\string` polecenie zostanie rozwinięte, dając sekwencję tokenów znakowych z kategorią kodu 12. Po `\string` zostaje rozwinięte, wynikowe tokeny znakowe (reprezentujące każdy znak w `\newcommand`) zostaną włączone do głównej listy tokenów konstruowanej przez `\directlua`. Gdy `\directlua` zakończy budowanie swojej głównej listy tokenów, jej składowe tokeny są konwertowane z powrotem do reprezentacji tekstowej, co daje następujący kod do przekazania interpreterowi Lua:

`local x="I will use \newcommand" print(x)`

Gdy ten kod zostanie przekazany do Lua, `print(x)` wyświetli ciąg `x` na ekranie (konsoli). Jednak byliśmy nieco sprytni i celowo użyliśmy przykładowego polecenia zaczynającego się od `\n`. Jeśli możesz uruchomić ten przykład w lokalnej instalacji TeX, zauważysz, że Lua wypisze na ekran następujący tekst:

```
   Użyję
   ewcommand
```

Aby uruchomić ten kod w Overleaf, możesz polecić LuaTeX-owi pisać bezpośrednio do `.log` pliku, używając funkcji LuaTeX Lua API `texio.write(*string*)`:

```
\directlua{
   local x="I will use \string\newcommand"
   texio.write(x)
}
```

Jeśli sprawdzisz wynikowy `.log` plik, zobaczysz, że zawiera również

```
   Użyję
   ewcommand
```

Ten nieoczekiwany wynik wynika z tego, że Lua interpretuje `\n` na początku `**\n**ewcommand` jako sekwencję ucieczki dla znaku nowej linii (kod znaku 10): zakłada, że chcesz rozpocząć nowy wiersz tekstu, który zaczyna się od `ewcommand`. Sekwencje ucieczki Lua omówimy później w tym artykule.

### \detokenize{⟨material⟩}

`\detokenize` w swoich skutkach jest wielotokenową wersją `\string` i również jest rozwijalnym poleceniem, które konwertuje wszystko w `⟨material⟩` na sekwencję tokenów znakowych z kategorią kodu 12—*z wyjątkiem* znaki spacji (wartość ASCII/Unicode 32), którym nadawana jest kategoria kodu 10. `\detokenize` wstawia także końcowy znak spacji po nazwach poleceń, które są *słowa sterujące* (np. `\foo`ale po *symbole sterujące* (np. `\#`, `\%` itp.) nie jest wstawiany żaden znak spacji.

### Przykład

Nawet jeśli makra `\foohoo`, `\foo`, `\bar` i `\foobar` nie są zdefiniowane, jeśli napiszesz to:

```
\directlua{
   local x = "\string\foohoo\detokenize{\foo\bar\foobar}"
}
```

spowoduje wygenerowanie następującego tekstu jako kodu do przekazania interpreterowi Lua

`local x = "\foohoo\foo \bar \foobar "`

Jeśli nie użyjesz `\string` i `\detokenize` i napiszesz:

`\directlua{local x = "\foohoo\foo\bar\foobar"}`

`\directlua` przetworzyłoby `\foohoo`, rozpoznałoby, że to polecenie, i spróbowało je rozwinąć; ale ponieważ `\foohoo` nie jest zdefiniowane, spowodowałoby błąd:

```
   ! Undefined control sequence.
   l.1 \directlua{local x = "\foohoo
                      \foo\bar\foobar"}
         ?
```

Ponieważ `\string` i `\detokenize` konwertują swoje argumenty na sekwencję tokenów znakowych, `\directlua`proces rozwijania ma możliwość wykrycia tokenów rozwijalnych poleceń `\foohoo`, `\foo`, `\bar`, lub `\foobar`: zostają one przekształcone w sekwencje tokenów znakowych na długo przed tym, zanim mogą uruchomić rozwijanie.

Jak wspomniano wcześniej, rozwinięcie polecenia polega na usunięciu go z wejścia i zastąpieniu wynikiem jego „zachowania rozwijającego”. Wyniki rozwinięcia (zwykle tokeny) są następnie odczytywane przez silnik TeX. Tutaj „zachowaniem rozwijającym” dla `\string` i `\detokenize` jest pochłanianie tokenów znakowych i poleceń z wejścia oraz konwertowanie ich na sekwencje tokenów znakowych, początkowo przechowywane w tymczasowej liście tokenów, którą `\directlua` następnie odczytuje. Te tokeny znakowe zostają włączone do głównej listy tokenów budowanej przez `\directlua`.

Poniższa grafika przedstawia, jak `\string` konwertuje `\foohoo` polecenie na sekwencję tokenów znakowych, tworząc tymczasową listę tokenów, która jest następnie odczytywana przez `\directlua` aby włączyć te tokeny znakowe do budowanej głównej listy tokenów.

![](/files/8a8aa83f9fb8b1a1390512ad4f53ba9afd94d8db)

Jeśli `\string` lub `\detokenize` napotykają znaki w swoim argumencie, np. `\string a` lub `\detokenize{abc}` te znaki (tutaj z kategorią kodu 11) tworzą tokeny znakowe, ale z kategorią kodu 12.

Uwagi:

Jeśli wrócimy do powyższego przykładu:

`\directlua{local x = "\string\foohoo\detokenize{\foo\bar\foobar}"}`

co daje następujący tekst jako kod do przekazania interpreterowi Lua

`local x = "\foohoo\foo \bar \foobar "`

możemy zauważyć następujące rzeczy:

* `\detokenize` wstawiło znak spacji po każdej nazwie makra, ale `\string` nie zrobiło tego.
* `\string` działa na pojedynczym tokenie.
* W łańcuchu `"\foohoo\foo \bar \foobar "` użytym do zdefiniowania `x` ponownie napotkamy mechanizm znaków ucieczki Lua (omówiony poniżej):

  * `\bar` zaczyna się od `\b` która jest sekwencją ucieczki Lua używaną do reprezentowania [znaku backspace](https://en.wikipedia.org/wiki/Backspace) (kod znaku 8);
  * polecenia `\foohoo`, `\foo` i `\foobar` wszystko zaczyna się od `\f`, sekwencja ucieczki Lua używana do reprezentowania [znaku form feed](https://en.wikipedia.org/wiki/Page_break#Form_feed) (kod znaku 12).

  Ponieważ sekwencje znaków `\b` i `\f` są używane wewnątrz ciągu utworzonego za pomocą cudzysłowów `"..."` dadzą niepożądane rezultaty, chyba że podejmie się kroki, aby temu zapobiec, używając tak zwanych w Lua *długich nawiasów* metody tworzenia ciągów znaków: temat, o którym możemy teraz mówić razem z sekwencjami ucieczki Lua.

## Czym są „sekwencje ucieczki Lua”?

Języki programowania rezerwują pewne znaki do „specjalnego użycia” jako część składni języka: w praktyce oznacza to, że znaki te mają przypisaną jakąś formę specjalnego znaczenia. Jednak bywają sytuacje, w których trzeba tymczasowo „wyłączyć” specjalne znaczenie takiego znaku, na przykład wtedy, gdy chcesz osadzić go jako część dłuższego ciągu, w którym jego standardowe zachowanie wprowadziłoby błąd składniowy. W istocie taki znak musi zostać przetworzony *bez* uruchamiając jego standardową interpretację — przemknąć niezauważenie. W tym celu programiści używają techniki zwanej *escape'owanie* w której „znak specjalny” jest reprezentowany przez tak zwaną *sekwencję ucieczki*.

Standardowym przykładem (obsługiwanym także przez Lua) jest używanie cudzysłowów wewnątrz ciągu, gdzie wewnętrzne cudzysłowy są poprzedzane sekwencją ucieczki `\\\"`:

`"Zapytani o LuaTeX odpowiedzieli: \\\"To jest niesamowity silnik TeX!\\\" Zgodziłem się."`

Język Lua udostępnia szereg mechanizmów do pracy z sekwencjami ucieczki:

* standardowe sekwencje, w tym `\n` (nowa linia), `\\r` (powrót karetki), `\\` (ukośnik odwrotny), `\\\"` (cudzysłów), `\\t` (tabulacja pozioma), `\\v` (tabulacja pionowa) oraz `\\'` (apostrof);
* `\\xXX`, gdzie `XX` jest sekwencją dokładnie dwóch cyfr szesnastkowych;
* `\\ddd`, gdzie `ddd` jest sekwencją od jednej do trzech cyfr dziesiętnych;
* w chwili pisania tego artykułu (sierpień 2019) najnowsza wersja LuaTeX, choć jeszcze niedostępna w Overleaf, korzysta z wersji 5.3 Lua, która wprowadziła obsługę sekwencji ucieczki UTF-8: `\\u{XXX}`. Ten mechanizm ucieczki służy dla znaków Unicode zakodowanych w UTF-8, gdzie `XXX` jest sekwencją jednej lub więcej cyfr szesnastkowych reprezentujących punkt kodowy znaku. Zauważ, że nawiasy otaczające `{ }` są obowiązkowe.

### Kontrolowanie sekwencji ucieczki

Tradycyjnie ciągi znaków definiuje się za pomocą cudzysłowów, jak w `"to jest ciąg znaków"`; wewnątrz takiego ciągu można używać sekwencji ucieczki: `"to jest ciąg znaków.\\nTeraz zacznę nową linię."`. Jednak Lua ma drugi i *bardzo* wygodny mechanizm definiowania ciągów znaków: tak zwane *długie nawiasy* mechanizm, w którym definiujesz ciąg, ujmując tekst w `[[` i `]]`:

`[[Jestem ciągiem znaków z długimi nawiasami]]`

W ciągu utworzonym metodą długich nawiasów mechanizm ucieczki znaków w Lua jest *wyłączony*: sekwencje ucieczki są traktowane jak zwykłe znaki. Na przykład w ciągu

`[[Jestem ciągiem znaków z długimi nawiasami\\n string]]`

stronie `\n` sekwencja ucieczki nie jest traktowana jako pojedynczy znak powrotu karetki (kod ASCII 13), lecz jako dwa zwykłe znaki: `\` po którym następuje `n`.

### Dlaczego ciągi z długimi nawiasami są tak użyteczne?

Jak później zobaczymy, LuaTeX udostępnia zestaw specjalistycznych, wbudowanych funkcji Lua, których możesz używać z `\directlua` aby kontrolować zachowanie składu LuaTeX. Wśród tych wielu funkcji jest jedna o nazwie `tex.print(*string*)` która pozwala przekazać `*string*` materiał z kodu Lua z powrotem do LuaTeX w celu składu. Bardzo prosty przykład to:

`\\directlua{tex.print("Witaj, świecie!")}`

co spowoduje, że LuaTeX złoży `Witaj, świecie!`

Ta `*string*` użyte w `tex.print(*string*)` może również zawierać tekst reprezentujący polecenia TeX i LaTeX do przetworzenia przez LuaTeX. Jednak polecenia TeX/LaTeX zaczynają się od `\` znaku, co stanowi problem w przypadku ciągów utworzonych za pomocą cudzysłowów, ponieważ Lua próbowałoby przeanalizować ciąg, wykryć początkowy `\` znak i zinterpretować go jako początek sekwencji ucieczki. Gdy Lua próbuje przetworzyć sekwencję ucieczki, zwykle kończy się to niepowodzeniem, ponieważ początkowy `\` w połączeniu z pierwszym znakiem wielu nazw poleceń TeX/LaTeX nie tworzy poprawnej sekwencji ucieczki znanej Lua. Na przykład podczas przetwarzania ciągu takiego jak `"Lubię \\LaTeX"` Lua zobaczyłoby `\\L` i zakończyłoby się błędem „invalid escape sequence”, a to jest przyczyną błędów wspomnianych powyżej.

#### Ciągi z długimi nawiasami przychodzą z pomocą!

Metoda tworzenia ciągów za pomocą długich nawiasów jest niezwykle użyteczna, ponieważ mimo że polecenia TeX/LaTeX zaczynają się od `\` znaku, metoda ciągów z długimi nawiasami wyłącza mechanizm sekwencji ucieczki Lua. Oto krótki przykład, pamiętając, że musimy zapobiec rozwijaniu makr, używając na przykład, `\protected` lub `\noexpand`.

Załóżmy, że definiujemy `\\newtest` makro w ten sposób

`**\\protected**\\def\\newtest#1{Argument: #1}`

i używamy go w `\directlua` z funkcją Lua API LuaTeX `tex.print()`:

```
\directlua{
   tex.print("\\newtest{Witaj}")
}
```

Ze względu na użycie `\protected`\\\protected `\\newtest` nie jest rozwijane, co skutkuje następującym tekstem przekazanym do Lua:

`tex.print("\\newtest {Witaj}")`

Znak spacji dodany po `\\newtest` i przed nawiasem klamrowym otwierającym (`{`) jest efektem ubocznym `\directlua`konwersji tokenów poleceń z powrotem do ich reprezentacji tekstowej przez

Ten kod jest przekazywany do Lua, które następnie wykonuje funkcję LuaTeX `tex.print()` ale pojawia się problem, który ujawnia się na sposoby zależne od używanych czcionek. W LaTeX w Overleaf zobaczysz wynik podobny do tego:

![](/files/37a89b2ec598645fc256a96e2d90fff9bd299ade)

wraz z ostrzeżeniem w pliku dziennika:

```
   Brak znaku: nie ma
   (U+000A) w czcionce [lmroman10-regular]:+tlig;!
```

W plain TeX możesz zobaczyć wynik mniej więcej taki:

![](/files/9608a7c8ce37b16db3f12f5e994503f675c7f551)

W obu przypadkach `\\newtest` makro nie jest wywoływane, a wynik nie jest taki, jak zamierzaliśmy. Błąd powoduje mechanizm znaków ucieczki Lua: w tekście `\\newtest {Witaj}` nazwa makra zaczyna się od `\n` który Lua rozpoznaje jako sekwencję ucieczki dla znaku nowej linii, więc zastępuje `\n` go znakiem ASCII 10, czyli szesnastkowo 0A. W komunikacie błędu LaTeX, `U+000A` to sposób zapisu wartości Unicode za pomocą 4 cyfr szesnastkowych.

Ponieważ `\n` zostaje zamienione na znak nowej linii, LuaTeX nie widzi wywołania makra, lecz uznaje, że ma złożyć jakiś tekst zaczynający się od kodu znaku ASCII 10:

`⟨ASCII 10⟩ewtest {Witaj}`

W zależności od użytej czcionki LuaTeX może, ale nie musi, być w stanie złożyć `⟨ASCII 10⟩` znak, ale pozostały tekst jest wypisywany bez zmian, a `{` i `}` jest traktowany jako grupa i nie jest drukowany.

Plain TeX daje inny wynik, ponieważ domyślna czcionka to Computer Modern Roman, która ma dziwne kodowanie, skutkujące złożeniem wielkiej Omegi, gdy napotkany zostanie kod znaku 10.

Aby zapobiec tym problemom, musimy używać ciągów z długimi nawiasami, by uniemożliwić zastosowanie mechanizmu ucieczki Lua. Poprawny wynik uzyskuje się za pomocą

`\\directlua{tex.print([[\\newtest{Hello}]])}`

co daje wynik pokazany na poniższym zrzucie ekranu:

![](/files/173f834c85a223db072f39ad50f82e2d7e297e2e)

### Rozwijanie i niewykonywanie nierozwijalnych poleceń

Rozważając rozwijanie, zauważyliśmy, że jest to proces, w którym silnik TeX *usuwa* rozwijalne polecenie (token) z bieżącego wejścia i *zastępuje* je wynikiem/wynikami wytworzonymi przez to rozwijalne polecenie. Ponieważ \\\directlua wykonuje *wyłącznie rozwijającego* nie posuwa przetwarzania LuaTeX dalej. Gdy rozwijalne polecenie zostanie odczytane i w pełni rozwinięte, wyniki tego rozwinięcia — które często obejmują nierozwijalne polecenia (tokeny) — zostaną włączone do budowanej listy tokenów, gotowej do ponownej konwersji na tekst i przekazania do Lua. *nie* Działa tu ważna zasada: podczas

czynności mających na celu utworzenie listy tokenów silniki TeX, w tym LuaTeX, *wyłącznie rozwijającego* nie wykonują *żadnych nierozwijalnych poleceń pierwotnych, wbudowanych poleceń TeX.* 任何

W przypadku `\directlua{⟨code⟩}`, jeśli w pełni rozwinięta wersja twojego `⟨code⟩` zawiera albo zawiera nierozwijalne polecenia TeX/LaTeX, to one *zostaną przekazane do Lua* (w postaci tekstu).

#### Przykład

Oto przykład pokazujący, że nierozwijalne prymitywy nie są wykonywane podczas przetwarzania wyłącznie rozwijającego (na przykład wewnątrz `\directlua`). Załóżmy, że definiujemy makro `\\setcountreg` w ten sposób:

`\\def\\setcountreg#1#2{\\count#1=#2\\relax}`

**Uwaga**: Używamy `\\relax` po parametrze `#2` aby zapobiec „przeskoczeniu” przez LuaTeX podczas skanowania wejścia w poszukiwaniu wartości liczbowej (argumentu) pasującej do parametru `#2`.

Jeśli, poza `\directlua`, później uruchomimy makro w ten sposób

```
   \\setcountreg{100}{50}
   Wartość w rejestrze licznikowym 100 wynosi \\the\\count100.
```

wyświetliłoby

`Wartość w rejestrze licznikowym 100 wynosi 50.`

W tym kontekście każdy silnik TeX przetworzyłby makro `\\setcountreg`—rozwinąłby makro, określił argumenty i kontynuował odczyt *oraz wykonywanie* (wykonywanie) poleceń zawartych w tekście zastępczym makra (definicji). Rezultatem jest przypisanie `50` jako wartości przechowywanej w rejestrze `\\count100`.

Jednak gdy silnik TeX wykonuje *wyłącznie rozwijającego* czynności, jak ma to miejsce w `\directlua`, to *nie wykona* nierozwijalnych poleceń zawartych w definicji makra.

Jeśli zapiszemy

```
\\def\\setcountreg#1#2{\\count#1=#2\\relax}
\directlua{
   local x = [[\\setcountreg{100}{50}]]
}
```

wytwarza następujący tekst jako kod dla Lua:

`local x = [[\\count 100=50\\relax ]]`

Wygenerowany powyżej kod Lua pokazuje, że wewnątrz `\directlua` stronie `\\setcountreg` zostało rozwinięte, jego argumenty zostały rozpoznane i podstawione do odpowiedniego parametru (`#1` i `#2`) ale nie idzie dalej: nierozwijalne prymitywne polecenie TeX `\count` została *nie jest wykonywane* podczas `\directlua`przetwarzania rozwijającego przez

Jednak LuaTeX wykona kod TeX, jeśli przekażemy wynikowy ciąg `x` *z powrotem do LuaTeX* za pomocą `tex.print(x)` w ten sposób

```
\\count100=50 % ustaw \\count100 na początkową wartość 50
\\def\\setcountreg#1#2{\\count#1=#2\\relax}
\directlua{
   local x = [[\\setcountreg{100}{250}]]
   tex.print(x)
}
Wartość przechowywana w rejestrze licznikowym 100 wynosi \\the\\count100.
```

Po `\directlua` zakończeniu, wynik byłby

`Wartość przechowywana w rejestrze licznikowym 100 wynosi 250.`

co pokazuje, że rejestr licznikowy `100` zawiera teraz wartość `250`.

Kod Lua wygenerowany z powyższego przykładu to

`local x = [[\\count 100=250\\relax ]] tex.print(x)`

Ten kod definiuje `x` jako ciąg utworzony metodą długich nawiasów, która służy do unikania błędów spowodowanych nieprawidłowymi sekwencjami ucieczki. Gdybyśmy użyli cudzysłowów `"..."` do zdefiniowania x, kombinacja znaków `\\c` na początku `\count` spowodowałaby błąd: `invalid escape sequence near ' "\\c'`.

Wywołanie Lua API LuaTeX `tex.print(x)` powoduje, że LuaTeX wykonuje sekwencję kodu TeX `\\count 100=250\\relax` i `\\count100` otrzymuje wartość `250` jak widać w złożonym wyniku:

`Wartość przechowywana w rejestrze licznikowym 100 wynosi 250.`

#### Uwaga: makra i Lua API LuaTeX

W powyższym przykładzie widzieliśmy, że podczas `\directlua`wstępnego przetwarzania (rozwijania) przez LuaTeX nie wykonano kodu `\\count 100=250`, który zawiera `nierozwijalnych` prymitywne polecenie `\count`: aby uruchomić (wykonać) ten kod, musieliśmy *przekazać go z powrotem do LuaTeX* za pomocą `tex.print()`.

`\directlua` to tylko jeden z przypadków, gdy LuaTeX wykonuje przetwarzanie wyłącznie rozwijające, aby zbudować listę tokenów. Istnieją inne polecenia, które wykonują podobne przetwarzanie rozwijające i generowanie listy tokenów, takie jak `\write` i `\edef`: te polecenia również nie wykonują nierozwijalnych prymitywów podczas swojego przetwarzania rozwijającego. Ogólna zasada jest taka, że silniki TeX nie wykonują nierozwijalnych prymitywów podczas budowania listy tokenów w ramach czynności wyłącznie rozwijającego przetwarzania.

**Przepisanie naszego makra tak, aby korzystało z Lua API LuaTeX**

Możemy przepisać `\\setcountreg` makro, używając funkcji Lua API LuaTeX o nazwie `tex.setcount()`, unikając w ten sposób poleceń TeX do zmiany wartości przechowywanej w rejestrze licznikowym `100`:

```
   \\def\\setcount#1#2{\\directlua{tex.setcount(#1,#2)}}
   \\count100=50
   rejestr licznikowy 100 zawiera \\the\\count100\\par
   \\setcount{100}{250}
   rejestr licznikowy 100 teraz zawiera \\the\\count100\\par
```

Ten kod złoży:

```
rejestr licznikowy 100 zawiera 50
rejestr licznikowy 100 teraz zawiera 250
```

Tutaj używamy `tex.setcount()`, jednej z wielu funkcji Lua API LuaTeX, aby *bezpośrednio uzyskać dostęp do* wewnętrznego obszaru przechowywania danych LuaTeX, aby umieścić wartość `250` w lokalizacji pamięci reprezentującej rejestr licznikowy `100`. W efekcie *obejśliśmy* standardowe metody przetwarzania wejścia przez silnik TeX w LuaTeX: odczyt wejścia, tworzenie tokenów i wykonywanie prymitywnych poleceń TeX. Jest jednak ostrzeżenie: korzystanie z funkcji Lua API LuaTeX sprawia, że czynność wyłącznie rozwijającego przetwarzania *może prowadzić do efektów ubocznych*: zmian wartości przechowywanych wewnątrz silnika TeX, które nie byłyby możliwe przy użyciu samych poleceń TeX/LaTeX.

**Przykład: nieoczekiwane efekty uboczne**

Oto przykład pokazujący *nieoczekiwane* efekty uboczne, które mogą pojawić się w makrach używających `\directlua`. Załóżmy, że zapisujemy następujący kod:

```
\\def\\dochange{\\directlua{tex.setcount(999,12345)}}
\\edef\\careful{\\dochange}
\\the\\count999
```

Uruchomienie tego kodu złoży: `12345`!

Jak to możliwe? Nie *jawnie* wywołaliśmy żadnego kodu ani makr, aby umieścić tę wartość w rejestrze licznikowym `999`. A może jednak?

Zdefiniowaliśmy `\\dochange` przez `\directlua` polecenie, które używa `tex.setcount()` aby przechować wartość `12345` w rejestrze licznikowym `999`: w kodzie TeX jest to odpowiednik `\\count999=12345`. Następnie użyliśmy standardowego prymitywu TeX `\edef` aby zdefiniować makro `\\careful`—to właśnie użycie `\edef` powoduje ten nieoczekiwany efekt uboczny.

`\edef` w pełni rozwija swój argument: tutaj wykrywa rozwijalne makro `\\dochange` i je rozwija. Następnie `\\dochange` makro używa rozwijalnego polecenia `\directlua` które zawiera wywołanie Lua API; więc rozwinięcie `\\dochange` skutkuje rozwinięciem `\directlua` i to powoduje, że `tex.setcount()` zostało wywołane, co zmienia wartość w rejestrze licznikowym `999`.

Jeśli przedefiniujemy `\\dochange` tak, aby używało poleceń TeX:

```
   Przed: rejestr licznikowy 999 zawiera \\the\\count999.\\par
   \\def\\dochange{\\count999=12345\\relax}
   \\edef\\careful{\\dochange}
   Po: rejestr licznikowy 999 zawiera \\the\\count999.\\par
```

uruchomienie tego kodu złoży

```
Przed: rejestr licznikowy 999 zawiera 0.
Po: rejestr licznikowy 999 zawiera 0.
```

Wyraźnie widać, że nie było to wpływu na `\\count999`. Gdy `\edef` definiuje `\\careful` rozwija je `\\dochange` lecz to rozwinięcie wytwarza jedynie nierozwijalne prymitywy TeX: są one *nie jest wykonywane* lecz po prostu *zapisane* w liście tokenów tworzącej definicję `\\careful`.

Dla porządku ta sama zasada wyjaśnia, dlaczego to daje wynik złożony:

```
\\def\\dochange{\\directlua{tex.print("Witaj")}}
\\edef\\careful{\\dochange}
```

## Krótki wstęp do Lua API LuaTeX

Jak już widzieliśmy, `\directlua` umożliwia nie tylko pisanie zwykłego kodu Lua lub mieszaniny kodu Lua i TeX/LaTeX, ale także zapewnia dostęp do zestawu dodatkowych funkcji Lua (specyficznych dla LuaTeX), których możesz używać (wywoływać), aby komunikować się z wewnętrznymi mechanizmami oprogramowania składu LuaTeX lub bezpośrednio je kontrolować. W tym artykule użyliśmy kilku funkcji Lua, `tex.print()`, `texio.write()`, `tex.setcount()` a te, wraz z *wieloma* innymi, są opisane w [Podręczniku referencyjnym LuaTeX](http://www.pragma-ade.com/general/manuals/luatex.pdf) w którym grupy powiązanych funkcji określane są jako *biblioteki*.

Możesz traktować te funkcje Lua jako Lua API LuaTeX (**Skopiowany**aplikacja **P**rogramowanie **I**interfejs) które dostarczają narzędzia do tworzenia zaawansowanych rozwiązań składu i inżynierii dokumentów poprzez sterowanie zachowaniem składu LuaTeX przy użyciu Lua jako sterownika.

Jak wspomniano, LuaTeX organizuje swoje API w zestaw funkcji, które nazywa bibliotekami: grupy funkcji powiązane wspólnym celem lub działaniem. Każdy zestaw funkcji ma zapewniać dostęp do określonego aspektu wewnętrznych procesów LuaTeX, struktur danych, przechowywania danych i algorytmów składu. Wewnętrznie LuaTeX składa się z wielu komponentów: bibliotek/narzędzi programowych (głównie napisanych w C), które obejmują nie tylko sam silnik TeX, ale także inne podsystemy, w tym Lua, MetaPost, Kpathsea, FontForge, libpng i zlib. Biblioteki te są zintegrowane, aby budować możliwości i funkcje wykonywalnego oprogramowania LuaTeX, a to właśnie przez Lua API użytkownicy uzyskują dostęp do funkcjonalności LuaTeX wynikającej z integracji i współdziałania tych wielu komponentów programowych.

## Kilka przykładów i pułapek

W tej sekcji przedstawiamy kilka dalszych przykładów wykorzystujących tematy, pojęcia i wyjaśnienia przedstawione w tym artykule.

### Użycie znaku tyldy (\~)

Język Lua używa `~` znaku (zwanego tyldą) jako części swojej składni, w tym składni testu „nierówne”; na przykład aby sprawdzić, czy zmienna `x` jest różna od `4` moglibyśmy napisać:

```
   local x=3
   if x ~= 4 then
   print("x nie jest równe 4")
   end
```

Jeśli spróbujemy uruchomić ten prosty kod Lua za pomocą `\directlua`:

```
\directlua{
   local x=3
   if x ~= 4 then
   print("x nie jest równe 4")
   end
}
```

otrzymamy błąd:

`[\directlua]:1: oczekiwano 'then' w pobliżu '\'.`

To dziwne, ponieważ nasz kod jest poprawny: użyliśmy `'then'` i w naszym kodzie nie ma `\` znaku, więc co poszło nie tak? Aby to zrozumieć, musimy pamiętać, że dla TeX/LaTeX, `~` jest zwykle zdefiniowany jako „znak specjalny” z kodem kategorii 13: tzw. aktywne znaki, które są mini-makrami i dlatego podlegają rozwinięciu. Gdy `\directlua` wykrywa `~` znak *jest on rozwijany przez* usuwane z wejścia i *zastępując ją* usunięcie go `~` i zastąpienie wynikiem jego rozwinięcia. Przy użyciu zwykłego TeX, wynikowy tekst (kod), który LuaTeX generuje i przekazuje do interpretera Lua, w rzeczywistości nie zawiera znaku

`local x=3 if x \penalty \@M \ = 4 then print("x nie jest równe 4") end`

Ta `~` znak został *usuwana* i *rozwinięty* w swoje składowe polecenia — powyższy kod Lua wynika ze zwykłotekstowej definicji aktywnego znaku `~`. Teraz widzimy, dlaczego Lua odpowiada błędem `'then' expected near '\'`—zaczyna analizować ten kod, ale napotyka słowo `\penalty` które dla Lua nic nie znaczy i generuje błąd składni.

Aby to naprawić,  `~` znak musi mieć bezpieczny kod kategorii w momencie, gdy `\directlua` przetwarza twój kod; na przykład możemy tymczasowo zmienić kod kategorii `~` na 11 (litera), zamykając kod w grupie:

```
\begingroup
\catcode`\~=11
\directlua{
   local x=3
   if x ~= 4 then
   print("x nie jest równe 4")
   end
}
\endgroup
```

Ten kod działa zgodnie z oczekiwaniami i `x nie jest równe 4` jest wypisywane w konsoli. Istnieją też inne opcje: możemy użyć rozwijalnych poleceń `\noexpand` lub `\string`.

#### Używanie \string⟨token⟩

Możemy zastosować `\string` do jednoliterowego `⟨token⟩` `~` który ma kod kategorii 13 (aktywny znak); `\string` konwertuje `~` znaku, aby wygenerować token znaku, który ma kod kategorii 12. Jeśli zrobimy

```
\directlua{
   local x=3
   if x \string~= 4 then
   print("x nie jest równe 4")
   end
}
```

generuje wymagany przez nas kod Lua:

`local x=3 if x ~= 4 then tex.print("x nie jest równe 4") end`

#### Używanie \noexpand⟨token⟩

Możemy użyć `\noexpand~` aby wstrzymać rozwinięcie aktywnego znaku `~`

```
\directlua{
   local x=3
   if x \noexpand~= 4 then
   print("x nie jest równe 4")
   end
}
```

Nierozwinięty `~` token przechodzi do budowanej w `\directlua` listy tokenów i zostanie przekształcony z powrotem w tekst, co da działający kod Lua.

### Używanie znaku \#

W języku Lua `#` znak może być użyty do znalezienia długości tabeli. Jednak jeśli spróbujemy następującego kodu

```
\directlua{
   local tbl = {}
   tbl[1] = "Hello"
   tbl[2] = "World"
   tex.print("Długość tabeli wynosi "..#tbl)
}
```

moglibyśmy oczekiwać, że LuaTeX złoży

`Długość tabeli wynosi 2`

ale generuje błąd:

`\directlua]:1: próba uzyskania długości wartości liczbowej`

Ten błąd jest wywoływany, ponieważ znak `#` zwykle ma kod kategorii 6 (parametr makra) — znak `#` ma dwa zastosowania w TeX/LaTeX: do oznaczania parametrów makr (`#1`, `#2`… `#9`) oraz tekstu zastępczego w szablonach wyrównania (dla `\halign` i `\valign`).

Gdy `\directlua` generuje tokeny do budowania swojej listy tokenów, widzi znak `#` o kodzie kategorii 6 i tworzy odpowiedni token znaku, aby go reprezentować. Gdy przychodzi czas na przekształcenie końcowej listy tokenów z powrotem do postaci tekstowej, token znaku # (o kodzie kategorii 6) jest traktowany w szczególny sposób: jest wypisywany jako *dwa kolejne znaki*: `##`, co skutkuje przekazaniem do Lua następującego kodu:

`local tbl = {} tbl[1] = "Hello" tbl[2] = "World" print(##tbl)`

Podczas konwersji do kodu Lua oryginalny `#` został podwojony i to generuje błąd:

`\directlua]:1: próba uzyskania długości wartości liczbowej`

Problem ten wynika z składni TeX-a, która używa podwójnego znaku hash `##` do reprezentowania lub generowania pojedynczego `#` tokena; ta składnia jest używana w makrach definiujących inne makra przyjmujące parametry albo w makrach używanych do tworzenia szablonów dla `\halign` lub `\valign` poleceń konstruowania tabel. To dość mylące, więc przyjrzyjmy się przykładowi.

#### Przykład

Załóżmy, że definiujemy makro `\mymacro` które przyjmuje jeden parametr, `#1`, ale definiuje też drugie makro `\foo` które samo przyjmuje jeden parametr. Aby rozróżnić parametr `#1` używany z `\mymacro` i potrzebę zdefiniowania `\foo` tak, aby używało własnego parametru `#1` składnia TeX-a wymaga, aby użyć `##1` wewnątrz `\mymacro` aby reprezentować parametr używany z `\foo`:

`\def\mymacro#1{\def\foo##1{#1 Hello##1}}`

Gdybyś zapisał `\mymacro{Hey!}` zdefiniowałoby to makro `\foo` jako

`\def\foo#1{Hey! Hello#1}`

Zauważ, że `\mymacro`parametr `#1` (`Hey!`) został włączony do definicji `\foo` i sekwencja `##1` została przekształcona w `#1` w definicji `\foo`. Możemy więc użyć `\foo` w ten sposób:

`\foo{, World!}`

że zostanie złożone jako `Hey! Hello, World!`

Możemy rozwiązać `\directlua`traktowanie przez `#` znaku, tymczasowo zmieniając jego kod kategorii przed przetworzeniem kodu przez LuaTeX. Na przykład:

```
\begingroup
   \catcode`\#=11
   \directlua{
   local tbl = {}
   tbl[1] = "Hello"
   tbl[2] = "World"
   tex.print("Długość tabeli wynosi "..#tbl)
}
\endgroup
```

To generuje kod Lua

```
local tbl = {} tbl[1] = "Hello" tbl[2] = "World" tex.print("Długość tabeli wynosi "..#tbl)
```

co złoży oczekiwany przez nas wynik:

`Długość tabeli wynosi 2`

### Używanie znaku %

W TeX/LaTeX, znak `%` zazwyczaj służy do włączania jednolinijkowych komentarzy w kodzie: aby sygnalizować silnikowi TeX-a, że powinien zignorować wszystko od tego miejsca do końca linii, na której `%` jest zapisany. Jednak w języku Lua znak `%` jest używany w kilku bardzo przydatnych funkcjach przetwarzania łańcuchów, takich jak `string.format(...)`, `string.gmatch(...)`, oraz `string.gsub(...)` w których znak `%` odgrywa ważną rolę jako część składni tych funkcji.

Używany z TeX/LaTeX, `%` działa jako znak komentarza, ponieważ ma przypisany kod kategorii 14. Aby zachowywał się jak zwykły znak i wyłączyć jego zwykłe zachowanie w TeX/LaTeX, musimy zmienić jego kod kategorii na bezpieczny, na przykład 12. Poniższy `\directlua` przykład korzysta z kilku technik omówionych wcześniej w artykule, wraz z jedną, której jeszcze nie wspomnieliśmy: ``\catcode`\^^M=12``, co pozwala nam używać komentarzy Lua w naszym kodzie; zostanie to omówione poniżej.

#### Przykład

Poniższe przykłady pochodzą z [lua-users.org](http://lua-users.org/wiki/StringLibraryTutorial), odpowiednio zmodyfikowane do użycia w `\directlua`.

```
\documentclass{article}
\begin{document}
\begingroup
\ttfamily
\let\\\relax
\catcode`\^^M=12 %<---zagłębiamy się w to dalej poniżej!
\catcode`\%=12
\directlua{
   local str -- zadeklaruj lokalną zmienną do przechowania wyniku

   tex.print("Użycie string.format():".."\\par")

   str=string.format("%s %q", "Witaj", "użytkowniku Lua!") -- łańcuch i łańcuch w cudzysłowie
   tex.print(str.."\\par")
   str = string.format("%c%c%c", 76, 117, 97) -- znak
   tex.print(str.."\\par")
   str=string.format("%e, %E", math.pi, math.pi) -- wykładnik
   tex.print(str.."\\par")
   str=string.format("%f", math.pi) -- liczba zmiennoprzecinkowa
   tex.print(str.."\\par")
   str=string.format("%g, %g", math.pi, 10^9) -- liczba zmiennoprzecinkowa lub wykładnik
   tex.print(str.."\\par")
   str = string.format("%o, %x, %X", 99, 125, 125)  -- ósemkowy, szesnastkowy, szesnastkowy
   tex.print(str.."\\par")

   tex.print("\\vskip3mm".."Użycie string.gmatch():".."\\par")

   for word in string.gmatch("Witaj użytkowniku TeX", "%a+") do
      tex.print(word.."\\par")
   end

   tex.print("\\vskip3mm".."Użycie string.gsub():".."\\par")
   str=string.gsub("banana", "(an)", "%1-") -- wychwytuje wszelkie wystąpienia „an” i zastępuje
   tex.print(str.."\\par")
}
\endgroup
\end{document}
```

Poniższy zrzut ekranu pokazuje wynik składu powyższego kodu:

![Używanie funkcji łańcuchów Lua w \directlua](/files/0bb903c7f596add2a45f4192ff9491e1d695120c)

## Dlaczego kod Lua jest pokazany w jednej linii?

Jak mogłeś zauważyć, wszystkie fragmenty kodu Lua (wygenerowane) pokazane w przykładach tego artykułu są prezentowane jako pojedyncza linia tekstu: podziały wiersza pierwotnie obecne w `\directlua` fragmentach kodu nie są zachowywane. Dlaczego? Dzieje się tak, ponieważ podziały wiersza w kodzie Lua zostały *usunięte* podczas wstępnego przetwarzania przez LuaTeX w `\directlua`, przez co kod Lua staje się jedną długą linią tekstu. To zachowanie wynika ze sposobu, w jaki silniki TeX-a obsługują znaki końca wiersza — oznaczane przez `\\r` (carriage return) i `\n` (line feed) w literaturze programistycznej. Dlaczego w ogóle musimy przejmować się tymi drobnymi szczegółami, stanie się jasne, gdy omówimy używanie mechanizmów Lua do komentowania fragmentów kodu.

Gdy oprogramowanie zapisuje plik tekstowy, każdy pojedynczy wiersz tekstu jest zakończony tak zwanymi znakami „nowej linii” — rzeczywisty znak(i) nowej linii zależy od aplikacji i systemu operacyjnego używanego do zapisania tego pliku. Wikipedia ma [interesujący artykuł](https://en.wikipedia.org/wiki/Newline) który bada historię/ewolucję znaków nowej linii używanych dziś.

W każdym pliku tekstowym poszczególne wiersze mogą być zakończone różnymi kombinacjami znaków, określanych jako carriage return (ASCII/Unicode znak 13) i/lub line feed (ASCII/Unicode znak 10), oznaczanych odpowiednio przez `\\r` i `\n` Z tego powodu silniki TeX-a są zaprojektowane tak, aby były niezależne od platformy, potrzebują metody obejścia nieodłącznie zależnej od platformy natury zakończeń wierszy używanych w plikach tekstowych. Oczywiście silniki TeX-a mają wbudowaną (ale konfigurowalną) metodę radzenia sobie ze znakami końca wiersza.

### Jak silniki TeX-a radzą sobie z zakończeniami wierszy

Gdy LuaTeX przetwarza `\directlua{⟨code⟩}` odczytuje tekst zawarty w twoim `⟨code⟩` i stosuje standardowe metody silnika TeX do przetwarzania wszelkich zakończeń wierszy zawartych w twoim `⟨code⟩`. Domyślnie te standardowe metody TeX-a powodują, że wszystkie znaki końca wiersza (carriage returns i line feeds) są usuwane i zastępowane znakami spacji. Mówimy „domyślnie”, ponieważ sposób obsługi znaków końca wiersza przez silnik TeX można zmienić za pomocą konfigurowalnego przez użytkownika parametru o nazwie `\endlinechar`. Tutaj przedstawimy krótki przegląd w dwóch krokach, ale więcej szczegółów znajdziesz w artykule Overleaf [Wprowadzenie do \endlinechar: jak TeX odczytuje wiersze z plików tekstowych](/latex/pl/artykuly-szczegolowe/05-an-introduction-to-endlinechar-how-tex-reads-lines-from-text-files.md).

#### Krok 1: TeX wstawia własny znak końca wiersza

Po odczytaniu wiersza tekstu z pliku wejściowego, silniki TeX natychmiast usuwają wszelkie `\\r` lub `\n` znaki z końca tego wiersza. Następnie silniki TeX *wstawiają* (dodają z powrotem) własny znak końca wiersza na końcu tego wiersza. Ten znak jest określany przez wartość konfigurowalnego parametru TeX o nazwie `\endlinechar` i właśnie dzięki temu mechanizmowi silniki TeX mogą przetwarzać znaki końca wiersza w sposób niezależny od platformy: wybierają i ustawiają znak końca wiersza, niezależnie od tego, co pierwotnie znajdowało się w pliku wejściowym.

Zazwyczaj silniki TeX używają ustawienia

`\endlinechar=13`

które odpowiada znakowi carriage return (`\\r`). Jednak użytkownicy mogą zawsze przypisać innemu kodowi znaku wartość `\endlinechar`—co zobaczymy później w tym artykule.

W konsekwencji wszelkie znaki końca wiersza zawarte w twoim `⟨code⟩` do przetworzenia przez `\directlua{⟨code⟩}` są usuwane i zastępowane pojedynczym znakiem określonym przez sam silnik TeX. Zauważ, że silniki TeX wykonują to przetwarzanie końca wiersza natychmiast po odczytaniu nowego wiersza tekstu z pliku i *zanim* przetwarzaniu jakichkolwiek znaków w tym wierszu (w celu generowania tokenów). To jednak nie koniec: to, co silnik TeX *nie* z tymi znakami końca wiersza (które wstawił), wyjaśnia, dlaczego kod Lua staje się jedną pojedynczą linią.

#### Krok 2: TeX przekształca swój znak końca wiersza w spację

Oprócz wstawiania własnego znaku końca wiersza, określanego przez wartość `\endlinechar`, silniki TeX używają także kodu kategorii 5 dla znaków, które powinny być *traktowane jako* znak końca wiersza. To sprawia, że silniki TeX zazwyczaj pracują z:

1. znakiem końca wiersza określonym przez `\endlinechar`;
2. tym samym znakiem *zwykle* przypisany kod kategorii 5.

To, co TeX robi z tym znakiem końca wiersza, wyjaśnia nasze zakłopotanie związane z pojedynczymi liniami kodu Lua. Gdy silnik TeX przetwarza linię wejścia, ostatecznie wykryje ostatni znak w tej linii: znak określony przez `\endlinechar`. Zazwyczaj ten znak ma kod kategorii 5, co powoduje, że TeX *zastępuje go* znakiem spacji: tzn. na końcach wierszy TeX w efekcie usuwa swój znak końca wiersza i zastępuje go spacją. Na marginesie, silniki TeX używają także znaków z kodem kategorii 5 do wykrywania pustych wierszy i rozpoczynania nowego akapitu, ale nie będziemy się tym tutaj zajmować.

Oczywiście, w TeX można stosować różnego rodzaju specjalne sztuczki programowania makr, resetując `\endlinechar` na inny znak, i/lub nadając znakowi przypisanemu do `\endlinechar` wartość kodu kategorii według własnego wyboru.

Jeśli chcesz zapobiec temu, by kod Lua stawał się jedną pojedynczą linią tekstu, możesz albo (tymczasowo) zmienić wartość przypisaną do `\endlinechar` albo zmienić kod kategorii standardowego zakończenia wiersza `\\r`.

### Dziwna notacja TeX-a ^^

W następujących sekcjach napotkamy niezwykłą notację `^^` TeX-a, znaną jako „rozszerzony mechanizm znaków”. Została zaprojektowana przez Knutha jako sposób ułatwiający wpisywanie „znaków sterujących”, takich jak zakończenia wierszy, tabulatory i tym podobne. Na przykład:

* `^^J` reprezentuje kod znaku 10 (`\n`, line feed);
* `^^M` reprezentuje kod znaku 13 (`\\r`, carriage return).

Sekwencje znaków takie jak `^^M` są konwertowane na odpowiadające im kody znaków na wczesnym etapie procesu skanowania wejścia TeX-a, gdy TeX odczytuje znaki wejściowe, aby wygenerować odpowiadające im tokeny znaków.

### Zmiana znaku przypisanego do \endlinechar

Pamiętając, że nadal musimy zapobiec rozwinięciu znaku `~` , możemy zapisać

```
\begingroup
\endlinechar=10 % Zmień znak końca wiersza na \n
\directlua{
   local x=3
   if x \noexpand~= 4 then
   print("x nie jest równe 4")
   end
}% nie chcemy, aby \n pojawiło się tutaj
\endgroup% ani \n tutaj
```

Powyższe ustawienie dla `\endlinechar` sprawia, że LuaTeX dopisuje kod znaku 10 (`\n`, line feed) do końca każdego odczytywanego wiersza. Robimy tak, ponieważ `\n` (line feed) zwykle ma kod kategorii 12, co możesz sprawdzić, wpisując ``\the\catcode`\^^J``. Ponieważ `\n` nie ma kodu kategorii 5, LuaTeX nie przekonwertuje go na znak spacji, więc pozostanie on na końcu każdego wiersza odczytanego przez LuaTeX. Skutkuje to tym, że znak o kodzie 10 pozostaje na końcu każdego wiersza, dzięki czemu trafia do listy tokenów budowanej przez `\directlua` a następnie pojawia się ponownie w kodzie Lua, gdy lista tokenów zostaje przekształcona z powrotem w tekst. Po powyższej zmianie kod Lua jest przesyłany do interpretera Lua jako następująca sekwencja znaków:

**\n**local x=3\*\*\n**if x \~= 4 then**\n**print("x nie jest równe 4")**\n**end**\n\*\*

gdzie **\n** notacja ma reprezentować kod znaku 10 *nie* jakieś nieznane makro `\n`. Teraz interpreter Lua zobaczy w kodzie podziały wierszy, dokładnie tak, jak był on pierwotnie zapisany w `\directlua` polecenia:

```
   local x=3
   if x ~= 4 then
   print("x nie jest równe 4")
   end
```

Przy okazji zwróć uwagę, że pierwszy znak w łańcuchu kodu Lua to `\n` (przed słowem kluczowym `lokalną` ). To `\n` wynika z linii

`\directlua{`

ponieważ zaraz po otwierającym `{` występuje podział wiersza i to również jest zachowane. Aby temu zapobiec, możesz napisać

`\directlua{%`

### Zmiana kodu kategorii \r

Aby zachować podziały wierszy w naszym kodzie Lua, możemy również zmienić kod kategorii `\\r` na coś innego niż 5, tak aby `\\r` nie było już rozpoznawane (traktowane) jako znak końca wiersza. Dzięki tej technice LuaTeX nadal używa `\endlinechar=13` i będzie nadal dodawał `\\r` do końca każdego wiersza; jednak ponieważ `\\r` nie ma już kodu kategorii 5, LuaTeX nie rozpozna `\\r` znaku jako końca wiersza: nie przekonwertuje go na spację i przekaże go dalej bez zmian, tak aby pojawił się w kodzie Lua.

Pamiętając, że nadal musimy zapobiec rozwinięciu znaku `~` , możemy zapisać

```
\begingroup
\catcode`\^^M=12 % zmień kod kategorii \r na 12
\directlua{
   local x=3
   if x \noexpand~= 4 then
   print("x nie jest równe 4")
   end
}
\endgroup
```

W tym przypadku kod Lua jest przesyłany do interpretera Lua jako:

**\\\r**local x=3\*\*\r**if x \~= 4 then**\\\r**print("x nie jest równe 4")**\\\r**end**\r\*\*

gdzie `\\r` notacja ma reprezentować kod znaku 13, a nie jakieś nieznane makro `\\r`. Podobnie jak w `\endlinechar` przykładzie, interpreter Lua zobaczy teraz podziały wierszy w kodzie, dokładnie tak, jak był on pierwotnie zapisany w `\directlua` polecenia:

```
   local x=3
   if x ~= 4 then
   print("x nie jest równe 4")
   end
```

Przy okazji zwróć ponownie uwagę, że pierwszy znak w łańcuchu kodu Lua to `\\r` (przed słowem kluczowym local): to również wynika z linii

`\directlua{`

#### Dlaczego \r używał kodu kategorii 12, a nie 11?

Odpowiedź wynika z ryzyka przypadkowego wprowadzenia błędów wywołanych przez `\\r` (o kodzie kategorii 11) dodawany na końcu poleceń TeX/LaTeX odczytanych z naszego pliku wejściowego. Weźmy ten przykład:

```
\begingroup
\catcode`\^^M=11 % zmień kod kategorii \r na 11
\directlua{
   local x=3
   if x \noexpand~= 4 then
   print("x nie jest równe 4")
   end
}
\endgroup
```

co generuje błąd:

```
   ! Undefined control sequence.
   l.9 \endgroup
```

Jak to może być prawdą, skoro `\endgroup` to standardowe pierwotne polecenie TeX-a? Przyczyna błędu jest dość subtelna: gdy LuaTeX odczytał ostatnią linię tekstu — tę zawierającą `\endgroup`—dodał również `\endlinechar` znaku `\\r` na końcu tej linii. Teraz, w swojej pamięci, LuaTeX widzi sekwencję znaków

`\endgroup\r`

gdzie używamy `\\r` aby oznaczyć znak o kodzie 13 — nie nazwę jakiegoś nieznanego makra TeX `\\r`.

W momencie, gdy LuaTeX odczytał tę linię z naszego pliku tekstowego, oryginalny `\begingroup` nadal działa: jesteśmy wewnątrz grupy, która nie została jeszcze zamknięta przez wykonanie odpowiadającego jej `\endgroup` polecenia — co spowodowałoby, że `\\r` powróci do poprzedniej wartości kodu kategorii 5.

Gdy LuaTeX zaczyna przetwarzać (tworzyć tokeny) z linii tekstu `\endgroup\r` rozpoznaje pierwszy znak `\` jako znak ucieczki, co uruchamia LuaTeX do wyszukiwania nazwy polecenia. Aby zidentyfikować nazwę polecenia, LuaTeX szuka sekwencji znaków z kodem kategorii 11, ale ponieważ `\\r` również ma kod kategorii 11, LuaTeX myśli, że `\\r` znak (nadal z kodem kategorii 11) tworzy *część polecenia* o nazwie `\endgroup\r` , które oczywiście nie istnieje, więc LuaTeX zgłasza `Niezdefiniowana sekwencja sterująca` błąd. Dlatego użyliśmy kodu kategorii 12, a nie 11.

Ponieważ komunikat błędu LuaTeX został zapisany w konsoli, nie mogliśmy łatwo zobaczyć/zauważyć `\\r` znaku, więc nie było oczywiste, co spowodowało błąd.

### Dlaczego martwimy się zakończeniami wierszy?

Powód jest taki, aby umożliwić użycie w twoim kodzie metod komentarzy Lua! Możesz użyć standardowego mechanizmu LuaTeX dodawania `%` znaków do komentowania pojedynczych wierszy w kodzie; jednak język Lua ma własne, bardzo przydatne *wielowierszowe* mechanizmy komentarzy, z których możesz chcieć skorzystać.

Zacznijmy od sprawdzenia, co się stanie, jeśli spróbujemy użyć jednoliniowych komentarzy języka Lua bez rozwiązania problemów z podziałami wiersza. Podczas gdy TeX używa znaku `%` do komentowania pojedynczych linii kodu, Lua używa podwójnego myślnika: `--`.

Co się stanie, jeśli spróbujemy uruchomić to:

```
\directlua{
   local x=3
   if x \noexpand~= 4 then
   -- Zamierzam wypisać wynik tego złożonego testu
   print("x nie jest równe 4")
   end
}
```

Otrzymujemy błąd:

`[\directlua]:1: oczekiwano 'end' w pobliżu <eof>`

Błąd ten jest spowodowany brakiem podziałów wierszy w kodzie Lua przekazywanym do interpretera, który widzi tylko jeden ciągły łańcuch, w którym komentarz zaczyna się mniej więcej w połowie tego łańcucha:

```

local x=3 if x ~= 4 then -- Zamierzam wypisać wynik tego złożonego testu print("x nie jest równe 4") end
```

Wszystko po `**local x=3 if x ~= 4 then**` jest traktowane jako zakomentowane, co powoduje, że interpreter widzi niekompletny fragment kodu Lua, skutkując błędem

`'end' expected near <eof>`.

gdzie `<eof>` oznacza koniec pliku.

Jak zapewne się domyślasz, musimy to naprawić, zapewniając, że podziały wierszy są przekazywane do wynikowego kodu Lua, co możemy osiągnąć na przykład poprzez zmianę kodu kategorii `\\r` na 12:

```
\begingroup
\catcode`\^^M=12 % zmień kod kategorii \r na 12
\directlua{
   local x=3
   if x \noexpand~= 4 then
   -- Zamierzam wyświetlić wynik tego złożonego testu
   print("x nie jest równe 4")
   end
}
\endgroup
```

Teraz interpreter Lua widzi łańcuch, ale zawiera on `\\r` znaki nowej linii zapisane w `\directlua` fragmencie:

**\\\r**local x=3\*\*\r**if x \~= 4 then**\r\*\*-- Zamierzam wyświetlić wynik tego złożonego testu\*\*\r**tex.print("x is not equal to 4")**\\\r**end**\r\*\*

W praktyce jest to równoważne z zapisaniem

```
   local x=3
   if x \noexpand~= 4 then
   -- Zamierzam wyświetlić wynik tego złożonego testu
   print("x nie jest równe 4")
   end
```

co oznacza, że Lua jest w stanie poprawnie przetworzyć ten kod i zignorować linię, którą zakomentowaliśmy.

**Komentarze blokowe**

Język Lua obsługuje również składnię, którą nazywa [„komentarz blokowy”](https://www.lua.org/pil/1.3.html) (lub *długi komentarz*): zaczynają się od `--[[` i obowiązują aż do odpowiadającego im `]]`. Możemy użyć tej wygodnej składni do pisania komentarzy wielowierszowych albo do komentowania fragmentów kodu, które chcemy tymczasowo usunąć:

```
\begingroup
\catcode`\^^M=12 % zmień kod kategorii \r na 12
\directlua{
   local x=3
   if x \noexpand~= 4 then
   --[[ Zamierzam wyświetlić wynik tego złożonego testu
   po prostu dlatego, że naprawdę jest
   takim niesamowitym wnioskiem]]
   print("x nie jest równe 4")
   end
}
\endgroup
```

## Podsumowując

Po pierwsze, gratulacje, jeśli udało Ci się przeczytać ten obszerny artykuł! Staraliśmy się przygotować w miarę kompleksowy przewodnik po pojęciach i zagadnieniach związanych z TeX-em, które stanowią podstawę potrzebną, aby w pełni wykorzystać LuaTeX za pomocą `\directlua` polecenia. Mamy nadzieję, że przygotowaliśmy artykuł, który jest pouczający i wnosi coś użytecznego oraz wartościowego dla społeczności użytkowników Overleaf i nie tylko. Jak zawsze z przyjemnością przyjmujemy opinie, więc prosimy, śmiało [skontaktować się z nami](https://www.overleaf.com/contact) dzielcie się komentarzami do tego artykułu lub sugestiami dotyczącymi kolejnych tematów, o których chcielibyście, abyśmy napisali.

Szczęśliwego $$\text{Lua}\mathrm{\TeX}\text{-ing!}$$ od Grahama Douglasa i zespołu Overleaf.

### A na koniec... po prostu użyj pakietu luacode

Choć TeX i Lua działają w zasadniczo różny sposób, języki te dzielą wiele znaków, które mają „specjalne znaczenia” w kontekście każdego języka — takich jak \\, %, \~, #, ^, & — oczywiście Lua i TeX przypisują te specjalne znaczenia dla *bardzo* różnych celów. Nasza analiza problematycznych znaków pokazuje, dlaczego mogą pojawiać się trudności i jak można je rozwiązać; jednak ręczne poprawianie wielu małych fragmentów kodu Lua mogłoby być dość żmudne, więc większość użytkowników woli korzystać z pakietów LaTeX, które usuwają te problemy. Jednym z takich pakietów jest [`luacode`](https://ctan.org/pkg/luacode?lang=en) który oferuje zestaw funkcji zaprojektowanych, aby ułatwić pracę z `\directlua`, ale przynajmniej możesz teraz lepiej rozumieć problemy `luacode` które rozwiązuje za Ciebie.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/latex/pl/artykuly-szczegolowe/09-an-introduction-to-luatex-part-2-understanding-directlua.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
