Lua

Aus besserwiki.de
Lua
Lua-Logo
Lua-Logo
Basisdaten
Paradigmen: Skriptsprache, imperativ, funktional
Erscheinungsjahr: 1993
Entwickler: Roberto Ierusalimschy,
Waldemar Celes,
Luiz Henrique de Figueiredo
Typisierung: dynamisch, schwach (weak typing)
Wichtige Implementierungen: Lua, LuaJIT, LLVM-Lua, LuaCLR
Dialekte: Metalua, Idle, GSL Shell
Beeinflusst von: C++, CLU, Modula, Scheme, SNOBOL
Beeinflusste: Falcon, GameMonkey, Io, JavaScript, Julia, MiniD, MoonScript, Red, Ruby, Squirrel
Betriebssystem: plattformunabhängig
Lizenz: MIT-Lizenz
www.lua.org

Lua (portugiesisch für Mond) ist eine imperative und erweiterbare Skriptsprache zum Einbinden in Programme, um diese leichter weiterentwickeln und warten zu können. Eine der besonderen Eigenschaften von Lua ist die geringe Größe des kompilierten Skript-Interpreters.

Lua-Programme sind meist plattformunabhängig und werden vor der Ausführung in Bytecode übersetzt. Obwohl man mit Lua auch eigenständige Programme schreiben kann, ist sie vorrangig als eingebettete Skriptsprache für andere Programme konzipiert. In dieser Hinsicht ist sie mit Tcl vergleichbar. Vorteile von Lua sind die geringe Größe von 120 kB, die Erweiterbarkeit und die hohe Geschwindigkeit, verglichen mit anderen Skriptsprachen.

Der Lua-Interpreter kann über eine C-Bibliothek angesprochen werden, die auch ein API für die Laufzeitumgebung des Interpreters für Aufrufe vom C-Programm aus enthält. Mittels des API können verschiedene Teile des Programmes in C (oder C++) und Lua geschrieben werden, während Variablen und Funktionen in beiden Richtungen erreichbar bleiben (d. h. eine Funktion in Lua kann eine Funktion in C/C++ aufrufen und umgekehrt).

Es gibt auch einen freien JIT-Compiler namens LuaJIT, der die Revision 5.1 der Sprache unterstützt.

Lua ist in ANSI-C implementiert und unterstützt imperative und funktionale Programmierung. Implementiert man jedoch selbst Objekte mittels Metatables, wird auch objektorientierte Programmierung möglich.

Geschichte

Lua wurde 1993 von Roberto Ierusalimschy, Luiz Henrique de Figueiredo und Waldemar Celes, Mitglieder der Computer Graphics Technology Group (Tecgraf) an der Päpstlichen Katholischen Universität von Rio de Janeiro in Brasilien, entwickelt.

Von 1977 bis 1992 herrschte in Brasilien eine Politik der starken Handelsschranken (Marktreserve genannt) für Computerhardware und -software. In dieser Atmosphäre konnten es sich die Kunden von Tecgraf weder politisch noch finanziell leisten, maßgeschneiderte Software aus dem Ausland zu kaufen. Diese Gründe veranlassten Tecgraf, die grundlegenden Werkzeuge, die es benötigte, von Grund auf zu implementieren.

Die Vorgänger von Lua waren die Datenbeschreibungs-/Konfigurationssprachen SOL (Simple Object Language) und DEL (Dateneingabesprache). Sie waren 1992-1993 unabhängig voneinander bei Tecgraf entwickelt worden, um zwei verschiedenen Projekten mehr Flexibilität zu verleihen (beide waren interaktive grafische Programme für technische Anwendungen bei Petrobras). In SOL und DEL fehlten Flusskontrollstrukturen, und Petrobras sah ein wachsendes Bedürfnis, ihnen volle Programmierleistung zu verleihen.

In The Evolution of Lua schrieben die Autoren der Sprache:

Im Jahr 1993 war der einzige wirkliche Konkurrent Tcl, das ausdrücklich für die Einbettung in Anwendungen entwickelt worden war. Tcl hatte jedoch eine ungewohnte Syntax, bot keine gute Unterstützung für die Datenbeschreibung und lief nur auf Unix-Plattformen. LISP oder Scheme kamen wegen ihrer unfreundlichen Syntax nicht in Frage. Python befand sich noch in den Kinderschuhen. In der freien Do-it-yourself-Atmosphäre, die damals in Tecgraf herrschte, war es ganz natürlich, dass wir versuchten, unsere eigene Skriptsprache zu entwickeln ... Da viele potentielle Benutzer der Sprache keine professionellen Programmierer waren, sollte die Sprache eine kryptische Syntax und Semantik vermeiden. Die Implementierung der neuen Sprache sollte in hohem Maße portabel sein, da die Kunden von Tecgraf über sehr unterschiedliche Computerplattformen verfügten. Da wir davon ausgingen, dass auch andere Tecgraf-Produkte eine Skriptsprache benötigen würden, sollte die neue Sprache dem Beispiel von SOL folgen und als Bibliothek mit einer C-API bereitgestellt werden.

Lua 1.0 wurde so konzipiert, dass seine Objektkonstruktoren, die sich damals noch leicht von dem heutigen leichten und flexiblen Stil unterschieden, die Datenbeschreibungssyntax von SOL aufnahmen (daher der Name Lua: Sol bedeutet "Sonne" auf Portugiesisch und Lua "Mond"). Die Lua-Syntax für Kontrollstrukturen wurde größtenteils von Modula übernommen (if, while, repeat/until), aber auch von CLU (Mehrfachzuweisungen und Mehrfachrückgaben bei Funktionsaufrufen als einfachere Alternative zu Referenzparametern oder expliziten Zeigern), C++ ("nette Idee, eine lokale Variable nur dort zu deklarieren, wo wir sie brauchen"), SNOBOL und AWK (assoziative Arrays). In einem im Dr. Dobb's Journal veröffentlichten Artikel erklären die Schöpfer von Lua auch, dass LISP und Scheme mit ihrem einzigen, allgegenwärtigen Datenstrukturmechanismus (der Liste) einen großen Einfluss auf ihre Entscheidung hatten, die Tabelle als primäre Datenstruktur von Lua zu entwickeln.

