Le langage de programmation Scriptol

Manuel de référence complet pour la version 2 de Scriptol.

Ce manuel concerne le langage Scriptol 2. Pour utiliser un compilateur antérieur à 2014, reportez vous au manuel de Scriptol 1.

Le langage est entièrement implémenté dans le compilateur de Scriptol en JavaScript.
L'inclusion en page Web est possible seulement avec le compilateur de Scriptol en PHP ou JavaScript.

Page d'accueil: https://www.scriptol.fr/

Sommaire

Généralités

Le nouveau langage de programmation Scriptol peut être utilisé avec un interpréteur et des compilateurs.
Une version Windows et Unix existe pour chaque compilateur.
L'objectif du langage est d'être simple, naturel et donc de réduire le risque d'erreurs. Scriptol signifie: "Scriptwriter Oriented Language" ou "langage de scénariste" en français. C'est un langage universel conçu pour produire des pages web dynamiques, des scripts et des applications avec interface graphique. Ce peut être aussi un langage de script pour les applications traitant ou produisant des documents XML. Scriptol peut être imbriqué dans une page HTML et est converti en la même page avec du code PHP, prêt pour le Net et totalement portable. Le langage a été défini selon sept règles décrites sur le site.

Au sujet de ce manuel

Veuillez noter que les symboles [] inclus dans la syntaxe des instructions ne font pas partie de la syntaxe du langage et indiquent un élément optionel, sauf pour les indices et intervalles qui utilisent précisément ces caractères.

Compiler un programme Scriptol en JavaScript

Vous devez installer Node.js pour faire fonctionner le programme en ligne de commande. Cela s'installe automatiquement après téléchargement sous Windows. Sous Linux il faut taper cette commande:

sudo apt-get install nodejs

Ou équivalent, selon la distribution.

Pour compiler le programme en JavaScript, la commande est:

solj [options] nomfichier 

Si le source est déja compilé, le programme JS est interprété, sinon il est compilé avant d'être interprété s'il n'y a pas d'erreur.
Tant que le source a des erreurs une nouvelle commande "solp nomfichier" va le compiler. Si le source est une page HTML, il n'est pas exécuté après compilation.

Options du compilateur:

 aucune: compile un script en PHP/JavaScript ou le lance si déja compilé.
 -w     compile du code inclus dans une page et crée un fichier HTML.
 -j     génère un fichier JavaScript à inclure dans une page HTML.
 -r     force l'exécution. Compile si besoin seulement.
 -c     recompile le fichier et fichiers inclus. Le programme n'est pas lancé.
 -v     affiche plus d'informations lors de la compilation.
 -q     pas de message de compilation.

Ces lettres peuvent être combinées en une seule option. Ainsi -be est équivalent à -b -e.

Dans Powershell la commande est:

invoke-expression "solj [options] filename" 

Changer l'extension et le runtime

Le fichier solj.ini peut indiquer le chemin du fichier scriptol.js et l'extension du fichier HTML généré. Par exemple:

lib="c:/scriptolj/scriptol.js
htmlext=".php" 

Compiler un programme Scriptol en PHP

Sous Windows, la commande est:

solp [options] nomfichier

Mêmes option qu'avec JavaScript.

Dans Powershell la commande est:

invoke-expression "solp [options] filename" 

Mon premier programme

Un source Scriptol est juste un fichier de texte contenant des commandes inside, une par ligne.
Exemples:

   print x * 2
   print x + (y / 2)

Avec un éditeur de texte, comme Advanced Editor, taper cette ligne:

   print "Bonjour le monde"

Sauver dans le fichier bonjour.sol.

Si vous travaillez dans une fenêtre de ligne de commande (MS-DOS sous Windows, console sous Unix), tapez simplement:

   solj bonjour         ...ou
   solp bonjour

Vous pouvez aussi construire un exécutable avec la commande:

   solc -bre bonjour

et lancez le programme bonjour.exe généré.

Il est possible de travailler à la fois avec l'éditeur et une fenêtre de console.

Projet Scriptol

Aucun fichier projet n'est nécessaire.
En Java ou PHP, un programme est un source qui inclut d'autres sources. Scriptol conserve cette structure.
Un source scriptol doit avoir une instruction "include" pour chaque fichier dont le contenu est utilisé. Le compilateur calcule les dépendances sur plusieurs niveaux d'inclusions, et parmi les inclusions mutuelles.

Fichier source Scriptol

Un fichier Scriptol doit avoir l'extension "sol", et sera converti en un fichier d'extension php, ou cpp et hpp, ou un exécutable.
Cela la forme du source, on aura un script ou une application.

Script
Le source d'un script est une séquence d'instructions et de définitions de fonctions ou de classes. Il peut inclure d'autre fichiers contenant des déclarations de fonctions, de variables, de classes.

Application
Un fichier d'application contient seulement des déclarations de fonctions, variables et classes. Le source principal est celui que l'on passe en ligne de commande du compilateur, il doit contenir une fonction "main", et une commande d'appel de cette fonction, comme ci-dessous:

  int main()
     ... instructions ...
  return 0

  main()     // lancement du programme.

Caractéristiques du langage

Scriptol peut être défini comme:

Sensibilité à la casse:

Identifieurs:

Nombres:

Cela depend du langage cible.

Conversion (cast):

Orienté-objet:

Orienté-XML:

Orienté programmation réactive

Page HTML

Pour que le code Scriptol puisse être compilé en PHP dans une page HTML, il doit être inclus dans les balises suivantes:

<?sol
   ... code scriptol ...       
?>

La dernière ligne d'un script Scriptol doit être terminée par un point-virgule ou un saut de ligne, avant le symbole ?>

Tester les pages HTML Si vous avez installé un serveur comme Apache ou Xitami ou Windows Server sur votre ordinateur, et l'avez configuré pour reconnaitre l'extension php, votre code sera traité comme sur le web, une fois compilé en PHP. Autrement, il vous rediriger dans un fichier test.HTML la page dynamique, et ensuite exécuter le code PHP:

solp -w mapage
php mapage.php > test.HTML

Pour compiler to code Scriptol en JavaScript dans une page HTML, placez le dans ces marqueurs:

<scriptol>
... code scriptol ...
</scriptol> 

Instruction

Une instruction est terminée par un point virgule ou par la fin de la ligne. Quand une instruction dépasse la largeur d'une ligne, elle est concaténée avec la suivante pourvu qu'elle soit terminée par une virgule, un opérateur ou tout autre symbole qui ne peut terminer une instruction. Aucun symbole n'est requis pour continuer une instruction sur la ligne suivante. Plusieurs instructions sur une même ligne sont séparés par un point virgule. Cela peut être utile si vous placez du code Scriptol dans une page HTML et si l'éditeur concatène les lignes!

Commentaire

Copyright : Le symbole # se place en début de ligne et est suivi d'un commentaire sur la même ligne. Ce type de commentaire reste présent dans le code cible.

Commentaires de code source  suivants ne sont pas conservés dans le langage cible :

// le commentaire va du symbole jusqu'à la fin de la ligne.

/* et */ enclosent un commentaire sur plusieurs lignes.

Symboles

Le langage Scriptol n'utilise jamais le même symbole pour des usages conceptuellement différents.

+     addition
-     sousctraction
*     multiplication
/     division
=     opérateur d'assignement.
<     moins que.
>     supérieur à.
<=    inférieur ou égal.
>=    supérieur ou égal.
;     est un terminateur d'instruction.
,     sépare les éléments d'un initialiseur ou d'un tuple.
:     attache un corps à une en-tête, une valeur à une clé...
.     associe la référence d'une méthode à  un objet.
()    regroupe des sous-expressions, les paramètres d'une fonction.
..    sépare les limites d'un intervalle.
--    intervalle avec la limite supérieure non incluse.
[]    contiennent un index ou un intervalle.
?     sépare condition et action dans une structure d'une seule ligne.
<>    opérateur de différence.
&     et binaire ou intersection de tableaux.
|     ou binaire ou union de tableaux.
<<    décalage à gauche.
>>    décalage à droite.
and   et logique (sur valeurs booléennes).
or    ou logique.
not   négation logique.
mod   modulo  (C utilise %).
^     xor.
#     commentaire de copyright.
//    commentaire de code source sur une ligne.
/* */ commentaire sur plusieurs lignes.
~~    début et fin d'un bloc de code cible à insérer. 
`     début et fin d'un template, chaîne sur plusieurs lignes

Identifieurs et mot-clés

Les identifieurs sont les noms de variables, fonctions et objets. Ils commencent par une lettre, suivie de lettres, chiffres ou caractères de soulignement. On ne peut les différencier par la casse: on ne peut donner le même nom à deux objets différents, l'un en majuscules, l'autre en minuscules. Les mot-clés sont les mots réservés du langage, ils sont en minuscules.

Variables ou primitives

Les primitives sont des objets de base. Quand elles sont les paramètres d'une fonction, la fonction utilise une copie de leur contenu, de leur valeur, et ne modifie par l'original, tandis qu'elle utilise un alias pour les autres objets.

Les primitives de Scriptol sont celles-ci:

var        élément générique de array ou valeur de dict.
number     toute sorte de nombre (jusqu'au double du C++).
int        un nombre arrondi à la partie entière sur 32 bits. 
integer    identique.
natural    entier non signed de 64 bits sauf 0. 
real       un nombre avec des décimales.
boolean    la valeur vrai ou faux.
text       une chaîne de caractères. 
array      une liste dynamique indexée d'objets.
dict       une liste associative formée de couples clé:valeur.
react      une variable reactive.
file       un fichier.

D'autres types speciaux sont utilisés avec les imports de C:

byte       type externe de C.
cstring    utilisé dans les déclarations externes en langage C (traduit par char *).

Les primitives ont des constructeurs comme les autres objets avec différents paramètres, ce qui permet de les utiliser pour des conversions de type.
Syntaxe:

int(int | number | text)

Examples:

int("123")         ...représente le nombre 123
text(10)           ...représente la chaîne "10".

Les primitives sont des variables sauf si elles sont explicitement déclarées comme constantes, avec le mot-clé const.

Littéraux

Les nombres littéraux s'écrivent:

123          entier (int)
123n         naturel (natural)
123.0        réel (real)
0.123        réel (real)
1.2e10       réel (real)
0xf8         hexadécimal
0b011        binaire   
true/false  booléen (boolean)

Guillemets et échappement

Un texte litéral s'écrit: "untexte" ou 'untexte'.

Example:

  print "abc$xyz"
  print 'abc$xyz'

dans les deux cas affiche abc$xyz.

Codes d'échappement

Pour les caractères qui ne peuvent être placés directement dans un texte, on utilise le code spécial: \ Par exemple pour afficher un guillement, on écrira: "abc\"def"

   \"      insère un guillemet double.
   \'      insère un guillemet simple.
   \n      insère a retour à la ligne.
   \t      insère une tabulation.
   \\      insère l'anti-slash lui-même.

Supposons que vous voulez assigner la variable a avec exactement ce texte: ma "jolie" voiture. Vous ne pouvez le mettre entre guillements: a = "ma "jolie" voiture" Le compilateur ne saura comment le traiter! Un code special est utilisé pour dire que les guillemet sont dans le texte plutôt qu'ils ne le délimitent, c'est \ a = "ma \"jolie\" voiture" Vous pouvez aussi alterner les types de guillemets: a = "ma 'jolie' voiture" ou a = 'ma "jolie" voiture'

Multi-lignes

Vous pouvez aussi avoir un texte répartis sur plusieurs lignes enclos dans les symboles `comme en ECMAScript 6.

