3

J'implémente une console Python personnalisée (Iron).Algorithme Python utilise-t-il pour choisir entre l'invite >>> et ... dans la console interactive?

Je dois afficher une invite >>> en général, mais lorsqu'une instruction est incomplète, je dois la remplacer par ... et rassembler plus de lignes avant de les exécuter.

Comment savoir si une ligne entrée par un utilisateur est complète ou si j'ai besoin de lire plus de lignes? Un moyen simple semble être de vérifier si : est présent. Mais je ne suis pas sûr si je ne manque pas d'autres cas où : n'est pas présent. J'ai regardé dans le code source IronPython pour comprendre comment cela fonctionne, mais il y a beaucoup d'étapes impliquées et ma reproduction simple n'a pas fonctionné complètement.

Répondre

4

Il est impossible d'essayer de deviner simplement en regardant la chaîne de code pour les deux-points et les crochets.Vous finiriez par avoir besoin d'implémenter la moitié de l'analyseur Python pour y arriver.

Le module de la bibliothèque standard code reproduit le comportement de l'interpréteur interactif Python, et je crois que c'est ce module qu'utilise IronPython pour implémenter sa console. (Le CPython n'est pas implémenté dans Python lui-même.)

La logique de continuation de ligne qui vous intéresse provient de la fonction codeop.compile_command.

C'est un peu un hack. Essentiellement, il essaie de compile() le code donné en utilisant le drapeau obscur PyCF_DONT_IMPLY_DEDENT, ce qui signifie qu'il ne suppose pas que les retraits ouverts sont automatiquement fermés à la fin du bloc. Il essaie ensuite de le compiler à nouveau en ajoutant des retours à la ligne (provoquant des DEDENTS explicites). Si le second fonctionne mais que le premier ne fonctionne pas, vous avez une suite potentielle, vous pouvez en saisir davantage dans le bloc.

+0

Hackish, mais vu dans la nature, donc +1 – SingleNegationElimination

1

Avez-vous utilisé un : ou un \ (ou un délimiteur non fermé, comme des parenthèses ou des parens)? L'interpréteur interactif montre un .... La logique actuelle peut être un peu plus compliquée, mais c'est la règle de base.

3

Il y a plusieurs façons de penser à l'invite ....

  • À partir (ou poursuivre) un bloc
    • def foo():
  • parenthèse non fermée, brace, support carré (et faites attention à la nidification)
    • x = (
    • x = {
    • x = [
  • Unclosed triple chaîne entre guillemets
    • x = '''
  • barre oblique inverse à la fin de la ligne:
    • x = \
3

La boucle de repl a connaissance et l'accès à l'analyseur. Si l'état de l'analyseur est tel qu'il attend autre chose qu'une instruction, la boucle repl produit un .... Dans le cas de parenthèses non fermées, une instruction serait illégale sur la ligne suivante, car il n'y a pas de sous-expression possible qui peut contenir une instruction. Suite à un :, le prochain jeton attendu est toujours un retrait, une fois encore une déclaration serait toujours illégale. C'est pourquoi il est toujours nécessaire de taper une ligne vide à la fin d'un bloc indenté à la boucle repl, car vous devez fournir le délai de fermeture pour qu'une déclaration devienne la prochaine règle de production attendue.

Questions connexes