Knihovny a frameworky pro programovací jazyk Lua

Pavel Tišnovský 19. 5. 2009

V jedenácté a následně i dvanácté části seriálu o programovacím jazyce Lua budou popsány standardní knihovny dodávané společně s překladačem a interpretrem tohoto jazyka. Taktéž se budeme zabývat několika užitečnými externími knihovnami, frameworky a v neposlední řadě i sémantickými rozšířeními Lua.

Obsah

1. Knihovny a frameworky pro programovací jazyk Lua
2. Standardní knihovny dodávané s interpretrem jazyka Lua
3. Vstupně-výstupní operace
4. Matematické funkce, práce s řetězci a s tabulkami
5. Externí knihovny
6. Webové servery a frameworky
7. Alternativní implementace překladače a interpretru Lua
8. Rozšíření sémantiky jazyka – metalua
9. Odkazy na Internetu

1. Knihovny a frameworky pro programovací jazyk Lua

V předchozích částech tohoto seriálu jsme v demonstračních příkladech již mnohokrát použili některé funkce ze standardních knihoven jazyka Lua, které jsou dodávány již v základní instalaci spolu s překladačem a interpretrem. Funkce nabízené těmito knihovnami budou popsány ve druhé, třetíčtvrté kapitole. V navazujících kapitolách si stručně popíšeme některé zajímavé externí knihovny, zejména ty, které jsou dodávané s licencemi umožňujícími použití těchto knihoven ve vlastních projektech bez zásadních licenčních omezení (LGPL apod.). Použitelných externích knihoven v současnosti existuje již značné množství, od jednoduchých knihoven určených například pro numerické výpočty, přes různé grafické a multimediální knihovny a knihovny umožňující snadnou tvorbu grafického uživatelského rozhraní (s využitím GTK+ apod.) až po poměrně rozsáhlé webové frameworky, které obsahují jak podporu pro příjem a následné zpracování HTTP požadavků (tj. vlastní jednovláknový či vícevláknový webový server), tak i funkce pro přístup k relačním databázím, zpracování XMLJSON formátu, snadnou tvorbu dynamických HTML stránek s využitím šablon atd.

2. Standardní knihovny dodávané s interpretrem jazyka Lua

V základní instalaci jazyka Lua je, prakticky bez ohledu na použitou platformu, přítomno i několik standardních knihoven, jejichž funkce je možné volat z Lua skriptů a nepřímo též z céčkového programu v případě, že je interpretr jazyka Lua zabudován do větší aplikace. Standardní knihovny pokrývají základní potřeby tvůrců skriptů – usnadňují zpracování řetězců i asociativních polí, nabízí matematické funkce, funkce pro práci se soubory a pro styk s operačním systémem (vytvoření nového procesu apod.) a v neposlední řadě nabízí i rozhraní pro externí debuggery a profilery kódu (toto rozhraní je v případě potřeby možné použít i pro jiné účely, ovšem z několika důvodů to není tvůrci jazyka doporučováno). Většina funkcí ze základních knihoven je umístěna ve vlastním jmenném prostoru (namespace), tj. jedná se o funkce uložené do vhodně pojmenovaného asociativního pole, ovšem nejčastěji používané funkce a proměnné nemají vlastní jmenný prostor a jsou tak přístupné přímo pod svým jménem (před kterým se neuvádí jmenný prostor oddělený od jména tečkou). Jedná se o následující funkce a proměnné (podrobnějším popisem některých dále vypsaných funkcí se budeme zabývat v navazujících částech tohoto seriálu):

