La page src/pages/outils/interpreteur-ln.astro conserve son HTML et ses styles.
Son script gère l’éditeur, les préférences, la sauvegarde et les fenêtres existantes.
Le bouton Exécuter devient Arrêter pendant un programme. Ctrl+Entrée agit comme ce bouton.
Les raccourcis Ctrl+Alt+L/T sont conservés ; Ctrl+Maj+L/T sont également reconnus.
Organisation
syntax.mjs: découpage en jetons et analyse des instructions/expressions, avec lignes et colonnes.values.mjs: types, opérations, comparaisons, indices et affichage.builtins.mjs: fonctions mathématiques, statistiques et conversions.runtime.mjs: exécution de l’arbre, portées lexicales, fonctions et budgets.worker.mjs: messages du Worker et regroupement des sorties.client.mjs: lancement/arrêt du Worker, saisies et minuterie indépendante.console-input.mjs: champ de saisie intégré à la console, validation et annulation.highlight.mjs: coloration et majuscules automatiques, en préservant textes et commentaires.stylo.mjs: état et fonctions du module graphique, sans dépendance au DOM.stylo-view.mjs: rendu SVG et animation interruptible du curseur.
Aucun eval, constructeur Function ni traduction du code utilisateur en JavaScript.
Le langage ne donne accès ni au DOM, ni aux objets ou propriétés JavaScript.
Pour ajouter une fonction intégrée, modifier builtins.mjs et ajouter un cas de recette.
API et validation
import { interpret } from './runtime.mjs';
await interpret(source, {
onOutput: text => console.log(text),
onInput: async name => '12'
});
La page utilise startProgram(source, hooks) dans client.mjs, qui renvoie un objet
avec stop(). Les hooks sont onOutput, onInput, onError et onDone.
L’API directe accepte aussi signal, timeoutMs, now et random pour les tests.
Tests LN : node --test tests/ln*.test.mjs. Tous les tests : npm test.
Construction du site : npm run build.
Sémantique et décisions
La syntaxe du cahier des charges et de la documentation de l’ancien
public/interpreter.html est conservée. Les mots-clés sont en majuscules ;
la mise en majuscules automatique de l’éditeur existant est conservée.
L’indentation est libre, les deux-points et les fermetures FIN sont obligatoires.
Les commentaires commencent par # uniquement en dehors des textes.
- ENTRER conserve toujours le texte, y compris les zéros initiaux. Annuler arrête le programme.
- NOMBRE(x)/float(x), ENTIER(x)/int(x), TEXTE(x)/str(x) sont des conversions explicites. ENTIER tronque un nombre vers zéro ; un texte doit déjà représenter un entier.
- LONGUEUR(x)/len(x) et AJOUTER(liste, valeur) complètent la manipulation des listes.
- Les indices commencent à zéro ; les indices négatifs sont acceptés. Un indice hors limites est une erreur. Les textes sont immuables. Les caractères Unicode sont parcourus par points de code.
- Les listes sont partagées par référence et les comparaisons portent sur leur contenu. La concaténation et la répétition produisent une nouvelle liste, sans copie profonde.
- ET/OU sont évalués avec court-circuit et renvoient un opérande. Les collections vides sont fausses.
- Les comparaisons chaînées et la priorité Python de NON, ** et du signe unaire sont respectées.
- Le simple = reste accepté comme alias de == pour les anciens programmes. Le modulo % est ajouté.
- Texte + nombre est autorisé conformément au cahier des charges ; les autres opérations n’effectuent pas de conversion implicite entre texte et nombre.
- Les fonctions ont des variables locales, une portée lexicale et des arguments positionnels. Une affectation dans une fonction rend le nom local même avant sa première affectation. Les listes reçues peuvent être modifiées. Une fonction sans RENVOYER renvoie RIEN à l’affichage.
- Statistiques : listes numériques non vides, écart-type de population (division par n), médiane usuelle, quartiles scolaires aux rangs ceil(n/4) et ceil(3n/4). Les fonctions statistiques ne modifient pas leur argument.
- Trigonométrie en radians. ARRONDI utilise les égalités départagées vers le pair, sur la valeur binaire exacte du nombre, comme round de Python.
Le moteur est proche de Python, mais n’est pas Python complet : nombres IEEE-754 (pas d’entiers de précision arbitraire), pas de dictionnaires, classes, exceptions utilisateur, tranches de listes ni accès à des attributs. Seul le module intégré stylo peut être importé. Les calculs non finis sont refusés.
Module stylo
IMPORTER stylo active les fonctions en minuscules pour l’exécution en cours.
L’import est exécuté comme une instruction (une branche non exécutée ne l’active pas).
Le répéter ne remet pas le dessin à zéro. Les fonctions sont disponibles dans les
fonctions utilisateur via la portée globale des fonctions intégrées. Il n’y a pas
de préfixe stylo. ni de chargement de fichiers externes.
Fonctions : avancer(d), reculer(d), aller_a(x,y), gauche(a), droite(a),
orienter(a), lever_stylo(), poser_stylo(), couleur(c), epaisseur(e),
effacer(), reinitialiser(), position_x(), position_y(), direction(),
vitesse(v), montrer_curseur(), cacher_curseur().
État initial : (0,0), direction 0° vers la droite, stylo posé, trait noir d’épaisseur 2, curseur visible, vitesse 5. Les coordonnées verticales positives pointent vers le haut. La direction est normalisée entre 0° inclus et 360° exclu. Les rotations sont en degrés. La scène mesure 640 × 480 unités, origine au centre ; l’affichage s’adapte à la largeur disponible. Les tracés extérieurs sont masqués, sans rebond ni changement de coordonnées.
Couleurs françaises : noir, blanc, rouge, vert, bleu, jaune, orange, violet, rose, gris,
marron, cyan ; principaux équivalents anglais et hexadécimal #RGB/#RRGGBB acceptés.
Épaisseur : ]0,100]. Vitesse entière : 1 à 10, 0 instantané. Les mouvements animés
utilisent 60 × vitesse unités/seconde et 90 × vitesse degrés/seconde, avec une durée
maximale de deux secondes par commande. Aucun délai explicite ni cercle ni remplissage.
effacer() conserve tous les réglages, reinitialiser() remet l’état initial.
Une nouvelle exécution efface et masque la scène jusqu’au prochain import.
Le Worker transmet une seule commande graphique à la fois, puis attend l’accusé de réception du rendu. L’attente de rendu est exclue du budget de calcul dans le moteur et dans la page. Arrêter termine le Worker et annule requestAnimationFrame ; le dessin partiel reste visible. Une limite de 10 000 appels graphiques par exécution complète la limite de calcul, même pour les boucles qui ne font qu’animer ou lire la position. Les distances et coordonnées sont limitées en valeur absolue à un million d’unités. Le protocole reste interne : aucun objet JavaScript du navigateur n’est exposé au LN.
Pour tester sans navigateur, fournir onGraphics: async command => { ... } à
interpret. La commande décrit before/after, draw, clear, rotation et duration.
La promesse se résout après l’animation ; ne pas lancer une nouvelle exécution avec
le même rendu avant d’avoir annulé la précédente. Tests dédiés : tests/ln-stylo.test.mjs.
Limites et interface
Le calcul est interrompu après 10 secondes, avec une minuterie dans le moteur et une seconde dans la page qui peut terminer le Worker. L’attente de saisie est exclue. La page reste disponible pendant le calcul et pendant la saisie. ENTRER affiche un champ texte sous la console, associé au nom de variable. Entrée ou Valider transmet le texte exact (y compris une chaîne vide). Arrêter masque le champ et libère la saisie en attente.
Limites supplémentaires : 200 000 caractères de source, 100 blocs imbriqués, 150 niveaux d’expression, 200 appels de fonction imbriqués, 100 000 éléments par texte/liste, 100 000 caractères de sortie et 5 millions d’éléments cumulés pour les créations de textes/listes comptabilisées par l’exécution. Il s’agit de garde-fous, pas d’une mesure exacte de la mémoire du navigateur. Les listes cycliques s’affichent avec […].
Recette navigateur : exemple Fonction (36), factorielle récursive (120), affectation par indice, statistiques, arrêt manuel, boucle vide arrêtée à dix secondes, puis relance. Tester ENTRER avec validation au clavier, au bouton, saisies successives, chaîne vide et arrêt pendant l’attente. Vérifier qu’une attente supérieure à dix secondes n’épuise pas le temps de calcul.
Extensions hôtes de défis
interpret accepte options.createExtension(emit), une fabrique JavaScript de confiance retournant {functions: Map}. Ses valeurs sont ajoutées à la portée des fonctions intégrées après les noms réservés au stylo. Cette option ne provient jamais du source LN. emit(command,line) réutilise l’attente onGraphics et exclut le rendu du budget. options.allowedImports, quand présent, limite les imports dans ce contexte seulement.
startProgram(source,hooks,context) transmet un contexte sérialisable au Worker. Les contextes autorisés sont {kind:‘crates’,steps,initial?}, mappé vers createCraneExtension, et {kind:‘spiral’,radius,rotation}, mappé vers createSpiralExtension ; aucun chemin de module ou code JavaScript dynamique. Ces deux défis désactivent les imports pour éviter les collisions droite/gauche avec stylo. Les arguments et limites du modèle sont validés côté Worker. Sans contexte, comportement LN/stylo inchangé.
Le protocole graphics/graphics-done fournit une contre-pression : une seule action en attente. Le rendu du défi peut mettre en pause ou attendre le pas suivant ; ces attentes ne consomment pas les dix secondes de calcul. L’arrêt doit annuler animation, saisie et attente du pas suivant, et invalider les callbacks anciens avant de relancer.