===== Référence du langage =====
Liste des instructions par ordre alphabétique.
==== background ====
C'est la première instruction, hors commentaires, d'un programme W.\\
Elle peut être suivie d'un [[w:syntax|identifiant]], optionnel, permettant d'identifier le programme.
background
background monProgramme
L'instruction identifie le programme comme un //service// ; contrairement à un programme initialisé avec [[w:instr:begin|begin]], la main est rendue immédiatement à l'utilisateur et le programme s'exécute en tâche de fond.\\
\\
==== begin ====
C'est la première instruction, hors commentaires, d'un programme W.\\
Elle peut être suivie d'un [[w:syntax|identifiant]], optionnel, permettant d'identifier le programme.
begin
begin monProgramme
L'instruction identifie le programme comme un traitement //standard// ; la main est rendue à l'utilisateur quand le programme se termine.\\
\\
==== break ====
Cette instruction sort de la boucle en cours [[w:instr:loop|loop]] ou [[w:instr:foreach|foreach]], sans changer les conditions d'exception.\\
Elle fonctionne comme si le traitement "sautait" à l'instruction suivant la ligne de fin de la boucle en cours [[w:instr:endloop|endloop]] ou [[w:instr:endfor|endfor]].
loop
input v
if v = 0 then
break ; si v vaut 0, le programme sort de la boucle, sinon il continue en séquence
endif
endloop
; la sortie de la boucle par "break" fait arriver ici
==== breakon ====
Comme l'instruction [[w:instr:break|break]], cette instruction sort de la boucle en cours [[w:instr:loop|loop]] ou [[w:instr:foreach|foreach]], mais uniquement si la condition qui suit est évaluée à //vrai//.\\
Elle fonctionne comme si le traitement "sautait" à l'instruction suivant la ligne de fin de la boucle en cours [[w:instr:endloop|endloop]] ou [[w:instr:endfor|endfor]].
loop
input v
breakon v = 0 ; si v vaut 0, le programme sort de la boucle, sinon il continue en séquence
endloop
; la sortie de la boucle par "break" fait arriver ici
==== call ====
Cette instruction permet d'appeler un sous-programme externe au source en cours, de type //bibliothèque//. C'est un binaire au format W (en p-code) en mode compilé, ou un source W en mode interprété, chargé à la volée lors de l'appel.\\
La syntaxe est => ''call (params...)'' : appel d'un autre programme W de type //bibliothèque//, présent soit dans le répertoire des sources WSRC en mode interprété, soit celui des binaires WBIN en mode p-code.\\
Le passage des paramètres est facultatif et variable ; le contrôle est fait uniquement à l'exécution lors de l'utilisation des variables. Les paramètres en trop sont ignorés. Ceux manquant forceront la variable paramètre associée à l'état //non-déclarée//.\\
Les paramètres sont obligatoirement des variables simples ([[w:syntax|identifiant]] simple), passées par //référence// (PAS d'expression). Les variables chaînées, de type ''var.var2!var3'' etc., sont interdites et provoqueront une exception si utilisées comme paramètre.
call calculerRacineCarre(nombre, resultat)
==== catch ====
Cette instruction n'est utilisable QUE dans le bloc exception des programmes et sous-programmes.\\
Elle permet d'annuler l'exception en cours et de revenir au programme appelant sans remonter l'erreur.
catch
==== class ====
Cette instruction permet de créer une //classe// au sens de la programmation objet. Le nom de la classe n'a pas besoin d'être déclarrée par [[w:instr:declare|declare]].\\
Techniquement, la classe est identique à une hashtable, avec des éléments interne nécessaire à sa bonne gestion.\\
Une classe hérite obligatoirement d'une autre classe, et d'une seule. Une classe créée par le langage W, //Base//, est l'origine de toute classe et est la classe mère par défaut si besoin.\\
La syntaxe est : ''class = { cela correspond à un mode de fonctionnement //static//.\\
Enfin, une classe ne peut pas être définie dans une [[w:instr:library|library]], sous peine de provoquer une exception. En effet, les déclarations dans les library ne peuvent pas être globales, car le code n'est plus disponible une fois sorti de la library.\\
class Figure = {Base}
let Figure.nombreCote = 0
class Quadrilatère = {Figure} ; la classe "Quadrilatere" herite des membres de la classe mère
class Rectangle = {Quadrilatere}
let Rectangle.longueur = 10
let Rectangle.largeur = 8
sub Rectangle.Aire(aire)
aire = this.longueur * this.largeur
except
endsub
class Carre = {Quadrilatere}
let Carre.nombreCote = 4 ; tous les membres et méthodes sont publics et modifiables
declare a, c
let c = new Carre
let a = c.Aire(a)
; la méthode "Aire" n'est pas trouvée dans la classe Carre (classe de l'objet "c"), W va chercher une méthode du même nom dans les classes mères,
; et va trouver celle de "Rectangle", et affecter 80 à "a"
==== continue ====
Cette instruction fait revenir le programme au début de la boucle en cours [[w:instr:loop|loop]] ou [[w:instr:foreach|foreach]], sans changer les conditions d'exception.\\
Elle fonctionne comme si le traitement "arrivait" à l'instruction de fin de la boucle en cours [[w:instr:endloop|endloop]] ou [[w:instr:endfor|endfor]], ce qui provoque le retour au début de la boucle pour exécuter l'occurrence suivante.
loop ; l'instruction continue fait revenir le programme à cette ligne
input v
if v = 0 then
continue ; si v vaut 0, le programme repart en début de boucle
endif
if v > 0 then
echonl v ; si v est supérieur à 0, le programme affiche le contenu de "v" et sort de la boucle
break
endif
endloop
==== continueon ====
Comme l'instruction [[w:instr:continue|continue]], cette instruction fait revenir le programme au début de la boucle en cours [[w:instr:loop|loop]] ou [[w:instr:foreach|foreach]], mais uniquement si la condition qui suit est évaluée à //vrai//.\\
Elle fonctionne comme si le traitement "arrivait" à l'instruction de fin de la boucle en cours [[w:instr:endloop|endloop]] ou [[w:instr:endfor|endfor]], ce qui provoque le retour au début de la boucle pour exécuter l'occurrence suivante.
loop ; l'instruction continue fait revenir le programme à cette ligne
input v
continueon v = 0 ; si v vaut 0, le programme repart en début de boucle
;
if v > 0 then
echonl v ; si v est supérieur à 0, le programme affiche le contenu de "v" et sort de la boucle
break
endif
endloop
==== declare ====
Cette instruction définit les variables qui pourront être utilisées dans le bloc courant :
* dans le bloc principal, les variables ainsi définies sont //globales// à tout le traitement
* dans les autres blocs (subroutine), les variables sont locales à la subroutine
Plusieurs variables peuvent être déclarées sur la même ligne, séparées par '',''\\
Les variables appartenant à une hash table ne se déclarent pas, sous peine de déclencher une exception.\\
Une variable utilisée avant d'être déclarée provoquera une exception (variable inconnue).\\
Rappel : les noms des variables ont une longueur de [[w:syntax|24 caractères maximum]].
declare x, y
declare somme
let somme = x + y
declare hash
let hash = {}
; declare hash.couleur => est interdit !
==== delet ====
Cette instruction permet de dé-affecter une variable : son contenu est supprimé et la variable perd son type (état identique suite à l'instruction [[w:instr:declare|declare]]).\\
Si la variable est composée, imbrication de hashtable, la dernière est supprimée de la hashtable.\\
declare a,b,c,d
let a = 0 ; nombre
let b = "Bonjour" ; dynamic
let c = {} ; hashtable
let c.ligne = "123;A;8"
let c.ligne{1}[2,1] = b:" monsieur"
delet b ; la variable "b" est toujours déclarée, mais sans type ni contenu
delet c.ligne ; la variable "ligne" est supprimée de la hastable "c"
==== do ====
Cette instruction permet d'appeler un sous-programme interne au source en cours. La subroutine doit être déclarée au préalable, sous peine de générer une exception.\\
La syntaxe est => ''do (params...)'' : appel d'un sous-programme ''sub'' déjà déclaré dans le programme en cours (ou d'une méthode de classe/objet).\\
Le passage des paramètres est facultatif et variable ; le contrôle est fait uniquement à l'exécution lors de l'utilisation des variables. Les paramètres en trop sont ignorés. Ceux manquant forceront la variable paramètre associée à l'état //non-déclarée//.\\ Les paramètres sont obligatoirement des variables simples ([[w:syntax|identifiant]] simple), passées par //référence// (PAS d'expression). Les variables chaînées, de type ''var.var2!var3'' etc., sont interdites et provoqueront une exception si utilisées comme paramètre.
do complexe.calculer(operation, nombre1, nombre2)
==== echo ====
Cette instruction permet d'afficher sur la sortie standard (la console) le contenu d'une [[w:instr:varsys|variable]] ou une chaine (PAS d'expression ici).\\
Dans les programmes de type [[w:instr:background|background]], l'instruction n'a aucune action (il n'y a pas de console) et ne provoque pas d'exception ; équivalent dans ce cas à [[w:instr:nop|nop]].
echo "bonjour !"
==== echonl ====
Cette instruction est similaire à [[w:instr:echo|echo]], si ce n'est qu'un retour à la ligne est automatiquement ajouté à la fin de la chaîne affichée dans la console.\\
Dans les programmes de type [[w:instr:background|background]], l'instruction n'a aucune action (il n'y a pas de console) et ne provoque pas d'exception ; équivalent dans ce cas à [[w:instr:nop|nop]].
echonl "bonjour !" ; retour à la ligne automatiquement ajouté en fin de chaine
==== else elseif ====
A l'intérieur d'un bloc d'instructions commencé par [[w:instr:ifthen|if then]], l'instruction //else// marque le début du code qui sera exécuté quand la ou les conditions précédentes ont toutes été évaluées à //faux//.\\
L'instruction //elseif// est similaire à //else// si ce n'est qu'une nouvelle condition est complètement évaluée et testée, comme avec [[w:instr:ifthen|if]], condition qui se trouve à la suite de //elseif// jusqu'au mot clé //then//. Si le résultat est //vrai//, le programme continue à la ligne suivante ; dès que l'instruction else/elseif est rencontrée, le programme saute à la première instruction [[w:instr:endif|endif]]. Si le résultat est //faux//, le programme continue après la première instruction trouvée else/elseif/endif.
if dividende = 0 then
echonl "Division impossible" ; affichage si la variable "dividende" vaut 0 puis saute à "endif"
elseif dividende = 1 then
echonl "Pas de calcul nécessaire" ; affichage si la variable "dividende" ne vaut pas 0, mais s'il est égale à 1 puis saute à "endif"
else
echonl "Il faut faire un calcul pour trouver le résultat" ; affichage si la variable "dividende" ne vaut ni 0 ni 1
endif
; le programme reprend ici dans les 3 cas d'affichage
==== end ====
Cette instruction marque la fin du programme principal, que ce soit un programme //autonome// begin/background ou une library (bibliothèque).\\
Dans le cas d'un programme autonome, toutes les variables sont libérées de la mémoire avant de rendre la main. Dans le cas d'une bibliothèque, seules les variables locales sont libérées, comme pour un sous-programme. Attention, les éléments globaux comme les classes/objets sont conservés jusqu'à la fin du programme principal.\\
Les sous-programmes passés en paramètre de retour provoqueront une exception si ils sont appelées dans le programme appelant, car la bibliothèque est retirée de la mémoire, l'adresse du sous-programme devenant ainsi incorrecte. De la même manière, les classes et objets définis dans la bibliothèques et utilisés dans le programme appelant provoqueront une exception.
end
==== endfor ====
Cette instruction marque la fin du bloc [[w:instr:foreach|for each]] correspondant : récupération de la valeur suivante et //saut// à la ligne qui suit l'instruction //foreach//. S'il n'y a plus de valeur à récupérer, le programme continue après //endfor//.
foreach compteur in debut,fin
echonl compteur
endfor ; saute à la suite de foreach pour chaque valeur comptee entre debut et fin inclus
==== endif ====
Marque la fin d'un bloc d'instructions commencé par [[w:instr:ifthen|if then]], tous les chemins de code arrivent à cette instruction : quand une condition est //vrai//, le bloc de programme à suivre est exécuté jusqu'à la première instruction [[w:instr:elseelseif|else elseif]]. Puis le programme saute à endif. S'il n'en trouve pas, il s'arrête au prochain endif trouvé.\\
if dividende = 0 then
echonl "Division impossible" ; affichage si la variable "dividende" vaut 0 puis saute à "endif"
elseif dividende = 1 then
echonl "Pas de calcul nécessaire" ; affichage si la variable "dividende" ne vaut pas 0, mais s'il est égale à 1 puis saute à "endif"
else
echonl "Il faut faire un calcul pour trouver le résultat" ; affichage si la variable "dividende" ne vaut ni 0 ni 1
endif
; le programme reprend ici dans les 3 cas d'affichage
==== endloop ====
Cette instruction permet de revenir au début de la boucle définie auparavant par l'instruction [[w:instr:loop|loop]].\\
S'il n'y a pas de boucle en cours, une erreur de compilation est générée.
loop
echonl "Ceci est une boucle infinie"
endloop
==== endsub ====
Cette instruction marque la fin du sous-programme en cours.\\
Les variables locales sont libérées. Attention, les éléments globaux comme les classes/objets sont conservés jusqu'à la fin du programme principal. Les sous-programmes déclarés localement sont utilisable globalement, car leur adresse est stockée dans la hashtable globale du process (comme les classes et objets).
endsub
==== except ====
Cette instruction marque le début du bloc exception et la fin du bloc de traitement du programme ou d'un sous-programme.\\
Si l'exécuteur de traitement arrive à l'instruction //except// sans exception, le programme //saute// à l'instruction [[w:instr:endsub|endsub]] ou [[w:instr:end|end]] retourne à l'appelant, et se termine dans le cas du programme principal.\\
Si une exception survient dans le bloc de traitement, due à une autre instruction ou [[w:instr:throw|throw]], le programme saute automatiquement à la première ligne qui suit //except//. Une exception qui survient dans le bloc exception fait réagir le programme de la même manière que l'instruction [[w:instr:throw|throw]] : le code de la nouvelle exception est pris en compte et le programme saute à l'instruction [[w:instr:endsub|endsub]] ou [[w:instr:end|end]]. L'exception //remonte// dans le programme appelant et le fait arriver dans son bloc exception, etc. Enfin, uniquement dans le bloc exception, l'instruction [[w:instr:catch|catch]] permet d'annuler l'exception, et de revenir à l'appelant sans erreur.\\
Dans les bloc exceptions, la variable système [[w:instr:varsys|@except]] donne le numéro de l'exception en cours (de 1 à 16 777 215). Mais attention, lors du retour au shell appelant, le code attendu par le shell est sur 8 bits : le code retour envoyé risque ne pas être celui voulu.
begin test
except
; gestion des exceptions
end
==== foreach in like ====
Cette instruction permet de //boucler// sur le contenu d'une variable //Dynamic//,//Hashtable// ou de compter.\\
La syntaxe est => ''foreach in ou ,, optionnel like ''\\
Le mot clé //foreach// est suivi d'une variable, qui reçoit à chaque boucle/comptage la valeur suivante. Ensuite vient le mot clé //in// puis la source des éléments que l'on veut traiter un par un. Enfin l'instruction se termine par le mot clé facultatif //like// permettant d'ajouter un filtre lors de la récupération de la valeur suivante. Le programme continue jusqu'à la prochaine instruction [[w:instr:endfor|endfor]] : l'extraction de la valeur suivante est faite à ce moment là et le programme //saute// à la suite de la ligne contenant l'instruction //foreach// correspondante. S'il n'y a plus de valeurs à récupérer, le programme continue à la suite de //endfor//.\\
L'instruction n'accepte que des variables, qui doivent toutes avoir été déclarées au préalable.
En mode //comptage//, '''' est facultatif, et vaut implicitement 1 alors. De plus, le mot clé //like// n'est pas autorisé.\\
En mode boucle sur variable, une exception est générée si les variables utilisées ne sont pas aux types attendus. Lorsque la source est une //Hashtable//, l'élément retourné à chaque boucle est la clé de la hashtable (format //Dynamic//).\\
**__A préciser__** avec les règles détaillées (conversion variable, arrivée à '''' testée selon le signe de '''', syntaxe du filtre '''', ...)
declare compteur, debut, fin, increment
let debut = 1
let fin = 10
let increment = 1
foreach compteur in debut,fin,increment
echonl compteur ; affiche tous les nombres de 1 a 10
endfor
; avec une variable "Dynamic", la boucle se fait sur les champs et sous-champs trouvés, et renvoi une variable de type "Dynamic"
declare fruit, liste, filtre
let liste = "" ; préciser si cette initialisation est nécessaire
let liste{1} = "pomme"
let liste{2} = "poire"
let liste{3} = "peche"
let liste{4} = "banane"
foreach fruit in liste
echonl fruit ; affiche les 4 fruits dans l'ordre des champs
endfor
; avec filtre
let filtre = "po*"
foreach fruit in liste like filtre
echonl fruit ; affiche les fruits commençant par "po" : pomme et poire (2 affichages)
endfor
; avec une variable "Hashtable"", la boucle se fait sur les clés de la table
declare legume, panier, initiale
let panier = {}
let panier.carotte = 2.8
let panier.chou = 4
let panier.poireau = 1.9
let panier.radis = 3.1
foreach legume in panier
echonl panier!legume ; affiche les valeurs associées aux 4 éléments trouvées : 2.8 / 4 / 1.9 / 3.1
endfor
; avec filtre
let initiale = "c*"
foreach legume in panier like initiale
echonl legume ; affiche les clés de la hashtable dont le nom commence par "c" : carotte et chou (2 affichages)
endfor
==== free ====
Cette instruction permet de supprimer un objet instancié par //new//.
Les objets étant globaux, la référence à l'objet devient obsolète : tout accès postérieur provoquera une exception.\\
class Carre = {Quadrilatere}
declare a, c
let c = new Carre ; c = est un objet, instance de la classe "Carre"
let c.longueur = 5
let c.largeur = 5
let a = c.Aire(a)
free c ; supprimer l'objet "c"
==== if then ====
Cette instruction de tester une condition et d'exécuter du code différent en fonction du résultat du test.\\
Entre les mots clés //if// et //then// se trouve une [[w:instr:operator|expression]], qui est complètement évaluée. Si le résultat est //vrai//, le programme continue à la ligne suivante ; dès que l'instruction [[w:instr:elseelseif|else elseif]] est rencontrée, le programme saute à la première instruction [[w:instr:endif|endif]]. Si le résultat est //faux//, le programme continue après la première instruction trouvée else/elseif/endif.
if dividende = 0 then
echonl "Division impossible" ; affichage si la variable "dividende" vaut 0
endif
==== include ====
Cette instruction insère un fichier source W à la position courante. Son contenu est exécuté comme s'il faisait partie du source global.\\
Le fichier est récupéré dans l'arborescence dont le répertoire de base est défini dans la variable d'environnement [[w:env|WSRC]].\\
Attention : le nom du fichier à inclure ne doit __pas__ contenir de chemin, sinon le fichier ne sera pas trouvé et une exception sera générée.
include 'fichier.w'
==== input ====
Cette instruction permet de faire une saisie utilisateur au clavier, en lisant l'entrée standard. Elle est suivi d'une variable, qui sera mise au type Dynamic et contiendra les caractères saisis, hors retour-chariot final, validant la saisie.\\
Dans les programmes de type [[w:instr:background|background]], l'instruction n'a aucune action (la saisie n'est pas faite) et ne provoque pas d'exception ; équivalent dans ce cas à [[w:instr:nop|nop]].
input reponse
==== invoke ====
Cette instruction permet d'appeler un sous-programme de type //module//. Ce sont des sous-programmes écrits en C, compilé et appelés ici sous forme de binaire de l'OS (.o sous Linux, .dll sous Windows).\\
La syntaxe est => ''invoke &(param1, param2, param3)'' : appel d'un module, plugins du langage, écrit en C. Le fichier .o (ou .dll) doit se trouver dans le répertoire des exécutables WBIN.
Le passage des paramètres est facultatif et variable, avec un maximum de 3 paramètres ; le contrôle est fait uniquement à l'exécution lors de l'utilisation des variables. Les paramètres en trop sont ignorés. Ceux manquant forceront la variable paramètre associée à l'état //non-déclarée//.\\
Comme avec [[w:instr:do|do]] et [[w:instr:call|call]], Les paramètres sont obligatoirement des variables simples ([[w:syntax|identifiant]]), passées par //référence// (PAS d'expression). Les variables chaînées, de type var.var2!var3 etc., sont interdites et provoqueront une exception si utilisées comme paramètre.
invoke math&racinecarre(nombre, resultat)
==== let ====
Cette instruction permet de faire une affectation de variable. Elle est suivie d'une variable, qui doit être déclarée auparavant sous peine d'exception.\\
La variable peut être composée (imbrication de hashtable) et suffixée pour extraction de champs/sous-chaine : cf. [[w:syntax|syntaxe des variables]].\\
Ensuite, le signe ''='' doit apparaitre, suivi d'une [[w:instr:operator|expression]].\\
declare a,b,c,d
let a = 0 ; nombre
let b = "Bonjour" ; dynamic
let c = {} ; hashtable
let c.ligne = "123;A;8"
let c.ligne{1}[2,1] = b:" monsieur"
==== library ====
C'est la première instruction, hors commentaires, d'un programme W.\\
La bibliothèque peut avoir des paramètres, facultatifs, en nombre libre.
library(entree, resultat)
library()
library ; si pas de parametre, () peuvent être omis
L'instruction identifie le programme comme un traitement appelable depuis un autre programme W. Un programme de ce type ne peut pas s'exécuter de lui même ; il doit forcément être appelé depuis un autre traitement, initialisé par [[w:instr:begin|begin]]/[[w:instr:background|background]] ou une autre [[w:instr:library|library]]. Par contre, la récursion n'est pas autorisée et provoquera une exception.\\
==== loop ====
Marque le début dans le code d'une boucle inconditionnelle.\\
Cette instruction ne fait rien, si ce n'est de marquer la ligne comme celle de reprise lors du bouclage par l'instruction [[w:instr:endloop|endloop]].\\
A l'intérieur du bloc de code de la boucle, l'instruction [[w:instr:break|break]] permet d'en sortir, et l'instruction [[w:instr::continue|continue]] permet de forcer la reprise au début de la boucle.\\
loop
echonl "ceci est une boucle sans fin"
endloop
; code permettant de faire saisir un nombre et de sortir si un négatif est saisi.
declare nombre
loop
input nombre
breakon nombre < 0
endloop
==== new ====
Cette instruction sert à instancier un objet à partir d'une classe, mise à la suite du mot-clé //new//. La variable reçoit une référence à l'objet, les objets étant tous globaux au programme, comme les [[w:instr:class|classes]].\\
L'objet est affectée à une variable, de manière classique, mais sans suffixe d'extraction.\\
L'objet hérite de toutes les méthodes des classes mères (au moment de l'appel). Par contre, l'objet reçoit une copie de tous les membres de toutes les classes mères.\\
Techniquement, un objet est, comme une classe, identique à une hashtable, avec des éléments interne nécessaire à sa bonne gestion.\\
Les membres et méthodes d'un objet s'accèdent de la même manière qu'avec une hashtable.\\
class Figure = {Base}
let Figure.nombreCote = 0
class Quadrilatère = {Figure} ; la classe "Quadrilatere" herite des membres de la classe mère
class Rectangle = {Quadrilatere}
let Rectangle.longueur = 10
let Rectangle.largeur = 8
sub Rectangle.Aire(aire)
aire = this.longueur * this.largeur
except
endsub
class Carre = {Quadrilatere}
let Carre.nombreCote = 4 ; tous les membres et méthodes sont publics et modifiables
declare a, c
let c = new Carre ; c = est un objet, instance de la classe "Carre"
let c.longueur = 5
let c.largeur = 5
let a = c.Aire(a)
; la méthode "Aire" n'est pas trouvée dans la classe Carre (classe de l'objet "c"), W va chercher une méthode du même nom dans les classes mères,
; et va trouver celle de "Rectangle", et affecter 80 à "a"
let c{1} = new Carre ; interdit => provoque une erreur de compilation
==== nop ====
Cette instruction ne fait rien. Elle permet de notifier qu'une portion de code ne nécessite aucun traitement.\\
Elle permet également au debugger de mettre un point d'arrêt sur la ligne de l'instruction.
nop
==== Opérateurs ====
Les opérateurs du langage sont divisés selon 5 priorités, de la plus faible à la plus forte :
* or and
* ''= # <''''= >= < >'' (''#'' pour //différent//)
* '':'' (concaténation)
* ''+ -''
* ''* / \ %'' (multiplication, division, ''\'' division entière, ''%'' modulo)
Les parenthèses ''( )'' permettent d'isoler une expression de l'opération en cours.\\
Les opérations sont exécutées de la priorité la plus forte à la plus faible (//or// //and// en dernier, donc)
declare a,b,c,d
let a = b + c * d ; le calcul commence par "c * d" puis "d" est ajouté au résultat
let a = (b + c) * d ; le calcul commence par "b + c" puis le résultat est multiplié par "d"
let a = b = 1 or b = 0 and c + d % 2 = 0
; autre syntaxe de la même expression pour montrer les priorités
let a = ( (b = 1) or ((b = 0) and ((c + (d % 2)) = 0) ) )
; a reçoit la valeur numérique associée à @true ou @false, selon le résultat de l'expression
; lisible
let a = (b = 1) or (b = 99 and (c + d % 2 = 0))
==== part ====
Cette instruction sert de //tag// pour le code source en cours. Elle est suivi d'un nombre compris entre 0 et 255. A la fin de l'instruction, le source porte le tag indiqué par le nombre, et ne changera pas jusqu'au prochain appel d'une instruction //part//. L'appel d'un module ou d'une bilbiothèque remet à 0 le tag du source, mais sa valeur est restaurée au retour de l'appel. La variable système [[w:instr:varsys|@part]] contient le tag en cours.\\
Elle permet également au debugger de mettre un point d'arrêt sur la ligne de l'instruction.
part 5
Le //tag// est surtout utile lors d'une exception : dans le bloc [[w:instr:except|except]], @part permet de connaître la portion de code où a eue lieu l'exception, sous réserve que des instructions //part// aient été mises dans le bloc de traitement. Par défaut, sa valeur est 0.\\
==== precision ====
Cette instruction définit le nombre de décimales pour [[w:syntax|l'arrondi]] en fin d'expression, lors de l'affectation.\\
Les valeurs possible sont 0 1 2 3 4 5, 5 étant la valeur par défaut. Toute autre valeur provoquera une exception.
precision ; nombre de 0 à 5
==== return ====
Cette instruction //saute// à la fin du bloc en cours (instruction [[w:instr:endsub|endsub]]), sans changer les conditions d'exception.\\
Utilisée dans le bloc principal, elle //saute// à l'instruction [[w:instr:end|end]] finale, provoquant le retour à l'appelant. Le code retour au shell appelant est positionné avec le numéro d'exception, sur 8 bits, et 0 si pas d'exception.
return
==== returnon ====
Cette instruction, similaire à [[w:instr:return|return]], //saute// à la fin du bloc en cours (instruction [[w:instr:endsub|endsub]]) si l'expression qui suit le mot clé //returnon// est évaluée à //vrai//.\\
Sinon, le programme continue à la ligne suivante.\\
Utilisée dans le bloc principal, elle //saute// à l'instruction [[w:instr:end|end]] finale, provoquant le retour à l'appelant. Le code retour au shell appelant est positionné avec le numéro d'exception, sur 8 bits, et 0 si pas d'exception.
returnon compteur = 10
==== setsep ====
Cette instruction permet de définir les séparateurs de champs et sous-champs, servant à gérer les variables de type //Dynamic//.\\
Il faut indiquer d'abord le caractère séparateur de champ, puis celui de sous-champ, séparés par '',''\\
Si des chaînes sont passées, le premier caractère est pris en compte. Si un nombre est passé, il sera considéré comme le code ASCII du caractère (plage 0-255 sinon exception).\\
**__TODO__** pas de caractère UTF8 multi-byte permis ici
setsep 10, "|" ; pour gérer des variables dont les champs sont des lignes et les sous-champs des valeurs séparées par | sur chaque ligne
setsep @fm, @vm ; revient aux valeurs par défaut
==== sub ====
Cette instruction déclare une méthode (ou subroutine). l'instruction //sub// est suivie d'une variable, qui contiendra l'adresse de la subroutine et qui permettra son appel. Elle peut avoir des paramètres, facultatifs, en nombre libre.\\
Déclarée sans contexte, la portée des subroutine est globale. Mais déclarée dans une classe ou un objet, la subroutine devient une méthode de classe ou d'objet. Elle peut également être déclarée dans une hashtable. Dans ces derniers cas, la portée de la méthode est globale pour les classes/objets et liées à celle de la hashtable quand déclarée dans la hashtable.\\
Enfin, une subroutine déclarée dans une [[w:instr:library|library]] ne peut pas être affectée à une autre variable : elle reste forcément locale à la library (exception par rapport à la règle de portée globale).\\
Le bloc de traitement a une structure identique au bloc principal du programme : liste d'instructions, [[w:instr:except|except]], liste d'instructions et [[w:instr:endsub|endsub]]
sub Carre(nombre)
let nombre = nombre * nombre
except
endsub
; sans parametre
sub Traitement()
except
endsub
; autre syntaxe
sub TraitementSuivant
except
endsub
; dans une hashtable
declare math
let math = {}
sub math.carre(x, ret)
let ret = x * x
except
endsub
==== this parent ====
Ces 2 variables sont présentes dans tous les objets et classes. Ils permettent :
* ''this'' : de forcer l'accès aux membres de chaque objet/classe, et de ne pas faire la recherche dans les classes mères pour les méthodes non présentes dans l'objet/classe courant
* ''parent'' : de forcer la recherche des méthodes non pas depuis l'objet/classe en cours mais depuis la classe mère, et de lire les membres depuis la classe mère
Ces variables ne sont utilisables que depuis un objet ou une classe, sinon une exception est générée à l'exécution.
class Figure = {Base}
let Figure.nombreCote = 0
class Quadrilatère = {Figure} ; la classe "Quadrilatere" herite des membres de la classe mère
class Rectangle = {Quadrilatere}
let Rectangle.longueur = 10
let Rectangle.largeur = 8
sub Rectangle.Aire(aire)
aire = this.longueur * this.largeur ; pour utiliser la variable de la classe/objet courant
except
endsub
class Carre = {Quadrilatere}
let Carre.nombreCote = 4 ; tous les membres et méthodes sont publics et modifiables
declare a, c
let c = new Carre ; c = est un objet, instance de la classe "Carre"
let c.longueur = 5
let c.largeur = 5
let a = c.Aire(a)
; la méthode "Aire" n'est pas trouvée dans la classe Carre (classe de l'objet "c"), W va chercher une méthode du même nom dans les classes mères,
; et va trouver celle de "Rectangle", et affecter 80 à "a"
let a = c.parent.Aire(a) ; fonctionnement identique a ci-dessous, car pas de méthode "Aire" dans la classe Carre
let a = c.this.Aire(a) ; la variable "this" permet de forcer l'appel de la méthode de la classe Carre : comme elle n'est pas présente, il y a exception
==== throw ====
Cette instruction provoque une exception et est suivi d'un numéro d'exception de 1 à 16 777 215 (2^24-1). Les autres valeurs ne sont pas autorisées et provoqueront une (autre) exception. Elle entraîne :
* dans le bloc de traitement, un saut direct au début du bloc exception du programme/sous-programme
* dans le bloc exception, le remplacement de l'exception originelle par celle indiquée à la suite, et le saut à la fin du programme/sous-programme pour un retour à l'appelant
Dans les bloc exception, la variable système [[w:instr:varsys|@except]] donne le numéro de l'exception en cours, modifié par l'instruction //throw//.
throw 1000
===== Variables systèmes =====
Le langage W dispose de plusieurs variables dites systèmes, c'est à dire mises à jour automatiquement par l'exécuteur du langage. Ces variables sont en lecture seule et ne peuvent donc pas être mises à jour par programme. Leur présence dans l'instruction [[w:instr:let|let]] provoquera une erreur à compilation ou une exception si exécution en mode interprété.\\
Les noms des variables @xxx est sensible à la casse ; elles sont toutes en minuscule.
^ Nom ^ Libellé ^ Numéro pour instruction [[w:instrpcode|PSHA]] ^
| @varnull| Code du type de variable Null, retour de [[w:instr:function#typeof|typeof()]] => 1 | 1 |
| @varnumber| Code du type de variable Number, retour de [[w:instr:function#typeof|typeof()]] => 2 | 2 |
| @vardynamic | Code du type de variable Dynamic, retour de [[w:instr:function#typeof|typeof()]] => 5 | 5 |
| @varhashtable| Code du type de variable Hashtable, retour de [[w:instr:function#typeof|typeof()]] => 6 | 6 |
| @varsubroutine| Code du type de variable Subroutine (sub et méthode de classes/objets), retour de [[w:instr:function#typeof|typeof()]] => 3 | 3 |
| @varparam| Code du type de variable //paramètre//, retour de [[w:instr:function#typeof|typeof()]] => 4 | __**A preciser**__ 4 |
| @varobjet| Code du type de variable classe/objet, retour de [[w:instr:function#typeof|typeof()]] => 7 | 7 |
| @varbuffer| Code du type de variable buffer, réservé à un usage interne de W (piles...) => 8 | 8 |
| @part| Valeur du tag de portion de code source en cours, 0 par défaut | 21 |
| @except| Code exception en cour, 0 = pas d'exception | 20 |
| @exceptline | N° de la ligne du source W où a eu lieue la dernière exception | 19 |
| @pi | Nombre Pi => 3.14159| 30 |
| @true | 1 (tout nombre différent de 0 sera évalué à @true) | 11 |
| @false | 0 | 10 |
| @forcount | Donne la valeur du compteur de boucle [[w:instr:foreach|foreach]], de 1 à //n// | **__TODO__** A préciser 12 |
| @kill | @true quand un signal SIGTERM ou SIGINT a été reçu, @false sinon | 13 |
| @fork | Vaut 0 dans le process fils, sinon dans le process père donne le pid du process fils créé | 14 |
| @line | N° de la ligne du source W en cours | 22 |
| @file | Nom du fichier source en cours (sans le chemin) | **__TODO__** A préciser 28 |
| @vers | Version du programme p-code en cours | 24 |
| @verw | Version de l'exécuteur de p-code en cours | 25 |
| @arg | //Dynamic// contenant les paramètres d'appel du programme principal, en multi-champs | 29 |
| @demon | 1 si programme principal de type BACK, 0 si PROG | 26 |
| @endian | Endianess de l'architecture en cours d'exécution : 0 big-endian, 1 little-endian | 27 |
| @os | Code de l'OS d'exécution du binaire : 10 Unix, 20 autre | 23 |
| @number | Valeur de retour possible pour la fonction [[w:instr:function#type|type()]] => 2 | 40 |
| @dynamic | Valeur de retour possible pour la fonction [[w:instr:function#type|type()]] => 5 | 41 |
| @empty | Valeur de retour possible pour la fonction [[w:instr:function#type|type()]] => 0 | 42 |
| @trim | Paramètre pour la fonction [[w:instr:function#format|format()]] => 1 | 50 |
| @left | Paramètre pour la fonction [[w:instr:function#format|format()]] => 2 | 51 |
| @right | Paramètre pour la fonction [[w:instr:function#format|format()]] => 3 | 52 |
| @center | Paramètre pour la fonction [[w:instr:function#format|format()]] => 4 | 53|
| @surround | Paramètre pour la fonction [[w:instr:function#format|format()]] => 5 | 54 |
| @fm | Caractère séparateur de champ, par défaut => ''"0xFE"'' | 31 |
| @vm | Caractère séparateur de sous-champ, par défaut => ''"0xFD"'' | 32 |
| @svm | Caractère pouvant servir de séparateur complémentaire => ''"0xFC"'' | 33 |
| @tm | Caractère pouvant servir de séparateur complémentaire => ''"0xFB"'' | 34 |
| @currfm | Caractère séparateur de champ en cours (modifiable avec l'instruction [[w:instr:setsep|setsep]]) | 35 |
| @currvm | Caractère séparateur de sous-champ en cours (modifiable avec l'instruction [[w:instr:setsep|setsep]]) | 36 |
===== Variables, nombres et chaînes : syntaxe =====
Les identifiants/noms de variables sont composés de 1 à 24 caractères, dans la gamme A-Za-z0-9 ; le premier caractère étant uniquement A-Za-z.\\
Les nombres sont composés d'un éventuel signe négatif ''-'', de 1 à 13 chiffres pour la partie décimale et de 0 à 5 décimales, avec le ''.'' comme signe décimal si au moins une décimale est présente.\\
**__A préciser__** comment utiliser les paramètres régionaux\\
Lors des calculs, le résultat final, affecté à la variable, est arrondi à la précision courante, de 0 à 5 décimales, 5 étant la valeur par défaut. L'instruction [[w:instr:precision|precision]] permet de changer la précision.
Les chaines de caractères sont entourées soit par des quotes ''''' soit des double-quotes ''"''. A l'intérieur, un caractère peut être mis avec son code hexadécimal selon la forme ''#FF'' FF étant la valeur hexa du code, en majuscule (gamme 0-9A-F).\\
**__A préciser__** avec la prise en charge d'UTF8\\
declare variable, nombre
let variable = "abc"
let variable = "#61b#63" ; valeur identique qu'à l'affectation précédente
let variable = 'ABC'
let variable = "L'exemple avec une simple quote"
let nombre = -12
let nombre = 3.14
let nombre = 0
let nombre = 0.001
let nombre = 1/3 ; nombre vaut 0,33333
precision 2
let nombre = 1/3 ; maintenant nombre vaut 0,33
precision 0
let nombre = 5/3 ; nombre vaut 2 (1.66666 arrondi avec aucune décimale)
L'utilisation de variables appartenant à une autre variable de type //HashTable// nécessite de mettre le séparateur ''.''\\
Une hashtable pouvant contenir n'importe quelle autre variable, hashtable comprise, l'imbrication est possible, avec ou sans indirection.\\
Il est possible de faire un accès indirect en remplaçant ''.'' par ''!''
declare hash, nom, carre, chainage, fonction
let hash = {} ; déclaration d'une hashtable
let hash.x = 10 ; "x" est une variable appartenant à la hashtable
let hash.y = 20
let nom = "x" ; la chaine "x"
let carre = hash!nom * hash!nom ; avec l'opérateur d'indirection "!", nom est remplacé par sa valeur, "x" => carre vaut donc ici "hash.x * hash.x"
let fonction = "responsable"
let chainage = hash!fonction.nom ; dans la hashtable "hash", prend la hashtable "responsable" et renvoi le contenu de sa variable "nom"
Les variables de type //Dynamic// peuvent être utilisées avec 2 suffixes optionnels, permettant de récupérer ou mettre à jour une sous-partie de la variable.\\
* ''{ }'' syntaxe permettant de récupérer un champs/sous-champ (les champs/sous-champs sont numérotés en base 1)
* ''{}'' extrait le champ
* ''{, }'' extrait du champ le sous-champ
* ''[ ]'' syntaxe permettant de récupérer une partie de la chaîne
* ''[, ]'' extrait la chaîne à partir de la position (en base 1), de longueur (quand vaut 0, cela signifie jusqu'à la fin de la chaine)
* ''[]'' extrait les derniers caractères de la variable
Les 2 suffixes sont combinables, obligatoirement dans l'ordre ''{}[]''
declare d, e
let d = "champ1"
let d{2} = "champ2"
;
let e = d[1,3] ; renvoi "cha"
let e = d{2,1}[2] ; renvoi "p2"
;
let d{1,2} = d{2} ; affecte au sous-champ 2 du champ 1, la valeur du champ 2
;
let d{1}[4,2] = d{2}[1,3] ; le champ n° 1 passe de "champ1" à "chacha1"
===== Fonctions =====
Dans les expressions, utilisées lors des [[w:instr:let|affectations]] de variable et des tests ([[w:instr:ifthen|if then]]), un certain nombre de fonctions sont disponibles.
==== abs ====
Renvoie la valeur absolue de son paramètre. Le paramètre est automatiquement converti en numérique, en générant une exception si le contenu n'est pas numérique.
declare v
let v = abs(-6) ; renvoie 6
let v = abs("667":".8") ; renvoie le nombre 667.8
let v = abs("---4") ; exception
==== change ====
Remplace dans la variable source de type //Dynamic// une sous chaine par une autre.
declare v,w
let v = "20240101"
let w = change(v, "01", "9")
echonl w ; affichage de "202499"
==== count ====
Renvoie le nombre d'occurrences, trouvées dans le premier paramètre, du caractère en deuxième paramètre.
declare var, nb
let var = "20240101"
let nb = count(var, "0") ; renvoie 3 car il y 3 fois le caractère "0" dans "var"
==== dcount ====
Renvoie le nombre de champs trouvés dans le premier paramètre. Le deuxième paramètre est optionnel et donne le n° du champ dans lequel la fonction compte alors les sous-champs.\\
declare var, nb
let var = ""
let var{1} = "premier"
let var{2} = "deuxieme"
let var{3} = "troisieme"
let nb = dcount(var) ; renvoie 3 car 3 champs sont présents dans "var"
let nb = dcount(var, 2) ; renvoie 1 car il n'y a qu'un seul sous-champ dans le champ n° 2 ("deuxieme")
==== field ====
Extrait de la variable source un champ, en indiquant le caractère séparateur et le numéro du champ. Le quatrième paramètre est optionnel et permet de définir le nombre de champs consécutifs à extraire. Dans ce cas, la variable destinatrice, de type //Dynamic// sera au format multi-champs. Si absent, par défaut 1 seul champ est extrait. Fonctionnement identique à celui de la syntaxe var{x}, mais en pouvant choisir le séparateur et le nombre de champs à extraire.\\
declare v,w
let v = "20240101"
let w = field(v, "0", 2)
echonl w ; affichage de "24" car si "0" est le séparateur de "v", le deuxième champ est 24
setsep "0", @vm
let w = v{2}
echonl w ; affichage de "24"
==== format ====
Formate la valeur passée en 1er paramètre, selon le [[w:instr:varsys|format]] donné en 2ème paramètre. D'éventuels 3ème et 4ème paramètres sont à passer selon le format demandé.\\
Si l'expression ne peut pas être convertie au format chaine (//Dynamic//), ou si un des paramètres attendus n'est pas au bon type, une exception est générée.\\
Lorsqu'un caractère est attendu, c'est le premier qui est pris en compte si une chaine trop longue est donnée.\\
Pour //@trim// **__A préciser__**
declare i,j
let i = format(j, @trim) ; supprimer les espaces en début, fin de chaine et n'en conserve qu'un à l'intérieur de la chaine s'il y en a plusieurs consécutifs
let i = format(j, @left, " ", 10) ; formate le contenu de la chaine j à gauche, sur 10 positions, et ajoute le caractère " " à droite si trop court, tronque si trop long
let i = format(j, @right, " ", 10) ; formate le contenu de la chaine j à droite, sur 10 positions, et ajoute le caractère " " à gauche si trop court, tronque si trop long
let i = format(j, @center, " ", 10) ; centre le contenu de la chaine j, sur 10 positions, et ajoute le caractère " " à gauche et à droite si trop court, tronque si trop long
let i = format(j, @surround, '"') ; encadre la chaine j avec le caractère " en début et fin de chaine
==== frac ====
Renvoie la partie fractionnaire de son paramètre. Le paramètre est automatiquement converti en numérique, en générant une exception si le contenu n'est pas numérique.
declare v
let v = frac(6.2) ; renvoie 0.2
let v = frac(-3.8) ; renvoie -0.8
let v = frac(123) ; renvoie 0
==== index ====
Renvoie la position d'une sous chaine dans la source. Le troisième paramètre, optionnel, permet de choisir l'occurrence de la sous chaine à chercher. Si absent, par défaut, la première est recherchée.\\
Le comptage de la position commence à 1. La fonction renvoie 0 quand la sous chaine n'est pas trouvée, pour l'occurrence demandée.
declare v, pos
let v = "20240101"
let pos = index(v, "01")
echonl pos ; affichage de "5" car la chaine "01" se trouve en position 5 (la première trouvée)
let pos = index(v, "01", 2)
echonl pos ; affichage de "7" car la deuxième occurrence de la chaine "01" se trouve en position 7.
let pos = index(v, "01", 3)
echonl pos ; affichage de "0" car il n'y a pas de 3ème occurrence de la sous chaine.
==== insert ====
Insère un champ/sous-champ à une variable //Dynamic//. Il y a deux syntaxes, une pour insérer un champ et une pour un sous-champ d'un champ.\\
L'élément à insérer est de type //Number// ou //Dynamic//, sous peine d'exception.
declare v, w
let v = ""
let v = insert(v, "123", 3) ; insère "123" dans le champ n° 3 de "v"
let w = insert(v, "ABC", 1, 2) ; insère "ABC" dans le champ n° 1, sous-champ n° 2, et met le résultat dans "w" ("v" n'est pas affecté)
==== int ====
Renvoie la partie entière de son paramètre. Le paramètre est automatiquement converti en numérique, en générant une exception si le contenu n'est pas numérique.
declare v
let v = int(6.2) ; renvoie 6
let v = int(-3.8) ; renvoie -3
==== len ====
Renvoie la longueur de l'expression en paramètre. Le paramètre peut être soit numérique, soit une chaine (type //Dynamic//). Tout autre type de variable génère une exception.\\
**__A préciser__** avec l'utilisation d'UTF8
declare v
let v = len(6.2) ; renvoie 3
let v = len("x = -3.8") ; renvoie 8
==== neg ====
Renvoie l'opposé de son paramètre. Le paramètre est automatiquement converti en numérique, en générant une exception si le contenu n'est pas numérique.
declare v
let v = neg(6.2) ; renvoie -6
let v = neg(-3.8) ; renvoie 3.8
let v = neg(0) ; renvoie 0
==== not ====
Renvoie le booléen contraire du paramètre. Le paramètre est automatiquement converti en numérique, en générant une exception si le contenu n'est pas numérique.\\
En W, le booléen [[w:instr:varsys|@false]] vaut 0 et le booléen [[w:instr:varsys|@true]] vaut 1 ou tout nombre différent de 0.
declare v
let v = not(@true) ; renvoie @false
let v = not(0) ; renvoie @true
let v = not(-15) ; renvoie @false
==== remove ====
Supprime un champ/sous-champ d'une variable //Dynamic//. Il y a deux syntaxes, une pour supprimer un champ et une pour un sous-champ d'un champ.\\
declare x, y
setsep ';' , ','
let x = "123;A,B,C;4,5;ZZZ"
let x = remove(x, 4) ; supprime le champ n° 4 de "x" => reste "123;A,B,C;4,5"
let x = remove(x, 2, 1) ; supprime dans le champ n° 2 le sous-champ n° 1 et met le résultat dans "y" (=> "123;B,C;4,5"), "x" n'est pas affecté
==== round ====
Arrondit le 1er paramètre à l'entier le plus proche, sur le nombre de décimales donné en 2ème paramètre. Le 1er paramètre est automatiquement converti en numérique, en générant une exception si le contenu n'est pas numérique.\\
Le 2ème paramètre, nombre de décimales, est optionnel. S'il est omis, c'est la valeur de la [[w:instr:precision|précision]] qui est utilisée.
declare v
let v = round(6.2, 0) ; renvoie 6
let v = round(-3.856, 1) ; renvoie -4
==== search ====
Renvoie la position d'un champ ou sous-champ dans la source. Avec 2 paramètres, la recherche s'effectue sur les champs de la source. Avec 3 paramètres, la recherche s'effectue sur les sous champs présents dans le champ dont le numéro est donnée par ce 3ème paramètre.\\
Le comptage des champs et sous champs commence à 1. La fonction renvoie 0 quand la sous chaine n'est pas trouvée, dans aucun champ ni sous champ.
declare var, pos
let var = ""
let var{1} = "premier"
let var{2} = "deuxieme"
let var{3} = "troisieme"
let pos = search(var, "troisimme")
echonl pos ; renvoie 3 car la chaine "troisième" est le champ numéro 3
let pos = search(var, "ieme")
echonl pos ; renvoie 0 car la chaine "ieme" ne correspond pas exactement à un champ
let pos = search(var, "deuxieme", 2)
echonl pos ; renvoie 1 car "deuxieme" est trouvé dans le premier sous-champ du champ n° 2 de "var"
==== sortsearch ====
Fonction similaire à //search// si ce n'est qu'elle ne renvoie jamais //non trouvé// (0). Dans le cas où l'élément n'est pas trouvé, la fonction renvoie la position, en négatif, dans le champ/sous-champ ou il faudrait insérer l'élément cherché, pour conserver les champs/sous-champs triés, soit en croissant avec le paramètre //@asc//, soit décroissant avec //@desc//.\\
Cette fonction permet de créer des listes triées, au fur et à mesure.
__**TODO**__ A implémenter (v2)
TODO : à implémenter dans W
==== tonum ====
Force le type de l'expression au type @number, génère une exception si forçage impossible
declare v
let v = tonum("12")
==== tostring ====
Force le type de l'expression au type @dynamic, génère une exception si forçage impossible
declare v
let v = tostring(@pi * 10)
==== type ====
Renvoie le type de l'expression en paramètre :
* [[w:instr:varsys|@number]] si numérique
* [[w:instr:varsys|@dynamic]] si chaine de caractère
* [[w:instr:varsys|@empty]] si valeur //vide//
declare v
let v = type(1+2) ; renvoie @number
let v = type("12":"45") ; renvoie @number
let v = type('') ; renvoie @empty
let v = type("ABC") ; renvoie @dynamic
==== typeof ====
Renvoie le type de la variable en paramètre (PAS d'une expression), valeurs [[w:instr:varsys|@varxxx]].\\
Si la variable est une imbrication de hashtable, seule la dernière sera évaluée.
declare w,x,y,z,a
let x = 12
let w = typeof(x) ; @varnumber
let y = "ABC"
let w = typeof(y) ; @vardynamic
let z = {}
let w = typeof(z) ; @varhashtable
let w = typeof(a) ; @varnull