[PYTHON] Jusqu'à ce que vous hébergiez vous-même votre propre interprète

Je crée un interprète appelé Calcium. Cette fois, j'ai repensé à l'implémentation de l'interpréteur Calcium dans le langage Calcium lui-même.

Quelle est la langue Calcium?

Tout d'abord, essayons Hello, World.

hello.json


[
  [1, [], "#", "0_18"],
  [1, [], "call", null, ["var", "print"], ["Hello, World!"]],
  [1, [], "end"]
]

Le code de langue Calcium est composé de tableaux JSON. La raison pour laquelle j'ai essayé d'écrire le code en JSON est qu'il ne nécessite pas d'analyse de phrase (JSON.parse () etc.). J'ai également pensé que ce serait probablement compatible avec l'environnement Web. S'il peut être décrit comme un format de données, il pourrait être utilisé pour quelque chose. (Quand je l'ai recherché plus tard, par exemple, je pense avoir vu quelque part que la VM interne de Scratch était écrite en JSON.) Donc, écrire Calcium in Calcium signifie écrire un interpréteur en ** JSON? ** Mais personne n'a envie d'écrire un tel code directement. Ce sera un programme qui souffre autant des parenthèses que LISP. De plus, il existe de nombreuses virgules et guillemets doubles.

Convertir de Python en Calcium (JSON)

Heureusement, le code Calcium peut maintenant être converti à partir d'un ** sous-ensemble ** de Python. Dès le début, j'étais conscient de Python et j'ai décidé des instructions à prendre en charge. À première vue, l'exemple ci-dessus ressemble à un code mnémonique de type assemblage. Mais c'est Python qui est affecté. Chaque élément du tableau Calcium JSON (également un tableau) correspond à une ligne en Python. Utilisez le module ʻastde Python pour sortir le code Calcium correspondant à partir du code Python. Dans Calcium, l'entier du premier élément correspond au retrait. Les retraits augmentent dans les instructions de bloc. Par exemple, l'instructionfor` suivante

loop.py


for i in range(10):
    print(i)

Il est converti comme suit. (Le libellé est pour la beauté)

loop.json


[
  [1, [], "#", "0_18"],
  [1, [], "for range", "i", [10]],
    [2, [], "call", null, ["var", "print"], [["var", "i"]]],
  [1, [], "end"]
]

J'ai écrit ** sous-ensemble ** de Python plus tôt, mais il existe des restrictions sur la façon de convertir réellement en langage Calcium. Cela signifie que vous ne pouvez utiliser que certaines des fonctionnalités du langage Python. Il existe d'autres "liaisons" telles que l'appel de fonction est une instruction plutôt qu'une expression. Cependant, la syntaxe de base telle que «for», «while», «if-elif-else», «def», «class» peut être convertie en Calcium. Autrement dit, l'interpréteur Calcium prend en charge ces instructions. C'est un peu long, mais ce qui suit peut être converti en code Calcium valide.

sample.py


def is_remainder_zero(a, b):
    return (a % b) == 0

prime = []
for i in range(101):
    j = 2
    while j < i:
        is_zero = is_remainder_zero(i, j)
        if is_zero:
            break
        else:
            j += 1
    if j == i:
        prime.append(i)
result = prime
print(result)

sample.json


[
  [1, [], "#", "0_18"],
  [1, [], "def", "is_remainder_zero", ["a", "b"]],
    [2, [], "return", ["==", ["%", ["var", "a"], ["var", "b"]], 0]],
  [1, [], "=", ["var", "prime"], [[]]],
  [1, [], "for range", "i", [101]],
    [2, [], "=", ["var", "j"], 2],
    [2, [], "while", ["<", ["var", "j"], ["var", "i"]]],
      [3, [], "call", ["var", "is_zero"], ["var", "is_remainder_zero"], [["var", "i"], ["var", "j"]]],
      [3, [], "ifs"],
        [4, [], "if", ["var", "is_zero"]],
          [5, [], "break"],
        [4, [], "else"],
          [5, [], "+=", ["var", "j"], 1],
    [2, [], "ifs"],
      [3, [], "if", ["==", ["var", "j"], ["var", "i"]]],
        [4, [], "call", null, ["attr", "prime", "append"], [["var", "i"]]],
  [1, [], "=", ["var", "result"], ["var", "prime"]],
  [1, [], "call", null, ["var", "print"], [["var", "result"]]],
  [1, [], "end"]
]