Název funkce/proměnné Popis
_G proměnná obsahující globální prostředí, do nějž jsou ukládány všechny funkce i proměnné
_VERSION proměnná obsahující jméno a verzi interpretru jazyka Lua v řetězcové podobě
assert kontrola, zda je zadaná podmínka splněna; v případě jejího nesplnění je vypsáno chybové hlášení (lze použít i pro typovou kontrolu)
collectgarbage funkce, pomocí níž je možné spustit, zastavit či nakonfigurovat garbage collector, jenž se stará o uvolňování paměti po již neaktivních objektech
dofile soubor, který je této funkci předán jako parametr, je spuštěn jako Lua skript
error výpis chybového hlášení a ukončení právě probíhající chráněné funkce (viz další část tohoto seriálu)
getfenv vrací prostředí, ve kterém je spuštěna právě aktivní funkce
getmetatable tuto funkci jsme již použili v předchozích částech seriálu – slouží pro získání metatabulky nějakého objektu
ipairs i tuto funkci již známe – lze ji využít pro získání iterátoru, pomocí nějž lze iterovat přes všechny prvky pole
load načtení (nebo zkonstruování) bloku příkazů zadanou callback funkcí
loadfile načtení bloku příkazů ze souboru zadaného svým jménem
loadstring načtení bloků příkazů z řetězce (ten může být například získán deserializací skriptu z archivu nebo zkonstruován na základě uživatelského vstupu)
next lze použít pro procházení tabulkou – pro zadanou tabulku a index prvku vrátí index dalšího prvku v tabulce i hodnotu tohoto prvku
pairs tato funkce vrací pro zadanou tabulku trojici hodnot: funkci next, vlastní tabulku a hodnotu nil, takže ji lze využít pro konstrukci smyčky za účelem procházení tabulky
pcall spuštění funkce v chráněném režimu
print základní funkce pro výpis hodnot na standardní výstup, která akceptuje libovolný počet a typ parametrů
rawequal zjištění, zda jsou dva objekty shodné bez volání metametody __eq z metatabulky, lze tak obejít přetížení tohoto operátoru
rawget získání hodnoty uložené na zadaném indexu v tabulce (asociativním poli) bez volání metametody __index z metatabulky – i tato funkce tedy obchází uživatelsky přetížené operátory
rawset uložení hodnoty do tabulky (asociativního pole), opět bez volání přetíženého operátoru představovaného metametodou __newindex
module vytvoření modulu se zadaným jménem. Podrobnosti o modulech si řekneme v navazujících částech tohoto seriálu.
require načtení modulu se zadaným jménem, ovšem jen tehdy, pokud již daný modul není načtený
select získání hodnot všech parametrů uložených za parametrem se zadaným indexem, popř. získání počtu těchto parametrů
setfenv nastavení prostředí pro zvolenou funkci
setmetatable nastavení metatabulky pro zadaný objekt
tonumber převod řetězcové hodnoty na číslo, lze specifikovat i základ pro převod (dvojková, osmičková, desítková, šestnáctková atd. soustava)
tostring převod libovolné hodnoty na řetězec; funkci pro převod na řetězec lze „přetížit“ zápisem události __tostring do metatabulky
type pro libovolný objekt vrátí jeho typ v řetězcové podobě (tuto funkci jsme již použili v předchozích částech seriálu)
unpack získání několika po sobě uložených položek z tabulky
xpcall spuštění funkce v chráněném režimu se specifikací další funkce (předané jako druhý parametr), která je použita pro zpracování chyby (error handler)

3. Vstupně-výstupní operace

Funkce pro vstupně/výstupní operace jsou rozděleny do dvou standardních knihoven. V knihovně io můžeme najít funkce pracující s implicitním objektem představujícím otevřený soubor (deskriptorem). Tento soubor je nejprve otevřen a jeho deskriptor je uschován přímo v asociativním poli io). Naproti tomu knihovna file obsahuje funkce použitelné jako metody – jejich prvním parametrem je vždy deskriptor otevřeného souboru, proto lze místo volání typu file.názevFun­kce(deskriptor) použít syntaktický cukr a volání provést „objektově“: deskriptor:ná­zevFunkce(), což je nejen kratší, ale i přehlednější (podrobnější informace o této vlastnosti jazyka Lua byla uvedena v části věnované objektově orientovanému programování).

