La Syntaxe

Pour Haxe toutes les expressions ont le même poids. Cela veut dire qu'il est possible de les emboiter sans problème. L'expression,"foo(if (x==3) 5 else 8)", est donc parfaitement valide. Cette exemple montre aussi que toutes les expressions retournent une valeur d'un type donné.

Constantes

Les constantes suivantes peuvent être directement utilisées dans Haxe:

0; // Int
-134; // Int
0xFF00; // Int

123.0; // Float
.14179; // Float
13e50; // Float
-1e-99; // Float

"hello"; // String
"hello \"world\" !"; // String
'hello "world" !'; // String

true; // Bool
false; // Bool

null; // Unknown<0>

~/[a-z]+/i; // EReg : Expression Régulière

Vous noterez que null est spécial et peut être utilisé pour n'importe quel type. Il a un comportement différent de celui du type Dynamic. Ce point sera développé plus en détails dans le chapitre introductif sur l'inférence de type.

Operations

Les opérations suivantes peuvent être utilisées dans Haxe (elles sont présentées par ordre de priorité) :

  • v = e : assigne une valeur à une expression, retourne ici e
  • += -= *= /= %= &= |= ^= <<= >>= >>>= : assigne après avoir effectué l'opération correspondante
  • e1 || e2 : Si e1 est true alors true sinon évalue e2 . e1 et e2 doivent tous deux être du type Bool.
  • e1 && e2 : Si e1 est false alors false sinon evalue e2 . e1 et e2 doivent tous deux être du type Bool.
  • e1...e2 : Construit un itérateur d'entiers (voir plus loin le chapitre sur les itérateurs).
  • == != > < >= <= : effectue une comparaison classique ou physique entre deux expressions du même type, retourne une valeur du type Bool.
  • | & ^ : Effectue les opérations correspondantes au niveau du bit entre deux Int', retourne un Int''.
  • << >> >>> : Effectue les glissements de bits correspondants entre deux Int, retourne un Int.
  • e1 + e2 : Additionne les deux valeurs retournées par les expressions e1 et e2. Si les deux valeurs sont des Int, retourne un Int. Si une valeur est du type Int et l'autre du type Float, retourne un Float. Dans les autres cas, retourne un String.
  • e1 - e2 : Soustrait les deux valeurs retournées par les expressions e1 et e2. Si les deux valeurs sont des Int, retourne un Int. Si une valeur est du type Int et l'autre du type Float, retourne un Float.
  • e1 * e2 : Multiplie les deux valeurs numériques retournées par les expressions e1 et e2. Les règles de retour sont celles de la soustraction.
  • e1 / e2 : Divise deux nombre, returne un Float.
  • e1 % e2 : Retourne le modulo de deux nombres en respectant les règles de la soustraction.

Operations Unaires

Les opérations unaires sont possibles dans Haxe :

  • ! : Opération binaire not. Inverse la valeur booléenne de l'expression.
  • - : Nombre négatif, change le signe d'un Float ou d'un Int.
  • ++ et -- peuvent être positionnés avant ou après une expression. En pré-position, retourne la valeur incrémentée de l'expression. En post-position, retourne la valeur de l'expression et incrémente seulement après. Ces opérations ne peuvent être utilisées que sur les Int et les Float.
  • ~ : complémentaire binaire d'un Int.

Note: ~ est habituellement utilisé pour les entiers sur 32 bits. Il ne produira donc pas les resultats attendus avec Neko 31-bits, c'est pour cela qu'il ne fonctionne pas avec Neko.

Parenthèses

Les expressions peuvent être entourées de parenthèses afin de lui donner une priorité spéciale lors de l'évaluation. Le type de (e) est le même que celui de e et retournent la même valeur.

Blocs

Les blocs exécutent plusieurs expressions. La syntaxe d'un bloc est la suivante :

{
    e1;
    e2;
        // ...
    eX;
}

Un bloc retourne la valeur, et est du type, de la dernière expression qu'elle contient. Par exemple :

{ f(); x = 124; true; }

Ce bloc est du type Bool et est évalué à true.

Le bloc vide {} est une exception. Il est évalué en tant que Void.

Variables locales

Les variables locales peuvent être déclarées dans un bloc en utilisant l'instruction var, comme dans l'exemple suivant :

{
    var x;
    var y = 3;
    var z : String;
    var w : String = "";
    var a, b : Bool, c : Int = 0;
}