J'ai pu convertir à partir d'un sous-ensemble Python, avec des différences majeures telles que les instructions d'appel de fonction et l'imbrication à deux niveaux des instructions ʻif`. Le convertisseur prend un sous-ensemble Python comme entrée et produit du code Calcium. (Ce convertisseur s'appelle py3ca.py) Cela signifie que si vous implémentez l'interpréteur Calcium dans un sous-ensemble Python, vous pouvez générer l'interpréteur Calcium écrit par Calcium lui-même.

Implémentation de l'interpréteur Calcium

Actuellement, Calcium est implémenté en JavaScript ou Python. Il existe des différences dans chaque implémentation (prise en charge de «try-except», comportement de l'opérateur d'équivalence, etc.), mais il lit et exécute le tableau JSON comme décrit ci-dessus.

Implémentation de calcium.js

Nous l'avons d'abord implémenté en JavaScript comme un environnement qui peut être exécuté dans un navigateur. La raison est que vous pouvez utiliser la fonction de débogage. Tout d'abord, il convenait de l'implémenter en JavaScript pour voir s'il pouvait être implémenté.

Réalisation de «si»

Dans le langage Calcium, chaque instruction est placée en coordonnées bidimensionnelles en mosaïque. L'adresse actuelle est représentée par (retrait, index du tableau). スクリーンショット 2020-04-27 10.05.13.png Par exemple, l'instruction ʻif` évalue l'expression conditionnelle et incrémente le retrait de un si vrai (à droite de la figure). Si faux, augmentez l'index sans changer le retrait (vers le bas). Les détails de l'ordre d'exécution peuvent être trouvés ici. L'image est que les retraits dans le code Python sont utilisés comme nombres au moment de l'exécution.

Réalisation de l'instruction for

Dans Calcium, les appels de fonction sont des instructions, nous avons donc dû séparer les itérations telles que for i in range (10): des instructions foreach telles que for elem in my_list:. Correspond respectivement aux instructions "for range" et "for each".

Implémentation de calcium.py

Porté calcium.js vers Python. Comme mentionné ci-dessus, nous avons dû implémenter calcium.py avec la limitation que seules certaines fonctionnalités du langage Python pouvaient être utilisées. Par exemple

Il y avait de nombreuses restrictions, mais quand je l'ai implémenté, j'ai été capable de l'écrire étonnamment bien. Il tient dans un total d'environ 1500 lignes de code (calcium.js fait environ 2500 lignes). La différence est que calcium.py ne prend pas en charge try-except, mais je ne m'attendais pas à ce que ce soit aussi court.

Chargez calcium.py dans py3ca.py

C'est le sujet principal. Puisqu'il s'agit d'un programme qui convertit un sous-ensemble Python en code Calcium, passer calcium.py produira le code qui décrit Calcium in Calcium. Le résultat est d'environ 1300 lignes. Il est plus court que calcium.py car il n'y a pas de lignes vides. Situé ici.

Exécutez l'interpréteur de calcium

Actuellement, seul calcium.js prend en charge try-except, alors vérifiez si Calcium peut exécuter du calcium dessus. J'ai préparé le code suivant.

cac03.py


class Engine:
    # calcium.Contenu de py...
code = [
  [1, [], "#", "0_18"],
  [1, [], "call", None, ["var", "print"], ["Hello, World!"]],
  [1, [], "end"]
]
engine = Engine(code)
engine.run()

Chargez ceci dans py3ca.py.

cac03.json


[
  [1, [], "#", "0_18"],
  [1, [], "class", "Engine", "object"],
 ...Abréviation...
  [1, [], "=", ["var", "code"], [[[[1, [[]], "#", "0_18"]], [[1, [[]], "call", null, [["var", "print"]], [["Hello, World!"]]]], [[1, [[]], "end"]]]]],
  [1, [], "call", ["var", "engine"], ["var", "Engine"], [["var", "code"]]],
  [1, [], "call", null, ["attr", "engine", "run"], []],
  [1, [], "end"]
]

Passez-le à calcium.js.

const code = [...]; //Au-dessus du tableau JSON
const engine = new calcium.Engine(code);
engine.setPrintFunction((desc) => { console.log(desc); });
engine.run();

Ceci termine l'exécution.

Enfin (publicité ...)

Le calcium se caractérise par son écriture dans un tableau JSON, mais il prend en charge des fonctionnalités telles que des fonctions et des classes simples.

Application de calcium

Lorsque j'ai recherché un bon moyen de modifier le tableau JSON, j'ai trouvé Blockly. Je n'entrerai pas dans les détails, mais vous pouvez accéder à l'éditeur de développement ici (https://crepekit.web.app/). Notre objectif est d'être un éditeur visuel que les débutants en programmation peuvent utiliser avant d'apprendre Python. (Cet environnement d'éditeur utilise calcium.js)

Le calcium est open source

Si vous êtes intéressé, veuillez nous contacter depuis GitHub. Nous recherchons également des personnes pour discuter et évoluer avec nous. Nous vous serions reconnaissants de bien vouloir nous donner votre avis.

Recommended Posts

Jusqu'à ce que vous hébergiez vous-même votre propre interprète
Jusqu'à ce que vous installiez votre propre bibliothèque Python
Jusqu'à ce que vous puissiez installer votre propre bibliothèque Python avec pip
Essayez de créer votre propre CorDapp. (Jusqu'à la création des États)
Créez votre propre exception
Jusqu'à ce que vous installiez MySQL-python
Créez votre propre middleware Django
Introduction à l'utilisation de Pytorch Lightning ~ Jusqu'à ce que vous formatez votre propre modèle et le produisez sur tensorboard ~
Jusqu'à ce que le kit Crashlytics soit incorporé dans une application iOS basée sur kivy
Examinez s'il s'agit d'un PDF et du traitement des exceptions Jusqu'à ce que vous créiez votre propre traitement des exceptions