[JAVA] 18 Correspond à la définition d'objet de type JSON

introduction

Je souhaite prendre en charge les définitions d'objets de type JSON. Cet article est une suite de "Correspondant à Array".

Ce que vous voulez faire avec la prise en charge de la définition d'objet de type JSON

Confirmez ce que vous voulez faire avec une définition d'objet de type JSON. Par exemple, il existe le programme suivant. Créez un objet sur la première ligne et affectez-le à la variable ʻobj`. La 5ème ligne affiche le nombre d'éléments «2» de l'objet. Dans la 6ème ligne, nous visons à afficher la valeur correspondant à l'objet «key2», «value2» «.

var obj = {
  "key1": "value1",
  "key2": "value2",
}
println(obj.size())
println(obj["key2"])

Il ne prend pas en charge l'accès aux valeurs par «.» Comme «obj.key2».

Comment mettre en œuvre

Nous examinerons comment l'implémenter dans l'ordre de l'analyse des phrases (Lexer), de l'analyse syntaxique (Parser) et de l'interpréteur (Interpreter).

Comment implémenter l'analyse de phrases (Lexer)

Puisqu'il n'y a pas de fonction à analyser :, ajoutez-le.

Comment implémenter l'analyseur

Les implémentations pour l'analyse syntaxique correspondent à la syntaxe de génération des définitions d'objets. La syntaxe pour accéder aux éléments d'un objet est couverte par la correspondance avec la syntaxe pour accéder au tableau précédent.

La syntaxe de création d'un objet commence par un jeton {. Implémentez-le dans la méthode lead (), tout comme l'autre premier jeton est déterminé syntaxiquement.

Comment implémenter Interpreter

J'ai décidé d'utiliser LinkedHashMap <String, Object> comme objet réel.

Le traitement de la syntaxe implémente la création de l'objet et l'accès aux éléments de l'objet. Lors de la génération d'objets, LinkedHashMap <String, Object> est généré et des éléments sont ajoutés. Pour accéder à l'élément objet, appelez la méthode LinkedHashMap <String, Object> :: get ().

Essayez de mettre en œuvre en Java

Passez à la mise en œuvre. À propos de l'analyse de phrases (Lexer), de l'analyse syntaxique (Parser), de l'interpréteur (Interpreter) Jetons un coup d'œil aux modifications et aux ajouts dans l'ordre.

Lexer.java

Une implémentation de Lexer.java.

Ajoute la fonction d'analyse de phrase de :.