Example:

x = `
     ligne 1
     ligne 2
    `

Le retour à la ligne peut être direct ou introduit par un code d'échappement.

x = "un\ndeux"            ...valide
x = "un
deux"                          ... non valide

x = `un
deux`                       ... valide

Variable dans une chaîne

Si une chaîne est entre double guillemets, les séquences de caractères commençant pas $ sont des noms de variables.

   text xyz = "def"
   text t = "abc$xyz"

On assign à t la chaîne "abc" suivie du contenu de la variable abc. C'est ce qu'on appelle l'interpolation de chaîne.

Les symboles {} ont une signification particulière pour l'interpréteur PHP et ils doivent être échappé dans une chaîne en double guillement avec le caractère \.

Les textes entre guillemets simples, et précédés de $ ne sont pas interprétés du tout.

  text t = 'av$er\n'

affichera: av$er\n

Déclaration

La déclaration d'une variable a la forme:

type nom [ = valeur ]
int x
text t = "demo"

Pourvu qu'elles aient toutes le même type, il est possible de déclarer et initialiser plusieurs variables à la fois.
La syntaxe est alors:

type nom [= value], name [= value], etc...
int x = 1, y, z = 2

On ne peut mêler plusieurs types dans une seule déclaration. On ne peut faire d'assignements multiples, comme il est décrit plus loin, dans une déclaration.
La forme suivante n'est pas valide:

int x, y = 0, 0      // non valide

Alors que la suivante est reconnue:

text a = "a"
text b = "b"
text c, d
c, d = [a, b]

Constante

Le modifieur const dénote une primitive dont la valeur ne peut changer. Une valeur doit être assignée lors de la déclaration.

Syntaxe et exemples de déclarations de constantes:

const type nom = valeur
const int X = 1
const boolean B = true
const text T = "texte quelconque"

Les constantes sont usuellement en majuscules.

Il y a des constantes prédéfinies qui sont des mot-clés du langage:

true        correspond à une expression vraie.
false       le contraire.
zero        la valeur 0.
nil         objet non trouvé dans une séquence (Not In List)ou symbole de suppression.
null        assigné à un objet quand il n'est pas encore initialisé.

PI est une constante prédéfinie pour représenter le symbole mathématique.

Nil et null

Nil signifie "pas dans la liste" tandis que null signifie "sans valeur", ou "déclaré mais non défini".

Nil n'est pas une vraie valeur mais plutôt une construction du langage. En lecture, il dénote le fait qu'un objet ne soit pas trouvé lors d'une recherche dans une liste. En écriture il a pour effet de supprimer un élément ou un intervalle dans une liste. On ne peut pas initialiser une variable avec nil.

Exemples d'usage:

array a = [1,2,3,4,5]
a[1..3] = nil

Maintenant le contenu du tableau est [1,5].

int i = "démo".find("x")
if i = nil print "Non trouvé"

Puisque "x" n'est pas dans le texte "démo", le message "Non trouvé" sera affiché.

Voici les valeurs de nil en différents contextes...

Quand du code C++ est généré, nil est remplacé par ces valeurs:

 boolean      false
 int          -1
 natural      -1
 real         -1
 text         ""
 array        []
 dict         {}
 file         null
 dir          null
 objet        null
 var          selon le type du contenu.

Quand du code PHP est généré, nil est remplacé par false pour un nombre, par "" pour un texte.

Quand du code JavaScript est généré, nil vaut -1 pour un nombre, "" pour un texte.

Null

Le mot-clé null est converti en "null" en PHP, "NULL" en C++ et "undefined" en JavaScript;

Si null est assigné à un identifieur, il ne peut être référencé ou donc utilisé jusqu'à ce qu'on lui assigne une valeur. On peut seulement le comparer dans une condition avec le mot-clé null.

Exemple d'usage:

text a = null

La variable "a" peut être assignée mais reférencée seulement pour être comparée à la valeur null, sinon un message d'erreur s'affiche.

Assignement

La syntaxe d'un assignement simple est:

identifieur = expression

La valeur assignée doit avoir le type de la variable:

   int i = 10
   int j = "343"            ... incorrect

Cependant, les constructeurs de primitives permettent de faire des conversions.

Assignement augmenté

Lorsque une opération est effectuée sur une variable, et le résultat assigné à la même variable, il est possible de simplifier l'instruction, en assignement augmenté (d'une opération) .

La syntaxe d'un assignement augmenté est:

   identifieur opérateur expression

Par exemple, ajouter 10 à x et mettre le résultat dans x. Au lieu d'écrire x = x + 10, on écrira plus simplement: x + 10

Les opérateurs possibles sont: + - * / mod << >> & | ^ #
Examples:

  a = 1              ... donne à a la valeur 1.
  a + 1              ... ajoute 1 à a.
  x * y               ... remplace le contenu de x par le résultat x * y.
  a * (x + 2)       ... multiplie a par l'expression.
  a = a * (x + 2)  ... comme ci-dessus.
  a & b               ... remplace le tableau a par l'intersection des tableaux a et b.

Noter que dans un test de condition, x + 10 retourne simplement le résultat de l'addition de 10 au contenu de x, sans modifier x. Dans une instruction augmentée, ce résultat est affecté à x.

  if x + 1 : ...     ici x n'est pas modifié.

Assignements multiples

Un tuple de valeurs peut être assigné à un groupe de variable. Syntaxe et exemple:

   nom [, nom]* = expression [, expression]*

   x, y, z = 1, x2, 8

Le nombre d'expressions à droite doit correspondre au nombre d'expressions à gauche.
Sauf dans le cas ou une seule expression figure à droite, elle sera assignée à chaque variable du groupe.
Noter qu'une fonction peut retourner plusieurs valeurs et sera assignée à un groupe de variables.
Exemples:

   x, y, z = 0
   a, b = mafonction()

Au contraire de la déclaration multiple, un assignement multiple peut se faire avec des variables de types différents.
Exemple:

  int x
  text t
  x, t = 1000, "abc"

L'assignement multiple peut s'utiliser avec les éléments d'un tableau. Les tableaux ont une taille dynamique et donc, le nombre de cible n'a pas besoin de correspondre au nombre d'éléments, et si le tableau n'a qu'un seul élément, seule la première variable sera assignée.
Exemple:

  x, y, z = array(1, 2, 3, 4)

Est équivalent à: x = 1, y = 2, z = 3.

  x, y, z = array(1)

Est équivalent à: x = 1.

Vous pouvez assigner plusieurs variables à la fois avec: - une valeur ou expression.
- un array
- les valeurs d'un dict (utiliser la méthode values()).
- un appel de fonction.
- un tuple de valeurs ou expressions séparées par des virgules.
Dans le cas d'array ou dict, de tuple, de fonction retournant plusieurs valeurs, on affecte aux variables 1 à n les éléments 1 à n, dans le même ordre. Si le nombre ne correspond pas, c'est une erreur.
Si la fonction ne retourne qu'une seule valeur, la même valeur est assignée à toutes les variables à gauche.

Assignement destructurant

On peut assigner plusieurs variables à la fois à partir de plusieurs autres, ou les mêmes dans un ordre différent. Exemple:

var a = "alpha"
var b = "beta"

a,b = [b, a]
print a, b

Ce qui affichera: beta, alpha.

L'exemple montre comment échanger le contenu de deux variables, mais cela fonctionne aussi en assignant des variables différentes. En fait on a créé un tableau avec deux variables et assigné deux variables à son contenu.

Opérateurs

Les opérateurs de comparaison sont:

   =    (égal)
   <    (inférieur)
   >    (supérieur)
   <=  (inférieur ou égal)
   >=  (supérieur ou égal)
   <>  (différent)

L'opérateur "in" teste la présence d'un élément dans une séquence: texte dans un texte, objet dans un tableau, valeur dans un intervalle.

   if "a" in line  print "dans le texte"
   if x in 1..10  print "dans l'intervalle"

Les opérateurs binaires sont:

  &  (et)
  |  (ou)
  ^  (ou exclusif)
  ~  (non)
  << (décalage à gauche)
  >> (décalage à droite).

