Nous vous remercions de votre visite
Nous utilisons un cookie pour mesurer l'audience et améliorer votre expérience sur le site.
  
Talenha
LE LANGAGE DE PROGRAMMATION
Nous avons abordé le langage talenha avec les deux fonctions escape et unescape. Nous allons maintenant voir les principes généraux du langage puis chaque élément en détail.

Principes généraux du langage talenha

Il y a trois syntaxes générales dépendantes du contexte, c'est-à-dire la structure.
  1. Appel à une fonction
  2. Les instructions ou commandes
  3. Une expression

Appel d'une fonction

On fait appel à une fonction par son nom
 nomFonction(paramètre 1, paramètre 2, ...) 
.
Elle est définie dans tous les fichiers dès lors qu'elle est créée par l'instruction suivante :
 fun local|global nomFonction[globales](paramètres) {
  ...corps de la fonction
}

Une fonction peut retourner une ou plusieurs valeurs par la commande
 output(e, ...) 
e est une expression. Lorsque l'on retourne plusieurs valeurs, le résultat de la fonction est une liste. La fonction output ne retourne pas à l'appelant. On peut faire appel à une fonction dans une expression. Le résultat de la fonction est alors partie prenante de l'expression.

Dans le corps de la fonction, les variables sont locales à la fonction. Les variables existantes hors de la fonction peuvent lui être transmises en indiquant leurs noms entre crochets dans la définition de la fonction. La fonction est alors transparente pour ces variables. Si la commande comporte le terme 'local' alors toutes les variables sont transmises à la fonction sauf celles entre crochets.

a = 1,
print("valeur de a = " a), // a affiche 1
fun f[a]() {
  a = 2
},
f(),
print("valeur de a = " a), // a affiche 2
fun g(a) {
  a = 3
},
g(a),
print("valeur de a = " a) // a affiche 2

Un paramètre peut comporter l'option out pour indiquer qu'il s'agit d'un paramètre de sortie. La variable passée en paramètre reçoit alors le résultat calculé par la fonction. Si le paramètre donné n'est pas une variable, le résultat calculé par la fonction est sans effet.

fun f(out a) {
  a = 1
},
f(a),
print("valeur de a = " a), // a affiche 1
fun g(out b) {
  b = b + 1
},
g(a),
print("valeur de a = " a) // a affiche 2

Chaque instruction doit être séparée par une virgule.
L'instruction
 print(s, ...) 
affiche le résultat sur la console de l'application.
La concaténation de textes s'écrit sans opérateur
 "a" "b" "c" 

Les instructions ou commandes

Les instructions sont séparées par une virgule. Si une virgule manque alors la colorisation syntaxique n'est plus effectuée, ce qui permet de détecter cette erreur.
L'ensemble des instructions est:
 if (expression) { ... code ... } else { ... code ... } 

 while(expression) { ... code ... } 

 foreach(e from liste) { ... code ... } 

 fun local|global nomFonction[global1,global2,...](paramètres) {
  ... code ...
} 

 sandbox{closure}[globals](paramètres) {
  ... code ...
} 
 select name { name { ... code ...}, ... } 

 jump expression 
 reverse { ... code ... } 

 request(ihm, paramètre 1, ...) 

 configure(option=valeur, ...) 

 write(fichier, liste) 

 aspect(fichier, expression, after|before|replace, liste) 

 store(variable, valeur) 

 play(variable, valeur) 

 dispatch(fonction, paramètres) 

 compile(expression) 

 compile f1 f2 ... 

 output(e, ...) 

 dump(e, ...) 

 doc {
  description "description"
  param name "description"
  global name "description"
  returns "valeur de retour"
} 

 { ... code ... } becomes nomFunction{closure}[globals](params) 

 print(e, ...) 

 a = expression 

 nomFonction(expression 1, expression 2, ...) 
 \objet 

if

