Laboratoire Microsoft Utiliser le langage de script Luaen C#

motiontachyphagiaSoftware and s/w Development

Jul 5, 2012 (5 years and 3 months ago)

386 views

 
 
   
Laboratoire
Microsoft
Utiliser le langage de script Lua en C# 
via la bibliothèque LuaInterface 
Jean LAULIAC
Version 1.0 
12 Pages 
07/04/2010 
MTI ‐ LabMS 
 
Laboratoire  Microsoft ‐ Jean LAULIAC 
7 avril 2010 
 
Laboratoire  Microsoft| Introduction 
2 / 12 
 
Propriétés du document 
Auteur  Jean LAULIAC 
Version 
1.0 
Nombre de pages  12 
Références 
MTI - LabMS

 
Historique du document 
Date de révi‐
sion 
Version  Auteur  Changements 
07/04/2010 
0.1 
Jean 
Lauliac 
Document terminé 
 
   
 
Laboratoire  Microsoft ‐ Jean LAULIAC 
7 avril 2010 
 
Laboratoire  Microsoft| Introduction 
3 / 12 
 
Sommaire 
Introduction ........................................................................................................................................... 4

Pourquoi utiliser un langage de script ? ................................................................................................ 5

Pour le prototypage ........................................................................................................................... 5

Pour l’intégration dans les données .................................................................................................. 5

Pour étendre un comportement applicatif ....................................................................................... 6

Présentation du Lua ............................................................................................................................... 7

Un langage simple : les fonctions et les tables .................................................................................. 7

Un langage extensible : créer des nouveaux éléments de langage .................................................. 9

LuaInterface, une bibliothèque C# d’intégration Lua .......................................................................... 10

Appels de fonctions et variables ...................................................................................................... 10

Exporter des objets complets de manière transparente ................................................................ 10

Exemple d’utilisation ....................................................................................................................... 11

Conclusion ............................................................................................................................................ 12

 
 

 
Laboratoire  Microsoft ‐ Jean LAULIAC 
7 avril 2010 
 
Laboratoire  Microsoft| Introduction 
4 / 12 
 
Introduction 
Cet article va s’intéresser à l’intégration de script Lua au sein de code C#. Nous verrons pour quelles 
raisons il peut être utile d’utiliser un langage de script imbriqué dans le C#. Nous parlerons des carac‐
téristiques spécifiques du Lua, et enfin, comment celui peut être utilisé en C# par le biais de la biblio‐
thèque LuaInterface. 
 
Laboratoire  Microsoft ‐ Jean LAULIAC 
7 avril 2010 
 
Laboratoire  Microsoft| Pourquoi utiliser un langage de script ? 
5 / 12 
 
Pourquoi utiliser un langage de script ? 
Pour le prototypage 
Les langages de scripts remportent un grand succès dès lors qu’il s’agit d’être comparé aux lan‐
gages compilés classiques, et notamment le C/C++. Ce dernier fait en effet partie des langages les plus 
lents à compiler : cela peut aller de quelques secondes en compilation incrémentale jusqu’à plusieurs 
heures pour les projets conséquents en compilation complète. 
Le C/C++ étant aussi l’un des langages les plus utilisés, on voit rapidement l’intérêt que peut appor‐
ter l’utilisation de langages de scripts pour le prototypage. Concrètement, celui‐ci va consister à élabo‐
rer des algorithmes dans un langage de script en particulier, éventuellement intégré dans un ensemble 
qui lui sera programmé en langage compilé. De tels algorithmes, une fois mis au point, pourront alors 
être reprogrammés en un langage compilé. 
L’intérêt principal d’une telle technique repose dans la rapidité du temps d’itération : en effet, une 
fois le script modifié, aucune action supplémentaire n’est nécessaire. Les modifications peuvent être 
immédiatement prises en compte si le script est intégré et utilisé par un programme hôte, qui va alors 
simplement recharger le fichier du script en question. 
Le simple fait de passer de quelques secondes (de 5 à 10 sec. en C++) à moins d’une seconde lors 
de la mise au point et le débogage d’un algorithme rend le développement particulièrement efficient. 
Cela est particulièrement vrai pour des algorithmes dont on ne connait pas forcément la forme finale à 
la première itération ; par exemple, dans le jeu vidéo, les mécaniques de jeu (gameplay) connaissent 
un grand nombre de modifications au cours du temps, et sont testés via une méthode d’erreur et es‐
sai. Les scripts n’apporteront en revanche pas grand‐chose sur des algorithmes dont on connait la 
forme précise à l’avance, tel que des algorithmes de gestion de données (listes, dictionnaires, etc.). 
Le gain du temps d’itération existe aussi en C#, notamment lorsque l’application est lourde à re‐
charger ou que la fonctionnalité d’edit‐and‐continue ne peut être utilisé facilement dans un contexte 
particulier. Mais la rapidité de prototypage n’est pas le seul intérêt d’un langage de script. 
Pour l’intégration dans les données 
La particularité d’un certain nombre de langages de scripts est leur capacité à être  extensibles, 
c'est‐à‐dire à pouvoir créer des structures pouvant représenter des concepts de plus haut niveau.   Par 
exemple, le Lua n’est pas un langage nativement orienté objet ; cependant, il est possible 
d’implémenter un comportement objet via les différents outils d’extensibilité proposés par le langage. 
Le fait de pouvoir construire de telles structures peut permettre de définir, en quelque sorte, un 
nouveau langage de plus haut niveau pour représenter des données complexes et diverses, tel que 
nous le verrons après. L’intérêt de ces structures de données par rapport à des langages dédiés aux 
données tel que le XML est la possibilité d’y inclure des comportements plus complexes (des fonctions 
anonymes, par exemple, pour gérer des évènements sur des entités) ; c’est également l’occasion 
d’obtenir une syntaxe plus claire, plus concise, plus rapidement éditable à la main. Le JSON est un bon 
exemple de « langage » créé par au‐dessus du JavaScript pour représenter des données. 
Nous verrons en Lua comment l’on peut représenter des données aisément. 
 