Die Semantik von Lua wurde im Laufe der Zeit zunehmend von Scheme beeinflusst, insbesondere durch die Einführung anonymer Funktionen und des vollständigen lexikalischen Scopings. Mehrere Funktionen wurden in neuen Lua-Versionen hinzugefügt.

Versionen von Lua vor Version 5.0 wurden unter einer Lizenz veröffentlicht, die der BSD-Lizenz ähnelt. Seit Version 5.0 wird Lua unter der MIT-Lizenz lizenziert. Beides sind permissive Lizenzen für freie Software und nahezu identisch.

Eigenschaften

Lua wird gemeinhin als "Multi-Paradigma"-Sprache beschrieben, die einen kleinen Satz allgemeiner Funktionen bietet, die erweitert werden können, um verschiedenen Problemtypen gerecht zu werden. Lua enthält keine explizite Unterstützung für Vererbung, erlaubt aber deren Implementierung mit Metatabellen. Ebenso ermöglicht Lua Programmierern die Implementierung von Namespaces, Klassen und anderen verwandten Funktionen mit Hilfe einer einzigen Tabellenimplementierung; Funktionen erster Klasse ermöglichen die Anwendung vieler Techniken aus der funktionalen Programmierung; und vollständiges lexikalisches Scoping ermöglicht das feinkörnige Ausblenden von Informationen, um das Prinzip des geringsten Privilegs durchzusetzen.

Im Allgemeinen ist Lua bestrebt, einfache, flexible Meta-Funktionen bereitzustellen, die je nach Bedarf erweitert werden können, anstatt einen für ein bestimmtes Programmierparadigma spezifischen Funktionsumfang zu bieten. Infolgedessen ist die Basissprache leicht - der vollständige Referenzinterpreter ist kompiliert nur etwa 247 kB groß - und lässt sich leicht an ein breites Spektrum von Anwendungen anpassen.

Als dynamisch typisierte Sprache, die als Erweiterungs- oder Skriptsprache verwendet werden kann, ist Lua kompakt genug, um auf eine Vielzahl von Host-Plattformen zu passen. Sie unterstützt nur wenige atomare Datenstrukturen wie boolesche Werte, Zahlen (standardmäßig doppelpräzise Fließkommazahlen und 64-Bit-Ganzzahlen) und Zeichenketten. Typische Datenstrukturen wie Arrays, Sets, Listen und Records können mit der einzigen nativen Datenstruktur von Lua, der Tabelle, dargestellt werden, die im Wesentlichen ein heterogenes assoziatives Array ist.

Lua implementiert eine kleine Anzahl fortgeschrittener Funktionen wie Funktionen erster Klasse, Garbage Collection, Closures, korrekte Tail Calls, Coercion (automatische Konvertierung zwischen String- und Zahlenwerten zur Laufzeit), Coroutines (kooperatives Multitasking) und dynamisches Laden von Modulen.

Syntax

Das klassische "Hello, World!"-Programm kann wie folgt geschrieben werden:

print("Hallo, Welt!")

oder als:

print 'Hello, World!' <span title="Aus: Englische Wikipedia, Abschnitt &quot;Syntax&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Syntax <span style="color:#dddddd">ⓘ</span>]</span>

Ein Kommentar in Lua beginnt mit einem doppelten Bindestrich und läuft bis zum Ende der Zeile, ähnlich wie in Ada, Eiffel, Haskell, SQL und VHDL. Mehrzeilige Zeichenketten und Kommentare werden mit doppelten eckigen Klammern versehen.

In diesem Beispiel ist die Funktion factorial als Funktion implementiert:

function factorial(n)
  local x = 1
  for i = 2, n do
    x = x * i
  end
  return x
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Syntax&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Syntax <span style="color:#dddddd">ⓘ</span>]</span>

Kontrollfluss

Lua hat eine Art von bedingten Tests: if then end mit optionalen else und elseif then Konstrukten zur Ausführungskontrolle.

Die generische if then end-Anweisung erfordert alle drei Schlüsselwörter:

if Bedingung then
	--Anweisungskörper
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Control flow&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Control_flow <span style="color:#dddddd">ⓘ</span>]</span>

Das else-Schlüsselwort kann mit einem begleitenden Anweisungsblock hinzugefügt werden, um die Ausführung zu steuern, wenn die if-Bedingung als falsch bewertet wird:

if condition then
	--Anweisungskörper
else
	--Anweisungsblock
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Control flow&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Control_flow <span style="color:#dddddd">ⓘ</span>]</span>

Mit den elseif then-Schlüsselwörtern kann die Ausführung auch von mehreren Bedingungen abhängig gemacht werden:

if Bedingung then
	--Anweisungsrumpf
elseif Bedingung then
	--Anweisungsrumpf
else -- optional
	--optionaler Standard-Anweisungsrumpf
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Control flow&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Control_flow <span style="color:#dddddd">ⓘ</span>]</span>

Lua kennt vier Arten von bedingten Schleifen: die while-Schleife, die repeat-Schleife (ähnlich einer do while-Schleife), die numerische for-Schleife und die generische for-Schleife.

--condition = true <span title="Aus: Englische Wikipedia, Abschnitt &quot;Control flow&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Control_flow <span style="color:#dddddd">ⓘ</span>]</span>

while Bedingung do
  -Anweisungen
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Control flow&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Control_flow <span style="color:#dddddd">ⓘ</span>]</span>

repeat
  -Anweisungen
bis Bedingung <span title="Aus: Englische Wikipedia, Abschnitt &quot;Control flow&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Control_flow <span style="color:#dddddd">ⓘ</span>]</span>