C'est l'instruction conditionnelle classique. Selon une expression conditionnelle et, lorsqu'elle est évaluée à vrai alors le bloc de code suivant est effectué. Si l'instruction comporte un else et si l'expression conditionnelle est évaluée à faux alors c'est uniquement le bloc de code après le else qui est effectué. Dans les deux cas, les instructions suivantes sont traitées.

a = -3,
if (a > 0) print("a > 0"),
print("valeur de a = " a)

while

C'est la seule instruction du langage permettant d'effectuer une boucle (avec le jump). Tant que l'expression conditionnelle est vrai alors le bloc de code suivant est effectué; à la fin du bloc, l'expression conditionnelle est à nouveau évaluée et si elle est encore vrai alors le bloc de code suivant est à nouveau effectué avec les nouvelles valeurs des variables. Si l'expression conditionnelle devient fausse une seule fois alors, les instructions suivantes sont traitées.

counter = 1,
while(counter < 10) {
  print("counter = " counter),
  counter = counter + 1
},
print("suite...")

foreach

Cette instruction permet d'itérer les éléments d'une liste d'éléments numérotés ou une liste d'éléments nommés.

list = [ "a", "b", "c" ],
foreach(e from list) {
  print(e list(e))
} // affiche 0a 1b 2c

hashTable = { a : 1, b : 2, c : 3 },
foreach(e from hashTable) {
  print(e hashTable(e))
} // affiche a1 b2 c3

La variable définie dans le foreach peut être de n'importe quelle forme. Par exemple:

foreach(vars.currentCounter from list) {
  ... code ...
}

sandbox

Il s'agit de la déclaration d'une fonction anonyme qui peut être stockée dans une variable ou bien être appelée pour éliminer des effets de bords et l'utilisation de variables existantes. On peut faire appel à une instruction sandbox avec une fermeture, c'est-à-dire des variables dont la valeur est considérée comme une constante dans la fonction.

fun f() {
  a = 1,
  output(sandbox{a}[b]() {
    b = b + a,
    print("valeur de a dans la fonction = " a)
  })
},
b = 0,
u = f(),
\u(),
print("valeur de b = " b),
print("valeur de a = " a)

Nous verrons plus loin l'explication du backslash (\) devant u().

select

Il permet d'effectuer des goto, des exceptions ou des choix conditionnels (switch).

x = 0,
select loop {
  loop {
    print(x),
    x = x + 1,
    jump "test"
  },
  test if (x < 10) jump "loop"
}

fun f(x) {
  if (x >= 10) jump "exception"
  else {
    print(x),
    f(x+1)
  }
}
select {
  default f(0),
  exception print("end")
}

a = "pomme"
select {
  pomme print("pomme"),
  fraise print("fraise"),
  framboise print("framboise"),
  default jump a
}

Le paramètre dans l'instruction jump est une expression.

reverse

Elle renverse l'ordre d'interprétation des instructions. Au lieu de lire de haut en bas, les instructions sont lues de bas en haut.

reverse {
  print(a + b),
  b = a + 1,
  a = 1
}

Cela permet de commencer par le résultat et de terminer par les éléments qui lui sont subordonnés. En terme de lecture, il est plus clair de voir l'ensemble final présenté à la première ligne qu'à la dernière.

request

Définit un contrôle d'interface graphique tel qu'un bouton ou une zone de saisie. La fonction display affiche ces éléments à l'écran.

configure

C'est une commande qui active ou désactive des fonctionnalités configurables. Actuellement, seule la fonctionnalité debug est possible.

configure(debug=true),
configure(debug=false)

write

Ecrit dans un fichier sur le serveur de base de données dans la rubrique "Sorties". Le second paramètre doit être une liste.

content = "...",
write("result.txt", [ content ])

aspect

Insère avant, après ou remplace la donnée de substitution $name ou #name du fichier la liste indiquée en paramètre.

