Hlavní navigace

Emacs pro mírně pokročilé (9): Elisp

7. 6. 2001
Doba čtení: 5 minut

Sdílet

Značná část editoru Emacs je napsána v jazyce Elisp. Pomocí tohoto jazyka lze editor rozšiřovat a upravovat podle vlastních potřeb. Navíc je Elisp víc než pouze jazyk určený pro rozšiřování možností Emacsu, jedná se o plnohodnotný programovací jazyk.

Protože je Elisp (nazývaný také Emacs Lisp) primárně určený pro práci v textovém editoru, obsahuje speciální funkce pro zpracovávání textu, ale také pro práci se soubory apod. Historie jazyka Lisp (LISt Processing) sahá do začátku padesátých let dnes již minulého století a během této doby se jazyk vyskytl v mnoha podobách a mutacích. Elisp je nejvíce inspirován tzv. Maclispem, ale najdeme zde i prvky Common Lispu.

Jak již název programovacího jazyka napovídá, pracuje Lisp převážně se seznamy. Nejprve si vysvětlíme některé pojmy, které budou pro pokročilé uživatele Emacsu patrně nudným opakováním. Symbol nil má v Elispu tři odlišné významy: je to symbol pojmenovaný nil; představuje logickou hodnotu FALSE; a konečně je to prázdný list. Symbolem představujícím logickou hodnotu TRUE je symbol t. Oba tyto symboly ( nil a t) se vždy vyhodnocují samy na sebe a nelze jich použít jako konstant. Dále se v jazyce Elisp vyskytují běžné datové typy (označují se jako tzv. primitivní typy), například celá či desetinná čísla, již zmíněné seznamy, textové řetězce, atd. Pro každý z datových typů existuje odpovídající funkce, která kontroluje, zda je objekt prvkem daného typu.

Pro většinu z těchto datových typů existuje celá řada vestavěných funkcí. Tak například pro čísla jsou v jazyce Elisp dostupné všechny běžné aritmetické operace (včetně například bitových operací, goniometrických funkcí apod.). Podobně lze velmi dobře pracovat s textovými řetězci, seznamy, vektory atd. Podrobný popis všech těchto funkcí lze nalézt v manuálu. Jejich chování lze nejsnáze ověřit ve zvláštním Emacsovském bufferu *scratch*, který slouží pro vyhodnocování Elispovských výrazů.

Vyhodnocování výrazů provádí lispovský interpret – tj. program, který na vstupu obdrží lispovský objekt a „spočte&quot jeho “hodnotu jako výraz". Jak to dělá, závisí na datovém typu objektu. Interpret provádí vyhodnocování částí programu automaticky, ale vyhodnocení lze také „vynutit“ explicitně pomocí funkce eval. Vyhodnocování je rekursivní proces. Například volání funkce nejprve vyhodnotí každý argument a poté vyhodnotí všechny formy (viz níže) těla funkce. Provedení funkce je realizováno vyhodnocením definice funkce.

Lispovský objekt, který se má vyhodnotit, se nazývá forma (form). Emacs rozeznává tři základní typy forem: symboly, seznamy (listy) a ostatní objekty. Například čísla patří mezi tzv. „samo-vyhodnocující“ se formy, kam kromě nich patří všechny formy, které nejsou seznamem nebo symbolem. Tedy číslo 25 se vyhodnotí jako 25 a řetězec „linux“ se vyhodnotí jako řetězec „linux“. Symbol se vyhodnocuje, jako proměnná. Výsledkem je hodnota proměnné, pokud forma nějakou obsahuje (v opačném případě se signalizována chyba). Například (setq a 123) nastaví hodnotu proměnné na 123. Výše zmíněné symboly nil a t mají výsadní postavení a jejich hodnotu nelze takto měnit. Neprázdný list je buď volání funkce, makro, nebo zvláštní forma. Každá z těchto tří forem je vyhodnocována zvláštním způsobem.