Název funkce Význam
io.close uzavření souboru
io.flush uložení všech dat z vyrovnávacích pamětí
io.input otevření souboru v textovém režimu pro čtení
io.lines otevření souboru a vrácení iterátoru, který lze použít při čtení dat po celých řádcích
io.open otevření souboru v zadaném režimu (čtení, zápis, připojení na konec souboru, binární čtení/zápis/při­pojení)
io.output otevření souboru v textovém režimu pro zápis
io.popen spuštění programu v samostatném procesu a získání standardního vstupu či výstupu tohoto programu (lze použít pro posílání či naopak příjem dat)
io.read čtení dat ze souboru v uživatelsky nastaveném formátu
io.stderr deskriptor souboru představující standardní chybový výstup
io.stdin deskriptor souboru představující standardní vstup
io.stdout deskriptor souboru představující standardní výstup
io.tmpfile vytvoření dočasného souboru, který je smazán po ukončení skriptu
io.type zjištění, zda daná hodnota představuje otevřený či uzavřený soubor (vrací se řetězec „file“ popř. „closed file“). Pokud je hodnota jiného typu, vrátí se nil.
io.write zápis dat do souboru v uživatelsky nastaveném formátu

Funkce dostupné z knihovny file:

Název funkce Význam
file:close uzavření souboru
file:flush vyprázdnění vyrovnávacích pamětí a zápis jejich obsahu do souboru
file:lines vrací iterátor, pomocí něhož lze ve smyčce načítat data ze souboru po jednotlivých řádcích
file:read načtení dat ze souboru ve specifikovaném formátu
file:seek nastavení aktivního místa v souboru, od kterého se bude provádět čtení či zápis
file:setvbuf nastavení vyrovnávací paměti pro soubor – vyrovnávací paměť může být zakázána, povolena globálně či povolena jen pro jeden řádek
file:write zápis dat – numerických hodnot či řetězců – do souboru

4. Matematické funkce, práce s řetězci a s tabulkami

Ve standardních knihovnách jazyka Lua jsou dostupné i základní matematické (logaritmické, goniometrické atd.) funkce, funkce zjednodušující práci s řetězci a taktéž funkce pro práci s tabulkami (poli), pomocí nichž lze do tabulek vkládat nové položky, mazat položky či celou tabulku setřídit. Nejprve bude uveden výpis všech dostupných matematických funkcí:

Název funkce Význam
math.abs výpočet absolutní hodnoty
math.acos arkus kosinus
math.asin arkus sinus
math.atan arkus tangens
math.atan2 arkus tangens volaný se dvěma parametry představujícími dvě přepony pravoúhlého trojúhelníka
math.ceil zaokrouhlení směrem ke kladnému nekonečnu
math.cos kosinus
math.cosh hyperbolický kosinus
math.deg převod z radiánů na úhel zadaný ve stupních
math.exp ex
math.floor zaokrouhlení směrem k zápornému nekonečnu
math.fmod výpočet zbytku po dělení
math.frexp výpočet hodnot m a e z výrazu x=m2e
math.huge vrací nejvyšší reprezentovatelné číslo
math.ldexp výpočet m2e
math.log přirozený logaritmus
math.log10 desítkový logaritmus
math.max maximální hodnota z předané sekvence (její délka není omezena)
math.min minimální hodnota z předané sekvence (její délka není omezena)
math.modf výpočet celé a desetinné části předané hodnoty
math.pi konstanta Π
math.pow výpočet xy
math.rad převod úhlu zadaného ve stupních na radiány
math.random vrací náhodné číslo (založeno na céčkové funkci rand())
math.randomseed nastavení „semínka“ pro generátor náhodných čísel
math.sin sinus
math.sinh hyperbolický sinus
math.sqrt druhá odmocnina
math.tan tangens
math.tanh hyperbolický tangens

Mezi funkce pro práci s řetězci patří:

Název funkce Význam
string.byte vrátí sekvenci numerických hodnot představujících kódy znaků v řetězci
string.char opak předchozí funkce – převod sekvence numerických hodnot na řetězec
string.dump tato funkce dokáže vrátit řetězcovou reprezentaci funkce předané jako parametr, vhodné pro serializaci (opakem je výše uvedená funkce loadstring)
string.find vyhledávání podřetězce v řetězci, lze použít i regulární výraz
string.format zadané parametry jsou zformátovány a převedeny na řetězec, odpovídá céčkovské sprintf()
string.gmatch vrací iterátor na základě zadaného regulárního výrazu
string.gsub globální nahrazení části řetězce na základě regulárního výrazu (velmi užitečná funkce, kterou si ještě popíšeme)
string.len vrací délku řetězce
string.lower převod znaků na malá písmena
string.match zjištění, zda řetězec obsahuje text specifikovaný regulárním výrazem
string.rep řetězec předaný jako parametr se n-krát zopakuje ve výsledném řetězci
string.reverse vrátí řetězec s opačným pořadím znaků
string.sub nahrazení části řetězce na základě regulárního výrazu (velmi užitečná funkce, kterou si ještě popíšeme)
string.upper převod řetězce na velká písmena