for i = first, last, delta do --delta kann negativ sein, damit die for-Schleife abwärts oder aufwärts zählen kann
  --Befehle
  ---Beispiel: print(i)
end

Die generische for-Schleife:

for key, value in pairs(_G) do
  print(schlüssel, wert)
end

würde über die Tabelle _G iterieren und dabei die Standard-Iteratorfunktion pairs verwenden, bis sie null zurückgibt.

Schleifen können auch verschachtelt werden (innerhalb einer anderen Schleife).

local grid = {
  { 11, 12, 13 },
  { 21, 22, 23 },
  { 31, 32, 33 }
} <span title="Aus: Englische Wikipedia, Abschnitt &quot;Control flow&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Control_flow <span style="color:#dddddd">ⓘ</span>]</span>

for y, row in ipairs(grid) do
  for x, value in ipairs(row) do
    print(x, y, wert)
  end
end

Das Schlüsselwort nil steht (neben false) für falsch und generell für nicht initialisierte Variablen oder nicht interpretierbare Werte.

Funktionen

Wie Lua Funktionen als Werte erster Klasse behandelt, zeigt das folgende Beispiel, in dem das Verhalten der Funktion print geändert wurde:

do
  local oldprint = print
  -- Aktuelle Druckfunktion als oldprint speichern
  function print(s)
    --[[ Druckfunktion umdefinieren. Die übliche Druckfunktion kann weiterhin
      durch oldprint verwendet werden. Die neue hat nur ein Argument.]]
    oldprint(s == "foo" und "bar" oder s)
  end
end

Alle zukünftigen Aufrufe von print werden nun über die neue Funktion geleitet, und aufgrund des lexikalischen Scopings von Lua ist die alte print-Funktion nur noch über die neue, modifizierte print-Funktion zugänglich.

Lua unterstützt auch Closures, wie im Folgenden gezeigt wird:

function addto(x)
  -- Gibt eine neue Funktion zurück, die x zum Argument addiert
  return function(y)
    --[=[ Wenn wir uns auf die Variable x beziehen, die sich außerhalb des aktuellen
      Geltungsbereich liegt und deren Lebensdauer kürzer ist als die dieser anonymen
      Funktion, erzeugt Lua eine Schließung.]]
    return x + y
  end
end
vierplus = addto(4)
print(fourplus(3)) -- Druckt 7 <span title="Aus: Englische Wikipedia, Abschnitt &quot;Functions&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Functions <span style="color:#dddddd">ⓘ</span>]</span>

--Dies kann auch erreicht werden, indem die Funktion wie folgt aufgerufen wird:
print(addto(4)(3))
--[[ Das liegt daran, dass wir die zurückgegebene Funktion von 'addto(4)' mit dem Argument '3' direkt aufrufen.
  Dies hilft auch, die Datenkosten zu reduzieren und die Leistung zu erhöhen, wenn die Funktion iterativ aufgerufen wird.
]]

Bei jedem Aufruf von addto wird eine neue Closure für die Variable x erstellt, so dass jede neue anonyme Funktion, die zurückgegeben wird, immer auf ihren eigenen Parameter x zugreift. Die Closure wird vom Garbage Collector von Lua verwaltet, wie jedes andere Objekt auch.

Tabellen

Tabellen sind die wichtigsten Datenstrukturen (und der einzige eingebaute zusammengesetzte Datentyp) in Lua und bilden die Grundlage für alle vom Benutzer erstellten Typen. Sie sind assoziative Arrays mit zusätzlichen automatischen numerischen Schlüsseln und einer speziellen Syntax.

Eine Tabelle ist eine Sammlung von Schlüssel- und Datenpaaren, wobei die Daten durch den Schlüssel referenziert werden; mit anderen Worten, es ist ein heterogenes assoziatives Hash-Array.

Tabellen werden mit der {}-Konstruktorsyntax erstellt.

a_table = {} -- Erzeugt eine neue, leere Tabelle <span title="Aus: Englische Wikipedia, Abschnitt &quot;Tables&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Tables <span style="color:#dddddd">ⓘ</span>]</span>

Tabellen werden immer per Referenz übergeben (siehe Aufruf durch Freigabe).

Ein Schlüssel (Index) kann jeder Wert außer nil und NaN sein, einschließlich Funktionen.

a_table = {x = 10} -- Erzeugt eine neue Tabelle mit einem Eintrag, der "x" auf die Zahl 10 abbildet.
print(a_table["x"]) -- Gibt den mit dem String-Schlüssel verbundenen Wert aus, in diesem Fall 10.
b_table = a_table
b_table["x"] = 20 -- Der Wert in der Tabelle wurde in 20 geändert.
print(b_table["x"]) -- Druckt 20.
print(a_table["x"]) -- Gibt ebenfalls 20 aus, da a_table und b_table sich beide auf dieselbe Tabelle beziehen. <span title="Aus: Englische Wikipedia, Abschnitt &quot;Tables&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Tables <span style="color:#dddddd">ⓘ</span>]</span>

Eine Tabelle wird oft als Struktur (oder Datensatz) verwendet, indem Zeichenketten als Schlüssel verwendet werden. Da dies sehr häufig vorkommt, bietet Lua eine spezielle Syntax für den Zugriff auf solche Felder.

Punkt = { x = 10, y = 20 }   -- Neue Tabelle erstellen
print(punkt["x"]) -- Druckt 10
print(point.x) -- Hat genau die gleiche Bedeutung wie die obige Zeile. Die leichter zu lesende Punktschreibweise ist nur syntaktischer Zucker. <span title="Aus: Englische Wikipedia, Abschnitt &quot;Tables&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Tables <span style="color:#dddddd">ⓘ</span>]</span>

Indem man eine Tabelle verwendet, um verwandte Funktionen zu speichern, kann sie als Namensraum fungieren.

Punkt = {} <span title="Aus: Englische Wikipedia, Abschnitt &quot;Tables&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Tables <span style="color:#dddddd">ⓘ</span>]</span>