Les opérateurs de tableaux sont:

   &  (intersection)
   |  (union)
   ^  (complément d'intersection).

Précédence

Les opérateurs unaires ont la précédence sur les opérateurs binaires. Entre opérateurs de même arité, la précédence est donnée par les parenthèses.

Expression

Une expression est une combinaison de valeurs et d'opérateurs.

Expressions arithmétiques

Ce sont des valeurs arithmétiques ou des appels de fonctions combinés avec ces opérateurs:

  +
  -
  *
  /
  ^        puissance
  mod     modulo, retourne le reste d'une division...
 

Example:

   print 100 mod 3     ... affiche 1 le rester de  100 divisé par 3.

Expressions relationnelles

Les expressions arithmétiques peuvent être comparées grâce à un ensemble d'opérateurs:

  =    égal
  <    inférieur à
  >    supérieur à
  <=  inférieur ou égal
  >=  supérieur ou égal
  <>  différent

La comparaison retourne une valeur booléenne: true ou false (vrai ou faux). Cette valeur booléenne peut être assignée à une variable booléenne ou utilisée comme condition d'une structure de contrôle, telle que "if" notamment.

Expressions logiques

Une expression logique est une combinaison de valeurs booléennes ou d'expressions (relationnelles ou logiques) et d'opérateurs logiques.
Les opérateurs logiques sont:

  and     et
  or       ou
  not     non

L'expression "and" retourne vrai si les deux termes sont vrais, faux sinon.
L'expression "or" retourne vrai si un des deux termes est vrai, faux si les deux sont faux.
Example:

   boolean x = true
   boolean y = false
   if x and y print "vrai"; else print "faux"           ... doit afficher faux
   not(x or y)          ... est faux
   x and not y          ... est vrai

Expressions binaires

Les opérateurs binaires sont ceux que la plupart des langages utilisent:

 &  et binaire
 |  ou binaire
 ^  ou exclusif
 ~  négation binaire
 << rotation à gauche qui équivaud à multiplier par 2
 >> rotation à droite qui équivaud à diviser par 2

Expressions textuelles

Les opérateurs de texte sont:

 =, <, >, <=, >=   comparaison de deux textes.
 +                 concaténation de deux textes.
 []                indexation, slicing ou splicing (voir chapitre Text).
 in                teste si un text fait partie d'un autre.

Exemple:

 text t = "préfixe"
 print t + "suffixe"
 ...affichera: préfixesuffixe

Expressions de listes dynamiques

Les opérateurs de listes (array, dict) sont:

= < > <= >= <>  compare les valeurs de deux listes.
+               concatène deux listes (des doubles peuvent en résulter).
-               enlève d'une liste les éléments d'une autre (sauf doubles).
[]              indexation, slicing or splicing (voir Array et Dict).
in              teste si un élément est dans la liste.
&               intersection.
|               union.
^               complément d'intersection.

L'intersection de deux listes retourne les éléments communs aux deux. L'union de deux listes retourne l'ensemble de leurs éléments. Les éléments appartenant aux deux ne sont gardés qu'une fois. Si une des listes a déja un élément en double, seule la première occurence est conservée.

Précédence

Quelques langages de programmation on institué des règles de précédence, ainsi, quand les parenthèses sont omises, on sait quel terme est concerné par chaque opérateur. Bien que le précédence ait été construite dans le parseur Scriptol, des erreurs de messages seront envoyés si les parenthèses sont omises, car elles sont nécessaires à la lisibilité.
Le seul cas ou la précédence est admise sans parenthèse est pour les opérateurs unaires: not, ~ Un opérateur unaire s'applique toujours au terme qui le suit, donc pour l'appliquer à une expression il faut la mettre entre parenthèses. Exemple:

  if not a and b
  if not (a and b)

L'opérateur not est associé à l'objet "a" dans le premier, dans le second on a la négation de l'expression.

Dans les assignements composé (voir plus loin) le premier opérateur concerne la variable à assigner avec l'expression à sa droite.

Fonction

Une fonction est définie avec une interface qui indique comment l'appeler, un ensemble d'instrucitons, et se termine avec le mot-clé "return".
Le type de retour est requis et le type des paramètres aussi. On utilise "void" si la fonction ne retourne rien.

Syntaxe:

  type [,type]* nom ( paramètre [, paramètre]* ) [:]
    ... instructions ...
  return [expression [, expression]*]

Example:

  int multiply(int x, int y)
     int z
     z = x * y
  return z
 

Cela peut être écrit plus simplement:

  int multiply(int x, int y)
  return x * y

Le corps de la fonction est une liste d'instructions, incluant des instructions "return" si besoin.
La fin de définition est un return avec zéro, une, ou plusieurs valeurs.

return
return x
return x, y, 5

Si la fonction retourne plusieurs valeurs, elle doit avoir plusieurs types de retour et l'instruction de retour à plusieurs paramètres (dans le même ordre que les types de retour).

Exemple:

  text, int, int coordonnees(int num)
    int x = matable[num].x
    int y = matable[num].y
  return "coordonnées=", x, y

Appel de fonction

L'appel d'une fonction peut assigner zéro, une, ou plusieurs variables.

   mafonc()
   a = mafonc()
   a,b,c = mafonc()

Alias: passage par valeur ou par référence

Quand une fonction a des objects comme paramètres, les noms des paramètres sont des alias des objects, et toute modification dans la fonction sont effectués en fait sur les objets originaux. Par défaut, les primitives sont des copies et les objets des alias. On peut le changer avec un modifieur: "alias": le nom de la primitive devient un alias de l'original.

  void mafonc(number x)
    x + 1
    print x
  return

  void foncalias(alias number x)
    x + 1
    print x
  return

  number y = 5
  mafonc(y)
  print y
  ... doit afficher 6 puis 5

  foncalias(y)
  print y
  ...  doit afficher 6 puis 6.

Valeurs par défaut

Assigner une valeur par défaut permet d'ommettre un paramètre à l'appel d'une fonction. La syntaxe complète de l'interface est:

 type [,type]* nom(type nom [= expression] [, type nom [= expression]]* )

Exemple:

  int increment(int x, int y = 1)
    x + y
  return x
  print increment(10, 5)          ...affichera:  15
  print increment(10)             ...affichera: 11

La valeur par défaut 1 a été utilisée pour remplacer le paramètre manquant.

Si l'interface d'une fonction a plusieurs arugments avec une valeur par défaut, vous ne pouvez en omettre un lors de l'appel sans omettre tous les suivants. Les paramètres ne peuvent être reconnus par leur type.
Si ce que vous voulez, c'est écrire une fonction ayant un nombre et des types de paramètres variable, vous devez plutôt utiliser un tableau ou dictionnaire.

Example:

  void param(dict parlist)
    taille = parlist["taille"]
    nom = parlist["nom"]
    valeur = parlist["valeur"]
  return

Dans cet exemple, les variables "taille", "nom", "valeur" sont globales, et elle sont assignée par le contenu du dict en paramètre.

Scope et fonction

Le scope est un niveau de l'espace de visibilité des objets déclarés. Une fonction ouvre un nouveau scope pour toutes les variables déclarées à l'intérieur. Si la fonction est dans le scope global, toutes les variables globales compilées avant la fonction sont visibles dans la fonction.
On ne peut redéclarer dans la fonction une variable avec le même nom qu'une variable globale.
Si la fonction est une méthode d'une classe, toutes les variables déclarées dans la classe avant la fonction sont visibles dans la fonction.
Les objets déclarés dans la fonction sont visibles dans les structures de contrôle à l'intérieur de la fonction.

Le mode silencieux

Il est possible d'empêcher que l'interpréteur PHP n'affiche les messages d'erreur ou d'avertissement en faisant précéder l'appel d'une fonction du symbole @.
Le symbole est ignoré par le compilateur binaire.

  @mafonction(x, y)

La fonction "main"

Il est utile de pouvoir passer des paramètres à un programme à partir de la ligne de commande.
Un script Scriptol (comme PHP) utilise la variable PHP $argv". Pour imiter la façon dont C++ passe des paramètres à un programme, créer une fonction "main" et appelez-la avec $argv en argument (et $argc si besoin):

  int main(int argnum, array arglist)
    print argnum, "arguments"
    for arg in arglist
       print arg
    /for
  return 0

  main($argv, $argc) // $argv and $argc sont des variables système. Elles sont assignés automatiquement.

La fonction main, soit n'a aucun paramètre, soit en a deux:

   int main()
   int main(int, array)

Le type de retour int est obligatoire si le source est compilé en binaire.

Print et echo

Echo

Affiche une expression, ou une liste d'expressions séparées par des virgules, sans espaces entre elles et sans retour à la ligne à la fin (comme le fait print).

Syntaxe: echo expression [, expression]

Exemple:

  x = 5
  y = 20
  z = 1
  echo "values", x, y / 2
  echo z

Ce sera affiché à l'écran comme ceci:
values5101

Exemple:

  echo "demo", 5
  echo "next"

affiche: demo5next

Print

Un affichage plus élaboré est obtenu avec l'instruction print. Les expressions sont séparées et on va à la ligne en fin d'instruction.

Syntaxe: print expression [, expression]

Exemple:

  print "demo", 5

affiche: demo 5

Une instruction print simple, sans expression, envoie un retour à la ligne.
Exemple:

  print

Input

Pour entrer du texte à partir du clavier, utiliser la commande input.
Un texte peut être affiché avant la saisie du texte.

Exemple:

  text name
  input name
  print name

Example:

  input "who are you? ", name

La variable a assigner doit être déclarée avant la commande input, ce peut être un text ou un nombre de type quelconque.

Structures de contrôle

Les structures de contrôle sont:

 if
   if else /if.
   if une instruction.
   if composite.
 for
   for /for.
   for une instruction.
   - options: in intervalle, in séquence.
 while
   while let.
   while une instruction.
   while forever
 do while
   do until.
   do /do condition.
   do case / else / always /do.
 enum
   enum simple.
   enum dictionnaire.
 error
  error /error.
  error une instruction.

Pour JavaScript seulement:

to for /to
to while /to
to une instruction 

Scriptol a une syntaxe différente pour les structures de contrôle d'une instruction, ou multi-lignes.

Une structure de contrôle d'une seule instruction a la forme:

    mot-clé-de-structure expression let instruction
 ou mot-clé-de-structure expression ? instruction
 ou mot-clé-de-structure expression instruction commençant par un mot-clé.

Il n'y a pas d'autre marqueur de fin que la fin de ligne. L'instruction est basique et ne peut être un autre construct.
L'instruction "let" est toujours la dernière partie d'une structure de contrôle et peut être la seule. Le symbole "?" est simplement une abbréviation de "let". Let est requis si l'instruction est un assignement ou un appel de fonction, mais optionel si un mot-clé le suit. Si "else" ou "let" complète la structure de contrôle sur la même ligne, l'instruction doit être terminée par un point-virgule.

Une structure de contrôle multi-lignes a la forme:

    nom-structure expression [:]
      ... instructions ...
    /nom-structure

Le symbole deux-points est optionnel (sauf si une instruction est mise sur la même ligne).

Exemple avec séparateurs:

   if a = b : print t ; /if

If

Une structure de contrôle conditionnelle d'une ligne à la forme:

if condition ? instruction ; else instruction

Cela se lit ainsi: si condition vraie? alors action; sinon action

La structure if then else peut s'écrire sous une forme plus succincte:

if expression ? action1 ; : action2 

Examples:

   if a = 5 ? break
   if a < 5 ? print "moins que"
      else print "plus que ou égal"
   if a = 1 ? print "un"; else print "plusieurs"

Multi-lignes

Syntaxe:

  if condition-booléenne [:]
    ... instruction ...
  else                                      ...optionnel
    ... instructions ...
  /if

N.B.: Le symbole deux-points est optionnel après la condition, comme le point-virgule après une instruction, mais il est requis quand on concatène les lignes.

Exemple:

  if (x + y) > 8
    print "> 8"
    print x
  else
    print "<= 8"
  /if

  if (x + y) > 8 : print "> 8" ; print x ; else print "<= 8"; /if

If composite

Le construct switch case du C++ ou Java n'existe pas en Scriptol car il est trop limité et inutile (en Scriptol). Il est replacé par une variante du construct if plus puissante, qui peut tester tout type de variable et plusieurs genres de comparaisons.

La syntaxe est:

 if expression non-booléenne [:]
   operateur expression : instructions
   operateur expression : instructions
        ...
 else
   ... instructions ...
 /if

Une expression non-booléenne est une variable, un littéral, ou toute expression qui ne retourne pas la valeur booléenne vrai ou faux.
On ne place pas le mot-clé "break" à la fin d'un groupe case comme en C. Un break produirait une sortie de la structure de contrôle qui contient le construct if.
Les opérateurs valides sont: =, <, >, <=, >=, !=, <>, in, else.
Le "else" ici est équivalent au "default" du switch case de C.

Exemple:

  if a
  = 1: print 1
  = 2: print 2
  > 2: print ">2"
  else print "<1"
  /if


  if x
  in array(1,2,3): print "premier"
  in array(4,5,6): print "second"
  in array(7,8)  : print "troisième"
  else print "autre"
 /if

For in

Cettre structure de contrôle parcourt soit un intervalle d'entiers, soit une tableau et assigne tour à tour chaque élément à une variable.

Syntaxe de for sur un intervalle:

 for variable in début..fin [step s] [:]
   ... instructions ...
 /for

Début, fin, et le pas (step) sont des identifieurs ou des littéraux.
Le pas est optionnel, la valeur par défaut est 1.
La limite fin est incluse dans l'intervalle, si le symbole d'intervalle est ".." et pas si le symbole est "-".
La fin peut avoir une valeur inférieure au début, si "step" est présent et contient un pas négatif.
La variable conteneur peut être déclarée dans l'en-tête. Dans ce cas elle est locale à la structure de contrôle.

Syntaxe de for sur une liste:

  for variable in expression-tableau [:]
     ... instructions ...
  /for

Dans ce cas, le contenu de l'expression est parcouru et chaque élément assigné à la variable. Cette expression doit être un tableau ou une combinaison produisant un tableau.

Exemples:

  for i in 1..10
      print i
  /for

 for w in montableau
    print w
 /for

 for w in arr1 + (arr2 & arr3[0..5])
    print w
 /for

For à une instruction

La syntaxe courte, d'une instruction est:

  for variable in liste let instruction-basique

Exemples:

  for w in maliste let print w
  for x in 10..1 step -1 let print w + 10

Obtenir l'indice et la valeur

La boucle for scanne un tableau associatif valeur par valeur. C'est équivalent au for .. of de JavaScript alors que for .. in en JavaScript scanne les clés.

for var v in d let print v        // affiche les valeurs 

Mais vous pouvez obtenir la clé et la valeur:

for text k, var v in d let print k, ":", v // affiche clés et valeurs 

Cela fonctionne aussi sur un tableau simple:

array a = (10,20,30)
for int indice, int val in a
  print indice, ")", val
/for

Cela affichera:

1) 10
2) 20
3) 30