Poslední sada funkcí zjednodušuje práci s tabulkami (implementovanými většinou jako asociativní pole):

Název funkce Význam
table.concat pomocí této funkce lze hodnoty z tabulky převést na řetězec, v němž jsou jednotlivé položky odděleny zadaným separátorem (například čárkou či středníkem)
table.insert vložení nové hodnoty na zadaný index (zbylé položky v poli se posunou)
table.maxn vrátí maximální index použitý v tabulce (asociativním poli)
table.remove vymazání hodnoty uložené na zadaném indexu (zbylé položky v poli se posunou)
table.sort setřídění tabulky, lze zadat i vlastní funkci volanou při porovnávání dvou položek tabulky

5. Externí knihovny

V úvodních odstavcích této části seriálu o programovacím jazyku Lua jsme si řekli, že v současnosti již existuje velké množství externích knihoven, s jejichž pomocí lze tento jazyk využít v mnoha odvětvích. Pro práci s 2D a 3D grafikou slouží především knihovny luacairo (http://luafor­ge.net/projec­ts/luacairo/) a LuaGL (http://luagl­.wikidot.com/) podporující kromě vlastního OpenGL i GLUT (OpenGL Utility Toolkit); pamětníci multiplatformní herní knihovny Allegro (která původně vznikla na Atari ST a dnes je podporována na DOSu, MS Windows a samozřejmě i Linuxu) jistě ocení existenci LuAllegro (http://luafor­ge.net/projec­ts/luallegro/) či rozhraní pro knihovnu SDL s podobnou funkcionalitou – LuaSDL. Pro vytváření dynamických souborů PDF lze použít lpdf (http://www.tec­graf.puc-rio.br/~lhf/ftp­/lua/#lpdf) a s relačními databázemi postavenými na standardu SQL lze pracovat pomocí LuaSQL. Seznam většiny volně dostupných knihoven lze získat na adrese http://lua-users.org/wiki/Li­brariesAndBin­dings, popřípadě přímo na LuaForge. Některými dalšími knihovnami, určenými například pro tvorbu či skriptování her, se budeme podrobněji zabývat v navazující části tohoto seriálu.

6. Webové servery a frameworky

Programovací jazyk Lua je možné, ostatně jako téměř každý dnes používaný jazyk, použít pro zpracování dotazů posílaných na HTTP server, jejichž výsledkem má být dynamicky generovaná HTML stránka, rastrový obrázek či vektorová kresba, soubor ve formátu PDF či další dynamický obsah vytvářený na základě uživatelova dotazu. Pro úlohy, které se nespouští s příliš velkou frekvencí, nebo v případě, že nemáme jinou možnost (omezení daná provozovatelem serveru) je možné využít rozhraní CGI nabízené prakticky všemi v současnosti používanými webovými servery (práce přes CGI se v podstatě omezuje na zpracování proměnných prostředí, standardního vstupu a tisku na standardní výstup). Toto řešení ovšem není optimální pro často volané dynamické stránky, protože je nutné pro každý dotaz zavolat nový interpretr Lua jako novou úlohu operačního systému, což je – i přes velmi malé systémové nároky interpretru – relativně pomalé. Navíc tvoří samotné zpracování HTTP požadavku mnohdy jen velmi malou část webových aplikací – většinou je zapotřebí komunikovat s databází, zpracovávat XML, číst a zapisovat cookies, uchovávat stav session mezi jednotlivými požadavky, jednoduše generovat výsledné HTTP stránky s využitím šablon atd.

Pro tyto účely lze použít webový framework nazvaný Kepler, který je z větší části představován přímo Lua knihovnami. Tento framework se skládá z více částí, zejména HTTP serveru Xavante (Xavante je mj. i označení jazyka Brazilských domorodců), podporou pro práci s SQL (LuaSQL), podporou rozhraní CGI (CGILua), XML (užitečné například při použití AJAXu na webových stránkách či komunikaci s webovými službami) atd. Nad tímto frameworkem je (můžeme říci, že i jako technologické demo) postavena Wiki nazvaná Sputnik. Ve skutečnosti je většina stránek věnovaných jazyku Lua provozována právě na Sputniku – viz odkazy uvedené v deváté kapitole. Součástí frameworku Kepler je i podpora pro snazší vytváření dynamických stránek. Nejpřímější cestu pro tvorbu dynamických HTML stránek představuje použití knihovny CGILua a takzvaných here řetězců (here string), tj. řetězcových literálů, při jejichž interpretaci jsou zachovány i formátovací znaky, včetně konců řádků – jedná se o řetězce s prakticky libovolnou délkou, které jsou ukončeny dohodnutou sekvencí znaků (většinou se nejedná o uvozovky, protože ty tvoří běžnou součást řetězců). Jednoduchou dynamickou webovou stránku lze vytvořit následujícím způsobem:

cgilua.htmlheader()
cgilua.put([[
<html>
<head>
  <title>Hello World</title>
</head>
<body>
  <strong>Hello World!</strong>
</body>
</html>]]) 

Práce s here řetězci však není v případě rozsáhlejší stránky příliš snadná a mnohdy vede k nežádoucímu míchání statického HTML kódu s částmi Lua skriptu. Jednodušší je použít technologii, která je inspirována PHP a JSP (Java Server Pages), při níž je zvolen ve své podstatě opačný postup – namísto Lua skriptu, který se sám stará o postupnou tvorbu HTML stránky, jsou zde do kostry HTML stránky vloženy speciální značky sloužící k zápisu Lua skriptů či vkládání hodnot vypočtených výrazů do vytvářené stránky (náhrada za explicitní volání funkce print). Při pohledu na následující kód bude podobnost s PHP či JSP zřejmá. Tento kód je před svým dalším zpracováním nejprve transformován do podoby validního Lua skriptu a posléze přeložen a interpretován, přičemž výsledkem je HTML stránka zaslaná serverem do uživatelova webového prohlížeče:

<html>
<?lua
if cgilua.QUERY.language == 'english' then
  greeting = 'Hello World!'
elseif cgilua.QUERY.language == 'portuguese' then
  greeting = 'Olá Mundo!'
else
  greeting = '[unknown language]'
end
?>
<head>
  <title><%= greeting %></title>
</head>
<body>
  <strong><%= greeting %></strong>
</body>
</html> 

7. Alternativní implementace překladače a interpretru Lua

Původní překladač a interpretr jazyka Lua je naprogramován v čistém céčku (ANSI/ISO C), ovšem kromě tohoto „etalonu“ (oficiální standard prozatím neexistuje) existují i další implementace jazyka, jejichž výhodou je například to, že je lze snadno zabudovat do aplikací určených pro běhové prostředí .NET či JRE (Java Runtime Environment), aniž by bylo nutné vkládat mezi Lua skripty a tato prostředí mezistupeň v podobě céčkových funkcí. Velmi zdařilou implementací je LuaJ, jež je, jak ostatně už její název napovídá, vytvořena v Javě a lze ji tak použít prakticky na jakémkoli počítači s dostupným JRE (viz ukázkový příklad uvedený níže, ve kterém je v Lua naskriptována jednoduchá aplikace používající pro tvorbu grafického uživatelského rozhraní knihovnu Swing). Samozřejmě existují i poměrně kvalitní implementace Luy pro prostředí .NET s názvy Lua.NET (akademický projekt), LuaCLR (s MIT licencí) a Lua2IL – vid odkazy uvedené v deváté kapitole.

frame = luajava.newInstance( "javax.swing.JFrame", "Texts" );
pane = luajava.newInstance( "javax.swing.JPanel" );
borderFactory = luajava.bindClass( "javax.swing.BorderFactory" )
border = borderFactory:createEmptyBorder( 30, 30, 10, 30 )
pane:setBorder( border )
label = luajava.newInstance( "javax.swing.JLabel", "This is a Label" );

layout = luajava.newInstance( "java.awt.GridLayout", 2, 2 );
pane:setLayout( layout )
pane:add( label )
pane:setBounds( 20, 30, 10, 30 )

borderLayout = luajava.bindClass( "java.awt.BorderLayout" )
frame:getContentPane():add(pane, borderLayout.CENTER )
jframe = luajava.bindClass( "javax.swing.JFrame" )
frame:setDefaultCloseOperation(jframe.EXIT_ON_CLOSE)
frame:pack()
frame:setVisible(true)

local listener = luajava.createProxy("java.awt.event.MouseListener",
    {
        mouseClicked = function(me)
            print("clicked!", me)
        end
    })

frame:addMouseListener(listener) 

Kromě těchto dvou hlavních „alternativních“ překladačů a interpretrů je možné získat překladač a/nebo interpretr jazyka Lua napsaný v Lispu či JavaScriptu (teoreticky je tak možné Luu použít na webových stránkách, i když dvojí interpretace se negativně projeví nižší rychlostí běhu takové aplikace) či překladač do bajtkódu zpracovávaného virtuálním strojem Parrot (tento překladač je kupodivu vytvořen v Perlu a ne v samotné Lua či céčku – samotné virtuální stroje Lua a Parrotu jsou si v mnohém podobné). Zajímavý je taktéž překladač z Lua do céčka, což je vlastně transformátor bajtkódu tohoto jazyka na volání céčkových funkcí – kromě zvýšení rychlosti běhu skriptu je taktéž umožněno šíření přeloženého programu, ve kterém není obsažen ani původní skript ani jeho bajtkód, čímž je umožněno, aby na cílové platformě nemusel být přítomen ani překladač ani interpretr jazyka Lua (důležité například u jednočipových mikropočítačů s omezenou kapacitou operační paměti).

widgety

8. Rozšíření sémantiky jazyka – metalua

Velmi zajímavé a současně i užitečné rozšíření původního (ve své podstatě minimalistického) programovacího jazyka Lua představuje projekt metalua. Jedná se o změnu vlastního překladače, který je rozšířen o některé vlastnosti, které můžeme najít například v Lispovských jazycích – podporu maker, metaprogramování a možnosti rozšíření syntaxe jazyka o další jazykové konstrukce (nové operátory, další typy smyček, řídicí struktury atd.). Tyto vlastnosti jsou do překladače přidány takovým způsobem, že je možné vlastní překládaný kód modifikovat na základě speciálních konstrukcí zapisovaných přímo do zdrojového kódu programu (kód, přesněji jemu odpovídající AST – abstract syntax tree, je tedy modifikován v době překladu, nikoli běhu). V Lispovských jazycích je manipulace s překládaným či interpretovaným kódem velmi jednoduchá, protože zde existuje ekvivalence mezi kódem a daty (vše je chápáno jako seznam, přesněji sekvence provázaných tečka-dvojic tvořících binární strom, odpovídající výše zmíněnému AST), tudíž lze s kódem manipulovat stejně jako s jinými daty. Tuto velmi mocnou techniku se tvůrci systému metalua snažili použít i pro jazyk Lua, což se jim v rámci daných možností podařilo. Možnostmi systému metalua se ještě budeme zabývat v následujících částech tohoto seriálu, dnes si pro ilustraci pouze ukážeme některé možnosti, které toto rozšíření může programátorům přinést:

-- rozšíření syntaxe počítané smyčky for při konstrukci pole
x = { i for i = 2, 50, 2 }

-- filtrace hodnot (sudá čísla) na základě zapsané podmínky
y = { i for i = 1, 50 if i%2==0 }

-- přidání ternárního operátoru do sémantiky jazyka
-- (tento operátor je použitý v jazycích odvozených od céčka:
--  C++, Java, JavaScript atd.)
-- Povšimněte si nové konstrukce +{ a }, která v původní Lua neexistuje
local function b(x, suffix)
   local v, ontrue, onfalse = mlp.gensym "test", unpack (suffix)
   return `Stat{
      +{ block:
         local -{v}
         if -{x} then (-{v}) = -{ontrue} else (-{v}) = -{onfalse or `Nil} end },
      v }
