Ajouter une expression

Pour créer une nouvelle expression, commencez par créer une nouvelle classe qui héritera de la classe ScriptExpression. Puis, implémentez les méthodes abstraites de la classe mère. Jusqu'ici, l'expression nouvellement créée n'a aucune utilité. Comme pour les types, il faut l'enregistrer, via l'annotation @Expression. Cette annotation est légèrement plus complexe à compléter.

Premièrement, il faut fournir un nom, une description et des exemples d'usage de l'expression. Ces paramètres servent uniquement à la génération de documentation et à une meilleure lecture du code. En effet, plusieurs expressions peuvent être reconnues par une même classe, le nom doit donc être le plus générique possible.

La partie la plus importante concerne les patterns. Il faut en fournir un par expression à créer, en notant l'ordre dans lequel ils sont ajoutés. C'est cet ordre qui permet de savoir quel pattern est à traiter. Pour rappel, la syntaxe pour les expressions est : pattern:type de retour. Par exemple, le pattern type of {element}:string retournera une chaîne de caractère.


La méthode la plus importante à implémenter est la méthode get(ScriptContext, ScriptType[]). C'est elle qui permet de retourner un élément en particulier. La méthode set(ScriptContext, ScriptType, ScriptType[]) permet de mettre à jour la valeur de l'expression lorsque l'action set sera appelée. Dans les deux cas, la première étape est de savoir quel pattern a été reconnu, afin d'adapter notre code. Le plus simple est d'utiliser un switch sur la valeur de retour de la méthode getMatchedIndex():

    @Override
    public ScriptType get(ScriptContext context, ScriptType[] parameters) {
        switch(getMatchedIndex()){
            case 1:
                //C'est le premier pattern qui a été reconnu.
                ...
            case 2:
                //C'est le deuxième pattern qui a été reconnu.
               ...
            etc.
        }
    }

Pour obtenir les références aux paramètres renseignés dans le pattern, on utilise l'argument parameters, qui est une liste contenant les éléments, dans l'ordre, renseignés dans le pattern. Par exemple, dans le pattern type of {element}:string, parameters[0] retournera l'élément passé à l'expression dans le script (les listes en java commencent à l'indice 0).

La deuxième méthode à implémenter pour les expressions est la méthode set(ScriptContext, ScriptType, ScriptType[]). Elle permet de mettre à jour une valeur lors du passage de l'expression dans l'action set. De la même manière, récupère le pattern reconnu, puis en fonction de ce dernier on effectue les changements sur les variables passées en paramètres. Si l'expression ou un pattern en particulier ne peut pas être modifié, il faut retourner la valeur false, sinon, une fois le changement effectué, il faut retourner true. Dans le cas où la valeur retournée est false, une erreur est levée car l'expression n'est pas censée être modifiée par l'action set.

Par exemple, voici une classe ScriptExpression complète :

@Expression(name = "Types", //On définit un nom général pour la classe.
        description = "Manipulate the type of a variable", //On décrit ce à quoi l'expression peut servir.
        examples = "type of \"test\"", //On donne un ou plusieurs exemples.
        patterns = { 
            "type of {element}:string", //On définit le pattern n°0 qui retournera le type du premier paramètre.
            "{element} parsed as {string}:element" //On définit le pattern n°1 qui retourne un element qui sera le premier paramètre parsé selon le type fourni en deuxième paramètre.sam
        })
public class ExprTypeOf extends ScriptExpression{

    @Override
    public ScriptType get(ScriptContext context, ScriptType[] parameters) {
        switch(getMatchedIndex()){ //On regarde quel pattern a été reconnu.
            case 0: //Si c'est le premier, on retourne le nom du type du premier paramètre.
                return new TypeString(ScriptType.getTypeName(parameters[0].getClass()));
            case 1: //Si c'est le deuxième pattern,
                ScriptType parameter_element = parameters[0]; //On récupère le premier paramètre.
                TypeString parameter_string = (TypeString) parameters[1]; //On récupère le second paramètre.
                return (ScriptType) parameter_element.parse(parameter_string.getObject()); //On retourne le premier paramètre parsé selon le deuxième paramètre.
        }
        return null; //Sinon, on retourne null;
    }

    @Override
    public boolean set(ScriptContext context, ScriptType to,ScriptType[] parameters) throws ScriptException.ScriptUndefinedReferenceException {
        return false; //Aucun de nos patterns ne peut modifier une valeur d'un paramètre, on retourne donc false dans tous les cas.
    }
}