Pokud je tedy prvním prvkem v seznamu lispovská funkce, vyhodnocuje se list jako volání funkce. Toto je příklad volání funkce +: (+ 1 2). Nejprve jsou vyhodnoceny zbývající elementy – argumenty funkce, poté je volána samotná funkce a výsledkem vyhodnocení je tedy v tomto případě číslo 3. Je-li na prvním místě seznamu objekt typu makro, je list vyhodnocen jako volání makra. Zvláštní (speciální) formou jsou primitivní funkce, u kterých se nevyhodnocují všechny argumenty (např. podmínky, smyčky apod.). Vyhodnocení výrazu lze předejít uvozením výrazu apostrofem (nebo též zvláštní formou quote). Například tedy kód `(+ 1 2) se nehodnotí na součet čísel 1 a 2 jako v předchozím příkladě, ale na seznam  (+ 1 2).

Zavedením (nahráním) souboru obsahujícího lispovský kód se rozumí přidání jeho obsahu do lispovského prostředí ve formě lispovských objektů. Emacs otevře soubor, přečte text, vyhodnotí všechny formy a soubor uzavře. Soubor, který obsahuje lispovský kód, se často nazývá knihovna. V Emacsu existuje mnoho způsobů pro toto zavádění kódu. Počínaje funkcí autoload pro automatické zavádění, dále pak různé verze load funkcí lišící se zejména v zadávaní parametrů či ve výsledku volání (viz manuál).

Elisp obsahuje „kompilátor“, který převádí funkce napsané v lispu do zvláštní reprezentace nazývající se byte-code, která urychluje provádění programu. Tento byte-code je interpretován byte-code interpretem a není proto třeba jej znovu překládat na jiné architektuře. Takto „zkompilovat“ lze jednu konkrétní funkci, celý soubor nebo dokonce několik souborů. Pokud máme k dispozici pouze nějakou knihovnu v podobě byte-code, netřeba zoufat, neboť existuje „disassebler“, který převádí „zkompilovaný kód“ do podoby čitelné pro člověka.

Další velmi silnou zbraní tohoto jazyka je přidávání rad (advice) již existujícím funkcím. Jedná se o velmi čistý způsob rozšiřování funkcí. Namísto rozšíření funkce přepsáním jejího kódu lze této funkci přidat tuto tzv. radu (advice). Každá funkce může mít více těchto „poradců“. Nejlépe si ukážeme tuto vlastnost na jednoduchém příkladě (převzatém z dokumentace Elispu). Představme si, že chceme rozšířit chování funkce previous-line takto: nachází-li si kursor na prvním řádku soubor,u vloží se při pokusu o posun na předchozí řádek řádek nový. A namísto přepsání původního kódu přidáme funkci radu:


(defadvice previous-line (before next-line-at-end (arg))
       "Vloží prázný řádek při pohybu nahoru z první řádky."
       (if (and next-line-add-newlines (= arg 1)
                (save-excursion (beginning-of-line) (bobp)))
           (progn
             (beginning-of-line)
             (newline))))

Tato část kódu definuje radu pojmenovanou next-line-at-end. Jelikož je rada uvozena klíčovým slovem before, spustí se před vykonáním samotné funkce. Definováním této rady se nezmění chování funkce previous-line, radu je nutno ještě aktivovat:  (ad-activate 'previous-line).

Existují celkem tři způsoby, jak hledat problémy a chyby v kódu Elispu v závislosti na tom, kde se chyba vyskytuje. Pokud program právě běží, lze použít debugger (edebug). Je-li problém v syntaxi (tedy Lisp nemůže program ani přečíst), lze využít schopnosti Emacsu k nalezení chyby. Nedaří-li se program „zkompilovat“ byte kompilátorem, je třeba chybu hledat v *Compile-Log*  bufferu, kam kompilátor chyby zapisuje.

CS24_early

Velmi podrobný a dobře čitelný popis tohoto jazyka existuje v již zmíněné on-line dokumentaci. Výhodou je předchozí znalost Lispu, nicméně Emacs poskytuje velmi silné prostředky pro úvodní seznámení se s tímto jazykem. Navíc existuje celá řada knihoven, které velmi usnadňují programátorskou práci. Při tvorbě vlastních lispovských programů se doporučuje dodržovat určité konvence týkající se například pojmenovávání globálních proměnných přidáním jednotného prefixu pro danou knihovnu a celá řada dalších. Příště si povíme něco o w3 (tedy o tom, jak brouzdat webem v Emacsu).

Byl pro vás článek přínosný?