While

La structure de contrôle while est une boucle conditionnelle.

Syntaxe à instruction unique:

   while expression let instruction

Syntaxe standard:

  while expression [:]
     ... instructions ...
  /while

Exemple:

  int x = 10
  while x <  20
     print x
     x + 1
  /while

Une instruction "break" sort de la boucle.
Une instruction "continue" ignore tout ce qui suit et commence une nouvelle boucle.

While let

Cette syntaxe est recommandée pour éviter le risque de boucles infinies.
L'instruction qui fait évoluer la valeur de l'expression testée comme condition de l'itération est déplacée après le marqueur /while grâce à l'instruction "let".

Exemple:

  while x < 10
     if (x mod 2) = 0 continue
     print x
  /while let x + 1

L'instruction continue saute sur l'instruction let.
Il n'y a pas d'équivalent en C ou PHP parceque l'instruction continue saute le code qui suit, y compris l'incrémentation de x, d'ou une boucle infinie.

La syntaxe simplifiée et recommendée est:

  while condition
    ...instructions...
  let incrementation

Exemple sur une instruction:

   while x < 10 let x + 1
   while x < 10 : print x; let x + 1

La condition de la boucle while peut être le mot-clé "forever", et l'on entre dans une boucle infinie, dont on sort par un break.

Do until

Le bloc d'instructions entre les marqueurs do /do est un nouvel espace de visibilité, et les instructions encloses sont excécutée selon une condition éventuelle.

Syntaxe générale:

  do
      ... instructions ...
  /do [ condition ]

et /do condition peut être simplifié en "until".
Le bloc d'instruction est exécuté tant que la condition est fausse, et laissé quand la condition devient vraie.

Syntaxe de do until:

  do
      .. instructions ...
  until expression

  do
    print x
    x + 1
  until x = 10

Do case

C'est un puissant construct de "pattern-matching". Il contient un ou plusieurs groupes case suivis par un "else" optionnel, et un "always" optionnel. Un seul groupe case est exécuté, le premier dont la condition est satisfaite. Always est toujours exécuté, else quand aucune condition n'est satisfaite.

Syntaxe de do case:

  do
    case condition : instructions
    [ case condition : instructions ]
    [ else instructions ]
    [ always instructions ]
  /do [while expression]

- une condition est suivie par un deux-points, ou une fin de ligne. "else" et "always" aussi, pour homogéniser mais optionnellement. - un seul case est exécuté, ou aucun si l'expression n'est pas reconnue.
- un groupe else équivaud au "default" de de c.
- un groupe always est toujours exécuté, après un autre cas éventuellement. - the end tag is /do or /do forever or /do while.
- Une commande forever ou while fait de la structure un automate. Il peut falloir un break pour en sortir.
- Il ne faut pas placer un break à la fin d'un groupe comme en C. Cela quitterait la structure, non le groupe.