Punkt.neu = function(x, y)
  return {x = x, y = y} -- return {["x"] = x, ["y"] = y}
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Tables&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Tables <span style="color:#dddddd">ⓘ</span>]</span>

Punkt.set_x = function(punkt, x)
  Punkt.x = x -- Punkt["x"] = x;
end

Tabellen werden automatisch mit einem numerischen Schlüssel versehen, so dass sie als Array-Datentyp verwendet werden können. Der erste automatische Index ist 1 und nicht 0 wie in vielen anderen Programmiersprachen (obwohl ein expliziter Index von 0 erlaubt ist).

Ein numerischer Schlüssel 1 unterscheidet sich von einem String-Schlüssel "1".

array = { "a", "b", "c", "d" }   -- Indizes werden automatisch zugewiesen.
print(array[2]) -- Druckt "b". Die automatische Indizierung in Lua beginnt bei 1.
print(#array) -- Druckt 4.  # ist der Längenoperator für Tabellen und Strings.
array[0] = "z" -- Null ist ein legaler Index.
print(#array) -- Gibt immer noch 4 aus, da Lua-Arrays 1-basiert sind. <span title="Aus: Englische Wikipedia, Abschnitt &quot;Tables&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Tables <span style="color:#dddddd">ⓘ</span>]</span>

Die Länge einer Tabelle t ist definiert als ein beliebiger ganzzahliger Index n, so dass t[n] nicht Null ist und t[n+1] Null ist; wenn t[1] Null ist, kann n auch Null sein. Bei einer regulären Matrix mit Werten von 1 bis zu einem bestimmten n, die nicht null sind, ist die Länge genau dieses n, der Index des letzten Wertes. Wenn das Array "Löcher" hat (d.h. Null-Werte zwischen anderen Nicht-Null-Werten), dann kann #t jeder der Indizes sein, der einem Null-Wert direkt vorausgeht (d.h., es kann jeden solchen Null-Wert als das Ende des Arrays betrachten).

BeispielTabelle =
{
  {1, 2, 3, 4},
  {5, 6, 7, 8}
}
print(Beispieltabelle[1][3]) -- Druckt "3"
print(Beispieltabelle[2][4]) -- Druckt "8" <span title="Aus: Englische Wikipedia, Abschnitt &quot;Tables&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Tables <span style="color:#dddddd">ⓘ</span>]</span>

Eine Tabelle kann ein Array von Objekten sein.

function Punkt(x, y) -- "Punkt"-Objekt-Konstruktor
  return { x = x, y = y }   -- Erzeugt und liefert ein neues Objekt (Tabelle)
Ende
array = { Punkt(10, 20), Punkt(30, 40), Punkt(50, 60) }   -- Erzeugt ein Array von Punkten
                        -- array = { { x = 10, y = 20 }, { x = 30, y = 40 }, { x = 50, y = 60 } };
print(array[2].y) -- Druckt 40 <span title="Aus: Englische Wikipedia, Abschnitt &quot;Tables&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Tables <span style="color:#dddddd">ⓘ</span>]</span>

Die Verwendung einer Hash-Map zur Emulation eines Arrays ist normalerweise langsamer als die Verwendung eines echten Arrays; Lua-Tabellen sind jedoch für die Verwendung als Arrays optimiert, um dieses Problem zu vermeiden.

Neben den Datentypen nil, boolean, number (mit den internen Subtypen integer und float), string, function, userdata und thread kennt Lua als einzigen strukturierten Datentyp table (Tabelle).

Metatabellen

Erweiterbare Semantik ist ein Schlüsselmerkmal von Lua, und das Metatables-Konzept ermöglicht eine leistungsstarke Anpassung von Tabellen. Das folgende Beispiel demonstriert eine "unendliche" Tabelle. Für ein beliebiges n liefert fibs[n] die n-te Fibonacci-Zahl durch dynamische Programmierung und Memoisierung.

fibs = { 1, 1 } -- Anfangswerte für fibs[1] und fibs[2].
setmetatable(fibs, {
  __index = function(values, n) --[[__index ist eine von Lua vordefinierte Funktion, 
                                                   sie wird aufgerufen, wenn der Schlüssel "n" nicht vorhanden ist]]
    values[n] = values[n - 1] + values[n - 2] -- Berechne und speichere fibs[n].
    return values[n]
  end
}) <span title="Aus: Englische Wikipedia, Abschnitt &quot;Metatables&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Metatables <span style="color:#dddddd">ⓘ</span>]</span>

Objektorientierte Programmierung

Obwohl Lua kein eingebautes Klassenkonzept hat, kann die objektorientierte Programmierung mit Hilfe von Funktionen und Tabellen emuliert werden. Ein Objekt wird gebildet, indem man Methoden und Felder in eine Tabelle einfügt. Vererbung (sowohl einfach als auch mehrfach) kann mit Metatabellen implementiert werden, wobei nicht existierende Methoden und Felder an ein übergeordnetes Objekt delegiert werden.

Bei diesen Techniken gibt es kein Konzept einer "Klasse", sondern es werden Prototypen verwendet, ähnlich wie bei Self oder JavaScript. Neue Objekte werden entweder mit einer Factory-Methode (die neue Objekte von Grund auf konstruiert) oder durch Klonen eines bestehenden Objekts erstellt.

Erstellen eines einfachen Vektorobjekts:

local Vector = {}
local VectorMeta = { __index = Vector} <span title="Aus: Englische Wikipedia, Abschnitt &quot;Object-oriented programming&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Object-oriented_programming <span style="color:#dddddd">ⓘ</span>]</span>

function Vector.new(x, y, z) -- Der Konstruktor
  return setmetatable({x = x, y = y, z = z}, VectorMeta)
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Object-oriented programming&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Object-oriented_programming <span style="color:#dddddd">ⓘ</span>]</span>

function Vector.magnitude(self) -- Eine weitere Methode
  return math.sqrt(self.x^2 + self.y^2 + self.z^2)
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Object-oriented programming&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Object-oriented_programming <span style="color:#dddddd">ⓘ</span>]</span>