Laboratoire  Microsoft ‐ Jean LAULIAC 
7 avril 2010 
 
Laboratoire  Microsoft| Pourquoi utiliser un langage de script ? 
6 / 12 
 
Pour étendre un comportement applicatif 
Pour terminer, on notera que les langages de scripts sont un moyen de laisser à l’utilisateur dit 
« avancé » la capacité à personnaliser son environnement de travail à son potentiel maximum, ce par 
la réalisation de macros en script. Par exemple, Visual Basic for Applications permet d’étendre le com‐
portement de documents Microsoft Word, Excel, voire Powerpoint. 
Dans cette application, les scripts se révèlent encore plus facile d’accès pour l’utilisateur que la réa‐
lisation de « plugin » écrits directement dans le langage hôte ; ce qui est, ceci étant, presque tout aussi 
aisément implémentable en C# (via la réflexion). Par ailleurs, un script est facilement additionnable à 
un document contenu dans un seul fichier, par simple sauvegarde du texte du script. On peut ainsi 
fournir un script spécifique à un document en particulier. 
 
Laboratoire  Microsoft ‐ Jean LAULIAC 
7 avril 2010 
 
Laboratoire  Microsoft| Présentation du Lua 
7 / 12 
 
Présentation du Lua 
Un langage simple : les fonctions et les tables 
Le langage Lua est un bon exemple de langage de script intégrable dans des applications, de par sa 
simplicité et son extensibilité. Les deux concepts de base à connaitre sont les fonctions et les tables. 
Les fonctions en Lua sont un peu particulières, puisqu’il s’agit de valeurs similaires à n’importe 
quelle autre valeur : chaines, nombres, etc. Par exemple, le code suivant crée une fonction et appelle 
celle‐ci : 
myfunction = function(name)
return "Hello " .. name .. "!"
end
print(myfunction("foo"))
 