content = "...",
aspect("result.txt", #insertion, after, [ content ])

store et play

Stocke dans une variable l'expression indiquée en paramètre. L'instruction play lit le contenu de la variable.

store("varName", 1)
play("varName", paramètres)

dispatch

Fait appel à une fonction via son nom ou bien anonyme sandbox en indiquant les paramètres dans une liste.

dispatch("nomFonction", [ paramètre 1, paramètre 2, ... ]),
s = sandbox() {
  ... code ...
},
dispatch(s, [])

compile

Compile un texte ou un fichier et retourne le résultat.

compile(unescape("[<<[ print("ok") ]>>]")),
result = compile(unescape("[<<[ output("ok") ]>>]")),
compile "chemin/fichier"

output

Retourne à la sortie les paramètres indiqués. Dans une fonction, la commande output ajoute une valeur de retour dans la liste de retour. Dans un fichier, la valeur de retour est celle tranmise au résultat de la commande compile.

output("valeur 1", "valeur 2", ...)

dump

Cette instruction affiche dans la console de l'application, le contenu interne d'une variable ou d'une expression. Le contenu interne est une structure JSON.
Elle permet de savoir ce qu'il y a dans la variable pour pouvoir y lire ses éléments. L'instruction foreach permet aussi de lire tous les éléments de premier niveau. L'instruction dump affiche tous les éléments de tous les niveaux.

a = 1,
dump(a)

doc

Documentation qu'il faut placer avant la déclaration d'une fonction pour que cette fonction soit automatiquement ajoutée dans la documentation. Cette documentation est réalisée au moment de l'analyse et de la coloration syntaxique.

Les éléments dans l'instruction doc sont :
  1. description  suivi d'un texte entre guillemets
  2. param  suivi du nom du paramètre et d'un texte de description entre guillemets
  3. returns  suivi du descriptif de la valeur de retour
  4. global  suivi du nom de la variable globale et d'un texte de description.

becomes

C'est une instruction qui crée une fonction à partir d'une partie d'un code évitant de répéter plusieurs fois le même code à un autre endroit. L'utilisation d'une fermeture permet de traiter les cas où la valeur est connue à l'avance.
Le code dans l'instruction becomes est interprété de façon transparente.
La fonction est créée par l'interpréteur de sorte qu'il faut qu'elle aie été définie avant son utilisation ailleurs. Une fois la fonction définie ou redéfinie, le programme connait la fonction.
Elle peut être utile lors du développement du programme.

print

Affiche dans la console de l'application la valeur des expressions entre parenthèses.

print(1, 2, 3, 1+2+3)

Affectation

Affecte une expression à une variable. L'expression est évaluée, calculée et le résultat de cette expression est enregistré dans la variable. Reportez-vous au format des variables pour de plus amples informations.

Le trapcode

Il s'agit d'une interprétation secondaire utilisée pour le transpilateur. Elle a aussi pour raison d'ajouter la sortie d'une fonction dans la liste de retour.

fun f(x) {
  output(x)
},
f(1), // ne retourne rien
\f(1) // retourne 1

\f(1)
est un raccourci de
 output(f(1)) 

Les expressions

Les opérateurs arithmétiques usuels sont : +, -, *, /, %. La division est toujours décimale. Pour une division entière, il suffit de retirer au dividende le reste de la division avec le diviseur.

Les opérateurs de comparaison sont : >, <, >=, <=, ==. Notez que l'opérateur != n'existe pas car l'instruction if suffit.

Les opérateurs booléens sont : &&, ||. L'opérateur de négation n'existe pas.

L'opérateur exists se place après une variable et retourne un booléen vrai ou faux pour dire si elle existe ou non.

if (a exists) print(a) else print("a n'existe pas")
	

L'opérateur defer se place avant toute une expression pour différer l'évaluation de l'expression.

y = defer x + 1,
x = 1,
print(y), // affiche 2
x = 2,
print(y) // affiche 3

Expression

Les expressions permettent d'effectuer des calculs mathématiques et des opérations booléennes.

Notation des variables

Une variable est identifiée de manière unique par son nom unique. Sous ce nom utilisé, l'affectation permet d'y stocker une valeur numérique, texte, booléenne, une liste ou bien des champs.

Listes

Pour lire dans une liste, il suffit d'ajouter l'index de lecture dans la liste entre parenthèses après le nom. L'index de lecture va de 0 à MAX_INT.

list = [ 1, 2, 3 ],
print(list(0), list(1), list(2), list(3)),

Les listes peuvent être multi-dimensionnelles. De manière interne, ce sont des listes de listes; ainsi, aucune liste n'est de longueur fixe. Les éléments d'une liste peuvent être de différents types.

m(0) = 1,
m(1) = 2,
m(2) = [3,4],
m(3) = fun { output(m(0),m(1),m(2)) },
print(m(2),m(2,0),m(2,1)),
print(m(2).type),
print(m(3,0),m(3,1),m(3,2),m(3,2,0)),
print(m(3).type)

L'expression
fun { } 
est une fonction anonyme et partage les variables locales.

Champs

Pour ajouter un champ dans une variable, il suffit d'intercaler un point (.) avant le champ. Notez que l'objet doit déjà être une liste de champ ou rien sinon une erreur de type s'affiche. Les champs peuvent se succéder indéfiniment.

h = { a : 1, b : 2 },
h.c = 3,
print(h.a, h.b, h.c),
a.champ1.champ12.champ123 = "bonjour !",
print(a.champ1.champ12.champ123)

On peut combiner les champs et les listes afin de former un ensemble de données JSON que l'on pourra lire et modifier.

j = {
  a : 1,
  b : [ {
    c : 2
  },
  {
    d : [4,5,6]
  } ],
  e : 7
},
print(j.e,j.b(1).d),
j.b(0).f = 8,
print(j.b(0).f)

On peut lire un champ via un texte. Par exemple, si
 a = { b : 1, c : 2 } 
alors
 a("b") 
est équivalent à
 a.b 
.

Construire dynamiquement une liste

On peut créer dynamiquement une liste à l'aide d'un compteur.

list = [],
counter = 0,
while(counter < 10) {
  list(counter) = (counter + 1) * 2,
  counter = counter + 1
},
list.length = 10,
print(list@ToSequence(list, ","))

La fonction list@ToSequence est définie dans un fichier partagé. L'arobase (@) sépare l'espace de nom list du nom de la fonction ToSequence.
Notez qu'il faut spécifier la longueur de la liste lorsqu'elle est construite dynamiquement.

Type de données

Chaque élément de donnée a un type stocké dans le champ type. On accède à ce champ par
 u = 1, print(u.type) 
. Les types définis par défaut sont:
  1. number
  2. constantString
  3. boolean
  4. list
  5. hash
  6. sandbox
Le type permet de connaitre le type de donnée de la variable afin de pouvoir traiter toutes les situations.

Modifier le type de donnée n'est pas recommandé. Cependant, vous êtes libre de créer une structure de données avec un champ 'type' contenant un nouveau type. Il revient à vous de traiter les différents cas pour afficher les données correspondantes au champ type en écrivant par exemple des fonctions de lecture et d'écriture.

Une liste est stockée dans le champ 'elements'. Le champ 'length' dans ce champ permet de connaitre la taille exacte de la liste.
list = [ 1, 2, 3 ],
print(list.elements.length),
print(list.elements(0))

Un nombre ou un texte est stocké dans le champ 'value'. Vous pouvez accéder à ce champ.
a = "bonjour !",
print(a.value),
b = 1,
print(b.value)

Accéder au champ 'value' d'un texte affiche le texte entre guillemets.
En fait, toutes les données sont des structures avec un champ 'type' et un champ 'value' ou un champ 'elements' selon le type de donnée. La machine virtuelle traite automatiquement chaque type de manière transparente.

Création d'un langage

Le langage Talenha permet de créer des langages de programmation. Vous pouvez cliquer ici pour connaitre la syntaxe de création d'un langage avec talenha.