ʻJe change la méthode SymbolStart () `. Ajout de la détection de «:».

Lexer.java


    private boolean isSymbolStart(char c) {
        // Update
        return c == ',' || c == ':';
    }

C'est tout pour changer Lexer.java.

Parser.java

Une implémentation de Parser.java.

Implémente l'analyse syntaxique de la syntaxe de création d'objets. De la méthode lead () qui implémente la syntaxe déterminée par le premier jeton Ajout d'un appel à la méthode newMap () qui effectue une analyse de la syntaxe de création d'objet à // Add.

Parser.java


    private Token lead(Token token) throws Exception {
        if (token.kind.equals("ident") && token.value.equals("function")) {
            return func(token);
        } else if (token.kind.equals("ident") && token.value.equals("return")) {
            token.kind = "ret";
            if (!token().kind.equals("eob")) {
                token.left = expression(0);
            }
            return token;
        } else if (token.kind.equals("ident") && token.value.equals("if")) {
            return if_(token);
        } else if (token.kind.equals("ident") && token.value.equals("while")) {
            return while_(token);
        } else if (token.kind.equals("ident") && token.value.equals("break")) {
            token.kind = "brk";
            return token;
        } else if (token.kind.equals("ident") && token.value.equals("var")) {
            return var(token);
        } else if (factorKinds.contains(token.kind)) {
            return token;
        } else if (unaryOperators.contains(token.value)) {
            token.kind = "unary";
            token.left = expression(70);
            return token;
        } else if (token.kind.equals("paren") && token.value.equals("(")) {
            Token expr = expression(0);
            consume(")");
            return expr;
        } else if (token.kind.equals("bracket") && token.value.equals("[")) {
            return newArray(token);
            // Add
        } else if (token.kind.equals("curly") && token.value.equals("{")) {
            return newMap(token);
        } else {
            throw new Exception("The token cannot place there.");
        }
    }

Ajout de la méthode newMap () pour effectuer une analyse de la syntaxe de création d'objets. Collectez les éléments séparés par , dans les params du jeton { jusqu'à ce que le jeton} soit atteint. L'élément contient l'élément clé dans la «gauche» du jeton «:» et l'élément de valeur dans la «droite». Ajoutez le jeton ":" aux params du jeton {. Le type de jeton «kind» est défini sur «newMap». Si le dernier élément est vide, comme [{" key1 ":" value1 "}, {" key2 ":" value2 "},] J'ai essayé de l'ignorer en tant qu'élément.

Parser.java


    private Token newMap(Token token) throws Exception {
        token.kind = "newMap";
        token.params = new ArrayList<Token>();
        while(true) {
            if (token().value.equals("}")) {
                consume("}");
                break;
            }
            Token key = expression(0);
            Token colon = consume(":");
            colon.left = key;
            token.params.add(colon);
            if (token().value.equals(",")) {
                colon.right = blank;
                consume(",");
                continue;
            }
            colon.right = expression(0);
            if (token().value.equals(",")) {
                consume(",");
                continue;
            } else {
                consume("}");
                break;
            }
        }
        return token;
    }

C'est tout pour changer Parser.java.

Interpreter.java

Une implémentation d'Interpreter.java.

Modification de la méthode ʻExpression () . C'est un processus qui se ramifie en fonction de la signification (sorte) du jeton qui représente l'expression. Ajout d'un appel de méthode newMap ()pour la création d'objet sous// Add. Changement de la méthode ʻaccessArray () pour l'accès aux tableaux sous // Update par la méthode ʻaccessArrayOrMap () `. En effet, la méthode a désormais à la fois un accès au tableau et un accès aux objets.

Interpreter.java


    public Object expression(Token expr) throws Exception {
        if (expr.kind.equals("digit")) {
            return digit(expr);
        } else if (expr.kind.equals("string")) {
            return string(expr);
        } else if (expr.kind.equals("ident")) {
            return ident(expr);
        } else if (expr.kind.equals("blank")) {
            return blank(expr);
            // Add
        } else if (expr.kind.equals("newMap")) {
            return newMap(expr);
        } else if (expr.kind.equals("newArray")) {
            return newArray(expr);
            // Update
        } else if (expr.kind.equals("bracket")) {
            return accessArrayOrMap(expr);
        } else if (expr.kind.equals("func")) {
            return func(expr);
        } else if (expr.kind.equals("fexpr")) {
            return fexpr(expr);
        } else if (expr.kind.equals("paren")) {
            return invoke(expr);
        } else if (expr.kind.equals("sign") && expr.value.equals("=")) {
            return assign(expr);
        } else if (expr.kind.equals("unary")) {
            return unaryCalc(expr);
        } else if (expr.kind.equals("sign")) {
            return calc(expr);
        } else if (expr.kind.equals("dot")) {
            return dot(expr);
        } else {
            throw new Exception("Expression error");
        }
    }

Ajout de la méthode newMap () pour la création d'objets. Génère LinkedHashMap <String, Object>, ajoute un élément et le renvoie.

Interpreter.java


    public Object newMap(Token expr) throws Exception {
        Map<String, Object> m = new LinkedHashMap<>();
        for (Token item : expr.params) {
            String key = identOrString(item.left);
            Object value = value(expression(item.right));
            m.put(key, value);
        }
        return m;
    }

