Lua (język programowania) - Lua (programming language)
Paradygmat | Wieloparadygmat : skryptowy , imperatywny ( proceduralny , prototypowy , obiektowy ), funkcjonalny |
---|---|
Zaprojektowany przez |
Roberto Ierusalimschy Waldemar Celes Luiz Henrique de Figueiredo |
Po raz pierwszy pojawiły się | 1993 |
Wersja stabilna | |
Dyscyplina pisania | Dynamiczny , mocny , kaczy |
Język implementacji | ANSI C |
OS | Wieloplatformowy |
Licencja | Licencja MIT |
Rozszerzenia nazw plików | .lua |
Strona internetowa | www |
Główne wdrożenia | |
Lua , LuaJIT , LuaVela , MoonSharp , Luvit , LuaRT | |
Dialekty | |
Metalua , Bezczynny , GSL Shell , Luau | |
Wpływem | |
C++ , CLU , Moduł , Schemat , SNOBOL | |
Pod wpływem | |
GameMonkey , Io , JavaScript , Julia , MiniD, czerwony , pierścień, Ruby , wiewiórka , MoonScript, C-- |
Lua ( / l ù ə / LOO -ə , od języku : lua [Lu. (W) ɐ] Znaczenie księżyc ) jest lekki , wysoki poziom , multi-paradygmat język programowania przeznaczony głównie dla osadzonych wykorzystania w aplikacjach. Lua jest cross-platform , ponieważ interpreter z skompilowanego kodu bajtowego jest napisany w języku ANSI C i Lua ma stosunkowo proste C API , aby umieścić go w aplikacji.
Lua został pierwotnie zaprojektowany w 1993 roku jako język do rozszerzania aplikacji, aby sprostać rosnącemu w tamtym czasie zapotrzebowaniu na dostosowywanie. Zapewniał podstawowe udogodnienia większości proceduralnych języków programowania , ale nie uwzględniono bardziej skomplikowanych lub specyficznych dla domeny funkcji; zawierał raczej mechanizmy rozszerzania języka, pozwalające programistom na implementację takich funkcji. Ponieważ Lua miał być ogólnym językiem rozszerzeń do osadzania, projektanci Lua skupili się na poprawie jego szybkości , przenośności , rozszerzalności i łatwości użytkowania w rozwoju.
Historia
Lua została stworzona w 1993 roku przez Roberto Ierusalimschy'ego , Luiza Henrique de Figueiredo i Waldemara Celesa, członków Computer Graphics Technology Group (Tecgraf) przy Papieskim Uniwersytecie Katolickim w Rio de Janeiro w Brazylii .
Od 1977 do 1992 roku Brazylia prowadziła politykę silnych barier handlowych (zwanych rezerwą rynkową) dla sprzętu komputerowego i oprogramowania. W takiej atmosferze klienci Tecgrafu nie mogli pozwolić sobie ani politycznie, ani finansowo na kupowanie spersonalizowanego oprogramowania z zagranicy. Te powody skłoniły Tecgraf do wdrożenia od podstaw potrzebnych jej podstawowych narzędzi.
Poprzednikami Lua były języki opisu/konfiguracji danych SOL (Simple Object Language) i DEL (język wprowadzania danych). Zostały one niezależnie opracowane w Tecgraf w latach 1992-1993, aby dodać pewną elastyczność do dwóch różnych projektów (oba były interaktywnymi programami graficznymi do zastosowań inżynierskich w firmie Petrobras ). Brakowało jakichkolwiek struktur kontroli przepływu w SOL i DEL, a Petrobras odczuwał rosnącą potrzebę dodania do nich pełnej mocy programistycznej.
W The Evolution of Lua autorzy języka napisali:
W 1993 roku jedynym prawdziwym pretendentem był Tcl , który został specjalnie zaprojektowany do osadzania w aplikacjach. Jednak Tcl miał nieznaną składnię, nie oferował dobrego wsparcia dla opisu danych i działał tylko na platformach Unix. Nie braliśmy pod uwagę LISP ani Scheme z powodu ich nieprzyjaznej składni. Python był jeszcze w powijakach. W swobodnej atmosferze majsterkowania, jaka wtedy panowała w Tecgraf, było całkiem naturalne, że powinniśmy spróbować opracować własny język skryptowy… Ponieważ wielu potencjalnych użytkowników języka nie było profesjonalnymi programistami, język powinien unikać zagadek składnia i semantyka. Implementacja nowego języka powinna być wysoce przenośna, ponieważ klienci Tecgrafu mieli bardzo różnorodną kolekcję platform komputerowych. Wreszcie, ponieważ spodziewaliśmy się, że inne produkty Tecgraf również będą musiały zawierać język skryptowy, nowy język powinien podążać za przykładem SOL i być dostarczany jako biblioteka z C API.
Lua 1.0 została zaprojektowana w taki sposób, że jej konstruktory obiektów, nieco różniące się wówczas od obecnego lekkiego i elastycznego stylu, zawierały składnię opisu danych z SOL (stąd nazwa Lua: Sol oznaczające po portugalsku „Słońce”, a Lua oznaczające "Księżyc"). Składnia Lua dla struktur kontrolnych została w większości zapożyczona z Moduli ( if
, while
, repeat
/ until
), ale również przejęła wpływ CLU (wielokrotne przypisania i wielokrotne zwroty z wywołań funkcji, jako prostsza alternatywa dla parametrów referencyjnych lub jawnych wskaźników ), C++ ("fajny pomysł zezwalania na deklarowanie zmiennej lokalnej tylko tam, gdzie jej potrzebujemy”), SNOBOL i AWK (tablice asocjacyjne). W artykule opublikowanym w Dr. Dobb's Journal , twórcy Lua stwierdzają również, że LISP i Scheme z ich pojedynczym, wszechobecnym mechanizmem struktury danych ( lista ) miały duży wpływ na ich decyzję o opracowaniu tabeli jako podstawowej struktury danych Lua.
Semantyka Lua była z czasem coraz bardziej pod wpływem Scheme, zwłaszcza po wprowadzeniu funkcji anonimowych i pełnego zakresu leksykalnego . W nowych wersjach Lua dodano kilka funkcji.
Wersje Lua przed wersją 5.0 były wydawane na licencji podobnej do licencji BSD . Od wersji 5.0 Lua jest licencjonowany na podstawie licencji MIT . Obie są liberalnymi licencjami wolnego oprogramowania i są prawie identyczne.
Cechy
Lua jest powszechnie opisywany jako język " wieloparadygmatyczny ", dostarczający niewielki zestaw ogólnych funkcji, które można rozszerzyć, aby dopasować je do różnych typów problemów. Lua nie zawiera wyraźnego wsparcia dla dziedziczenia , ale pozwala na jego implementację z metatablicami . Podobnie Lua pozwala programistom na implementację przestrzeni nazw , klas i innych powiązanych funkcji przy użyciu implementacji pojedynczej tabeli; pierwszorzędne funkcje pozwalają na zastosowanie wielu technik z programowania funkcyjnego ; a pełny zakres leksykalny pozwala na ukrywanie drobnoziarnistych informacji w celu wyegzekwowania zasady najmniejszych uprawnień .
Ogólnie rzecz biorąc, Lua dąży do zapewnienia prostych, elastycznych meta-funkcji, które można rozszerzać w razie potrzeby, zamiast dostarczania zestawu funkcji specyficznych dla jednego paradygmatu programowania. W rezultacie język bazowy jest lekki — pełny interpreter referencyjny ma tylko około 247 kB skompilowanych — i można go łatwo dostosować do szerokiego zakresu aplikacji.
Dynamicznie wpisany język przeznaczony do stosowania jako języka przedłużacza lub języka skryptowego , Lua jest na tyle kompaktowy, aby zmieścić się na różnych platformach gospodarza. Obsługuje tylko niewielką liczbę atomowych struktur danych, takich jak wartości logiczne , liczby ( domyślnie zmiennoprzecinkowe o podwójnej precyzji i 64-bitowe liczby całkowite ) oraz strings . Typowe struktury danych, takie jak tablice , zestawy , listy i rekordy , mogą być reprezentowane za pomocą pojedynczej natywnej struktury danych Lua , tabeli , która jest zasadniczo heterogeniczną tablicą asocjacyjną .
Lua implementuje niewielki zestaw zaawansowanych funkcji, takich jak pierwszorzędne funkcje , wyrzucanie śmieci , domknięcia , odpowiednie wywołania ogona , koercja (automatyczna konwersja między wartościami łańcuchowymi i liczbowymi w czasie wykonywania), współprogramy (wielozadaniowość kooperacyjna) i dynamiczne ładowanie modułów .
Składnia
Klasyczne „Witaj świecie!” program można zapisać w następujący sposób:
print("Hello, World!")
lub jako:
print 'Hello, World!'
Komentarz w Lua zaczyna się od podwójnego myślnika i biegnie do końca linii, podobnie jak Ada , Eiffel , Haskell , SQL i VHDL . Ciągi wielowierszowe i komentarze są ozdobione podwójnymi nawiasami kwadratowymi.
W tym przykładzie funkcja silnia jest zaimplementowana jako funkcja:
function factorial(n)
local x = 1
for i = 2, n do
x = x * i
end
return x
end
Kontrola przepływu
Lua ma cztery typy pętli : while
pętlę , repeat
pętlę (podobną do do while
pętli ), for
pętlę numeryczną i for
pętlę generyczną .
--condition = true
while condition do
--statements
end
repeat
--statements
until condition
for i = first, last, delta do --delta may be negative, allowing the for loop to count down or up
--statements
--example: print(i)
end
Ogólna for
pętla:
for key, value in pairs(_G) do
print(key, value)
end
będzie iterować po tabeli _G
przy użyciu standardowej funkcji iteratora pairs
, dopóki nie zwróci nil
.
Pętle mogą być również zagnieżdżane (wstawiane do innej pętli).
local grid = {
{ 11, 12, 13 },
{ 21, 22, 23 },
{ 31, 32, 33 }
}
for y, row in ipairs(grid) do
for x, value in ipairs(row) do
print(x, y, value)
end
end
Funkcje
Traktowanie funkcji przez Lua jako wartości pierwszej klasy jest pokazane w poniższym przykładzie, w którym zmodyfikowano zachowanie funkcji print:
do
local oldprint = print
-- Store current print function as oldprint
function print(s)
--[[ Redefine print function. The usual print function can still be used
through oldprint. The new one has only one argument.]]
oldprint(s == "foo" and "bar" or s)
end
end
Wszelkie przyszłe wywołania do print
będą teraz kierowane przez nową funkcję, a ze względu na zakres leksykalny Lua , stara funkcja drukowania będzie dostępna tylko dla nowego, zmodyfikowanego drukowania.
Lua obsługuje również domknięcia , jak pokazano poniżej:
function addto(x)
-- Return a new function that adds x to the argument
return function(y)
--[=[ When we refer to the variable x, which is outside the current
scope and whose lifetime would be shorter than that of this anonymous
function, Lua creates a closure.]=]
return x + y
end
end
fourplus = addto(4)
print(fourplus(3)) -- Prints 7
--This can also be achieved by calling the function in the following way:
print(addto(4)(3))
--[[ This is because we are calling the returned function from 'addto(4)' with the argument '3' directly.
This also helps to reduce data cost and up performance if being called iteratively.
]]
Przy x
każdym addto
wywołaniu tworzone jest nowe zamknięcie dla zmiennej , dzięki czemu każda nowa zwrócona funkcja anonimowa zawsze będzie miała dostęp do własnego x
parametru. Zamknięciem zarządza śmieciarz Lui, tak jak każdy inny obiekt.
Stoły
Tabele są najważniejszymi strukturami danych (i, z założenia, jedynym wbudowanym złożonym typem danych ) w Lua i stanowią podstawę wszystkich typów tworzonych przez użytkowników. Są to tablice asocjacyjne z dodatkiem automatycznego klucza numerycznego i specjalnej składni.
Tabela to zbiór par kluczy i danych, w których do danych odwołuje się klucz; innymi słowy, jest to zaszyfrowana heterogeniczna tablica asocjacyjna.
Tabele są tworzone przy użyciu {}
składni konstruktora.
a_table = {} -- Creates a new, empty table
Tabele są zawsze przekazywane przez odniesienie (patrz Wywołanie przez udostępnienie ).
Klucz (indeks) może mieć dowolną wartość z wyjątkiem nil
i NaN , w tym funkcji.
a_table = {x = 10} -- Creates a new table, with one entry mapping "x" to the number 10.
print(a_table["x"]) -- Prints the value associated with the string key, in this case 10.
b_table = a_table
b_table["x"] = 20 -- The value in the table has been changed to 20.
print(b_table["x"]) -- Prints 20.
print(a_table["x"]) -- Also prints 20, because a_table and b_table both refer to the same table.
Tabela jest często używana jako struktura (lub rekord ) przy użyciu ciągów jako kluczy. Ponieważ takie użycie jest bardzo powszechne, Lua posiada specjalną składnię dostępu do takich pól.
point = { x = 10, y = 20 } -- Create new table
print(point["x"]) -- Prints 10
print(point.x) -- Has exactly the same meaning as line above. The easier-to-read dot notation is just syntactic sugar.
Używając tabeli do przechowywania powiązanych funkcji, może ona działać jako przestrzeń nazw.
Point = {}
Point.new = function(x, y)
return {x = x, y = y} -- return {["x"] = x, ["y"] = y}
end
Point.set_x = function(point, x)
point.x = x -- point["x"] = x;
end
Tabele są automatycznie przypisywane do klucza numerycznego, dzięki czemu mogą być używane jako typ danych tablicowych . Pierwszy automatyczny indeks to 1, a nie 0, jak w przypadku wielu innych języków programowania (choć dozwolony jest wyraźny indeks 0).
Klucz numeryczny 1
różni się od klucza łańcuchowego "1"
.
array = { "a", "b", "c", "d" } -- Indices are assigned automatically.
print(array[2]) -- Prints "b". Automatic indexing in Lua starts at 1.
print(#array) -- Prints 4. # is the length operator for tables and strings.
array[0] = "z" -- Zero is a legal index.
print(#array) -- Still prints 4, as Lua arrays are 1-based.
Długość tabeli t
jest zdefiniowana jako dowolny indeks całkowity, n
taki, który t[n]
nie jest nil
i t[n+1]
jest nil
; ponadto, jeśli t[1]
jest nil
, n
może wynosić zero. W przypadku zwykłej tablicy z wartościami innymi niż zero od 1 do danego n
, jej długość jest dokładnie taka n
, jak indeks jej ostatniej wartości. Jeśli tablica ma "dziury" (to znaczy wartości zero pomiędzy innymi wartościami niezerowymi), to #t
może być dowolnym indeksem bezpośrednio poprzedzającym nil
wartość (to znaczy, może uznać każdą taką wartość zero za koniec tablicy ).
ExampleTable =
{
{1, 2, 3, 4},
{5, 6, 7, 8}
}
print(ExampleTable[1][3]) -- Prints "3"
print(ExampleTable[2][4]) -- Prints "8"
Tabela może być tablicą obiektów.
function Point(x, y) -- "Point" object constructor
return { x = x, y = y } -- Creates and returns a new object (table)
end
array = { Point(10, 20), Point(30, 40), Point(50, 60) } -- Creates array of points
-- array = { { x = 10, y = 20 }, { x = 30, y = 40 }, { x = 50, y = 60 } };
print(array[2].y) -- Prints 40
Używanie mapy mieszania do emulacji tablicy jest zwykle wolniejsze niż użycie rzeczywistej tablicy; jednak tabele Lua są zoptymalizowane do użycia jako tablice, aby uniknąć tego problemu.
Metatabele
Rozszerzalna semantyka jest kluczową cechą Lua, a koncepcja metatablic pozwala na zaawansowane dostosowywanie tabel. Poniższy przykład ilustruje tabelę „nieskończoną”. Dla każdego n
, fibs[n]
poda n
-ty numer Fibonacciego za pomocą programowania dynamicznego i zapamiętywania .
fibs = { 1, 1 } -- Initial values for fibs[1] and fibs[2].
setmetatable(fibs, {
__index = function(values, n) --[[__index is a function predefined by Lua,
it is called if key "n" does not exist.]]
values[n] = values[n - 1] + values[n - 2] -- Calculate and memorize fibs[n].
return values[n]
end
})
Programowanie obiektowe
Chociaż Lua nie ma wbudowanej koncepcji klas , programowanie obiektowe może być emulowane za pomocą funkcji i tabel. Obiekt tworzy się poprzez umieszczenie metod i pól w tabeli. Dziedziczenie (zarówno pojedyncze, jak i wielokrotne) można zaimplementować za pomocą metatablic , delegując nieistniejące metody i pola do obiektu nadrzędnego.
W przypadku tych technik nie istnieje pojęcie „klasa”; używane są raczej prototypy , podobne do Self lub JavaScript . Nowe obiekty są tworzone za pomocą metody fabryki (która konstruuje nowe obiekty od podstaw) lub przez klonowanie istniejącego obiektu.
Tworzenie podstawowego obiektu wektorowego :
local Vector = {}
local VectorMeta = { __index = Vector}
function Vector.new(x, y, z) -- The constructor
return setmetatable({x = x, y = y, z = z}, VectorMeta)
end
function Vector.magnitude(self) -- Another method
return math.sqrt(self.x^2 + self.y^2 + self.z^2)
end
local vec = Vector.new(0, 1, 0) -- Create a vector
print(vec.magnitude(vec)) -- Call a method (output: 1)
print(vec.x) -- Access a member variable (output: 0)
Tutaj setmetatable
mówi Lua, aby szukał elementu w Vector
tabeli, jeśli nie ma go w vec
tabeli. , który jest odpowiednikiem , najpierw szuka elementu w tabeli . Tabela nie posiada elementu, ale jego metatable delegaci do tabeli dla elementu, gdy nie znajduje się w tabeli.
vec.magnitude
vec["magnitude"]
vec
magnitude
vec
magnitude
Vector
magnitude
vec
Lua dostarcza trochę cukru składniowego, aby ułatwić orientację obiektową. Aby zadeklarować funkcje składowe wewnątrz tabeli prototypowej, można użyć , który jest odpowiednikiem . Wywołanie metod klas również wykorzystuje dwukropek: jest równoważny .
function table:func(args)
function table.func(self, args)
object:func(args)
object.func(object, args)
Mając to na uwadze, oto odpowiednia klasa z :
cukrem składniowym:
local Vector = {}
Vector.__index = Vector
function Vector:new(x, y, z) -- The constructor
-- Since the function definition uses a colon,
-- its first argument is "self" which refers
-- to "Vector"
return setmetatable({x = x, y = y, z = z}, self)
end
function Vector:magnitude() -- Another method
-- Reference the implicit object using self
return math.sqrt(self.x^2 + self.y^2 + self.z^2)
end
local vec = Vector:new(0, 1, 0) -- Create a vector
print(vec:magnitude()) -- Call a method (output: 1)
print(vec.x) -- Access a member variable (output: 0)
Dziedzictwo
Lua obsługuje używanie metatab, aby dziedziczyć klasę Lua. W tym przykładzie umożliwiamy wektorom pomnożenie ich wartości przez stałą w klasie pochodnej.
local Vector = {}
Vector.__index = Vector
function Vector:new(x, y, z) -- The constructor
-- Here, self refers to whatever class's "new"
-- method we call. In a derived class, self will
-- be the derived class; in the Vector class, self
-- will be Vector
return setmetatable({x = x, y = y, z = z}, self)
end
function Vector:magnitude() -- Another method
-- Reference the implicit object using self
return math.sqrt(self.x^2 + self.y^2 + self.z^2)
end
-- Example of class inheritance
local VectorMult = {}
VectorMult.__index = VectorMult
setmetatable(VectorMult, Vector) -- Make VectorMult a child of Vector
function VectorMult:multiply(value)
self.x = self.x * value
self.y = self.y * value
self.z = self.z * value
return self
end
local vec = VectorMult:new(0, 1, 0) -- Create a vector
print(vec:magnitude()) -- Call a method (output: 1)
print(vec.y) -- Access a member variable (output: 1)
vec:multiply(2) -- Multiply all components of vector by 2
print(vec.y) -- Access member again (output: 2)
Lua obsługuje także dziedziczenie wielokrotne ; __index
może być funkcją lub tabelą. Możliwe jest również przeciążenie operatora ; Metatables Lua może mieć elementy takie jak __add
, __sub
i tak dalej.
Realizacja
Programy Lua nie są interpretowane bezpośrednio z tekstowego pliku Lua, ale są kompilowane do kodu bajtowego, który jest następnie uruchamiany na wirtualnej maszynie Lua . Proces kompilacji jest zwykle niewidoczny dla użytkownika i jest wykonywany w czasie wykonywania , zwłaszcza gdy używany jest kompilator JIT , ale można go wykonać w trybie offline w celu zwiększenia wydajności ładowania lub zmniejszenia zużycia pamięci środowiska hosta poprzez pominięcie kompilator. Kod bajtowy Lua można również utworzyć i wykonać z poziomu Lua, używając dump
funkcji z biblioteki ciągów i load/loadstring/loadfile
funkcji. Lua w wersji 5.3.4 jest zaimplementowana w około 24 000 linijek kodu C.
Podobnie jak większość procesorów i w przeciwieństwie do większości maszyn wirtualnych (które są oparte na stosie ), maszyna wirtualna Lua jest oparta na rejestrach , a zatem bardziej przypomina rzeczywisty projekt sprzętu. Architektura rejestru zarówno pozwala uniknąć nadmiernego kopiowania wartości, jak i zmniejsza całkowitą liczbę instrukcji na funkcję. Maszyna wirtualna Lua 5 jest jedną z pierwszych czystych maszyn wirtualnych opartych na rejestrach, która ma szerokie zastosowanie. Parrot i Android „s Dalvik są dwa inne rejestr oparte VM dobrze znane. Maszyna wirtualna PCScheme również była oparta na rejestrach.
Ten przykład jest listą kodu bajtowego zdefiniowanej powyżej funkcji silni (jak pokazano w luac
kompilatorze 5.1):
function <factorial.lua:1,7> (9 instructions, 36 bytes at 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 ; to 7 6 [4] MUL 1 1 5 7 [3] FORLOOP 2 -2 ; to 6 8 [6] RETURN 1 2 9 [7] RETURN 0 1
C API
Lua jest przeznaczony do wbudowania w inne aplikacje i zapewnia w tym celu C API . API podzielone jest na dwie części: rdzeń Lua i bibliotekę pomocniczą Lua. Projekt Lua API eliminuje potrzebę ręcznego zarządzania referencjami w kodzie C, w przeciwieństwie do API Pythona . API, podobnie jak język, jest minimalistyczne. Zaawansowaną funkcjonalność zapewnia biblioteka pomocnicza, składająca się w dużej mierze z makr preprocesorowych, które wspomagają złożone operacje na tabelach.
Interfejs API Lua C jest oparty na stosie . Lua udostępnia funkcje do wypychania i usuwania większości prostych typów danych C (liczby całkowite, zmiennoprzecinkowe itp.) na stos i ze stosu, a także funkcje do manipulowania tabelami na stosie. Stos Lua różni się nieco od tradycyjnego stosu; na przykład stos można indeksować bezpośrednio. Indeksy ujemne wskazują przesunięcia od wierzchołka stosu. Na przykład -1 to góra (ostatnio wypchnięta wartość), podczas gdy indeksy dodatnie wskazują przesunięcia od dołu (najstarsza wartość). Za pomocą stosu odbywa się również marshalling danych między funkcjami C i Lua. Aby wywołać funkcję Lua, argumenty są odkładane na stos, a następnie lua_call
używany jest do wywołania właściwej funkcji. Podczas pisania funkcji C, która ma być bezpośrednio wywołana z Lua, argumenty są odczytywane ze stosu.
Oto przykład wywołania funkcji Lua z C:
#include <stdio.h>
#include <lua.h> // Lua main library (lua_*)
#include <lauxlib.h> // Lua auxiliary library (luaL_*)
int main(void)
{
// create a Lua state
lua_State *L = luaL_newstate();
// load and execute a string
if (luaL_dostring(L, "function foo (x,y) return x+y end")) {
lua_close(L);
return -1;
}
// push value of global "foo" (the function defined above)
// to the stack, followed by integers 5 and 3
lua_getglobal(L, "foo");
lua_pushinteger(L, 5);
lua_pushinteger(L, 3);
lua_call(L, 2, 1); // call a function with two arguments and one return value
printf("Result: %d\n", lua_tointeger(L, -1)); // print integer value of item at stack top
lua_pop(L, 1); // return stack to original state
lua_close(L); // close Lua state
return 0;
}
Uruchomienie tego przykładu daje:
$ cc -o example example.c -llua $ ./example Result: 8
API C zapewnia również kilka specjalnych tabel, znajdujących się w różnych "pseudo-indeksach" w stosie Lua. Co LUA_GLOBALSINDEX
przed Lua 5.2 jest tabela globalne, _G
od wewnątrz Lua, który jest głównym nazw . Istnieje również rejestr, w LUA_REGISTRYINDEX
którym programy w języku C mogą przechowywać wartości Lua w celu późniejszego odzyskania.
Możliwe jest pisanie modułów rozszerzeń za pomocą Lua API. Moduły rozszerzeń są obiektami współdzielonymi, które można wykorzystać do rozszerzenia funkcjonalności interpretera poprzez zapewnienie natywnych udogodnień dla skryptów Lua. Od strony Lua taki moduł pojawia się jako tablica przestrzeni nazw zawierająca jego funkcje i zmienne. Skrypty Lua mogą ładować moduły rozszerzeń za pomocą require
, tak jak moduły napisane w samym Lua. Rosnąca kolekcja modułów znanych jako skały jest dostępna poprzez system zarządzania pakietami o nazwie LuaRocks , w duchu CPAN , RubyGems i Python eggs . Istnieją wstępnie napisane powiązania Lua dla większości popularnych języków programowania, w tym innych języków skryptowych. W przypadku C++ istnieje wiele podejść opartych na szablonach i niektóre automatyczne generatory powiązań.
Aplikacje
W tworzeniu gier wideo Lua jest powszechnie używany jako język skryptowy przez programistów , głównie ze względu na łatwość osadzenia, szybkie wykonanie i krótką krzywą uczenia się . Jedną z godnych uwagi platform do gier jest Roblox, w której ich własny dialekt, Luau, służy do pisania skryptów szybkiego tworzenia gier. Innym jest World of Warcraft, który również wykorzystuje zmniejszoną wersję Lua.
W 2003 roku ankieta przeprowadzona przez GameDev.net wykazała, że Lua jest najpopularniejszym językiem skryptowym do programowania gier. 12 stycznia 2012 roku Lua został ogłoszony zwycięzcą nagrody Front Line Award 2011 magazynu Game Developer w kategorii Narzędzia programistyczne.
Wiele aplikacji innych niż gry również używa Lua do rozszerzania, takich jak LuaTeX , implementacja języka ustawiania typów TeX , Redis , baza danych klucz-wartość , Neovim , edytor tekstu i Nginx , serwer WWW .
Dzięki rozszerzeniu Scribunto Lua jest dostępny jako język skryptowy po stronie serwera w oprogramowaniu MediaWiki , które obsługuje Wikipedię i inne wiki. Wśród jego zastosowań jest umożliwienie integracji danych z Wikidanych z artykułami oraz zasilanie zautomatyzowanego systemu Taxobox .
Języki pochodne
Języki, które kompilują się do Lua
- MoonScript jest dynamiczny , spacje wrażliwego językiem skryptowym zainspirowany coffeescript , który jest kompilowany do Lua. Oznacza to, że zamiast używać
do
iend
(lub{
i}
) do rozgraniczania sekcji kodu używa podziałów wierszy i stylu wcięć . Godnym uwagi zastosowaniem MoonScriptu jest witryna dystrybucji gier wideo Itch.io . - Haxe obsługuje kompilację do celu Lua, wspierając Lua 5.1-5.3 oraz LuaJIT 2.0 i 2.1.
- Fennel, dialekt Lisp, którego celem jest Lua.
- Urn, dialekt Lisp zbudowany na Lua.
- Amulet, język funkcjonalny podobny do ML , którego kompilator generuje pliki Lua.
Dialekty
- LuaJIT (patrz poniżej), język Lua 5.1 z obsługą JIT z
goto
(z Lua 5.2) i C FFI . - Luau z Roblox , język Lua 5.1 ze stopniowym pisaniem i ergonomicznymi dodatkami.
- Ravi, język Lua 5.3 z obsługą JIT z opcjonalnym pisaniem statycznym. JIT kieruje się informacjami o typie.
- Shine, widelec LuaJIT z wieloma rozszerzeniami, w tym systemem modułów i systemem makr.
Ponadto społeczność użytkowników Lua udostępnia kilka poprawek mocy na szczycie referencyjnej implementacji C.
LuaJIT
Deweloper(zy) | Mike Pall |
---|---|
Wersja stabilna | 2.0.5/1 maja 2017
|
Magazyn | repozytorium |
Napisane w | C , Lua |
System operacyjny | zobacz listę |
Rodzaj | Kompilator just in time |
Licencja | Licencja MIT |
Strona internetowa | luajit |
LuaJIT to kompilator w sam raz dla Lua. Został użyty do osadzenia lub do ogólnych celów. W wersji 2.0 LuaJIT projekt został przepisany w celu lepszej optymalizacji wydajności.
Historia
Projekt LuaJIT rozpoczął się w 2005 roku przez programistę Mike Pall, wydany na licencji open source MIT. Najnowsza wersja, 2.0.5 została wydana w 2017 roku. Od tego czasu projekt nie jest obecnie utrzymywany przez programistów innych niż współtwórcy.
Instalacja
LuaJIT jest oprogramowaniem typu open source i projekt musi zostać skompilowany, aby można było z niego korzystać. Repozytorium będzie musiało zostać pobrane za pomocą Gita lub innych metod pobierania repozytoriów. Następnie jest kompilowany dowolnym kompilatorem C, zwykle GNU make , ale dostępne są inne opcje. Wreszcie, plik wykonywalny LuaJIT i Lua 5.1 DLL muszą znajdować się w tym samym katalogu, aby można było użyć kompilatora LuaJIT.
Istnieje przewodnik dotyczący korzystania z kompilatora LuaJIT, który zawiera opcje wiersza poleceń.
Wydajność
W porównaniu do innych środowisk wykonawczych Lua, LuaJIT jest często najszybszym kompilatorem Lua.
Platformy
LuaJIT może być używany w:
Może być skompilowany przy użyciu GCC , Clang lub MSVC .
Przykłady
Biblioteka FFi może być używana do wywoływania funkcji C i używania struktur danych C z kodu Lua. Istnieje przewodnik dostarczony przez LuaJIT na temat korzystania z tej biblioteki. W związku z tym istnieje wiele powiązań LuaJIT z bibliotekami C, które korzystają z Biblioteki FFI. Ten przykład wywoła funkcję C, printf z czystego kodu Lua i wyświetli Hello world! .
local ffi = require("ffi")
ffi.cdef[[
int printf(const char *fmt, ...);
]]
ffi.C.printf("Hello world!\n")
Kompilator LuaJIT dodał także kilka rozszerzeń do API C Lua. Ten przykład napisany w C++ byłby używany do celów debugowania .
#include <exception>
#include "lua.hpp"
// Catch C++ exceptions and convert them to Lua error messages.
// Customize as needed for your own exception classes.
static int wrap_exceptions(lua_State *L, lua_CFunction f)
{
try {
return f(L); // Call wrapped function and return result.
} catch (const char *s) { // Catch and convert exceptions.
lua_pushstring(L, s);
} catch (std::exception& e) {
lua_pushstring(L, e.what());
} catch (...) {
lua_pushliteral(L, "caught (...)");
}
return lua_error(L); // Rethrow as a Lua error.
}
static int myinit(lua_State *L)
{
...
// Define wrapper function and enable it.
lua_pushlightuserdata(L, (void *)wrap_exceptions);
luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_ON);
lua_pop(L, 1);
...
}
Zobacz też
Uwagi
Bibliografia
Dalsza lektura
- Jerusalimschy, R. (2013). Programowanie w Lua (3rd ed.). Lua.org. Numer ISBN 978-85-903798-5-0.(Pierwsze wydanie jest dostępne online .)
- Gutschmidt, T. (2003). Programowanie gier w Pythonie, Lua i Ruby . Kurs Technologia PTR. Numer ISBN 978-1-59200-077-7.
- Schuytema, P.; Manyen, M. (2005). Rozwój gry z Lua . Charles River Media. Numer ISBN 978-1-58450-404-7.
- Jung, K.; Brown, A. (2007). Rozpoczęcie programowania w Lua . Wrox Prasa . Numer ISBN 978-0-470-06917-2. Zarchiwizowane od oryginału w dniu 8 lipca 2018 r . Źródło 7 lipca 2018 .
- Figueiredo, LH; Celes, W.; Ierusalimschy, R., wyd. (2008). Perełki programowania Lua . Lua.org. Numer ISBN 978-85-903798-4-3.
- Taktejew, Jurij (2012). Coding Places: Software Practice w południowoamerykańskim mieście . MIT Naciśnij . Numer ISBN 978-0-262-01807-4. Zarchiwizowane od oryginału w dniu 2 listopada 2012 r. Rozdziały 6 i 7 są poświęcone Lua, podczas gdy inni patrzą na oprogramowanie w Brazylii szerzej.
- Varma, Jayant (2012). Naucz się Lua do tworzenia gier na iOS . Naciśnij . Numer ISBN 978-1-4302-4662-6.
- Matheson, Ash (29 kwietnia 2003). „Wprowadzenie do Lua” . GameDev.pl . Zarchiwizowane z oryginału w dniu 18 grudnia 2012 roku . Źródło 3 stycznia 2013 .
- Fieldhouse, Keith (16 lutego 2006). „Przedstawiamy Lua” . ONLamp.pl . O'Reilly Media . Zarchiwizowane z oryginału w dniu 12 marca 2006 roku . Pobrano 28 lutego 2006 .
- Streicher, Martin (28 kwietnia 2006). "Osadzane skrypty z Lua" . developerWorks . IBM .
- Quigley, Joseph (1 czerwca 2007). „Spojrzenie na Luę” . Dziennik Linuksa .
- Hamilton, Naomi (11 września 2008). „AZ języków programowania: Lua” . Komputerowy Świat . IDG . Zarchiwizowane od oryginału w dniu 8 lipca 2018 r . Źródło 7 lipca 2018 . Wywiad z Roberto Ierusalimschy.
- Jeruzalemski, Roberto; de Figueiredo, Luiz Henrique; Celes, Waldemar (12 maja 2011). „Przekazywanie języka przez ucho igły” . Kolejka ACM . 9 (5): 20–29. doi : 10.1145/1978862.1983083 . S2CID 19484689 . Jak możliwość osadzania Lua wpłynęła na jego projekt.
- Jeruzalemski, Roberto; de Figueiredo, Luiz Henrique; Celes, Waldemar (listopad 2018). „Spojrzenie na projekt Lua” . Komunikaty ACM . 61 (11): 114–123. doi : 10.1145/3186277 . S2CID 53114923 .
- Artykuły i tezy Lua