local vec = Vector.new(0, 1, 0) -- Erzeugen eines Vektors
print(vec.magnitude(vec)) -- Aufruf einer Methode (Ausgabe: 1)
print(vec.x) -- Zugriff auf eine Mitgliedsvariable (Ausgabe: 0)

hier, setmetatable Lua an, nach einem Element in der Datei Vektor Tabelle zu suchen, wenn es nicht in der vec Tabelle vorhanden ist. vec.magnitudewas gleichbedeutend ist mit vec["magnitude"]entspricht, sucht zunächst in der vec Tabelle nach dem Größenordnung Element. Die Tabelle vec Tabelle verfügt nicht über ein Größenordnung Element, aber seine metatable delegiert an das Vektor Tabelle nach dem Größenordnung Element, wenn es nicht in der Tabelle gefunden wird. vec Tabelle vorhanden ist.

Lua bietet einige syntaktische Hilfsmittel, um die Objektorientierung zu erleichtern. Um Mitgliedsfunktionen innerhalb einer Prototyp-Tabelle zu deklarieren, kann man verwenden function table:func(args)was gleichbedeutend ist mit Funktion table.func(self, args). Beim Aufruf von Klassenmethoden wird ebenfalls der Doppelpunkt verwendet: object:func(args) ist äquivalent zu object.func(object, args).

In diesem Sinne, hier ist eine entsprechende Klasse mit : syntaktischem Zucker:

local Vector = {}
Vector.__index = Vector <span title="Aus: Englische Wikipedia, Abschnitt &quot;Object-oriented programming&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Object-oriented_programming <span style="color:#dddddd">ⓘ</span>]</span>

function Vector:new(x, y, z) -- Der Konstruktor
  -- Da die Funktionsdefinition einen Doppelpunkt verwendet, 
  -- ist ihr erstes Argument "self", das sich auf
  -- auf "Vector"
  return setmetatable({x = x, y = y, z = z}, self)
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Object-oriented programming&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Object-oriented_programming <span style="color:#dddddd">ⓘ</span>]</span>

function Vector:magnitude() -- Eine weitere Methode
  -- Verweist auf das implizite Objekt mit self
  return math.sqrt(self.x^2 + self.y^2 + self.z^2)
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Object-oriented programming&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Object-oriented_programming <span style="color:#dddddd">ⓘ</span>]</span>

local vec = Vector:new(0, 1, 0) -- Erzeugen eines Vektors
print(vec:magnitude()) -- Aufruf einer Methode (Ausgabe: 1)
print(vec.x) -- Zugriff auf eine Mitgliedsvariable (Ausgabe: 0)

Vererbung

Lua unterstützt die Verwendung von Metatabellen, um Lua-Klassen zu vererben. In diesem Beispiel erlauben wir Vektoren, ihre Werte mit einer Konstante in einer abgeleiteten Klasse zu multiplizieren.

local Vector = {}
Vector.__index = Vector <span title="Aus: Englische Wikipedia, Abschnitt &quot;Inheritance&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Inheritance <span style="color:#dddddd">ⓘ</span>]</span>

function Vector:new(x, y, z) -- Der Konstruktor
  -- Hier bezieht sich self auf die "new"-Methode der jeweiligen Klasse
  -- Methode der Klasse, die wir aufrufen.  In einer abgeleiteten Klasse wird self
  -- die abgeleitete Klasse sein; in der Vector-Klasse ist self
  -- Vector sein
  return setmetatable({x = x, y = y, z = z}, self)
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Inheritance&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Inheritance <span style="color:#dddddd">ⓘ</span>]</span>

function Vector:magnitude() -- Eine weitere Methode
  -- Verweist auf das implizite Objekt mit self
  return math.sqrt(self.x^2 + self.y^2 + self.z^2)
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Inheritance&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Inheritance <span style="color:#dddddd">ⓘ</span>]</span>

-- Beispiel für Klassenvererbung
local VectorMult = {}
VectorMult.__index = VectorMult
setmetatable(VectorMult, Vector) -- Macht VectorMult zu einem Kind von Vector <span title="Aus: Englische Wikipedia, Abschnitt &quot;Inheritance&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Inheritance <span style="color:#dddddd">ⓘ</span>]</span>

function VectorMult:multiply(Wert) 
  self.x = self.x * Wert
  self.y = self.y * Wert
  self.z = self.z * Wert
  return self
end <span title="Aus: Englische Wikipedia, Abschnitt &quot;Inheritance&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#Inheritance <span style="color:#dddddd">ⓘ</span>]</span>

local vec = VectorMult:new(0, 1, 0) -- Erzeugen eines Vektors
print(vec:magnitude()) -- Aufruf einer Methode (Ausgabe: 1)
print(vec.y) -- Zugriff auf eine Mitgliedsvariable (Ausgabe: 1)
vec:multiply(2) -- Multipliziert alle Komponenten des Vektors mit 2
print(vec.y) -- Erneuter Zugriff auf eine Member-Variable (Ausgabe: 2)

Lua unterstützt auch Mehrfachvererbung; __index kann entweder eine Funktion oder eine Tabelle sein. Das Überladen von Operatoren ist ebenfalls möglich; Lua-Metatabellen können Elemente haben wie __add, __subund so weiter.

Implementierung

Lua-Programme werden nicht direkt aus der textuellen Lua-Datei interpretiert, sondern in Bytecode kompiliert, der dann auf der virtuellen Lua-Maschine ausgeführt wird. Der Kompilierungsprozess ist in der Regel für den Benutzer unsichtbar und wird während der Laufzeit durchgeführt, insbesondere wenn ein JIT-Compiler verwendet wird, aber er kann auch offline durchgeführt werden, um die Ladeleistung zu erhöhen oder den Speicherbedarf der Host-Umgebung zu verringern, indem der Compiler weggelassen wird. Lua-Bytecode kann auch innerhalb von Lua erzeugt und ausgeführt werden, indem die dump-Funktion der String-Bibliothek und die Funktionen load/loadstring/loadfile verwendet werden. Lua Version 5.3.4 ist in etwa 24.000 Zeilen C-Code implementiert.