Une variable peut être déclarée avec un type et une valeur optionels. Sans valeur, la variable est initialisée comme null. Sans type, la variable est initialisée comme du type Unknown mais est strictement typée. Plus de détails sont donnés dans l'introduction à l'inférence de type.

Plusieurs variables peuvent être déclarées en même temps dans la même expression.

Les variables locales ne sont accessibles qu'à l'intérieur du bloc dans lequel elles ont été déclarées.

Identificateurs

Quand un identificateur est rencontré, il est résolu avec les règles suivantes, dans l'ordre :

  • L'identificateur est la dernière variable locale ayant la priorité
  • L'identificateur est le membre d'une classe (celui de la classe courante ou appartenant à une classe héritée)
  • L'identificateur est un champ static de la classe courante
  • L'identificateur est un constructeur d'une énumération qui a été déclarée dans le même fichier ou qui a été importée.
    enum Axis {
        x;
        y;
        z;
    }

    class C {
        static var x : Int;
        var x : Int;

        function new() {
            {
               // x est ici le membre de la classe : this.x
                var x : String;
                // maintenant x est la variable locale déclarée dans le bloc 
            }
        }

        function f(x : String) {
            // ici x est le paramètre de la fonction
        }

        static function f() {
            // x est ici la variable statique
        }
    }

    class D {
        function new() {
            // x fait référence eu constructeur de l'énumération: l'axe x
        }
    }

Le type des identificateurs est résolu en fonction des paquets importés (voir un peu plus loin).

Acces aux champs

Les objets sont accessibles avec la notation classique par point :

    o.field

Appels

Les fonctions sont appellées en utilisant des parenthèses et en séparant les arguments par des virgules. Les méthodes sont accessibles en utilisation un point :

    f(1,2,3);
    objet.methode(1,2,3);

New

L'instruction new est utilisée dans une expression pour créer une instance d'une classe. Elle requiert un identificateur de classe et accepte des paramètres.

    a = new Array();
    s = new String("hello");

Tableaux

Il est possible de créer un tableau à partir d'une liste de valeurs en utilisant la syntaxe suivante :

    var a : Array<Int> = [1,2,3,4];

Il faut noter que le type Array requiert un paramètre de type qui détermine le type des éléments du tableau. De cette manière, toutes les opérations sur les tableaux sont sécurisées. Par conséquent, tous les éléments d'un tableau doivent avoir le même type :

L'accès aux éléments du tableau se fait par l'intermédiaire de la notation classique avec des crochets :

    premier = a[0];
    a[1] = valeurDuSecond;

L'indexation se fait par un entier du type Int.

If

Voici quelques exemples de conditions avec if :

    if (vies == 0) poubelle();
    if (drapeau) 1 else 2;

Voici la syntaxe générique pour if :

    if( expr-cond ) expr-1 [else expr-2]

L'expression expr-cond est évaluée en premier. Elle doit être du type Bool. Si elle est true alors expr-1 est évaluée, sinon if expr-2 est évaluée dans le cas où elle est présente.

S'il n'existe pas de else et que l'expression conditionnelle est false alors l'expresson if est du type Void. Si else est renseignée, alors les expressions expr-1 et expr-2 doivent être du même type et sera le type de l'expression if :

    var x : Void = if( drapeau ) poubelle();
    var y : Int = if( drapeau ) 1 else 2;

Le if de Haxe est similaire à l'expression a?b:c en C.