Exemples:

 do
 case nom = "pussycat":    print "c'est un chat"
 case nom = "flipper":        print "c'est un dauphin"
 case nom = "mobby dick": print "c'est une baleine"
 else
   print "un autre animal"
 /do

 int state = ON
 do
  case state = ON:  counter + 1
  case state = OFF: break
  always
    state = getState()     ` une fonction quelconque
 /do while forever

L'automate qui lit son état à partir d'une et continue de tourner jusqu'a ce que l'état OFF soit rencontré, produit par la fonction appelée.

Do while

Le marqueur de fin do peut être complété d'une condition, while ou forever.
Le bloc d'instruction sera exécuté au moins une fois et tant que la condtion est vraie.

Syntaxe:

  do
     ... instructions ...
  /do while expression

  do
     print x
     x + 1
  /do while x < 3

Options - do ... /do ... bloc d'instructions avec ou sans groupes case. - do ... /do while forever ... boucle infinie. - do ... /do forever ... boucle infinie simplifiée. une boucle infinie requiert un "break" pour cesser de s'exécuter.

Break et continue

Commande pour sortir d'une boucle.
Exemple utilisant le mot-clé "forever" (pour toujours) qui crée délibérément une boucle infinie.

  int x = 0
  while forever
    print x
    if x > 100
      break
    /if
    x + 1
  /while

Quand x atteint la valeur 100, l'instruction break fait que le programme saute au-dela de /while, sur l'instuction après la structure while.

Continue

Cette seconde commande permet de sauter toutes les instructions de la position actuelle, jusqu'en fin de structure, donc de démarrer une nouvelle boucle.

  int x = -1
  while x < 20
    x + 1
    if (x mod 2) = 0 continue
    print x
  /while

Cet exemple affiche seulement les valeurs paires de x, car lorsque l'on rencontre une valeur impaire, la condition x mod 2 est vérifié et une commande continue est exécutée.
Dans cet exemple, j'ai inséré l'incrémentation de x sur la première ligne. Si cela avait été placé après la commande continue, il en résulterait une boucle sans fin puisque l'incrémentation aurait été passée. La syntaxe while .. let évite ceci.

Enum

Enum permet d'assigner séquentiellement des valeurs à des identifieur, et en Scriptol, il permet d'assigner des valeurs non entière: des réels ou des textes.
Par défaut un nombre entier est assigné, à partir de zéro, et incrémenté pour chaque identifieur de la liste.
On utilise un double point pour assigner une valeur donnée à un identifieur et le signe égal pour redémarrer la une valeur donnée.

Syntaxe:

enum
  identifieur [ : value | = value ]
  [ identifieur ...]*
/enum
  enum:
     Z,
     UN,
     DEUX,
     TROIS
  /enum

Cela assigne 0 à Z, 1 à UN, et ainsi de suite. C'est équivalent à:

  const int Z = 0
  const int UN = 1
  etc...

ou:

  enum: Z:0, UN:1, DEUX:2 /enum

Exemple plus complexe assignant des valeur hétérogènes et démarrant une séquence:

  enum
    Z : "a0",                     ...  assigne a0
    UN  : "a1",                  ...  assigne a1
    TROIS,                        ...  assigne 0
    QUATRE : 3.15,            ...   assigne 3.15
    CINQ = 5,                     ...   assigne 5 et redémarre la séquence
    SIX                            ...   assigne 6
  /enum

Exemple de syntaxe simplifiée en une instruction:

  enum ZERO, UN, DEUX, TROIS

Indexation

La syntaxe d'un indice dans un texte ou un tableau est: [indice]. L'indice doit être une expression simple sans crochets imbriqués. Une expression simple est un nombre littéral, un identifieur, un appel de fonction, ou une expression arithmétique et doit être évaluée comme un nombre entier.

Intervalle

La syntaxe d'un intervalle est:

  début..fin

Pour indicer une liste, is est enclos entre crochets:

  nom-liste[début..fin]

Début et fin sont des expressions entières. Le dernier élément est inclus dans l'intervalle à moins que l'on utilise l'opérateur: "-"

  a[0 -- 100]        équivaud à [0..99]
  a[x -- y]            équivaud à a[x..y-1]

Exemples d'intervalles:

   0..10
   x..y
   x * 2 / 4 .. y + 10

Vous pouvez utiliser un intervalle pour:
- tester si une valeur est dans un intervalle: if x in 10..100
- scanner un intervalle: for x in 1..100
- extraire une partie de liste: array b = a[x..y]
- changer une partie de liste: a[x..y] = autre-liste

Intervalles dans une liste

Quand on indice une liste, la limite inférieure ou la limite supérieure de l'intervalle peut être omise.

Il y a trois moyens pour découper une liste:
   array a = array(x0, x1, x2, x3, x4, x5, x6, x7, x8)
   array b = a[..2]
   array c = a[3..5]
   array d = a[6..]

On obtient trois tableaux avec ces contenus:
   b:   (x0, x1, x2)
   c:   (x3, x4, x5)
   d:   (x6, x7, x8)

On les affiche:
   b.display()
   c.display()
   d.display()

On doit voir:
   array (
    [0] => x0
    [1] => x1
    [2] => x2
   )
et ainsi de suite...

Pour remplacer un intervalle par une autre liste, il suffit d'un assignement:
a[3..5] = array("a", "b", "c")
Le contenu devient:
(x0, x1, x2, "a", "b", "c", x6, x7, x8)

Avec la même syntaxe, on remplace une sous-liste par une liste ou un élément:
a[3..5] = "xyz"
The original liste become:
(x0, x1, x2, "xyz", x6, x7, x8)

Pour supprimer une sous-liste, on la déclare nil, "not in liste" (pas dans la liste):
a[3..5] = nil
On a supprimé la sous-liste 3..5 qui est (x3, x4, x5), on obtient:
(x0, x1, x2, x6, x7, x8)

On peut tester si une valeur appartient à une sous-liste.
Example:

  array a = array("un, "deux", "trois")
  if "deux" in a[2..5] print "dedans"

Text

Un texte est un objet basique avec des méthodes et qui contient une chaîne de caractères.
Quand un texte est argument d'une fonction, la fonction utilise une copie et non un alias sur le texte original.
Un indice peut être négatif dans un intervalle, pas dans l'indexation.

Syntaxe:

  text s                 crée un texte.
  s = "str"              initialise.
  s = s[i]               prend un caractère.
  s[i] = s2              remplace un caractère, s2 a un seul caractère.
  s = s[i..j]            prend une sous-chaîne, de i jusqu'à j inclus.
  s[i..j] = s            remplace une sous-chaîne.
  s[i..j] = ""           supprime une sous-chaîne.

Un texte litéral est une chaîne de caractères enclose par des guillemets simples ou doubles.
Le symbole + peut être utilisé avec les textes, et il représente la concaténation de deux chaînes.
Exemple:

  text b = "préfixe"
  text a = b + "suffixe"

Le contenu de a sera: "préfixesuffixe".

Méthodes de text

Retour   Méthode         Fonction

text     capitalize()    met la première lettre en majuscule.
int      compare(text)   compare lexicographiquement deux textes (ignore maj).
                         retourne -1, 0, 1.
text     dup(int)        retourne un texte dupliqué n fois. Ex: "*".dup(10).
void     fill(text, int) remplit avec le texte en argument dupliqué n fois.
int      find(text s2)   retourne la position du texte s2 dans le texte,
                         retourne "nil" si non trouvé.
                         (tester si = nil car <> nil ne va pas en PHP)
int      identical(text) compare, différencie maj/min. Retourne -1, 0, 1
void     insert(int, text) insère in text à la position donnée.
boolean  isNumber()      retourne true si le texte contient un nombre.
int      length()        retourne la longueur.
text     lower()         met en minuscules.
text     ltrim()         supprime blancs et codes de contrôle au début.
text     replace(ft, rt) remplace chaque occurence de ft par rt.
void     reserve(int)    alloue la taille donnée pour utiliser comme buffer.
array    split(sep)      découpe le texte en éléments séparés par sep.
int      toInt()         convertit en entier
natural  toNatural()     convertit en naturel.
real     toReal()        convertit en réel.
text     toText()        cast une chaîne littérale en text (pour C++).
text     trim()          supprime blancs et codes de contrôle en début et fin.
text     rtrim()         supprime blancs et codes de contrôle en fin.
text     upper()         met en majuscules.
text     wrap(int size)  mots non coupés.

Variable dynamique

Sont déclarées avec le type: var.
Les variables dynamiques ont les méthodes de tous les autres types de variables mais pas les méthodes de classes déclarées (voir extern). Quand une variable est assigned a un var, un cast est requis pour assigner le contenu à une variable typée.

Méthodes de var :

Séquence et liste

Une séquence est une liste soit statique (text) ou dynamique (array ou dict).
Listes et séquences ont les mêmes opérateurs, sauf & et | propres aux listes. Les opérations sur les listes sont:

  []   : indice, lecture ou modification de sous-liste.
  +    : fusion de deux séquences. Ou ajoute un élément à une liste.
  -    : supprime une séquence d'une autre, ou un élément d'une liste.
  =    : comparaison de deux séquences.
  in   : teste si un objet est dans une séquence.
  &    : intersection de deux listes (donne les éléments communs).
  |    : union sans doublons de deux listes.

Tableau

Il y a deux sortes de listes dynamiques en Scriptol:

 array:  (tableau) indicé par des nombres entiers.
 dict:    (dictionnaire) les clés sont des textes.

Un tableau est une liste dynamique d'objets ou litéraux indexée.

Un tableau vide est représenté par [].
Un tableau litéral est une liste d'expressions séparées par une virgule et enclose entre [].
Une variable peut être un élément de tableau.
Le constructeur débute par le mot-clé "array".

Pour afficher le contenu du tableau a, on type a.display(), et on obtient quelque chose de la forme:

  array(
  0 : un
  1 : deux
  2 : trois
  )

Créer un tableau

Le constructeur d'un tableau a la forme: array(valeur, valeur, etc...)
Le nombre de paramètres va de 0 à n. Un initialiseur vide s'écrit: array()
Un tableau litéral s'écrit: { ... valeurs ... } On peut définir un tableau en assignant le constructeur, ou un tableau litéral, ou une valeur unique.

Syntaxe:

  array a                               crée un tableau.
  array a = array()                     crée un tableau vide.
  array a = []                          crée un tableau vide.
  array a = array(x, y, ...)       crée et initialise un tableau.
  array a = {x, y, ...}                 crée et initialise un tableau.
  array a = array(8)            utilise le constructeur.
  array a = 3                           crée un tableau d'un élement.

Les éléments d'un array peuvent être toute expression, *** sauf une expression booléenne ***. Si vous placez la valeur vrai dans un tableau PHP retournera vrai chaque fois que vous utilisez l'opérateur "in", avec toute valeur cherchée.

Un tableau peut être déclaré sans assignement de contenu, et rempli par la suite:

  array a
  a.push("un")
  a.push("deux")
  a.push("trois")

Les éléments sont retrouvés par leur position dans le tableau.
Exemples:

  a[1] = "a"
  a[2] = "b"
  for x in a : print x
  ... doit afficher:  a b

Indexer un tableau

Les éléments d'un tableau sont accédés par un numéro entier.
Syntaxe:

  a[n]                   lit l'élément ayant le numéro n.
  a[n] = x               remplace l'élément à la position n.
  a[n] = nil             efface un élément.
  a = []                 efface le tableau entier.
  a[n].upper()          appel d'une méthode sur l'élément n du tableau.

Un index vide désigne l'élément courant:

   a[]                        élément à la position courante.

L'indice peut être toute expression qui s'évalue en un nombre entier. L'expression ne peut contenir un élément de tableau.

  a[10 + x / 2]            valide.
  a[10 + b[5]]             n'est pas valide.

Puisqu'un tableau peut contenir tout type d'objet, ou même d'autres tableaux, il faudra une variable dynamique pour lire un élément, à moins de connâitre le type de l'élément à lire.

  array a = [ x, "two", 3 ]
  var x = a[1]                utilisation de var pour lire l'élément de type inconnu.
  text t = a[2]
  int i = a[3]

Quand un élément est ajouté hors de la limite, il est placé en dernière position dans le tableau.
Si vous assignez un élement avec l'instruction suivante, le contenu changera selon le langage cible:

  a[1000] = "x"

En PHP et JavaScript:
 array(
  0 : un
  1 : deux
  2 : le dernier
  1000: x
 )

En C++:
 array(
  0 : un
  1 : deux
  2 : le dernier
  3: x
 )

En PHP, l'indice 1000 est seulement temporaire, et changera dès qu'une instruction change le tableau.
Une instruction de la forme a[n] = x sert à modifier la valeur à l'indice donné, il ne faut pas assigner un tableau de cette façon qui ne convient qu'aux dictionnaires (dict), comme on verra plus loin.

Itérateur

Le contenu d'un tableau peut être parcouru par un iterateur.
On pointe sur le premier élément avec la méthode begin(), ou sur le dernier avec end(), l'élément courant est obtenu par un index vide de la forme [].

  begin()     pointe sur le premier élement et retourne sa valeur.
  end()       pointe sur le dernier élement et retourne sa valeur.
  inc()       déplace sur l'élément suivant.
               Retourne la valeur pointée avant, ou nil au-delà du dernier élément.
  dec()       déplace sur l'élément précédant. Retourne la valeur ou nil.
  index()     retourne l'index de l'élément pointé.
  value()     retourne la valeur de l'élément pointé.
  []          indice de l'élément courant.
  nil         signifie "not in liste" et est retourné par différentes fonctions
              quand aucune valeur ne peut être retournée.

Exemple d'utilisation avec le tableau a:

  a.begin()                 ` déplace sur le premier élément
  while a[] <> nil          ` teste si la fin de liste est atteinte
    print a[]               ` affiche l'élément actuellement pointé
    a.inc()                 ` déplace sur l'élément suivant
  /while

En ordre descendant:

  a.end()
  while a[] <> nil
    print a[]
    a.dec()
  /while

Utiliser un tableau comme pile

Une fois le tableau créé, vous pouvez appliquer différentes fonctions de liste, ou de pile...

a.push("item")     ...ajoute un élément à la fin de la liste
a.unshift("item")  ...ajoute un élément au début de la liste
a.pop()            ...lit et enlève le dernier élement
a.shift()          ...lit et enlève le premier élement

Vous pouvez ainsi lire et éliminer les éléments d'un tableau par des instructions successives telles que:
print a.shift()

Intervalle dans un tableau

Un intervalle est délimité par un intervalle de positions.

a[pos..fin]           la rangée entre "pos" et "fin" inclus.
a[..fin]              du début jusqu'à la position "fin".
a[pos..]              de la position "pos" à la fin du tableau.
a[..]                 prend le tableau entier (peu utile).
a[pos..fin] = nil     supprime une rangée d'éléments.
a[pos..fin] = b     remplace une rangée par un tableau/élément (id).

Opérateurs de tableau

Un élément, ou un groupe d'éléments, peut être ajouté ou supprimé avec les opérateurs + et -.

Exemple:

array a = array("un", "deux")
array b
b = a + array("trois", "quatre")    maintenant le contenu de b est de quatre éléments.
a = b - array("un", "quatre")       maintenant le contenu de a est: ("deux", "trois").

Seuls les opérateurs arithmétiques + et - sont utilisables sur les tableaux, avec l'opérateur d'appartenance "in".

L'opérateur "in"

Cet opérateur peut être utilisé pour tester si une valeur est contenue dans une liste (array, dict ou même un text), et pour parcourir le contenu également.

Syntaxe et exemples:

if variable in array
for variable in array

if x in a :   print "dedans";  /if
if x in array(1,2,3) : print "dedans"; /if
for x in a print x
for t in array("un", "deux", "trois")  print t

Opérateurs binaires de listes dynamiques

Vous pouvez utilisez sur des listes dynamiques (array ou dict) les opérateurs binaires d'intersection et union. L'intersection de deux listes retourne seulement les éléments qui font partie à la fois des deux listes. L'union de deux listes est une nouvelle liste composée des éléments de la première, plus ceux de la seconde moins ceux qui font déja partie de la première.

&  intersection
|  union
^  complément d'intersection

a = array(1, 2, 3, 4) & array(3, 4, 5, 6)   fait que a contient (3, 4)..
a = array(1, 2, 3, 4) | array(3, 4, 5, 6)   fait que a contient (1, 2, 3, 4, 5, 6).

Appliquer une fonction à un tableau

La méthode map, qui est implémentée en JavaScript et PHP permet d'appliquer successivement une fonction à chaque élément d'un tableau et éventuellement retourner un nouveau tableau. Exemple:

int mapfun(int x) return x * 25

b = [1,2,3,4,5]
print b.map(mapfun)

Si l'on veut appliquer une fonction à plusieurs tableaux à la fois, ou à des dict, on utilise l'indice. Exemple:

for text k, var v in d1
  d1[k] + d2[k]
/for  

On ajoute, élément par élément, le contenu du tableau associatif d2 à d1.

En utilisant une fonction, à deux paramètres:

array d1 = [1,2,3,4,5]
array d2 = [10, 20, 30, 40, 50]
int mapfun(int x, int y) return x + y
for int i, var x in b print mapfun(d1[i], d2[i])

Tableau à plusieurs dimensions

Le nombre de dimensions n'est pas limité. Pour un tableau à deux dimensions, la syntax pour...
- accéder à un élément est: x = nomarray[i][j]
- changer un élément est: nomarray[i][j] = x
Pour créer un élément, la syntaxe est:

  nomarray[i] = array()
  nomarray[i][j] = x
  ou
  nomarray[i] = array(x)

On ne peut créer directement un élément dans un sous-tableau inexistant. L'index i et j supposent qu'il existe déja i et j éléments.

Comparer deux tableaux

Le langage peut faire des comparaisons entre des tableaux de nombres avec tous les opérateurs relationnels. Deux tableaux de tailles différentes sont considérés différents.

Entre deux tableaux de texte ou autres objets, il peut tester s'ils sont identiques ou s'ils sont différents. Pour d'autres comparaisons, on doit définir son propre algorithme.

Contenu d'un tableau en PHP, pas à pas

Nous devons savoir comment les clés entières d'un tableau en PHP changent selon les opérations que l'on peut accomplir. C'est important pour comprendre les tableaux associatifs et éviter pas mal de bogues.
Après chaque opération le contenu est affiché.

  array a = []
  array ()

  a.push("un")
  array
  (
   [0]=> un
  )

  a + array("deux", "trois", "quatre")
  array
  (
   [0]=> un
   [1]=> deux
   [2]=> trois
   [3]=> quatre
  )

  a.shift()       ... le premier élément est supprimé et les clés sont renumérotées.
  array
  (
   [0]=> deux
   [1]=> trois
   [2]=> quatre
  )

  a[1000] = "mille"
  array
  (
   [0]=> deux
   [1]=> trois
   [2]=> quatre
   [1000]=> mille
  )

  a.unshift("x")       ... toutes les clés sont renumérotées, même la clé 1000.
  array
  (
   [0]=> x
   [1]=> deux
   [2]=> trois
   [3]=> quatre
   [4]=> mille
  )

 Créons deux nouveaux tableaux:
  array a = array("un","deux")
  array b = array()
  b[1000] = "mille"
  a + b
  Les clés sont renumérotées.
  array
  (
   [0]=> un
   [1]=> deux
   [2]=> mille
  )

Si on remplace a + b par a.push("mille") le résultat sera le même.

Méthodes de array

Les itérateurs ne sont pas encore implémentés par le compilateur JavaScript, aussi les méthodes begin, dec etc. ne sont pas reconnues.

Retour  Nom               Action

var     begin()           pointe sur le premier élément.
var     dec()             retourne un élément et décrémente le pointeur.
void    display()         affiche le tableau.
var     end()             pointe sur le dernier élément.
boolean empty()           return true si le tableau est vide.
int     find(var)         recherche un élément, retourne l'index ou nil.
int     findLast(var)     recherche un élément à partir de la fin.
var     inc()             retourne un élément et incrémente le pointeur.
int     index()           retourne l'index de l'élément pointé.
void    insert(int, var)  insère un élément à un index entier (pas un text).
text    join(text sep)    convertit en text avec le séparateur donné.
text    key()             retourne la clé de l'élément pointé.
boolean load(text nom)    charge un fichier dans un tableau ("file" de PHP).
var     min()             retourne la valeur la plus faible.
var     max()             retourne la plus forte valeur.
array map(fonction) applique une fonction à chaque élément et retourne un nouveau tableau. void pack() rend les éléments du tableau consécutifs. var pop() lit et supprime le dernier élément. var pop(int) lit et supprime l'élément à la position donnée. void push(val) ajoute un élément à la fin. var rand() retourne un élément à une position aléatoire. array reverse() retourne la liste en ordre inversé. var shift() lit et supprime le premier élément. int size() retourne le nombre d'éléments. void sort(int) trie les valeurs en ordre ascendant. void rsort(int) trie les valeurs en ordre descendant. void store(text nom) sauve le tableau dans un fichier. Ajouter false en argument pour ne pas ajouter de code eol. number sum() calcule la somme des éléments. text toText([text]) convertit le tableau en chaîne avec code de séparation en option. array unique() retourne le tableau sans valeur en double, la première est gardée. void unshift(var) insère un élément en première position.

La méthode sort de tableau a un argument optionnel: 0 pour un classement alphanumérique (par défaut en JavaScript et PHP), 1 pour un classement numérique.

Dictionnaire

Un dict est une liste dymamique de couples clé et valeur. Les clés sont toujours des textes. Les valeurs peuvent être tout objet.
La clé et la valeur peuvent être des variables. Le format pour un couple clé et valeur est:

clé:valeur

Un dict vide est représenté par {}. Un dict litéral est une liste de couples separés par une virgule, et enclos entre {}.

Au contraire du tableau, le dict est créé par des assignements:

d[k] = "b"
d["un"] = "element 1"

Même si JavaScript supporte les clés numériques placées entre guillemets, donc considérées comme des textes, cela produit des résultats imprévisibles quand on les mêle à des clés alphabétiques. Il faut donc éviter des mêler les types.

Créer un dictionnaire

Un dict peut être créé à partir d'un litéral ou un constructeur.

Syntaxe:

dict d                                 // crée un dict.
dict d = {x:v, y:w,...}                // crée et initialise un dict.
dict d = {}                            // crée un dict vide.

Les valeurs peuvent être tout type d'objet.
La clé peut être une variable et la valeur une expression.

Exemple:

text k = "a"
text v = "b"
dict d = {k : v}
dict d = {k : v + "x".dup(4) + 20.toText()}

Cet exemple enregistre "bxxxx20" dans le dict d, avec la clé "a".

Indexer un dict

Les valeurs dans un dict sont accédées par une clé textuelle.

Syntaxe:

  d["clé"]              prend le premier élément avec la clé "clé".
  d[clé] = valeur       remplace une valeur ou ajoute un couple
                        clé-valeur si la clé n'est pas déja dans le dict.
  d[clé] = nil          supprime un élément.
  d = {}                efface le dict.

Exemple:

  dict d
  d["program"] = "ce que l'on veut accélerer"
  print d["program"]                   affiche le texte ci-dessus.

Intervalle dans un dict

La façon normale d'utiliser un dictionnaire est par le moyen des clés ou itérateurs. En quelques occasions il peut être utile d'accéder à un intervalle de valeurs directement.
- Quand on ajoute un élément ou un autre dict à un dict, au moyen d'intervalle, de push, unshift, PHP génère une nouvelle clé pour cet élément. La nouvelle clé est un nombre.
- Si vous remplacez un intervalle par un autre dict, certains éléments peuvent être perdus. Cela se passe aussi lors de la fusion.
- Les clés du dict qui replace un intervalle ne sont pas conservées.

Exemples d'affichage:
Il doivent présenter toutes les clés et valeurs dans le dict.

  dict d = {"a":"alia", "b":"beatrix", "c":"claudia"}  

  d.display()                     

  for k,v in d : print k, v; /for                      for

Méthodes de dict

Retour  Nom               Action

void    display([flat])   affiche le dict indenté. Si l'argument est false, il n'est pas indenté.
boolean empty()           retourne true si le tableau est vide.
int     hasKey(text)      retourne true si la clé existe.
int     find(var)         recherche un élément, retourne l'index ou nil.
dict    getById(text)     retourne un dictionnaire assigné à la propriété en paramètre.
array   getByName(text)   retourne la liste des éléments dont l'attribut name a l'argument pour valeur.
array   getByTag(text)    retourne la liste des objets donc l'attribut tag à l'argument pour valeur.
array   keys()            retourne la liste des clés.
void    kSort()           réordonne les index en préservant les associations.
void    load(text nom, [xml])    charge un fichier dans le dict. 
var     pop()             lit et supprime le dernier élément.
var     shift()           lit et supprime le premier élément.
int     size()            retourne le nombre d'éléments.
void    sort(int, bool)   trie les valeurs en ordre ascendant.
void    store(text nom)   sauve le dict dans un fichier.
text    toXML()           convertit le dict en fichier XML dans une chaîne.
void    unshift(text,var) insère une paire clé valeur première position.
array   values()          retourne la liste des valeurs.

Méthode load: Le fichier est converti de XML en dict s'il a l'extension xml, rss, svg ou si l'argument optionnel vaut 1.

Tableaux typés numériques

Un tableau typé contient un type d'objets unique. Il est beaucoup plus efficient que le tableau commun parcequ'il est indexé, et non associatif, et contient directement des objets de 32 ou 64 bits ou des pointeurs, plutôt que des objets dynamiques (var).
Un tableau d'entiers est 100 fois plus rapide qu'un tableau standard pour les exécutables binaires, mais il n'y a pas de différence en PHP.
Les tableaux typés sont aussi dynamiques, la taille n'est ni prédéfinie, ni limitée.

Constructeur et litéral

Le constucteur d'un tableau typé a la forme:

  type(...éléments...)

Exemple:

  int(1, 2, 3)

Le nombre d'élément va de 0 à n.

Quand il y a un seul élément, il n'y a pas de différence entre une constructeur de tableau typé et un constructeur scalaire:

  int(1)
  real(10r)

Ce n'est pas un problème lors de l'assignement, puisque l'on peut créer un tableau à un seul élément à partir d'un scalaire,.

Tableau d'entiers

La syntaxe pour déclarer un tableau d'entiers est:

  int[] i = int(x, y, ....)

Une fois qu'il est déclaré, il est utilisé comme un tableau mixte, mais seuls les nombres entiers peuvent être ajoutés au tableau.
Lors de la création on peut assigner un constructeur ou un litéral.
Un constructeur à un seul élément équivaud à un constructeur d'entier. Dans une expression il faudra utiliser un litéral.

Exemples:

  int[] x = int(5)
  int[] x = int(1,2)
  int[] x = y + int{5}

Tableau de real, natural, number

Les déclarations sont:

  real[] r    = real(1.0, 2.0, etc...)
  natural[] n = natural(1, 2, etc...)
  number[] n  = number(1, 2.0, ...)

Assignement et conversion

Vous pouvez assigner un tableau typé à un tableau mixte:
Exemple:

  int[] i = int(...)
  array a = i

Mais vous ne pouvez créer un tableau mixte avec un constructeur typé:

Exemples:

    [1,2,3]           ... c'est un tableau mixte, avec des éléments entiers
    int[] i = [1,2,3]     ... NON VALIDE, il faut plutôt écrire:
    int[] i = int(1,2,3)  ... valide.

Exemples:

  array a = int(1,2)          ... NON valide
  array a = array(int(1,2))   ... NON valide

Tableau typé et var

On peut assigner un tableau typé à un var.

  int[] i = int(1,2)
  var d = var(i)

Deux méthodes sont fournies pour utiliser ce var:
arrayType() retourne le type de tableau contenu dans le var.
toList(int = 0) retourne le tableau typé contenu.
Le paramètre est le type, et est requis quand le var se contient tableau mixte, que l'on veut convertir en tableau typé.

Types reconnus:

  $TYPE_INT        tableau d'entiers
  $TYPE_REAL
  $TYPE_NATURAL
  $TYPE_NUMBER

Exemple:

  d = var(int(1,2))
  if d.arrayType()
  = $TYPE_INT:
     int[] i = d.toList()
  = $TYPE_REAL:
     real[] r = d.toList()
  /if

Assignement direct

Pour la compatibilité avec PHP, ajouter un élément à un tableau au-dela de la taille actuelle, a le même effet qu'ajouter cet élément, quelque soit l'index donné.
Par exemple:

 int[] i = nil
 i[10] = 10                         équivaut à:  i.push(10)

Empiler des valeurs est le moyen correct pour remplier un tableau.

Si on veut réellement placer un élément à une position donnée, on doit remplier le tableau avec des valeurs nulles...

 for int k in 0 .. 10 let i.push(0)

Vous pouvez maintenant placer un élément en position10.

Limitations et compatibilité

- On ne peut appliquer une méthode directement à un élément indicé.

  i[10].toText()    .. non valide
  int x = i[10]
  x.toText()         .. valide

- La fonction "array_diff" de PHP ne fonctionne pas quand le tableau contient des objets, on ne peut donc soustraire de tels tableaux.

File

File est un objet virtuel, pour traiter des fichiers locaux ou distant.
Pour une explication complète du système de fichier, voir "fopen" dans le manuel C ou PHP.
Un objet file est créé par la déclaration d'une instance de type file. Le fichier sur le disque est créé par la commande open. Elle permet d'accéder à un fichier en différents modes, selon le second paramètre de la méthode.
La structure de contrôle error permet de tester si le fichier a été ouvert correctement ou non.

Syntaxe pour créer ou ouvrir un fichier:

  file nomfic                 declare un file.
  nomfic.open(path, mode)     ouvre un fichier selon un chemin et un mode.

Types de chemins:
  http://path                    fichier distant http.
  ftp://path                      fichier distant ftp.
  path                             fichier local.

Modes:
  "r"            lecture seulement, à partir du début.
  "w"            écriture  seulement à partir du début.
  "r+"           lecture ou écriture au début du fichier.
  "a"            ajout en fin de fichier en écriture seule.
  "a+"           lecture à la position courante, ou écriture à la fin.

Les méthodes de fichier sont:

retour     méthode                  action

int        eof()                    retourne true quand la fin de fichier est atteinte.
int        open(text, text)         crée ou ouvre un fichier. Positionne le drapeau "error".
int        close()                  ferme le fichier.
text       read(int)                lit un bloc selon la taille en argument, retourne un text.
text       readLine()               lit et retourne la ligne suivante dans un fichier de texte.
int        seek(int)                va à la position donnée en argument, retourne 1 si ok.
int        size()                    retourne la taille du fichier.
int        time()                   retourne la date de dernière modification.
int        write(text)              écrit le texte donné en argument, retourne la taille écrite.
void       writeLine(text)         écrit le texte en argument.

Exemples:

file nomfic                       crée un objet file.
nomfic.open("monfichier", "r")        ouvre un fichier physique.
nomfic.close()                    ferme le file.
boolean b = nomfic.eof()         assigne vrai à b si la fin de fichier est atteint.
nomfic.seek(250)                 lecture ou écriture en sautant 250 octets.

Les fichiers distants ne sont pas gérés par Scriptol C++ et l'interpréteur pour l'instant.

Read

Un fichier peut être lu ligne par ligne, ou par blocks binaires.
Dans le premier cas, la méthode readLine() est utilisée, sinon, on utilise la méthode read avec la taille du bloc en paramètre.
Le code de fin de ligne dans le fichier est inclus, et peut être supprimé par la méthode rTrim().

Exemples:

text t = nomfic.readLine()            lecture d'une ligne de texte.
text t = nomfic.read(1000)           lecture de 1000 octets.

Write

La méthode write place le contenu d'une variable de texte dans un fichier. Une fois le fichier ouvert soit avec le mode "w" ou "a", et donc enregistré soit à partir de zéro ou à la fin de son contenu actuel, chaque nouvel appel à write ajoute un nouveau texte à la fin.

Exemple simple:

text nomfic = "monfic"                 // nom du fichier
file sortie                                  // nom de l'objet virtuel
sortie.open(nomfic, "w")               // ouvert en écriture
error? die("impossible d'ouvrir " + nomfic)
for text ligne in maliste              // un tableau quelconque
   sortie.write(ligne)                  // enregistrer un élément
/for
sortie.close()                         // fermer le fichier

XML

Du code XML standard peut être inséré dans un programme scriptol. Il sera convertit en tableau associatif. Une balise contenue dans une autre balise est convertir en dict comme élément d'un autre dict.

Le contenu textuel d'une balise est associé à la clé data dans le tableau associatif généré.

Exemple:

<xml id="car" speed=150 name="Spitfire">
<engine id="engine1" power=100 />
<passengers id="pass1" num=4 >
"Clara, Dana, Elisa, Farah"
</passengers>
</xml>

Ce code JavaScript est généré par le compilateur:

var car={
  "_00" : "car",
  "tag" : "xml",
  "speed":150,
  "name":"Spitfire",
  "engine1":{
    "tag": "engine",
    "power":100
  },
  "pass1":{
    "tag": "passengers",
    "num":4,
    "data":"Clara, Dana, Elisa, Farah"
  }
};

Ou ce code PHP:

$car=[
  "speed"=>150,
  "name"=>"Spitfire",
"engine"=>[ "power"=>100 ],
"passengers"=>[ "num"=>4,
"data"=>"Clara, Dana, Elisa, Farah" ] ];

Le tableau associatif peut aussi être transformé en document XML dans une variable de type text, que l'on peut sauver dans un fichier:

car.toXML().store("fichier.xml")

La structure de contrôle error

Après une instruction open, le construct error ... /error devrait être exécuté en cas d'erreur d'accès. Mais l'interpréteur peut stopper le programme avant d'atteindre le construct. Sinon le contenu du bloc sera exécuté en cas d'erreur.

La syntaxe est:

xxx.open("nom fichier")
error
      ...instructions...
/error
ou:
  xxx.open("nom fichier"); error ? action
ou:
  xxx.open("nom fichier"); error action

Exemple:

file monfic
monfic.open("nom", "r")
error? exit()

Si le fichier n'est pas trouvé ou ne peut être ouvert, le programme s'arrête.

Scopes

Les règles de visibilités sont celles des principaux langages procéduraux, non celles des langages de scripts.
Scriptol ajoute des règles de sureté, il ne permet pas de donner le même nom à deux objets dans les scopes imbriqués (par exemple, dans le scope global et celui d'une fonction). Mais les mêmes noms peuvent se réutiliser dans des scopes successifs.

Il y a quatre niveaux de visibilité: - global, - classe, - corps d'une fonction, - et le corps d'une structure de contrôle.

La visibilité d'une variable est le niveau dans lequel elle est déclarée: global, classe, fonction ou bloc délimité (if, do, for, etc.), ainsi que les niveaux contenus.

On ne peut redéclarer une variable là ou elle reste visible. On ne peut la redéclarer que quand son scope est clos, dans des fonctions successives ou des structures de contrôles successives.

L'en-tête du construct for fait partie du scope du bloc.

for text t in a                 // t est visible seulement dans la boucle for.
   t = a.inc()
/for

La partie let qui termine une boucle while est dans le scope de la boucle.
Les arguments d'une fonction sont dans le scope de la fonction.
A l'intérieur d'une fonction, si une variable est référencée avant tout assignement, elle reférence une variable globale si elle existe, sinon c'est une erreur.
A l'intérieur d'une méthode d'une classe, si elle est référencée avant tout assignement, elle référence un attribut s'il existe, sinon c'est une erreur.
Les variables globales ne sont pas visibles dans une classe, sauf les variables externes.

Les variables externes (celles de PHP, Apache, etc...) sont toujours dans le scope, puisqu'il n'y a pas de contrôle sur elles. Donc vous devez connaître leur nom pour ne pas le réutiliser, car les variables Scriptol sont transformée en variable PHP avec $ devant.
Si vous utilisez des variables externes dans une fonction, il faut les déclarer "global", car le compilateur ne les gère pas.

Variables, constantes et fonctions externes

Variables et constantes

Les variables et constantes de PHP peuvent être utilisées comme celles de Scriptol dès lors qu'elle sont déclarées avec le mot-clé "extern".
Les déclarations externes comme les includes sont placées en tête de fichier.

La syntaxe pour une variable externe est:

  extern type identifieur
  extern const type identifieur

Aucun test de contrôle sur le type ou le scope d'un objet externe. Dans une fonction il faut une déclaration "global".

Exemple:

  global argv
  array a = $argv

Une constante PHP est déclarée comme une variable avec le mot-clé const:

   extern const text PHP_VERSION
    ...
   print PHP_VERSION

Il est possible aussi d'utiliser une variable PHP ou C++ sans déclaration avec le préfixe $ suivie d'un identifieur.
Celui-ci peut commencer par un caractère de soulignement.

  $var_name
  $(constant_name)                          in PHP
  $constant_name.                           in C++

Fonctions externes

Les fonctions PHP peuvent être utilisées sans déclaration, ce qui n'est pas le cas des fonctions C++.
On peut aussi les déclarer avec le mot-clé extern. Une valeur par défaut est spécifiée par un assignement. Cette valeur est utilisée en C++, elle est ignorée par PHP.

Syntaxe et exemple:

  extern type identifieur(... arguments...)
  extern text substr(text, int, int = 0)

Classe externe

Pour utiliser les méthodes de classes PHP ou C++, vous devez déclarer ces classes et les membres que vous voulez utiliser.

Exemple:

extern
  class phpClass
     int phpAttribute
     void phpMethod(int argument)
     ... déclaration ...
  /class
/extern

Types externes

C++ permet de définir des types avec les directives "typedef" and "#define". Il est possible d'intégrer ces nouveaux types avec l'instruction Scriptol define.
Exemple: define uint
Cela correspond à "#define uint unsigned int" en C++.
Aucun code n'est généré par l'instruction define: le code C++ doit se trouver dans un fichier C++ à inclure. Voir "L'instruction define" pour plus de détails.

Insérer du code cible

Si vous vouler insérer directement du code PHP dans votre programme, utilisez les symboles ~~ pour définir le début et la fin du code à inclure.
Le compilateur ignore le contenu, comme s'il s'agissait de commentaires mais l'inclut dans le code généré, PHP, JavaScript ou C++.

Vous pouvez insérer du code spécifique PHP ou C++ dans un même programme.
- Pour insérer du code PHP, utiliser:
require_once("lecode.php")
Cette instruction n'a d'effet que pour l'interpréteur PHP, compilée en C++ elle est ignorée.
- Pour insérer du code C++, utiliser:
#include "lecode.c++"
Ce sera compilé en C++, mais pour l'interréteur PHP c'est un commentaire.

Class

Une classe est une structure qui contient des variables (attributs) et a des fonctions (méthodes).
Une fois qu'une classe est définie, elle devient un nouveau type complexe du langage avec lequel on déclare des objets, instances de la classe. On utilise les attributs et méthodes de l'objet avec une commande de la forme:

  x = objet.attribut
  objet.methode()

Définir une classe

La description d'une classe débute avec le mot-clé "class" et se termine par "/class".

Les attributs (variables) doivent être placés avant les fonctions. Une classe ouvre un espace de visibilité. Les variables globales et les fonctions définies ne sont pas visibles à l'intérieur d'une classe. Les attributs et méthodes de la classe ou d'une instance d'une autre classe sont visibles dans toutes les méthodes de la classe avec le nom de l'instance en préfixe.

Exemple d'une déclaration de classe:

class voiture
     ...membres...
  /class

Exemple de classe avec attributes et méthodes:

class voiture
      int lavitesse = 50
      int passagers = 4

      void voiture.vitesse(int i)
          int x = lavitesse * 2
      return x
  /class

Exemple d'instance avec référence aux méthodes:

voiture mavoiture
print mavoiture.passagers
print mavoiture.vitesse()

Constructeur et instance

Un constructeur est une méthode dont le nom est celui de la classe et qui est appelée lors de la création d'une instance de la classe.
Il a toujours le type de retour "void", qui signifie: rien.

Exemple de constructeur:

  class Voiture
      int vitesse

      void Voiture(int p)          // cette méthode est un constructeur
         vitesse = 0               //vitesse est initialisée lors de la déclaration d'une instance
      return
  /class

La syntaxe pour créer une instance est:
Nomclasse nominstance = Nomclasse(argument [, arguments])
ou:
Nomclasse nominstance pour un constructeur sans arguments

Example:

  Voiture mavoiture = Voiture(60)               ... crée une voiture avec une vitesse de 60
  Camion moncamion                      ... equivalent à ci-dessous
  Camion moncamion = Camion()

Méthodes et attributs statiques

Il peut être pratique de rassembler toutes les fonctions concernant une tâche dans une classe et les déclarer "static". Ces fonctions peuvent alors être appelées directement avec le nom de la classe, sans avoir à créer d'instance.

Exemple:

  node, ext = Dir.splitExt(chemin)

Les attributs peuvent également être statiques. Un attribut statique est commun à toutes les instances et celles qui sont héritées. Une méthode statique ne peut référencer des attributs, puisqu'ils n'existent que dans les instances de la classe sauf s'ils sont statiques aussi.
On ne peut appeler une autre méthode dans le corps d'une méthode statique..
Le mot-clé "static" doit précéder le type de l'objet.
Un message d'erreur est émis quand une fonction statique utilise un attribut non statique ou qu'elle appelle une autre méthode.

Exemple d'attributs et méthodes statiques:

  class Voiture
    static usine = "Xxx"
    static void denomme(text x)
      usine = x
    return
  /class

  Voiture.denomme("nom")
  Voiture.usine = "nom"

Attributes et méthodes statiques peuvent être associés à une instance également:

  Voiture maVoiture
  maVoiture.denomme("nom")
  maVoiture.usine = "nom"

L'effet sera le même.

Héritage

Une classe peut hériter des attributs et méthodes d'une autre classe, si elle est déclarée sous-classe de celle-ci.
La classe "nom" hérite des attributs et méthodes de "autrenom". Cela fonctionne aussi avec les attributes et méthodes statiques.

La syntaxe de la déclaration d'héritage est:

  class nom is autrenom

Exemple:

  class Vehicule
    int fuel
    void Vehicule()
     fuel = 100
    return
  /class

  class Voiture is Vehicule
    int passagers
    void Voiture()
       passagers = 3
       fuel = 50
    return
  /class

  class Camion is Vehicule
    int charge
    void Camion()
      fuel = 200
      charge = 1000
     return
 /class

  Camion bibendum
  Voiture daisy
  print bibendum.charge         attribut de la classe Camion
  print bibendum.fuel             attribut de la superclasse Vehicule
  print bibendum.passagers     mauvais! passagers non accessible à Camion!
  print daisy.passagers          bon, passagers est attribut de Voiture

Surcharge

Une méthode peut être redéfinie avec des arguments différents, à la fois dans la même classe et dans les classes dérivées. Le type de retour de toutes les versions de la méthode doit être le même.

Exemple:

  void ajoute(int x, int y)
  void ajoute(real x, natural y)

Vous avez juste à appeler la méthode "ajoute" avec le type d'arguments voulus, le compilateur associe la définition correspondante...
Le langage cible C++ requiert que les méthodes surchargées aient le même type de retour, cela est conservé en Scriptol.

Include

La syntaxe pour inclure un fichier Scriptol externe est:

include "nomfichier.sol"

Les parenthèses sont optionnelles. Les guillemets simples ou doubles sont requis. Si vous voulez utiliser directement un fichier PHP, et que le compilateur ne le traite pas, utilisez l'extension PHP.
Seuls les fichiers avec l'extension ".sol" seront traités par les compilateur, si elle est différente:

Exemples:

include "exemple.php"
include "exemple.js

Le fichier PHP sera ignoré par le code JavaScript et le fichier JS sera ignoré par le code PHP.

Quand du code scriptol est inséré dans une page HTML, le contenu d'un fichier à inclure doit être placé à l'intérieur des balises <scriptol> et </scriptol>, même si le fichier ne contient que du code scriptol. Le code généré pour une page HTML peut être différent.

Utiliser une fonction comme argument

Vous pouvez utiliser une fonction comme argument d'une autre fonction en la définissant en tant que type. Cela ne fonctionne qu'au niveau global et pas dans une classe. Une fois un type défini, on ne peut le redéfinir.

1) définir une fonction:
Exemple:

  int compare(int a, int b)
    boolean b = (a < b)
  return b

2) Utiliser le type function comme argument:

  void mafonc(function a, int x, int y)
    print a(x,y)
  return

3) utiliser la fonction générique:
L'argument peut être la fonction originelle ou une autre fonction avec mêmes arguments et même types de retour.

  mafonc(compare, 10, 8)

Utiliser un type externe

La syntaxe:
define NOUVEAUTYPE
define NOUVEAUTYPE as
crée un nouveau type que l'on peut utiliser en argument de fonctions externes. Voir les exemples GTK sur l'utilisation d'un type externe.
Le modificateur "as" fait que le nouveau type n'est pas considéré comme un pointeur. Donc l'utiliser comme une primitive, comme uint ou gint par exemple.

Utiliser les librairies standards

Librairies PHP

Scriptol peut utiliser les fonctions PHP. Aucun contrôle n'est effectué sur les arguments et types de retour des fonctions PHP.
Il faut juste configurer php.ini pour rendre les extensions visibles à l'interpréteur PHP.
Les fonctions PHP les plus usuelles sont incluses dans la librairie Scriptol.
Pour utiliser les fonctions de librairies PHP dans un programme exécutable, il faudra écrire une interface à inclure dans le projet. phpgd.h et phpgd.cpp en est un exemple.

Librairies C

Une bibliothèque de fonctions en C ou C++, peut être utilisée simplement par l'ajout du fichier ".lib" ou ".a" ou ".so" à la liste dans le fichier de configuration ".ini" ou ".cfg".
Un fichier à inclure doit être écrit pour rendre visible au compilateur les variables et les classes de l'extension ajoutée.
L'instruction "define" permet de créer un type pour donner une fonction en paramètre d'une autre fonction.

Il est possible de déclarer directement des variables C:

  extern
     ~~extern char *message~~      pour le fichier d'en-tête.
     char *message                      pour la visibilité en scriptol.
  /extern

  ~~char *message~~              création effective de la variable C.

Equivalences:

C                       Scriptol
char *                  cstring
void *                  object
char **                 cstring *
unsigned char           byte

- Un nom de fonction foncname en argument est écrit "foncname", voir define.
- Une fonction interne ne peut être utilisée en argument. Il faut l'encapsuler dans une fonction définie par l'utilisateur.
- Si une instance est déclarée sous la forme C++: NomClasse instance, il faut créer un pointeur plutôt (selon la forme C++: NomClasse *instance).

Fonctions usuelles

Ces fonctions sont communes à PHP, C, C++ et Scriptol. Si le nom PHP diffère, il est donné dans la liste.

La liste complète est dans le fichier fun.hpp.

void die(text message)       Affiche un message en quittant le programme.
void exit()                  Quitte le programme. Peut afficher un message.
number min(number, number)   Retourne le plus petit de deux scalaires.
number max(number, number)   Retourne le plus grand de deux scalaires.
const cstring plural(int x)  Retourne le pluriel "s" si le nombre x > 0.
array range(int x, int y)    Génère un tableau des entiers compris entre x et y.
cstring str(number)          Convertit un nombre en chaîne de charactères.
void swap(var, var)          Echange le contenu de deux variables.
text pad(text t, len l , text c  [, int o]])
  Complète un texte avec des espaces ou la chaîne de caractères donnée.
  t: text à compléter.     l: longueur à atteindre.
  c: texte à ajouter, des espaces par défaut.
  o: option STR_PAD_LEFT, STR_PAD_BOTH, par défaut à droite. (Voir: str_pad)

Casting

text chr(integer)              Retourne le charactère pour une valeur ASCII.
                               Ex: chr(32) retourne un espace blanc.
int ord(text)                  Retourne la valeur ASCII d'un charactère.
int intval(any)
int doubleval(any)
natural naturalval(any) 
text strval(any)               Convertit un nombre en text. 
char *str(any)                 Convertit un nombre en chaîne de charactères C. 
boolean boolval(int) 

Fonctions de fichiers (voir aussi les méthodes du type File):

void exec(text)               Passe une commande au système d'exploitation.
boolean file_exists(text)     Teste si le fichier dont le nom est en argument existe.
number filesize(text)         Retourne la taille.
number filetime(text)         Retourne la taille (utiliser la fonction date pour afficher).
text filetype(text)           Retourne "dir" ou "file".
boolean rename(text, text)    Renomme un fichier. Retourne faux en cas d'échec.
void system(text commande)    Passe une commande au système d'exploitation.
boolean unlink(text)          Efface un fichier. Retourne true si effacé.
var require(text)             Déclare un module externe (JavaScript seulement).

Fonctions de répertoire:

boolean chdir(text)          Change le répertoire courant. Retourne false si échec.
boolean mkdir(text)          Crée un sous-répertoire. Retourne true si créé.
boolean rmdir(text)          Efface un sous-répertoire. Retourne true si éffacé.
text getcwd()                Retourne le chemin répertoire courant.

Fonctions mathématiques:

number  abs(number)          Retourne la valeur absolue d'un nombre.
real       acos(real)
real        asin(real)
real       atan(real)
number  ceil(number)         Retourne le nombre arrondi à l'entier supérieur.
real       cos(real)
real       exp(real)
number  floor(number)        Retourne le nombre arrondit à l'entier inférieur.
number  fmod(number, number) Return le modulo de deux nombres.
real       log(real)
number  pow(number, number)  Retourne la puissance n d'un nombre.
int        rand()            Retourne un nombre aléatoire.
void      randomize()        Démarre une séquence de nombres aléatoires.
real       round(real)       Arrondi au plus proche, plancher ou plafond.
real       sin(real)
number  sqrt(number)         Retourne la racine d'un nombre.
real       tan(real)

Fonctions de temps:

int         time()           Temps en millisecondes depuis le 1 Janvier 1970.
dict       localtime()       Temps et date courant lors de l'appel, dans un dictionaire, voir ci-dessous.

Clé du dict retourné par localtime:

tm_sec                  Secondes après la minute  [0,61]
tm_min                  Minutes après l'heure    [0,59]
tm_hour                 Heures après minuit      [0,23]
tm_mday                 Jour du mois          [1,31]
tm_mon                  Mois à partir de Janvier      [0,11]

tm_year                 Année depuis 1900
tm_wday                 Jour à partir de Dimanche         [0,6]
tm_yday                 Jour depuis le 1 Janvier     [0,365]
tm_isdst                Indicateur d'heure d'hivers

Gestion des exceptions

Le traitement des exceptions requiert une définition externe. Syntaxe:

  extern
     class exception
       string what()
     /class
  /extern

  try
     ... quelques instructions ...
  catch(exception e)
     print e.what()
  /try

Appendice: mots-clés

Des mots peuvent être réservés pour le langage cible mais ne font pas partie de Scriptol.

alias always and array await as async
bool boolean break byte
case catch char class const continue
define dict do
echo else enum error exception
false file finally float for forever from function
global
if import in include int integer is
let long
mod
nan natural new nil not null number
or
print private protected public
react real return
script scriptol sol static step super switch
text this to true try
undefined until
var void
while
yield
zero


© 2001-2017 Denis Sureau.