Ajout d'une méthode ʻidentOrString () qui garantit que le jeton d'argument est valide comme clé de l'objet. Utilisé dans la méthode newMap ()` ci-dessus. Si le jeton d'argument lui-même est un identificateur ou si le résultat de l'exécution du jeton d'argument est «String», il est valide.

Interpreter.java


    public String identOrString(Token expr) throws Exception {
        if (expr.kind.equals("ident")) {
            return expr.value;
        } else {
            return string(expression(expr));
        }
    }

Changement de la méthode value () de la méthode qui garantit que l'argument est une valeur. Le premier // Add autorise maintenant` Map <String, Object> ʻen tant que valeur.

Interpreter.java


    public Object value(Object value) throws Exception {
        if (value instanceof Integer) {
            return value;
        } else if (value instanceof String) {
            return value;
        } else if (value instanceof List<?>) {
            return value;
            // Add
        } else if (value instanceof Map<?, ?>) {
            return value;
        } else if (value == null) {
            return value;
        } else if (value instanceof Func) {
            return value;
        } else if (value instanceof Variable) {
            Variable v = (Variable) value;
            return value(v.value);
        }
        throw new Exception("right value error");
    }

La méthode ʻaccessArray () pour l'accès aux tableaux, Changé en méthode ʻaccessArrayOrMap () pour l'accès aux tableaux ou aux objets. L'argument ʻexpr reçoit un jeton [. Si le [jetongauche est List `, Il est traité comme un tableau, et s'il s'agit de` Map , Il est traité comme un objet. Le [tokenright` est traité comme un index s'il s'agit d'un tableau et comme une clé s'il s'agit d'un objet.

Interpreter.java


    @SuppressWarnings("unchecked")
    public Object accessArrayOrMap(Token expr) throws Exception {
        Object v = value(expression(expr.left));
        if (v instanceof List<?>) {
            List<Object> ar = (List<Object>) v;
            Integer index = integer(expression(expr.right));
            return ar.get(index);
        } else if (v instanceof Map<?, ?>) {
            Map<String, Object> map = (Map<String, Object>) v;
            String key = string(expression(expr.right));
            return map.get(key);
        } else {
            throw new Exception("accessArrayOrMap error");
        }
    }

Le programme ci-dessous utilisant l'implémentation ci-dessus

var obj = {
  "key1": "value1",
  "key2": "value2",
}
println(obj.size())
println(obj["key2"])

Et affichez la valeur "" v2 "" associée au nombre d'éléments "2" et "key2" de l'objet.

Interpreter.java


    public static void main(String[] args) throws Exception {
        String text = "";
        text += "var m = {";
        text += "  key1: \"v1\",";
        text += "  key2: \"v2\",";
        text += "}";
        text += "println(m.size())";
        text += "println(m[\"key2\"])";
        List<Token> tokens = new Lexer().init(text).tokenize();
        List<Token> blk = new Parser().init(tokens).block();
        new Interpreter().init(blk).run();
        // --> 2
        // --> v2
    }

C'est tout pour la mise en œuvre. Merci beaucoup.

en conclusion

La source complète est disponible ici.

Calc https://github.com/quwahara/Calc/tree/article-18-map/Calc/src/main/java

Il y a un article de suite.

** Correspond à la création d'objet ** http://qiita.com/quwahara/items/ced0e9e2bf487f4021f8

Recommended Posts

18 Correspond à la définition d'objet de type JSON
19 Correspond à la création d'objet
17 Correspond à un tableau
Correspond à la portée
Correspond à 15 chaînes
8 Correspond à plusieurs arguments
10 Correspond à l'instruction if
14 Correspond à une expression de fonction
5 Correspond aux parenthèses prioritaires
16 Correspond à l'invocation de méthode
9 Correspond à la valeur de retour
12 Correspond à l'instruction while
Convertir un objet sérialisable en octet []
20 Correspond aux appels de méthode statiques
11 Correspond aux opérateurs de comparaison et logiques
Convertir un objet ruby au format JSON