Il existe cependant une souplesse. Si l'expression if n'est pas supposée retourner de valeur (comme au milieu d'un bloc), les deux expressions expr-1 et expr-2 peuvent avoir des types différents. L'expression, dans ce cas, if sera du type Void.

While

Les boucles while sont standard et requièrent soit une pré-condition, soit une post-condition :

    while( expr-cond ) expr-loop;
    do expr-loop while( expr-cond );

Un exemple de pré-condition :

    var i = 0;
    while( i < 10 ) {
        // ...
        i++;
    }

Un exemple de post-condition :

    var i = 0;
    do {
        // ...
        i++;
    } while( i < 10 );

Comme dans l'expression if, l'expression expr-cond doit être du type Bool.

Voici un autre exemple permettant de décrémenter de 10 à 1 :

    var i = 10;
    while( i > 0 ) {
    .......
    i--;
    }

For

Les boucles for sont un peu différentes de leur homologues en C. Elles sont utilisées actuellement pour les itérations introduites plus loin dans un chapitre dédié. Voici un exemple d'itération avec la boucle for :

    for( i in 0...a.length ) {
        foo(a[i]);
    }

Return

L'instruction return est utilisée pour sortir d'une fonction avant la fin du bloc ou pour que la fonction retourne une valeur :

    function paire( x : Int ) : Bool {
        if( x % 2 != 0 )
            return true;
        return false;
    }

return peut être utilisée sans argument si la fonction n'a pas besoin de retourner une valeur :

    function foo() : Void {
        // ...
        if( abandon )
            return;
        // ....
    }

Break et Continue

Les deux instructions break et continue sont utilisées pour sortir et sauter, à l'itération suivante, prématurément dans une boucle :

    var i = 0;
    while( i < 10 ) {
        if( i == 7 )
            continue; // saute l'itération en cours sans évaluer 
            // les expressions suivantes mais continue 
            // l'évaluation de la boucle while
        if( drapeau )
            break; // sort de la boucle definitivement en ignorant 
            // les éventuelles expressions suivantes
    }

Exceptions

Les exceptions sont un moyen de faire des sauts non locaux. Il est possible de surveiller une exception et de la traiter depuis n'importe quel appel de fonction du bloc mémoire :

    function foo() {
        // ...
        throw new Error("invalide fonction foo");
    }

    // ...

    try {
        foo();
    } catch( e : Error ) {
        // handle exception
    }

Il peut y avoir plusieurs catch après un try pour traiter différents types d'exceptions. Les exceptions sont testées dans leur ordre de déclaration. Traiter Dynamic permet d'agir sur toutes les exceptions qui n'ont pas déjà été déclarées :

    try {
        foo();
    } catch( e : String ) {
        // Traite ce type d'erreur
    } catch( e : Error ) {
        // Traite un autre type d'erreur
    } catch( e : Dynamic ) {
        // Traite toutes les autres exeptions
    }

Toutes les expressions try et catch doivent retourner le même type sauf si aucune valeur de retour n'est requise (comme pour if).

Switch

Les commutations sont un moyen de simplifier les expressions if...else if...else if ... successives testant la même variable :

    if( v == 0 )
        e1
    else if( v == foo(1) )
        e2
    else if( v == 65 )
        e3
    else
        e4;

Sera traduit par :

    switch( v ) {
    case 0:
        e1;
    case foo(1):
        e2;
    case 65:
        e3;
    default:
        e4;
    }

Les commutations dans Haxe sont différentes de leur équivalents dans d'autres langages par le fait que toutes les expressions case sont cloisonnées - lorsqu'une expression case est évaluée, la commutation entière est terminée. L'instruction break est par conséquent inutile et la position de default n'a pas importance.

Pour certaines plateformes, l'expression switch a été optimisées pour des tests sur des valeurs constantes (particulièrement les valeurs constantes d'entiers) et sera donc plus rapide à l'exécution.

Les commutations peuvent être utilisées sur les constructions d'une énumération avec une sémantique différente (voir le chapitre dédié).

Fonctions locales

Les fonctions locales (lambda pour ceux qui en ont l'habitude) sont déclarées en utilisant l'instruction function. Mais elle ne peuvent être nommées. Ce sont des valeurs tout comme le sont les entiers ou les chaines de caractères :

    var f = function() { /* ... */ };
    f(); // appel de la fonction

Les fonction locales ont accès à leur paramètres, aux champs statiques de la classe courante et aux variables locales déclarées avant elles :

    var x = 10;
    var additionnerAX = function(n) { x += n; };
    additionnerAX(2);
    additionnerAX(3);
    // x vaut maintenant 15

Cependant, les fonction locales déclarée dans des méthodes ne peuvent avoir accès à la valeur de this. Pour y parvenir, il faut déclarer une variable locale tampon :

    class C {

        var x : Int;

        function f() {
            // provoquera une erreur de compilation
            var additionnerAX = function(n) { this.x += n };
        }

        function f2() {
            // Pas de problème de compilation ici
            var me = this;
            var add = function(n) { me.x += n };
        }
    }

Objets anonymes

Les objets anonymes peuvent être déclarés comme suit :

    var o = { age : 26, nom : "Tom" };

Note : Grâce à l'inférence de type, les objets anonymes sont strictement typés.

«« Types Basiques - L'Inférence de type »»

version #9270, modified 2010-09-30 10:20:36 by plonstic