Lua (język programowania) - Lua (programming language)

Lua
Lua-Logo.svg
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 ; 28 lat temu ( 1993 )
Wersja stabilna
5.4.3  Edytuj to na Wikidanych / 29 marca 2021 r .; 5 miesięcy temu ( 29 marca 2021 )
Dyscyplina pisania Dynamiczny , mocny , kaczy
Język implementacji ANSI C
OS Wieloplatformowy
Licencja Licencja MIT
Rozszerzenia nazw plików .lua
Strona internetowa www .lua .org
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 : whilepętlę , repeatpętlę (podobną do do whilepętli ), forpętlę numeryczną i forpę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 forpętla:

for key, value in pairs(_G) do
  print(key, value)
end

będzie iterować po tabeli _Gprzy 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 printbę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 xkażdym addtowywoł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 xparametru. 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 nili 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 1róż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 tjest zdefiniowana jako dowolny indeks całkowity, ntaki, który t[n]nie jest nili t[n+1]jest nil; ponadto, jeśli t[1]jest nil, nmoż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 #tmoże być dowolnym indeksem bezpośrednio poprzedzającym nilwartość (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 setmetatablemówi Lua, aby szukał elementu w Vectortabeli, jeśli nie ma go w vectabeli. , 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.magnitudevec["magnitude"]vecmagnitudevecmagnitudeVectormagnitudevec

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 ; __indexmoże być funkcją lub tabelą. Możliwe jest również przeciążenie operatora ; Metatables Lua może mieć elementy takie jak __add, __subi 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 dumpfunkcji z biblioteki ciągów i load/loadstring/loadfilefunkcji. 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 luackompilatorze 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_calluż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_GLOBALSINDEXprzed Lua 5.2 jest tabela globalne, _God wewnątrz Lua, który jest głównym nazw . Istnieje również rejestr, w LUA_REGISTRYINDEXktó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ć doi end(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

LuaJIT
Deweloper(zy) Mike Pall
Wersja stabilna
2.0.5/1 maja 2017 ; 4 lata temu ( 01.05.2017 )
Magazyn repozytorium .lub .cz /w /luajit-2 .0 .git
Napisane w C , Lua
System operacyjny zobacz listę
Rodzaj Kompilator just in time
Licencja Licencja MIT
Strona internetowa luajit .org

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

Zewnętrzne linki