(L’opérateur « .. » permet de concaténer des chaines. Pour plus d’information sur les opérateurs et 
les bases du Lua, consulter la documentation officielle : http://www.lua.org/manual/5.1/) 
Dans le cas présent, myfunction est une variable globale. Il existe un raccourci pour définir des 
fonctions globales : 
function myfunction(name)
return "Hello " .. name .. "!"
end
print(myfunction("foo"))
 
Mis à part leur caractère de « valeurs fonctionnelles », les fonctions Lua sont similaires aux fonc‐
tions des autres langages. Cependant cette condition de valeur va justement nous permettre d’insérer 
des fonctions au sein d’un ensemble de données sans aucune difficulté. 
Le second élément important du Lua à connaitre est la notion de « table ». Il  n’y a en effet aucune 
notion de structure ni de tableau en Lua, l’ensemble de ces éléments pouvant en fait être représentés 
en tant que table. A ce titre, il se rapproche de d’autres langages de scripts tels que le PHP où il existe 
peu de différences entre structures et tableaux. 
Une table en Lua s’initialise et s’utilise ainsi : 
mytable = { var1 = "bar", var2 = "foo" }

print(mytable["var1"]) -- première forme
print(mytable.var2) -- seconde forme
 
Dans la première forme présentée, on accède à la table comme s’il s’agissait d’un dictionnaire de 
valeurs (une hashtable). Cela permet d’accéder aux valeurs de la table avec une clé dynamique, que 
l’on ne connait pas à l’avance. 
Dans la seconde forme, on accède à la table comme s’il s’agissait d’une structure. Dans ce cas, le 
nom du champ à accéder doit être connu à l’avance. A noter que si l’on accède à un champ non exis‐
 
Laboratoire  Microsoft ‐ Jean LAULIAC 
7 avril 2010 
 
Laboratoire  Microsoft| Présentation du Lua 
8 / 12 
 
tant d’un tableau, quel que soit la forme, Lua retourne par défaut la valeur nulle (mot‐clé « nil » en 
Lua). 
Enfin, il existe une troisième forme un peu particulière : 
mytable = {
bar = "",

foo = function(this)
print(this.bar)
end,
}

mytable.bar = "hello, world"
mytable:foo()

 
Il s’agit ici de l’opérateur double‐point “:”. Il permet en fait d’appeler une fonction contenue dans 
une table, en passant implicitement la table elle‐même en premier paramètre de la fonction. Cela 
permet de simuler un comportement objet : ce paramètre simule, et à le même rôle que, le pointeur 
« this » en C++, l’objet « this » en C# ou encore « $this » en PHP, qui permettent d’accéder à l’objet 
local. Ainsi le code ci‐dessus affichera « hello, world » en sortie. 
Cet opérateur bien pratique ne remplit pas cependant toutes les missions d’un langage orienté ob‐
jet. Il n’y a pas de notion de classes et d’instanciation nativement en Lua. Cet opérateur peut nous ai‐
der néanmoins à les simuler à leur tour. 
Par ailleurs, Les tableaux en Lua sont simplement des tables dont les clés sont numériques. Il est 
possible de créer implicitement un tableau : 
myarray = {1, 3, 5, 7, 9}

print myarray[1] // Ecrit le premier élément
 
A noter : en Lua, les indices de tableaux commencent à 1. 
Une dernière chose est importante afin de mettre en place des structures personnalisées : en Lua, 
lorsque l’on appelle une fonction qui ne prend qu’un paramètre, et que celui‐ci est une chaine de ca‐
ractères ou une table, alors les parenthèses à l’appel sont optionnelles. Par exemple : 
myfonction = function(foo)
-- something interesting
end

myfunction("une chaine")
myfunction "une chaine" -- version sans parenthèses
myfunction({ bar=4, foo=6 })
myfunction { bar=4, foo=6 } -- version sans parenthèses
 
 
 
Laboratoire  Microsoft ‐ Jean LAULIAC 
7 avril 2010 
 
Laboratoire  Microsoft| Présentation du Lua 
9 / 12 
 
Un langage extensible : créer des nouveaux éléments de langage 
De par la flexibilité offerte par la syntaxe et les tables, il est possible de définir de nouveaux élé‐
ments de langage. Par exemple, la programmation orienté objet : 
class {
"ClassName",

_prop = "foo",

property {
"SomeProperty",
get = function(this)
return this._prop
end,
set = function(this, value)
this._prop = value
end,
},

doSomething = function(this)
-- [...]
end,

}
 
En ayant défini au préalable des function “class” et “property”. Ces fonctions, dont on ne détaillera 
pas ici l’implémentation, prennent en paramètre des tables. « class » pourrait, par exemple, créer une 
variable globale nommée « ClassName » (selon l’exemple), et effectuer des traitement sur celle‐ci. Par 
exemple, cela pourrait générer automatiquement une fonction « Create » qui créé une instance de la 
classe (une autre table, en somme). On pourrait alors utiliser la classe ainsi : 
myobject = ClassName.Create(param1, param2)
 
Bien entendu, on peut définir tout autre chose que des classes. On pourrait par exemple créer un 
système de description d’une scène de jeu vidéo : 
scene {
object {
model = "cube",
position = {4, 6, 2},
},
light {
position = {0, 100, 0},
color = "blue"
},


}
 
Dans lequel « scene », « object », « light » sont des fonctions globales qui prennent en paramètres 
des tables. 
Lua est donc un langage flexible, dynamique et efficient. Voyons comment l’intégrer dans des ap‐
plications C# plus lourdes. 
 
Laboratoire  Microsoft ‐ Jean LAULIAC 
7 avril 2010 
 
Laboratoire  Microsoft| LuaInterface, une bibliothèque C# d’intégration Lua 
10 / 12 
 
LuaInterface, une bibliothèque C# d’intégration Lua 
Pour intégrer Lua dans un programme C# (ou n’importe quel langage .NET, tel que le Visual Basic), 
nous aurons besoin de la bibliothèque LuaInterface, disponible ici : 
http://luaforge.net/projects/luainterface/ 
Appels de fonctions et variables 
Une fois la référence vers la bibliothèque LuaInterface ajoutée, la première chose à faire est de 
créer un objet à partir de la classe « Lua » contenue dans le namespace « LuaInterface ». Cette classe 
représente l’environnement d’exécution Lua, ainsi tant que cette variable est conservée, l’ensemble 
des fonctions et variables globales Lua déclarées restent définies. 
C’est donc avec cette variable que nous pouvons contrôler les fonctions exportés à partir du C#. 
Imaginons, par exemple, que nous voulions rediriger les appels à « print » (par défault, écrit sur la con‐
sole) pour afficher des messages à l’écran à la place. Nous pouvons écrire cela : 
public class MyLuaInterpreter
{
private Lua ; _lua

public MyLuaInterpreter()
{

_lua = new Lua();
_lua.RegisterFunction("print", this, this.GetType().GetMethod("Message"));

}

public void Message(string text)
{
MessageBox.Show(text);
}

}
 
Ainsi, ce code enregistre la fonction « print » (du point de vue du Lua) en tant que la méthode C# 
« Message », dans l’objet courant (que l’on récupère via la réflexion des types C#). Par exemple, ce 
code Lua affichera « hello, world » dans une boite de message standard : 
print "hello, world"
 
A noter que pour executer du code Lua (contenu dans une chaine de caractère) à partir du C#, il 
suffit d’appeler « DoString », par exemple : 
_lua.DoString("toto = 4\nprint \"hello, world\"");
Exporter des objets complets de manière transparente 
Grâce à LuaInterface, il est très simple d’exporter des objets C# complets. En fait, dès qu’une fonc‐
tion qui a été exporté en Lua possède un type de retour complexe (une structure, une classe), LuaIn‐
terface génère automatiquement une table possédant toutes les fonctions et propriétés nécessaires 
pour utiliser l’objet. Par exemple, on considère l’objet suivant : 
 
Laboratoire  Microsoft ‐ Jean LAULIAC 
7 avril 2010 
 
Laboratoire  Microsoft| LuaInterface, une bibliothèque C# d’intégration Lua 
11 / 12 
 
class MyObject
{
public string Foo { get; set; }
}
 
On définit alors la fonction suivante, qui retourne simplement une nouvelle instance de cet objet : 
public MyObject CreateMyObject()
{
return new MyObject();
}

 
Il ne reste plus qu’à enregistrer la fonction : 
_lua.RegisterFunction("CreateMyObject", this, this.GetType().GetMethod("CreateMyObject"));
 
On pourra alors très simplement accéder aux propriétés de l’objets (code Lua) : 
myobj = CreateMyObject()

myobj.Foo = "testing string"
 
La valeur de la propriété sera alors mise à jour directement et accessible à partir du C#. 
Exemple d’utilisation 
Un exemple simple est dans le cas où l’on souhaite intégrer des scripts dans une application lourde 
(tel que Word). On peut imaginer avoir une classe « Application » qui contienne les éléments de base 
et la liste des documents ouvert. Un document serait représenté par une classe « Document ». 
En exportant simplement une fonction « GetApplication », on peut alors accéder à cet ensemble de 
fonctionnalités directement. On pourrait alors écrire quelque chose de ce genre : 
app = GetApplication()
doc = app.GetActiveDocument()


doc.AppendText("some script generated text")


 
 
 
Laboratoire  Microsoft ‐ Jean LAULIAC 
7 avril 2010 
 
Laboratoire  Microsoft| Conclusion 
12 / 12 
 
Conclusion 
Nous avons ainsi vu quels étaient les intérêts d’utiliser un langage de script dans une application 
lourde, et à quel point la flexibilité du Lua pouvait à ce titre être utile. Nous avons également vu com‐
ment l’intégrer de manière très simple dans le C#. 
Il ne vous reste plus qu’à mettre cela en pratique dans un projet :)