end

mlp.expr.suffix:add{ "?", mlp.expr, gg.onkeyword{ ",", mlp.expr }, prec=5, builder=b } 

9. Odkazy na Internetu

  1. LuaForge
    http://luafor­ge.net/
  2. LuaForge: Project Tree
    http://luafor­ge.net/softwa­remap/trove_lis­t.php
  3. lua-users.org
    http://lua-users.org/
  4. Lua Faq
    http://lua-users.org/wiki/Lu­aFaq
  5. Lua Addons
    http://lua-users.org/wiki/Lu­aAddons
  6. Libraries And Bindings
    http://lua-users.org/wiki/Li­brariesAndBin­dings
  7. Lua Power Patches
    http://lua-users.org/wiki/Lu­aPowerPatches
  8. Lua Implementations
    http://lua-users.org/wiki/Lu­aImplementati­ons
  9. Metalua
    http://metalu­a.luaforge.net/
  10. Metalua manual
    http://metalu­a.luaforge.net/ma­nual000.html
  11. luacairo
    http://luafor­ge.net/projec­ts/luacairo/
  12. LuAllegro
    http://luafor­ge.net/projec­ts/luallegro/
  13. Kepler Project
    http://www.ke­plerproject.or­g/
  14. LuaRocks
    http://www.lu­arocks.org/
  15. An Extensible Wiki Engine in Lua
    http://spu.tnik­.org/
  16. Ukázka customizaci Sputniku
    http://spu.tnik­.org/en/Sightin­gs
  17. Interactive Lua
    http://lua-users.org/wiki/In­teractiveLua
  18. LuaGL
    http://luagl.wi­kidot.com/
  19. lpdf
    http://www.tec­graf.puc-rio.br/~lhf/ftp­/lua/#lpdf