Wie die meisten CPUs und im Gegensatz zu den meisten virtuellen Maschinen (die stapelbasiert sind), ist die Lua-VM registerbasiert und ähnelt daher eher einem tatsächlichen Hardware-Design. Die Registerarchitektur vermeidet sowohl das übermäßige Kopieren von Werten als auch die Reduzierung der Gesamtzahl der Anweisungen pro Funktion. Die virtuelle Maschine von Lua 5 ist eine der ersten registerbasierten, reinen VMs, die eine breite Anwendung finden. Parrot und Androids Dalvik sind zwei weitere bekannte registerbasierte VMs. Die VM von PCScheme war ebenfalls registerbasiert.

Dieses Beispiel ist das Bytecode-Listing der oben definierten Factorial-Funktion (wie vom luac 5.1 Compiler angezeigt):

Funktion <factorial.lua:1,7> (9 Anweisungen, 36 Bytes bei 0x8063c60)
1 param, 6 slots, 0 upvalues, 6 locals, 2 constants, 0 functions
	1 [2] LOADK 1 -1 ; 1
	2 [3] LOADK 2 -2 ; 2
	3 [3] MOVE 3 0
	4 [3] LOADK 4 -1 ; 1
	5 [3] FORPREP 2 1 ; bis 7
	6 [4] MUL 1 1 5
	7 [3] FORLOOP 2 -2 ; bis 6
	8 [6] RETURN 1 2
	9 [7] RÜCKGABE 0 1 

C-API

Lua ist dafür gedacht, in andere Anwendungen eingebettet zu werden, und bietet zu diesem Zweck eine C-API. Die API ist in zwei Teile unterteilt: den Lua-Kern und die Lua-Hilfsbibliothek. Durch das Design der Lua-API entfällt im Gegensatz zur Python-API die Notwendigkeit einer manuellen Referenzverwaltung im C-Code. Die API ist, wie die Sprache, minimalistisch. Erweiterte Funktionen werden von der Hilfsbibliothek bereitgestellt, die größtenteils aus Präprozessormakros besteht, die bei komplexen Tabellenoperationen helfen.

Die C-API von Lua ist stapelbasiert. Lua bietet Funktionen, um die meisten einfachen C-Datentypen (Integer, Floats usw.) auf den Stack zu schieben und von dort zu holen, sowie Funktionen zur Manipulation von Tabellen über den Stack. Der Lua-Stack unterscheidet sich etwas von einem traditionellen Stack; der Stack kann zum Beispiel direkt indiziert werden. Negative Indizes geben Offsets von der Spitze des Stacks an. Zum Beispiel ist -1 der oberste (zuletzt geschobene) Wert, während positive Indizes Offsets vom untersten (ältesten) Wert angeben. Das Marshalling von Daten zwischen C- und Lua-Funktionen erfolgt ebenfalls über den Stack. Um eine Lua-Funktion aufzurufen, werden Argumente auf den Stack geschoben, und dann wird lua_call verwendet, um die eigentliche Funktion aufzurufen. Beim Schreiben einer C-Funktion, die direkt aus Lua aufgerufen werden soll, werden die Argumente vom Stack gelesen.

Hier ist ein Beispiel für den Aufruf einer Lua-Funktion aus C:

#include <stdio.h>
#include <lua.h> // Lua-Hauptbibliothek (lua_*)
#include <lauxlib.h> // Lua-Hilfsbibliothek (luaL_*) <span title="Aus: Englische Wikipedia, Abschnitt &quot;C API&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#C_API <span style="color:#dddddd">ⓘ</span>]</span>

int main(void)
{
    // Erzeugen eines Lua-Status
    lua_State *L = luaL_newstate(); <span title="Aus: Englische Wikipedia, Abschnitt &quot;C API&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#C_API <span style="color:#dddddd">ⓘ</span>]</span>

    // Laden und Ausführen eines Strings
    if (luaL_dostring(L, "function foo (x,y) return x+y end")) {
        lua_close(L);
        return -1;
    } <span title="Aus: Englische Wikipedia, Abschnitt &quot;C API&quot;" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#C_API <span style="color:#dddddd">ⓘ</span>]</span>

    // Schiebe den Wert von global "foo" (die oben definierte Funktion)
    // auf den Stack, gefolgt von den Ganzzahlen 5 und 3
    lua_getglobal(L, "foo");
    lua_pushinteger(L, 5);
    lua_pushinteger(L, 3);
    lua_call(L, 2, 1); // Aufruf einer Funktion mit zwei Argumenten und einem Rückgabewert
    printf("Ergebnis: %d\n", lua_tointeger(L, -1)); // Ganzzahligen Wert des Elements oben auf dem Stapel drucken
    lua_pop(L, 1); // Stapel in den ursprünglichen Zustand zurückversetzen
    lua_close(L); // Lua-Status schließen
    Rückgabe 0;
}

Die Ausführung dieses Beispiels ergibt:

$ cc -o beispiel beispiel.c -llua
$ ./example
Ergebnis: 8 <span title="Aus: Englische Wikipedia, Abschnitt "C API"" class="plainlinks">[https://en.wikipedia.org/wiki/Lua_(programming_language)#C_API <span style="color:#dddddd">ⓘ</span>]</span>

Die C-API bietet auch einige spezielle Tabellen, die sich an verschiedenen "Pseudo-Indizes" im Lua-Stack befinden. Unter LUA_GLOBALSINDEX befindet sich vor Lua 5.2 die Tabelle globals, _G innerhalb von Lua, die den Hauptnamensraum darstellt. Es gibt auch eine Registry unter LUA_REGISTRYINDEX, in der C-Programme Lua-Werte zum späteren Abruf speichern können.

Es ist möglich, Erweiterungsmodule unter Verwendung der Lua-API zu schreiben. Erweiterungsmodule sind gemeinsam genutzte Objekte, die verwendet werden können, um die Funktionalität des Interpreters zu erweitern, indem sie Lua-Skripten native Funktionen zur Verfügung stellen. Lua-Skripte können Erweiterungsmodule mit require laden, genau wie in Lua selbst geschriebene Module, oder mit package.loadlib. Wenn eine C-Bibliothek über require("foo") geladen wird, sucht Lua nach der Funktion luaopen_foo und ruft sie auf, die sich wie jede von Lua aus aufrufbare C-Funktion verhält und im Allgemeinen eine Tabelle mit Methoden zurückgibt. Eine wachsende Sammlung von Modulen, die als Rocks bekannt sind, ist über ein Paketverwaltungssystem namens LuaRocks verfügbar, ganz im Geiste von CPAN, RubyGems und Python Eggs. Für die meisten gängigen Programmiersprachen, einschließlich anderer Skriptsprachen, gibt es vorgefertigte Lua-Bindings. Für C++ gibt es eine Reihe von vorlagenbasierten Ansätzen und einige automatische Bindungsgeneratoren.

Anwendungen

Bei der Entwicklung von Videospielen wird Lua von Programmierern häufig als Skriptsprache verwendet, vor allem wegen seiner vermeintlich einfachen Einbindung, schnellen Ausführung und kurzen Lernkurve. Bekannte Spiele, die Lua verwenden, sind Roblox, Garry's Mod, Payday 2, Phantasy Star Online 2, Dota 2, Angry Birds Space, Crysis und viele andere. Einige Spiele, die von Haus aus keine Lua-Programmierung oder Skripterstellung unterstützen, haben diese Funktionalität durch Mods hinzugefügt, wie zum Beispiel ComputerCraft für Minecraft. Darüber hinaus wird Lua auch in Software verwendet, die nicht für Videospiele gedacht ist, wie Adobe Lightroom, Moho, iClone, Aerospike und bestimmte Systemsoftware in FreeBSD und NetBSD, und wird als Template-Skriptsprache in MediaWiki mit der Erweiterung Scribunto verwendet.

Im Jahr 2003 ergab eine von GameDev.net durchgeführte Umfrage, dass Lua die beliebteste Skriptsprache für die Spieleprogrammierung ist. Am 12. Januar 2012 wurde Lua als Gewinner des Front Line Award 2011 der Zeitschrift Game Developer in der Kategorie Programmierwerkzeuge bekannt gegeben.

Eine große Anzahl von Anwendungen, die keine Spiele sind, nutzen Lua ebenfalls zur Erweiterung, wie LuaTeX, eine Implementierung der Schriftsatzsprache TeX, Redis, eine Key-Value-Datenbank, Neovim, ein Texteditor, Nginx, ein Webserver, und Wireshark, ein Netzwerk-Paketanalysator.

Über die Scribunto-Erweiterung ist Lua als serverseitige Skriptsprache in der MediaWiki-Software verfügbar, die Wikipedia und andere Wikis betreibt. Sie ermöglicht unter anderem die Integration von Daten aus Wikidata in Artikel und unterstützt das automatische Taxobox-System.

Lua kann sowohl zum Verfassen eigenständiger Programme verwendet werden als auch als eingebettete Sprache dienen.

Auch einige insbesondere dynamische und Tiling-Fenstermanager nutzen Lua für Konfiguration und Steuerung, darunter awesome und Ion3.

Abgeleitete Sprachen

Sprachen, die sich zu Lua kompilieren lassen

  • MoonScript ist eine dynamische, Whitespace-sensitive Skriptsprache, die von CoffeeScript inspiriert ist und in Lua kompiliert wird. Das bedeutet, dass anstelle von do und end (oder { und }) zur Abgrenzung von Codeabschnitten Zeilenumbrüche und Einrückungen verwendet werden. Eine bemerkenswerte Verwendung von MoonScript ist die Website Itch.io, die Videospiele vertreibt.
  • Haxe unterstützt die Kompilierung zu einem Lua-Target und unterstützt Lua 5.1-5.3 sowie LuaJIT 2.0 und 2.1.
  • Fennel, ein Lisp-Dialekt, der auf Lua zielt.
  • Urn, ein Lisp-Dialekt, der auf Lua aufgebaut ist.
  • Amulet, eine ML-ähnliche funktionale Sprache, deren Compiler Lua-Dateien ausgibt.

Dialekte

  • LuaJIT
  • Luau von Roblox, Lua 5.1 Sprache mit gradueller Typisierung und ergonomischen Ergänzungen.
  • Ravi, JIT-fähige Lua 5.3-Sprache mit optionaler statischer Typisierung. JIT wird durch Typinformationen gesteuert.
  • Shine, ein Fork von LuaJIT mit vielen Erweiterungen, darunter ein Modulsystem und ein Makrosystem.

Darüber hinaus stellt die Lua-Benutzergemeinschaft einige leistungsstarke Patches für die C-Referenzimplementierung bereit.

Syntax

Zuweisungen

a = 5
b = "hi"
local a = a
-- Einfache Zuweisungen. Variablen sind nicht typisiert und können verschiedene Datentypen haben.
-- Lokale Variablen (definiert mit "local") sind auf den aktuellen Namensbereich beschränkt.
a, b, c = 1, 2, 3 -- Mehrfachzuweisungen sind erlaubt.
a, b = b, a -- Wertetausch: Anweisungen werden von rechts nach links ausgewertet.
a, b = 4, 5, "6" -- Überflüssige Werte (Bsp: "6") werden ausgewertet, aber verworfen.
a, b = "da" -- Fehlende Werte auf der rechten Seite werden mit "nil" ersetzt.
a = nil -- Zerstört a. Der Speicherbereich von a wird vom Garbage-Collector freigegeben.
a = z -- Falls z nicht definiert ist, wird "nil" zugewiesen und somit a freigegeben.
a = "3" + "2" -- Der Operator + erwartet Zahlen, die Zeichenketten werden also
             -- in Zahlen konvertiert, also erfolgt hier die Zuweisung a = 5.
a = 3 .. 2 -- Der Verbindungsoperator erwartet Zeichenketten, die Zahlen werden
          -- konvertiert - a = "32".
local a <const> = 5 -- lexikalische (lokale) Konstanten wurden in Lua 5.4 eingeführt
local f <close> = io.open(file) -- ebenfalls ab 5.4: to-close-Variablen mit ähnlicher Semantik
                                -- wie Pythons Context Manager (with ...) <span title="Aus: Deutsche Wikipedia, Abschnitt &quot;Zuweisungen&quot;" class="plainlinks">[https://de.wikipedia.org/wiki/Lua#Zuweisungen <span style="color:#dddddd">ⓘ</span>]</span>

Funktionen

Funktionen können mit dem Schlüsselwort function erzeugt werden. Funktionen besitzen keine fixierte Anzahl an Parametern und Rückgabewerten.

function probe(zahl1, zahl2, text, tabelle)
    zahl3 = zahl1 + zahl2
    zahl4 = zahl1 - zahl2 <span title="Aus: Deutsche Wikipedia, Abschnitt &quot;Funktionen&quot;" class="plainlinks">[https://de.wikipedia.org/wiki/Lua#Funktionen <span style="color:#dddddd">ⓘ</span>]</span>

    print(text) <span title="Aus: Deutsche Wikipedia, Abschnitt &quot;Funktionen&quot;" class="plainlinks">[https://de.wikipedia.org/wiki/Lua#Funktionen <span style="color:#dddddd">ⓘ</span>]</span>

    if tabelle ~= nil then
        print(tabelle.eintrag)
    end <span title="Aus: Deutsche Wikipedia, Abschnitt &quot;Funktionen&quot;" class="plainlinks">[https://de.wikipedia.org/wiki/Lua#Funktionen <span style="color:#dddddd">ⓘ</span>]</span>

    return zahl3,zahl4
end <span title="Aus: Deutsche Wikipedia, Abschnitt &quot;Funktionen&quot;" class="plainlinks">[https://de.wikipedia.org/wiki/Lua#Funktionen <span style="color:#dddddd">ⓘ</span>]</span>

probe(10, 20, "Hallo ", {eintrag = "Welt"}) -- erlaubter Funktionsaufruf <span title="Aus: Deutsche Wikipedia, Abschnitt &quot;Funktionen&quot;" class="plainlinks">[https://de.wikipedia.org/wiki/Lua#Funktionen <span style="color:#dddddd">ⓘ</span>]</span>

x,y = probe(10,20) -- ebenfalls erlaubter Aufruf, text und tabelle sind nil.

Beim Aufruf der Funktion müssen nicht alle Variablen übergeben werden. Fehlende Parameter besitzen automatisch den Nullwert nil. Dasselbe gilt für Rückgabewerte. Dadurch lassen sich Funktionsüberladungen einfacher implementieren, das Vorkommen von Laufzeitfehlern steigt jedoch.

Module

Lua ist durch benutzerdefinierte Module beliebig erweiterbar. Um diese zu verwalten, ist der in Lua geschriebene Paketverwalter LuaRocks verfügbar.

Eine Liste mit verbreiteten Lua-Modulen:

Modul Beschreibung
LuaFileSystem Zugriff auf Ordnerstrukturen und Dateieigenschaften.
LuaDoc Dokumentationstool für Lua-Quellcode.
LuaSocket Bibliothek für Socketprogrammierung.
LuaSQL Lua-Interface für PostgreSQL, ODBC, MySQL, SQLite, Oracle, und OLE DB.
stdlib Bibliothek für häufige Programmieraufgaben; bezieht sich auf Listen, Tabellen, funktionale Programmierung, Reguläre Ausdrücke, Objekte, Pretty-Printing und getopt.
MD5 einfache kryptografische Hashfunktion
Copas Dispatcher, basierend auf Co-Routinen, der von TCP/IP-Servern verwendet werden kann.
LuaZip Bibliothek, die von ZIP-Dateien lesen kann.
LuaInterface Verbindung zwischen Lua und Microsofts .Net-Framework Common Language Runtime (CLR).
LuaBitOps Eine auf C basierende Erweiterung für Lua für bitweise Operationen von Zahlen.
LuaXML Einfache Verbindung zwischen XML und Lua.
Lanes Ermöglicht das parallele Laufen von verschiedenen Lua-Umgebungen.
Penlight Bibliothek, die den Umgang mit Tabellen, Arrays, Strings, Dateipfaden, Ordnern, Daten und funktionalen Programmieranwendungen vereinfacht.
Oil Einfacher und effizienter Object Request Broker (CORBA).

Literatur

  • Roberto Ierusalimschy: Programmieren in Lua, 4. Auflage, Open Source Press, 2016, ISBN 978-8-59037-986-7.
  • Roberto Ierusalimschy, L. H. Figueiredo, W. Celes: Lua 5.1 Reference Manual, August 2006, ISBN 85-903798-3-3.
  • Kurt Jung, Aaron Brown: Beginning Lua Programming, Wrox, 2007, ISBN 0-470-06917-1.
  • Claus Kühnel, Daniel Zwirner: Lua: Einsatz von Lua in Embedded Systems, 2. Auflage, Skript Verlag Kühnel, 2012, ISBN 978-3-90785-715-1.
  • David Young: Learning Game AI Programming with Lua, Packt Publishing, 2014, ISBN 1-783-28133-2.

Weblinks

Commons: Lua – Sammlung von Bildern, Videos und Audiodateien

Quellen und Anmerkungen