Lua ( /ˈluː.ə/ , LOO - ə ; du portugais : lua [ ˈlu(w)ɐ] signifiant lune ) est un langage de programmation léger , de haut niveau et multiparadigme , conçu principalement pour une utilisation embarquée dans des applications. ] Lua est un logiciel multiplateforme , car l’ interpréteur du bytecode compilé est écrit en C ANSI , programmation ( API ) en C relativement simple pour son intégration dans des applications.
Lua a vu le jour en 1993 comme langage d'extension des applications logicielles, afin de répondre à la demande croissante de personnalisation de l'époque. Il offrait les fonctionnalités de base de la plupart des langages de programmation procédurale , mais n'intégrait pas de fonctionnalités plus complexes ou spécifiques à un domaine . En revanche, il proposait des mécanismes d'extension permettant aux programmeurs d'implémenter ces fonctionnalités. Conçu comme un langage d'extension générique et intégrable, Lua a été développé en privilégiant la rapidité , la portabilité , l'extensibilité et la facilité d'utilisation.
Histoire
Lua a été créé en 1993 par Roberto Ierusalimschy , Luiz Henrique de Figueiredo et Waldemar Celes, membres du Computer Graphics Technology Group ( Tecgraf ) de l' Université pontificale catholique de Rio de Janeiro , au Brésil .
De 1977 à 1992, le Brésil a appliqué une politique de barrières commerciales strictes (appelée réserve de marché) sur le matériel et les logiciels informatiques , partant du principe que le pays pouvait et devait produire ses propres matériels et logiciels. Dans ce contexte, les clients de Tecgraf ne pouvaient se permettre, ni politiquement ni financièrement, d'acheter des logiciels personnalisés à l'étranger ; la réserve de marché les obligeait à se soumettre à une procédure bureaucratique complexe pour prouver que leurs besoins ne pouvaient être satisfaits par des entreprises brésiliennes. C'est pourquoi Tecgraf a développé elle-même les outils de base dont elle avait besoin.
Les prédécesseurs de Lua étaient les langages de description et de configuration de données SOL (Simple Object Language) et DEL (Data-Entry Language). Développés indépendamment chez Tecgraf entre 1992 et 1993, ils visaient à apporter plus de flexibilité à deux projets distincts (des programmes graphiques interactifs pour des applications d'ingénierie chez Petrobras ). SOL et DEL ne disposaient pas de structures de contrôle de flux, et Petrobras ressentait le besoin croissant de les doter de toutes les fonctionnalités de programmation nécessaires.
Dans The Evolution of Lua , les auteurs du langage ont écrit :
En 1993, le seul véritable concurrent était Tcl , conçu spécifiquement pour être intégré aux applications. Cependant, sa syntaxe était complexe, la description des données peu pratique et il ne fonctionnait que sur les plateformes Unix. Nous avons écarté LISP et Scheme en raison de leur syntaxe peu conviviale. Python était encore à ses balbutiements. Dans l'esprit libre et participatif qui régnait alors chez Tecgraf, il était tout naturel de développer notre propre langage de script. Comme de nombreux utilisateurs potentiels n'étaient pas des programmeurs professionnels, le langage devait éviter une syntaxe et une sémantique obscures. Son implémentation devait être hautement portable, car les clients de Tecgraf disposaient d'une grande diversité de plateformes informatiques. Enfin, anticipant le besoin d'intégrer un langage de script dans d'autres produits Tecgraf, le nouveau langage devait suivre l'exemple de SOL et être fourni sous forme de bibliothèque avec une API C.
Lua 1.0 a été conçu de telle sorte que ses constructeurs d'objets, alors légèrement différents du style léger et flexible actuel, intégraient la syntaxe de description de données de SOL (d'où le nom Lua : Sol signifiant « Soleil » en portugais et Lua « Lune »). La syntaxe Lua pour les structures de contrôle était principalement empruntée à Modula ( if`if`, while` if`, ` repeatif` until), mais avait également été influencée par CLU (affectations et retours multiples lors d'appels de fonctions, comme alternative plus simple aux paramètres de référence ou aux pointeurs explicites ), C++ (« l'idée ingénieuse de permettre la déclaration d'une variable locale uniquement là où on en a besoin » ), SNOBOL et AWK ( tableaux associatifs ). Dans un article publié dans le Dr. Dobb's Journal , les créateurs de Lua affirment également que LISP et Scheme, avec leur mécanisme de structure de données unique et omniprésent (la liste `list` ), ont fortement influencé leur décision de développer la liste `list` comme structure de données principale de Lua.
La sémantique de Lua a été de plus en plus influencée par Scheme au fil du temps , notamment avec l'introduction des fonctions anonymes et de la portée lexicale complète . Plusieurs fonctionnalités ont été ajoutées dans les nouvelles versions de Lua.
Les versions de Lua antérieures à la version 5.0 étaient distribuées sous une licence similaire à la licence BSD . À partir de la version 5.0, Lua est distribué sous la licence MIT . Ces deux licences de logiciel libre sont permissives et quasiment identiques.
Caractéristiques
Lua est généralement décrit comme un langage « multi-paradigme », offrant un ensemble restreint de fonctionnalités générales extensibles pour s'adapter à différents types de problèmes. Lua ne prend pas explicitement en charge l'héritage , mais permet de l'implémenter grâce aux métatables . De même, Lua permet aux programmeurs d'implémenter des espaces de noms , des classes et d'autres fonctionnalités connexes à l'aide de son implémentation à table unique ; les fonctions de première classe permettent l'utilisation de nombreuses techniques de programmation fonctionnelle et la portée lexicale complète permet un masquage fin des informations afin de garantir le principe du moindre privilège .
De manière générale, Lua s'efforce de fournir des métafonctionnalités simples et flexibles , extensibles selon les besoins, plutôt qu'un ensemble de fonctionnalités spécifique à un paradigme de programmation. Par conséquent, le langage de base est léger ; l' interpréteur de référence complet ne pèse qu'environ 293 ko une fois compilé et s'adapte facilement à une large gamme d'applications.
Lua, langage à typage dynamique conçu pour être utilisé comme langage d'extension ou de script , est suffisamment compact pour s'adapter à diverses plateformes hôtes. Il ne prend en charge qu'un nombre restreint de structures de données atomiques, telles que les valeurs booléennes , les nombres ( à virgule flottante double précision et entiers 64 bits par défaut) et les chaînes de caractères . Les structures de données classiques, comme les tableaux , les ensembles , les listes et les enregistrements, peuvent être représentées par la seule structure de données native de Lua : la table, qui est essentiellement un tableau associatif hétérogène .
Lua implémente un petit ensemble de fonctionnalités avancées telles que les fonctions de première classe , le ramasse-miettes , les fermetures , les appels terminaux appropriés , la coercition (conversion automatique entre les valeurs de chaîne et de nombre au moment de l'exécution), les coroutines (multitâche coopératif) et le chargement dynamique de modules .
Syntaxe
Le programme classique « Hello, World! » peut être écrit comme suit, avec ou sans parenthèses :
imprimer ( "Bonjour, monde !" )
imprimer "Bonjour, monde !"
La déclaration d'une variable, sans valeur.
variable locale
Déclaration d'une variable ayant la valeur 1000 (mille)
étudiants locaux = 1000
En Lua, un commentaire commence par un double tiret et s'étend jusqu'à la fin de la ligne, comme en Ada , Eiffel , Haskell , SQL et VHDL . Les chaînes de caractères et les commentaires multilignes sont encadrés par des doubles crochets.
-- Commentaire sur une seule ligne --[[ Commentaire multiligne --]]
La fonction factorielle est implémentée dans cet exemple :
fonction factorielle ( n ) local x = 1 pour i = 2 , n faire x = x * i fin retourner x fin
Flux de contrôle
Lua possède un seul type de test conditionnelif then end : avec des constructions optionnelles elseet elseif thende contrôle d’exécution.
L' if then endénoncé générique requiert les trois mots-clés :
si condition alors --fin du corps de l' instruction
Un exemple de ifdéclaration
si x ≠ 10 alors afficher ( x ) fin
Le elsemot-clé peut être ajouté avec un bloc d'instructions associé pour contrôler l'exécution lorsque la ifcondition est évaluée àfalse :
si condition alors --corps de l'instruction sinon --fin du corps de l'instruction
Un exemple de if elsedéclaration
si x == 10 alors afficher ( 10 ) sinon afficher ( x ) fin
L'exécution peut également être contrôlée selon plusieurs conditions à l'aide des elseif thenmots-clés suivants :
si condition alors --corps de l'instruction sinon si condition alors --corps de l'instruction sinon -- optionnel --corps de l'instruction par défaut optionnel fin
Un exemple de if elseif elsedéclaration
si x == y alors afficher ( "x = y" ) sinon si x == z alors afficher ( "x = z" ) sinon -- optionnel afficher ( "x n'est égal à aucune autre variable" ) fin
Lua possède quatre types de boucles conditionnelles : la whileboucle `if` , la repeatboucle `else` (similaire à une do whileboucle `for` ), la forboucle numérique et la forboucle générique.
--condition = vraitant que la condition faire --instructions finrépéter --instructions jusqu'à ce que la conditionfor i = first , last , delta do --delta peut être négatif, permettant à la boucle for de décompter ou d'incrémenter --instructions --exemple : print(i) end
Cette forboucle générique parcourrait le tableau _Gen utilisant la fonction d'itération standard pairs, jusqu'à ce qu'elle renvoienil :
pour chaque paire clé , valeur ( _G ) faire afficher ( clé , valeur ) fin
Les boucles peuvent également être imbriquées (placées à l'intérieur d'une autre boucle).
grille locale = { { 11 , 12 , 13 }, { 21 , 22 , 23 }, { 31 , 32 , 33 } }pour chaque paire y , ligne dans la grille , faire pour chaque paire x , valeur dans la ligne , faire afficher ( x , y , valeur ) fin fin
Fonctions
Le traitement des fonctions en Lua comme des valeurs de première classe est illustré dans l'exemple suivant, où le comportement de la fonction print est modifié :
do local oldprint = print -- Stocker la fonction d'impression actuelle sous le nom oldprint function print ( s ) --[[ Redéfinir la fonction d'impression. La fonction d'impression habituelle peut toujours être utilisée via oldprint. La nouvelle n'a qu'un seul argument.]] oldprint ( s == "foo" and "bar" or s ) end end
Tous les futurs appels à cette fonction printseront désormais acheminés via la nouvelle fonction, et en raison de la portée lexicale de Lua , l'ancienne fonction d'impression ne sera accessible que par la nouvelle fonction d'impression modifiée.
Lua prend également en charge les fermetures , comme illustré ci-dessous :
function addto ( x ) -- Renvoie une nouvelle fonction qui ajoute x à l'argument return function ( y ) --[[ Lorsque nous faisons référence à la variable x, qui est hors de la portée actuelle et dont la durée de vie serait plus courte que celle de cette fonction anonyme, Lua crée une fermeture.]] return x + y end end fourplus = addto ( 4 ) print ( fourplus ( 3 )) -- Affiche 7On peut également y parvenir en appelant la fonction de la manière suivante : `print ( addto ( 4 )( 3 )) `. Cela permet d'appeler directement la fonction renvoyée par `addto(4)` avec l'argument `3`. Cette méthode contribue également à réduire la consommation de données et à améliorer les performances en cas d'appels itératifs.
Une nouvelle fermeture est créée pour la variable à xchaque addtoappel, afin que chaque nouvelle fonction anonyme retournée accède toujours à son propre xparamètre. Cette fermeture est gérée par le ramasse-miettes de Lua, comme n'importe quel autre objet.
Tables
Les tables sont les structures de données les plus importantes (et, de par leur conception, le seul type de données composite intégré ) en Lua et constituent la base de tous les types créés par l'utilisateur. Ce sont des tableaux associatifs auxquels s'ajoutent une clé numérique automatique et une syntaxe spéciale.
Une table est un ensemble de paires clé-donnée, où les données sont référencées par une clé ; en d'autres termes, il s'agit d'un tableau associatif hétérogène haché .
Les tables sont créées à l'aide de la {}syntaxe du constructeur.
a_table = {} -- Crée une nouvelle table vide
Les tables sont toujours passées par référence (voir Appel par partage ).
Une clé (index) peut être n'importe quelle valeur sauf nilet NaN , y compris les fonctions.
a_table = { x = 10 } -- Crée une nouvelle table, avec une entrée associant "x" au nombre 10. print ( a_table [ "x" ]) -- Affiche la valeur associée à la clé chaîne, dans ce cas 10. b_table = a_table b_table [ "x" ] = 20 -- La valeur dans la table a été modifiée à 20. print ( b_table [ "x" ]) -- Affiche 20. print ( a_table [ "x" ]) -- Affiche également 20, car a_table et b_table font toutes deux référence à la même table.
Une table est souvent utilisée comme structure (ou enregistrement ) en utilisant des chaînes de caractères comme clés. Comme cet usage est très courant, Lua propose une syntaxe spéciale pour accéder à ces champs.
point = { x = 10 , y = 20 } -- Crée un nouveau tableau print ( point [ "x" ]) -- Affiche 10 print ( point . x ) -- A exactement la même signification que la ligne ci-dessus. La notation pointée, plus facile à lire, n'est qu'une simplification syntaxique.
En utilisant une table pour stocker les fonctions associées, celle-ci peut servir d'espace de noms.
Point = {}Point.new = function ( x , y ) return { x = x , y = y } -- return {["x"] = x, ["y"] = y } endPoint.set_x = function ( point , x ) point.x = x -- point["x" ] = x ; end
Les tables se voient automatiquement attribuer une clé numérique, ce qui permet de les utiliser comme un type de données de type tableau . Le premier index automatique est 1 et non 0 comme c'est le cas pour de nombreux autres langages de programmation (bien qu'un index explicite de 0 soit autorisé).
Une clé numérique 1est différente d'une clé de type chaîne de caractères "1".
tableau = { "a" , "b" , "c" , "d" } -- Les indices sont attribués automatiquement. print ( tableau [ 2 ]) -- Affiche "b". L'indexation automatique en Lua commence à 1. print (" # tableau ") -- Affiche 4. # est l'opérateur de longueur pour les tableaux et les chaînes de caractères. tableau [ 0 ] = "z" -- Zéro est un indice valide. print ( "# tableau ") -- Affiche toujours 4, car les tableaux Lua sont indexés à partir de 1.
La longueur d'un tableau test définie comme tout indice entier ntel que ` t[n]n` ne soit pas `n` nilet ` t[n+1]a` soit `n`nil ; de plus, si ` t[1]n` est `n` nil, n`a` peut être nul. Pour un tableau régulier, contenant des valeurs non nulles de 1 à `n` donné n, sa longueur est exactement `n` n, l'indice de sa dernière valeur. Si le tableau comporte des « trous » (c'est-à-dire des valeurs nulles entre d'autres valeurs non nulles), alors ` #tn` peut être n'importe quel indice qui précède directement une nilvaleur (autrement dit, toute valeur nulle peut être considérée comme la fin du tableau).
ExampleTable = { { 1 , 2 , 3 , 4 }, { 5 , 6 , 7 , 8 } } print ( ExampleTable [ 1 ][ 3 ]) -- Affiche "3" print ( ExampleTable [ 2 ][ 4 ]) -- Affiche "8"
Un tableau peut être un tableau d'objets.
fonction Point ( x , y ) -- Constructeur de l'objet « Point » return { x = x , y = y } -- Crée et retourne un nouvel objet (tableau) end array = { Point ( 10 , 20 ), Point ( 30 , 40 ), Point ( 50 , 60 ) } -- Crée un tableau de points -- array = { { x = 10, y = 20 }, { x = 30, y = 40 }, { x = 50, y = 60 } }; print ( array [ 2 ] .y ) -- Affiche 40
L’utilisation d’une table de hachage pour émuler un tableau est généralement plus lente que l’utilisation d’un tableau réel ; cependant, les tables Lua sont optimisées pour être utilisées comme des tableaux afin d’éviter ce problème.
Métatables
La sémantique extensible est une caractéristique essentielle de Lua, et la métatable permet une personnalisation poussée des tables. L'exemple suivant illustre une table « infinie ». Pour tout n, fibs[n]la fonction renverra le n-ième nombre de Fibonacci grâce à la programmation dynamique et à la mémoïsation .
fibs = { 1 , 1 } -- Valeurs initiales pour fibs[1] et fibs[2]. setmetatable ( fibs , { __index = function ( values , n ) --[[__index est une fonction prédéfinie par Lua, elle est appelée si la clé "n" n'existe pas.]] values [ n ] = values [ n - 1 ] + values [ n - 2 ] -- Calcul et mémorisation de fibs[n]. return values [ n ] end })
Programmation orientée objet
Bien que Lua ne possède pas de concept de classes intégré , la programmation orientée objet peut être simulée à l'aide de fonctions et de tables. Un objet est constitué de méthodes et de champs placés dans une table. L'héritage (simple et multiple) peut être implémenté grâce aux métatables , qui permettent de déléguer des méthodes et des champs inexistants à un objet parent.
Dans ces techniques, la notion de « classe » n'existe pas ; on utilise plutôt des prototypes , comme avec Self en JavaScript . Les nouveaux objets sont créés soit par une méthode de fabrique (qui construit de nouveaux objets à partir de zéro), soit par clonage d'un objet existant.
Création d'un objet vectoriel de base :
local Vector = {} local VectorMeta = { __index = Vector }function Vector.new ( x , y , z ) -- Le constructeur return setmetatable ( { x = x , y = y , z = z } , VectorMeta ) endfonction Vector.magnitude ( self ) -- Une autre méthode renvoie math.sqrt ( self.x ^ 2 + self.y ^ 2 + self.z ^ 2 ) endlocal vec = Vector.new ( 0 , 1 , 0 ) -- Créer un vecteur print ( vec.magnitude ( vec ) ) -- Appeler une méthode ( sortie : 1) print ( vec.x ) -- Accéder à une variable membre (sortie : 0)
Ici, setmetatable`this` indique à Lua de rechercher un élément dans la Vectortable s'il n'y est pas présent vec. `this`, équivalent à `this` , commence par rechercher l'élément dans la table `this` . Si cette table ne contient pas l' élément, sa métatable délègue la recherche à la table ` this` lorsqu'il est introuvable . vec.magnitudevec["magnitude"]vecmagnitudevecmagnitudeVectormagnitudevec
Lua offre une syntaxe simplifiée pour faciliter la programmation orientée objet. Pour déclarer des fonctions membres dans un tableau de prototypes, on utilise `<prototype>` , ce qui est équivalent à ` <prototype>`. L'appel de méthodes de classe utilise également le deux-points : `<prototype>` est équivalent à `<prototype> `. functiontable:func(args)functiontable.func(self,args)object:func(args)object.func(object,args)
Ceci étant dit, voici une classe correspondante avec :une syntaxe simplifiée :
local Vector = {} Vector . __index = Vectorfonction Vector : new ( x , y , z ) -- Le constructeur -- Puisque la définition de la fonction utilise un deux-points, -- son premier argument est "self" qui fait référence à -- "Vector" return setmetatable ({ x = x , y = y , z = z }, self ) endfonction Vector : magnitude () -- Autre méthode -- Référence à l'objet implicite en utilisant self return math.sqrt ( self . x ^ 2 + self . y ^ 2 + self . z ^ 2 ) endlocal vec = Vector : new ( 0 , 1 , 0 ) -- Créer un vecteur print ( vec : magnitude ()) -- Appeler une méthode (sortie : 1) print ( vec . x ) -- Accéder à une variable membre (sortie : 0)
Héritage
Il est possible d'utiliser des métatables pour imiter le comportement de l'héritage de classes en Lua. Dans cet exemple, nous autorisons les vecteurs à voir leurs valeurs multipliées par une constante dans une classe dérivée.
local Vector = {} Vector . __index = Vectorfonction Vector : new ( x , y , z ) -- Le constructeur -- Ici, self fait référence à la méthode « new » de la classe -- que nous appelons. Dans une classe dérivée, self -- sera la classe dérivée ; dans la classe Vector, self -- sera Vector return setmetatable ({ x = x , y = y , z = z }, self ) endfonction Vector : magnitude () -- Autre méthode -- Référence à l'objet implicite en utilisant self return math.sqrt ( self . x ^ 2 + self . y ^ 2 + self . z ^ 2 ) end-- Exemple d'héritage de pseudo-classe local VectorMult = {} VectorMult .__ index = VectorMult setmetatable ( VectorMult , Vector ) -- Faire de VectorMult un enfant de Vectorfonction VectorMult : multiplier ( valeur ) self . x = self . x * valeur self . y = self . y * valeur self . z = self . z * valeur retourner self finlocal vec = VectorMult : new ( 0 , 1 , 0 ) -- Créer un vecteur print ( vec : magnitude ()) -- Appeler une méthode (sortie : 1) print ( vec . y ) -- Accéder à une variable membre (sortie : 1) vec : multiply ( 2 ) -- Multiplier toutes les composantes du vecteur par 2 print ( vec . y ) -- Accéder à nouveau à la variable membre (sortie : 2)
Il est également possible d'implémenter l'héritage multiple ; __indexil peut s'agir d'une fonction ou d'une table. La surcharge d'opérateurs est également possible ; les métatables Lua peuvent contenir des éléments tels que __add, __subetc.
Mise en œuvre
Les programmes Lua ne sont pas interprétés directement à partir du fichier texte Lua, mais compilés en bytecode, lequel est ensuite exécuté sur la machine virtuelle Lua (VM). Le processus de compilation est généralement transparent pour l'utilisateur et s'effectue à l'exécution , notamment lorsqu'un compilateur à la volée (JIT) est utilisé. Cependant, il peut être réalisé hors ligne afin d'améliorer les performances de chargement ou de réduire l'empreinte mémoire de l'environnement hôte en omettant le compilateur. Le bytecode Lua peut également être produit et exécuté depuis Lua, à l'aide des dumpfonctions de la bibliothèque de chaînes de caractères load/loadstring/loadfile. La version 5.5.0 de Lua est implémentée en environ 32 000 lignes de code C.
Comme la plupart des processeurs, et contrairement à la plupart des machines virtuelles (qui utilisent une pile ), la machine virtuelle Lua est basée sur des registres et ressemble donc davantage à la conception matérielle. L'architecture à registres évite les copies excessives de valeurs et réduit le nombre total d'instructions par fonction. La machine virtuelle de Lua 5 est l'une des premières machines virtuelles purement basées sur des registres à avoir connu une large diffusion. Parrot et Dalvik d' Android sont deux autres machines virtuelles à registres bien connues. La machine virtuelle de PCScheme était également basée sur des registres.
Cet exemple est la liste de bytecode de la fonction factorielle définie ci-dessus (telle qu'affichée par le luaccompilateur 5.1) :
fonction <factorial.lua:1,7> (9 instructions, 36 octets à 0x8063c60) 1 paramètre, 6 emplacements, 0 valeurs ascendantes, 6 variables locales, 2 constantes, 0 fonction 1 [2] LOADK 1 -1 ; 1 2 [3] LOADK 2 -2 ; 2 3 [3] DÉPLACER 3 0 4 [3] LOADK 4 -1 ; 1 5 [3] FORPREP 2 1 ; à 7 6 [4] MUL 1 1 5 7 [3] BOUCLE 2 -2 ; à 6 8 [6] RETOUR 1 2 9 [7] RETOUR 0 1
API C
Lua est conçu pour être intégré à d'autres applications et fournit une API C à cet effet. Cette API est divisée en deux parties : le noyau Lua et la bibliothèque auxiliaire Lua. Contrairement à l'API Python , la conception de l'API Lua élimine le besoin de gérer manuellement le comptage des références dans le code C. L'API, à l'instar du langage, est minimaliste. Les fonctions avancées sont fournies par la bibliothèque auxiliaire, qui se compose principalement de macros de préprocesseur facilitant les opérations complexes sur les tables.
L'API C de Lua est basée sur une pile . Lua fournit des fonctions pour empiler et dépiler la plupart des types de données C simples (entiers, flottants, etc.) et manipuler les tables via la pile. La pile Lua diffère légèrement d'une pile traditionnelle ; elle est par exemple indexable directement. Les indices négatifs indiquent le décalage par rapport au sommet de la pile. Par exemple, -1 correspond au sommet (la valeur la plus récemment empilée), tandis que les indices positifs indiquent le décalage par rapport à la base (la valeur la plus ancienne). Le transfert de données entre les fonctions C et Lua s'effectue également via la pile. Pour appeler une fonction Lua, les arguments sont empilés, puis la lua_callfonction est appelée. Lors de l'écriture d'une fonction C destinée à être appelée directement depuis Lua, les arguments sont lus depuis la pile.
Voici un exemple d'appel d'une fonction Lua depuis C :
#include <stdio.h> #include <lua.h> // Bibliothèque principale Lua (lua_*) #include <lauxlib.h> // Bibliothèque auxiliaire Lua (luaL_*)int main ( void ) { // crée un état Lua lua_State * L = luaL_newstate ( );// Charger et exécuter une chaîne si ( luaL_dostring ( L , "function foo (x,y) return x+y end" )) { lua_close ( L ); return -1 ; }// Empile la valeur de la variable globale "foo" (la fonction définie ci-dessus) , suivie des entiers 5 et 3. lua_getglobal ( L , "foo" ); lua_pushinteger ( L , 5 ); lua_pushinteger ( L , 3 ); lua_call ( L , 2 , 1 ); // Appelle une fonction avec deux arguments et une valeur de retour. printf ( "Résultat : %d " , lua_tointeger ( L , -1 )); // Affiche la valeur entière de l'élément en haut de la pile. lua_pop ( L , 1 ); // Remet la pile à son état initial. lua_close ( L ); // Ferme l'état Lua. return 0 ; }
L'exécution de cet exemple donne :
$ cc -o example example.c -llua $ ./example Résultat : 8
L'API C fournit également des tables spécifiques, accessibles via différents « pseudo-indices » dans la pile Lua. Avant LUA_GLOBALSINDEXLua 5.2 , la table des variables globales _Gde Lua, qui constitue l' espace de noms principal , se trouvait à cet emplacement. Un registre permet également aux LUA_REGISTRYINDEXprogrammes C de stocker des valeurs Lua pour une utilisation ultérieure.
Modules
Outre les modules de la bibliothèque standard (noyau), il est possible d'écrire des extensions à l'aide de l'API Lua. Les modules d'extension sont des objets partagés qui permettent d'étendre les fonctionnalités de l'interpréteur en fournissant des fonctionnalités natives aux scripts Lua. Ces scripts peuvent charger des modules d'extension à l'aide de `lsl` require[ comme les modules écrits en Lua, ou avec `lsl` package.loadlib . Lorsqu'une bibliothèque C est chargée via `lsl`, Lua recherche la fonction correspondante et l'appelle. Cette fonction se comporte comme n'importe quelle fonction C appelable depuis Lua et renvoie généralement un tableau contenant les méthodes. Un ensemble croissant de modules, appelés « rocks », est disponible via un système de gestion de paquets nommé LuaRocks , dans l'esprit de CPAN , RubyGems et Python eggs . Des liaisons Lua pré-écrites existent pour la plupart des langages de programmation populaires, y compris d'autres langages de script . Pour C++, il existe plusieurs approches basées sur des modèles et des générateurs de liaisons automatiques. require('foo')luaopen_foo
Applications
Dans le développement de jeux vidéo , Lua est largement utilisé comme langage de script , principalement en raison de sa facilité d'intégration, de sa rapidité d'exécution et de sa prise en main aisée . Parmi les jeux notables utilisant Lua , on peut citer Roblox , Garry's Mod , World of Warcraft , Payday 2 , Project Zomboid , Phantasy Star Online 2 , Dota 2 , Crysis , et bien d'autres. Lua est également utilisé dans des logiciels non liés aux jeux vidéo, tels qu'Adobe Lightroom , Moho , iClone , Aerospike et certains logiciels système sous FreeBSD et NetBSD . Il sert également de langage de script pour les modèles sur MediaWiki grâce à l'extension Scribunto.
En 2003, un sondage réalisé par GameDev.net a montré que Lua était le langage de script le plus populaire pour la programmation de jeux. Le 12 janvier 2012, Lua a été désigné lauréat du Front Line Award 2011 du magazine Game Developer dans la catégorie Outils de programmation.
De nombreuses applications non ludiques utilisent également Lua pour son extensibilité, telles que LuaTeX , une implémentation du langage de composition TeX ; Redis , une base de données clé-valeur ; ScyllaDB , un système de stockage à colonnes larges ; Neovim , un éditeur de texte ; Nginx , un serveur web ; Wireshark , un analyseur de paquets réseau ; Discordia, une bibliothèque API Discord ; et Pure Data , un langage de programmation audio visuel (via l'extension pdlua).
Langues dérivées
Langages compilés en Lua
- MoonScript est un langage de script dynamique et sensible aux espaces , inspiré de CoffeeScript et compilé en Lua. Cela signifie qu'au lieu d'utiliser `&& ` (ou ` &&` ) pour délimiter les sections de code, il utilise des sauts de ligne et un style d'indentation . Un exemple notable d'utilisation de MoonScript est le site web de distribution de jeux vidéo Itch.io.
doend{} - Haxe prend en charge la compilation vers certaines cibles Lua, notamment Lua 5.1–5.3 et LuaJIT 2.0 et 2.1.
- Fennel, un dialecte Lisp qui cible Lua.
- Urn, un dialecte Lisp construit sur Lua.
- Amulet, un langage de programmation fonctionnelle de type ML , dont le compilateur génère des fichiers Lua.
- LunarML, compilateur ML standard qui produit du Lua/JavaScript
dialectes
- LuaJIT , un compilateur juste-à-temps de Lua 5.1.
- Luau, développé par Roblox Corporation , est un dérivé de Lua 5.1 avec lequel il est rétrocompatible. Il propose un typage progressif , des fonctionnalités supplémentaires et une optimisation des performances. Luau a amélioré le sandboxing afin de permettre l'exécution de code non fiable dans les applications embarquées.
- Ravi est un langage Lua 5.3 compatible JIT avec typage statique optionnel. La compilation JIT est guidée par les informations de type.
- Shine, une version dérivée de LuaJIT avec de nombreuses extensions, dont un système de modules et un système de macros.
- Glua, une version modifiée intégrée au jeu Garry's Mod comme langage de script.
- Teal, un dialecte Lua statiquement typé écrit en Lua.
- PICO-8 , une « console de jeux vidéo fantastique », utilise un sous-ensemble de Lua connu sous le nom de PICO-8 Lua.
- Pluto, un sur-ensemble de Lua 5.4 offrant une syntaxe améliorée, des bibliothèques et une meilleure expérience de développement, tout en restant compatible avec Lua standard.
De plus, la communauté des utilisateurs de Lua fournit des correctifs de puissance en plus de l'implémentation C de référence.