Našli jste v článku chybu?
120na80.cz: Pálení žáhy: která jídla ne a co nás uzdraví?

Pálení žáhy: která jídla ne a co nás uzdraví?

Lupa.cz: Blíží se konec Wi-Fi sítí bez hesla?

Blíží se konec Wi-Fi sítí bez hesla?

Lupa.cz: Jak levné procesory změnily svět?

Jak levné procesory změnily svět?

Lupa.cz: Cimrman má hry na YouTube i vlastní doodle

Cimrman má hry na YouTube i vlastní doodle

Vitalia.cz: Tesco nabízí desítky tun jídla zdarma

Tesco nabízí desítky tun jídla zdarma

Vitalia.cz: Fyzioterapeutka: Chůze naboso? Rozhodně ano!

Fyzioterapeutka: Chůze naboso? Rozhodně ano!

DigiZone.cz: Wimbledon na Nova Sport až do 2019

Wimbledon na Nova Sport až do 2019

120na80.cz: Co je padesátkrát sladší než cukr?

Co je padesátkrát sladší než cukr?

Podnikatel.cz: Tyto pojmy k #EET byste měli znát

Tyto pojmy k #EET byste měli znát

Lupa.cz: Jak se prodává firma za miliardu?

Jak se prodává firma za miliardu?

Vitalia.cz: Jsou vegani a vyrábějí nemléko

Jsou vegani a vyrábějí nemléko

Podnikatel.cz: Instalatér, malíř a elektrikář. "Vymřou"?

Instalatér, malíř a elektrikář. "Vymřou"?

DigiZone.cz: Funbox 4K v DVB-T2 má ostrý provoz

Funbox 4K v DVB-T2 má ostrý provoz

Lupa.cz: Další Češi si nechali vložit do těla čip

Další Češi si nechali vložit do těla čip

Podnikatel.cz: Babišovi se nedá věřit, stěžovali si hospodští

Babišovi se nedá věřit, stěžovali si hospodští

DigiZone.cz: DVB-T2 ověřeno: seznam TV zveřejněn

DVB-T2 ověřeno: seznam TV zveřejněn

Vitalia.cz: Muž, který miluje příliš. Ženám neimponuje

Muž, který miluje příliš. Ženám neimponuje

DigiZone.cz: Technisat připravuje trojici DAB

Technisat připravuje trojici DAB

Vitalia.cz: Test dětských svačinek: Tyhle ne!

Test dětských svačinek: Tyhle ne!

Vitalia.cz: Jak Ondra o astma přišel

Jak Ondra o astma přišel