Date: Tue Sep 23 22:04:49 2014 +0200
MAJ MicroAlg (gros boulot à venir encore…).
diff --git a/input/microalg.l b/input/microalg.l
index c9f6e2a..e1628ae 100644
@@ -1,75 +1,560 @@
(put 'version 'text "MicroAlg version 0.1.0")
(setq version "0.1.0")
-(setq apropos (pack
-"L’idée de MicroAlg est née lors d’une formation ISN, de la frustration due à "
-"l’abscence d’un langage vraiment axé sur la pédagogie.<br />"
-"À l’origine pensé comme DSL au sein de Tcl, il est finalement embarqué dans "
-"PicoLisp.<br />"
-"Voir <a href=\"http://microalg.info\">microalg.info</a>."))
+(setq apropos
+"L’idée de MicroAlg est née lors d’une formation ISN, de la frustration due à
+l’abscence d’un langage vraiment axé sur la pédagogie.
+À l’origine pensé comme DSL au sein de Tcl, il est finalement embarqué dans
+PicoLisp.
+Voir <http://microalg.info>.")
(put 'apropos 'doc "Symbole contenant des informations sur MicroAlg.")
+(setq symboles '(
+"+" "-" "*" "/" "%"
+"!!!" "=" "=/" "<" "<=" ">" ">="
+"Affecter_a" "Afficher" "Aide" "Alors"
+"Booleen?"
+"Concatener"
+"Decimal@"
+"Definir" "Demander"
+"Entier@" "Et"
+"Faire"
+"Faux" "Faux?"
+"Initialiser"
+"Longueur"
+"Nieme" "Nombre" "Nombre?" "Non"
+"Ou"
+"Queue"
+"Retourner" "Rien"
+"Si" "Sinon"
+"Tant_que" "Tete" "Texte" "Texte?" "Type"
+"Vide?" "Vrai" "Vrai?"
+))
+
+# picolisp.l shimz
+(ifn caadr
+ (de caadr (arg)
+ (car (car (cdr arg)))
+ )
+)
+(ifn glue
+ (de glue (c l)
+ (cond
+ ((= 0 (length l)) "")
+ ((= 1 (length l)) (car l))
+ (T (pack (car l) c (glue c (cdr l))))
+ )
+ )
+)
+(ifn member
+ (de member (elt lst)
+ (let (result lst)
+ (while (not (or (not (<> elt (car result)))
+ (not (n0 (length result)))))
+ (pop 'result))
+ result)
+ )
+)
+
+# Vérif et conversions de booléens MicroAlg <-> PicoLisp:
+(de !boolM2P (x) (if (<> Faux x) T NIL))
+(de !boolP2M (x) (if x Vrai Faux))
+(de !boolCheck (x) (if (member x '(Vrai Faux)) T))
+(de !boolCheckM2P (x msg)
+ (ifn (!boolCheck x) (quit msg x))
+ (!boolM2P x) )
+
+# Doc pour les fonctions PicoLisp
+(put '+ 'doc
+"Commande ajoute tous ses paramètres.")
+(put '- 'doc
+"Commande qui soustrait son second paramètre à son premier paramètre.")
+(put '* 'doc
+"Commande multiplie tous ses paramètres.")
+(put '/ 'doc
+"Commande qui divise son premier paramètre par son second paramètre.")
+(put '% 'doc
+"Commande qui donne le reste de la division euclidienne de son premier paramètre par son second paramètre.")
+
+# Commentaires
+(put '!!! 'doc
+"Commande qui ne fait rien et sert pour les commentaires.")
+(de !!! () Rien)
+
# Aide
-(put 'Aide 'doc (pack
-"Commande qui permet d’obtenir de l’aide."))
-(de Aide syms (let truc (car syms)
- (let doc (get truc 'doc)
- (cond
+(put 'Aide 'doc
+"Commande qui permet d’obtenir de l’aide.")
+(de Aide syms (let (truc (car syms)
+ doc (get truc 'doc))
+ (cond
((== truc NIL) (get 'Aide 'text))
- (doc (pack "Aide pour `" truc "’:<br />" doc))
+ ((== truc 'symboles) (glue " " symboles))
+ (doc (pack "Aide pour `" truc "` : ^J" doc))
((eval truc) (pack "Pas d’aide pour " truc "."))
(T (pack "`" truc "’ n’existe pas."))
- ))))
-(put 'Aide 'text (pack
-"MicroAlg permet de s’initier à l’algorithmique et à la programmation.<br />"
-"Pour valider une commande, taper <code>Ctrl</code>+<code>Entrée</code>.<br />"
-"<ul>"
-"<li><code>(Aide commande)</code> pour de l’aide sur une commande,</li>"
-"<li><code>version</code> ou <code>apropos</code> pour des informations sur"
-" MicroAlg.</li>"
-"<ul>"))
-
-# L’affichage se fait au travers de la variable globale *StdOut.
-(put 'Affecter_a 'doc (pack
-"Commande qui évalue son premier argument et l’affiche.<br />"
-"Attention, certains symboles particuliers comme `aide’ ou `version’ "
-"ont des comportements différents suivant qu’on les évalue, qu’on les "
-"affiche ou qu’on les appelle."))
-(setq *StdOut "")
+ )))
+(put 'Aide 'text
+"MicroAlg permet de s’initier à l’algorithmique et à la programmation.
+Si vous ne l’avez pas déjà fait, commencez par le
+[tutoriel](http://microalg.info/tuto.html).
+
+* `(Aide symboles)` pour une liste des symboles prédéfinis,
+* `(Aide «quoi»)` (sans «») pour de l’aide sur quelque chose en particulier,
+* `version` ou `apropos` pour des informations sur MicroAlg.")
+
+# Afficher.
+# Avec EmuLisp, l’affichage se fait au travers de la fonction _stdPrint,
+# surchargée par stdPrint dans piljs ou ide_injection.js
+# On garde une trace du dernier affichage dans la variable globale *LastStdOut.
+(put 'Afficher 'doc
+"Commande qui évalue son premier argument et l’affiche.
+Attention, certains symboles particuliers comme `aide` ou `version` ont des
+comportements différents suivant qu’on les évalue, qu’on les affiche ou qu’on
+les appelle.")
+(put 'Afficher 'text "Commande `Afficher`.")
+(setq *LastStdOut "?")
(de Afficher args (let (first (car args)
- text (get first 'text)
+ text (if (num? first) first (get first 'text))
a_afficher (if text text (eval first)))
- (prog
- (setq *StdOut (pack *StdOut a_afficher))
- (if text NIL a_afficher)
- )))
-(put 'Afficher 'text "Commande 'Afficher'.")
+ (setq *LastStdOut (if a_afficher a_afficher "?"))
+ (ifn !testing
+ (println (ifn a_afficher
+ (if (<> *EMUENV "browser")
+ " "
+ " ")
+ a_afficher)))
+ Rien # Pas de valeur de retour
+ )
+)
+
+# Concatener
+(put 'Concatener 'doc
+"Commande qui concatène les textes passés en paramètre.")
+(put 'Concatener 'text "Commande `Concatener`.")
+(de Concatener @ (let (
+ result (pack (rest))
+ )
+ (if result
+ result
+ ""
+ )))
# Gestion des variables
-(put 'Affecter_a 'doc (pack
-"Commande qui permet d’affecter une valeur à une variable."))
-(de Affecter_a arg_lst (set (car arg_lst) (cadr arg_lst)))
+(put 'Initialiser 'doc
+"Commande qui permet d’initialiser une variable avec une valeur.")
+(put 'Initialiser 'text "Commande `Initialiser`.")
+(de Initialiser arg_lst (let (nbr_args (length arg_lst))
+ (if (<> 2 nbr_args)
+ (quit (pack "Initialiser prend 2 paramètres. "
+ "Vous en donnez " nbr_args ".") )
+ ) # Du coup un deuxième arg NIL ne peut être que "".
+ )
+ (let (var (car arg_lst)
+ val (eval (cadr arg_lst))
+ type_var (get var 'type)
+ type_val (Type val))
+ (if (and type_var (<> type_val type_var))
+ (quit (pack "Valeur de type " type_val ", ne peut initialiser "
+ var " qui est de type " type_var "."))
+ )
+ (set var val)
+ (put var 'type (ifn val "texte" type_val))
+ Rien # Pas de valeur de retour
+ ))
+(put 'Affecter_a 'doc
+"Commande qui permet d’affecter une valeur à une variable.")
+(put 'Affecter_a 'text "Commande `Affecter_a`.")
+(de Affecter_a arg_lst
+ (let (preums (car arg_lst)
+ deuz (eval (cadr arg_lst))
+ troiz (eval (caddr arg_lst))
+ var preums
+ val (ifn troiz deuz troiz)
+ idx troiz)
+ (ifn idx
+ (prog
+ # Affectation au symbole dans `var`.
+ (ifn (get var 'type)
+ (quit "Variable non initialisée." var)
+ )
+ (if (or (not val) # Pour accepter "" qui est NIL.
+ (<> Faux (= (get var 'type) (Type val))))
+ (set var val)
+ (quit "Le type ne correspond pas."
+ (list var 'est 'un (get var 'type) '; val 'un (Type val))
+ )
+ )
+ )
+ (prog
+ # Affectation à l’élément `idx` du symbole dans `var`.
+ )
+ )
+ Rien # Pas de valeur de retour
+ )
+)
+
+# Tirages pseudo-aléatoires.
+(put 'Decimal@ 'doc
+"Retourne un nombre décimal pseudo-aléatoire dans [0;1[.
+
+Le suffixe `@` indique le caractère pseudo-aléatoire de cette commande.")
+(put 'Decimal@ 'text "Commande `Decimal@`.")
+(de Decimal@ () (/ (+ 2147483648 (rand)) 4294967296))
+(put 'Entier@ 'doc
+"Retourne un nombre entier pseudo-aléatoire dans [`min`;`max`].
+
+Le suffixe `@` indique le caractère pseudo-aléatoire de cette commande.")
+(put 'Entier@ 'text "Commande `Entier@`.")
+(de Entier@ arg_lst (let (nbr_args (length arg_lst))
+ (if (<> 2 nbr_args)
+ (quit (pack "`Entier@` prend 2 paramètres. "
+ "Vous en donnez " nbr_args ".") )
+ )
+ )
+ (let (min (eval (car arg_lst))
+ max (eval (cadr arg_lst)))
+ (ifn (num? min) (quit "Le premier paramètre de `Entier@` doit être un nombre."))
+ (ifn (num? max) (quit "Le second paramètre de `Entier@` doit être un nombre."))
+ (rand min max)
+ )
+)
# Demander.
-(put 'Demander 'doc (pack
-"Commande qui permet de demander une valeur à l’utilisateur."))
+# Avec EmuLisp, les entrées utilisateur se font au travers de la fonction
+# _stdPrompt, surchargée dans ide_injection.js. Dans un navigateur, la dernière
+# ligne ayant été affichée précédemment est réutilisée lors de l’appel à
+# window.prompt.
+(put 'Demander 'doc
+"Commande qui permet de demander une valeur à l’utilisateur.")
+(put 'Demander 'text "Commande `Demander`.")
(de Demander () (in NIL (read " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")))
# Références:
# https://fr.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange#Table_des_128_caract.C3.A8res_ASCII
# https://en.wikipedia.org/wiki/ASCII#ASCII_printable_character_code_chart
# >>> ''.join([chr(i) for i in range(32, 127) if not chr(i).isalnum()])
-# ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
+# ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' "
+
+# Manipulations de texte
+(put 'Longueur 'doc
+"Commande qui retourne la longueur d’une liste.")
+(put 'Longueur 'text "Commande `Longueur`.")
+(de Longueur (obj)
+ (length obj))
+(put 'Nieme 'doc
+"Permet d’accéder en lecture à un des éléments d’une liste (se lit « énième »).
+
+La numérotation commence à 1.")
+(put 'Nieme 'text "Commande `Nieme`.")
+(de Nieme (obj idx)
+ # Quelques vérifications
+ (let (len (length obj))
+ (cond
+ ((not idx) (quit "Il manque le deuxième paramètre : l’indice."))
+ ((<> idx (format (round idx 0))) (quit "Indice non entier." idx))
+ ((le0 idx) (quit "Indice négatif ou nul." idx))
+ ((le0 (- (length obj) idx)) (quit "Indice trop grand." (list idx '> len)))
+ )
+ )
+ # Le calcul
+ (cond
+ ((str? obj) (car (nth (chop obj) idx)))
+ #((lst? obj) (nth obj idx))
+ (T Rien)
+ ))
+(put 'Tete 'doc
+"Commande qui retourne le premier élément d’une liste.")
+(put 'Tete 'text "Commande `Tete`.")
+(de Tete (obj)
+ # Quelques vérifications
+ (if (!boolM2P (Vide? obj))
+ (quit "Un objet vide n’a pas de tête.")
+ )
+ # Le calcul
+ (cond
+ ((str? obj) (car (chop obj)))
+ #((lst? obj) (car obj))
+ (T Rien)
+ ))
+(put 'Queue 'doc
+"Commande qui retourne une copie de la liste en paramètre, mais sans son premier élément.")
+(put 'Queue 'text "Commande `Queue`.")
+(de Queue (obj)
+ # Quelques vérifications
+ (if (!boolM2P (Vide? obj))
+ (quit "Un objet vide n’a pas de queue.")
+ )
+ # Le calcul
+ (cond
+ ((str? obj) (pack (cdr (chop obj))))
+ #((lst? obj) (cdr obj))
+ (T Rien)
+ ))
+
+# Types et conversions
+(put 'Type 'doc
+"Commande qui retourne le type de son paramètre (sous forme de texte et
+en minuscule).")
+(put 'Type 'text "Commande `Type`.")
+(de Type arg_lst
+ (let (!x (car arg_lst)
+ !evaled_x (eval !x))
+ (cond
+ ((<> Faux (Texte? !evaled_x)) "texte")
+ ((<> Faux (Booleen? !evaled_x)) "booleen")
+ ((<> Faux (Nombre? !evaled_x)) "nombre")
+ ((<> Faux (== Rien !evaled_x)) "rien")
+ ((sym? x) (get !x 'type))
+ (T Rien)
+ ) ) )
+(put 'Texte 'doc
+"Commande qui retourne le texte correspondant à son paramètre.")
+(put 'Texte 'text "Commande `Texte`.")
+(de Texte (x) (cond
+ ((str? x) x)
+ ((num? x) (format x))
+ (T NIL)
+ ))
+(put 'Nombre 'doc
+"Commande qui retourne le nombre correspondant à son paramètre textuel.")
+(put 'Nombre 'text "Commande `Nombre`.")
+(de Nombre (x) (cond
+ ((num? x) x)
+ ((str? x) (or (format x) Rien))
+ (T NIL)
+ ))
# Structure conditionnelle
-(put 'Vrai 'doc (pack "Booléen valant Vrai."))
+(put 'Vrai 'doc "Booléen valant Vrai.")
(setq Vrai 'Vrai)
-(put 'Vrai 'doc (pack "Booléen valant Faux."))
+(put 'Faux 'doc "Booléen valant Faux.")
(setq Faux 'Faux)
+(put 'Alors 'doc "Mot-clef intermédiaire pour la commande `Si`.")
+(setq Alors 'Alors)
+(put 'Sinon 'doc "Mot-clef intermédiaire pour la commande `Si`.")
+(setq Sinon 'Sinon)
+(put 'Si 'doc
+"Structure conditionnelle, de la forme `Si ... Alors ... Sinon ...` où le
+`Sinon` est facultatif.")
+(put 'Si 'text "Commande `Si`.")
(de Si arg_lst (let (condition (car arg_lst)
- bloc_vrai (cadr arg_lst)
- bloc_faux (caddr arg_lst))
- (if (= Vrai (eval condition))
- (eval bloc_vrai) (eval bloc_faux))))
+ kw_alors (cadr arg_lst)
+ splitted (split (cddr arg_lst) 'Sinon)
+ bloc_vrai (car splitted)
+ bloc_faux (cadr splitted))
+ (if (<> Alors kw_alors) (quit "Mot-clef `Alors` manquant." arg_lst))
+ (if (!boolCheckM2P (eval condition) "La condition n’est pas un booléen.")
+ (run bloc_vrai)
+ (if (== NIL bloc_faux)
+ Rien
+ (run bloc_faux)))))
+
+# Opérations logiques
+(put 'Non 'doc
+"Non logique.
+
+Voir <http://fr.wikipedia.org/wiki/Fonction_NON>.")
+(put 'Non 'text "Commande `Non`.")
+(de Non (P)
+ (ifn (!boolCheck P) (quit "`Non` prend un paramètre booléen."))
+ (!boolP2M (not (!boolM2P P))) )
+(put 'Et 'doc
+"Et logique.
+
+Voir <http://fr.wikipedia.org/wiki/Fonction_ET>.")
+(put 'Et 'text "Commande `Et`.")
+(de Et (P Q)
+ (ifn (!boolCheck P) (quit "Le premier paramètre de `Et` doit être un booléen."))
+ (ifn (!boolCheck Q) (quit "Le second paramètre de `Et` doit être un booléen."))
+ (!boolP2M (and (!boolM2P P) (!boolM2P Q))) )
+(put 'Ou 'doc
+"Ou logique.
+
+Voir <http://fr.wikipedia.org/wiki/Fonction_OU>.")
+(put 'Ou 'text "Commande `Ou`.")
+(de Ou (P Q)
+ (ifn (!boolCheck P) (quit "Le premier paramètre de `Ou` doit être un booléen."))
+ (ifn (!boolCheck Q) (quit "Le second paramètre de `Ou` doit être un booléen."))
+ (!boolP2M (or (!boolM2P P) (!boolM2P Q))) )
+
+# Structures itératives
+(put 'Tant_que 'doc
+"Structure itérative de type « tant que ... faire ... ».")
+(put 'Tant_que 'text "Commande `Tant_que`.")
+(de Tant_que arg_lst (let (Bool (car arg_lst)
+ Mot-Clef (cadr arg_lst)
+ Corps (cddr arg_lst))
+ (if (<> 'Faire Mot-Clef) (quit "Commande Tant_que sans mot-clé Faire."))
+ (while (!boolCheckM2P (eval Bool) "La condition n’est pas un booléen.")
+ (run Corps))
+ Rien
+ )
+)
+(put 'Faire 'doc
+"Structure itérative de type « faire ... tant que ... ».")
+(put 'Faire 'text "Commande `Faire`.")
+(de Faire arg_lst (let (Splitted (split arg_lst 'Tant_que)
+ Corps (car Splitted)
+ Bool (caadr Splitted))
+ (run Corps)
+ (if (!boolCheckM2P (eval Bool) "La condition n’est pas un booléen.")
+ (while (!boolCheckM2P (eval Bool) "La condition n’est pas un booléen.")
+ (run Corps)))
+ Rien
+ )
+)
+
+# Procédures utilisateur
+(put 'Definir 'doc
+"Permet de définir une nouvelle commande (fonction mathématique ou procédure).
+
+La syntaxe de cette commande est :
+
+ (Definir (Nom_de_la_nouvelle_commande arg1 arg2 ...)
+ \"Une phrase expliquant le rôle de cette commande.\"
+ \"L’auteur de cette commande.\"
+ (... ici les ...)
+ (... instructions ...)
+ (... de la commande ...)
+ (Retourner la_valeur_de_retour)
+ )
+
+Il peut être intéressant de signer ses créations avec le pseudo utilisé sur
+[les questions/réponses](http://qr.microalg.info).
+
+Exemple 1 :
+
+ (Definir (Double x)
+ \"Retourne le double du nombre (paramètre `x`).\"
+ \"anonyme\"
+ (Retourner (* 2 x))
+ )
+
+Exemple 2 :
+
+ (Definir (Crier texte)
+ \"Affiche le texte (paramètre `texte`) avec un point d’exclamation.\"
+ \"ProfGra\"
+ (Afficher (Concatener texte \" !\"))
+ (Retourner Rien)
+ )
+")
+(put 'Definir 'text "Commande `Definir`.")
+(de Definir arg_lst
+ (let (signature (car arg_lst)
+ nom (car signature)
+ params (cdr signature)
+ corps (cdr arg_lst)
+ doc (car corps)
+ auteur (cadr corps))
+ (ifn (str? doc)
+ (put nom 'doc Rien)
+ (put nom 'doc (pack "`(" (str signature) ")` : " doc)))
+ (ifn (str? auteur) (setq auteur "un auteur anonyme"))
+ (put nom 'text (pack "Commande `"
+ (str nom)
+ "`, définie par *"
+ auteur
+ "*."))
+ (set nom (list params (list 'run (cons 'quote corps))))
+ Rien # Pas de valeur de retour
+ )
+)
+(put 'Retourner 'doc
+"Dernière instruction du corps d’une commande définie avec `Definir`.
+Indique la valeur que cette commande va retourner.
+
+Utiliser `(Retourner Rien)` pour ne rien retourner.
+
+**Attention !** Cette instruction doit être la dernière de la commande créée car
+`Retourner` n’en interrompt pas l’exécution.")
+(put 'Retourner 'text "Commande `Retourner`.")
+(de Retourner (val) val)
# Prédicats
-(de Vrai? (x) (if (= x Vrai) Vrai Faux))
-(de Faux? (x) (if (= x Faux) Vrai Faux))
+(put 'Vrai? 'doc
+"Prédicat retournant `Vrai` si la valeur de son argument est `Vrai`,
+et `Faux` sinon.")
+(put 'Vrai? 'text "Prédicat `Vrai?`.")
+(de Vrai? (x) (if (<> x Faux) Vrai Faux))
+(put 'Faux? 'doc
+"Prédicat retournant `Vrai` si la valeur de son argument est `Faux`,
+et `Faux` sinon.")
+(put 'Faux? 'text "Prédicat `Faux?`.")
+(de Faux? (x) (if (<> x Vrai) Vrai Faux))
+(put 'Texte? 'doc
+"Prédicat retournant `Vrai` si la valeur de son argument est du texte,
+et `Faux` sinon.")
+(put 'Texte? 'text "Prédicat `Texte?`.")
+(de Texte? (x) (if (str? x) Vrai Faux))
+(put 'Nombre? 'doc
+"Prédicat retournant `Vrai` si la valeur de son argument est un nombre,
+et `Faux` sinon.")
+(put 'Nombre? 'text "Prédicat `Nombre?`.")
+(de Nombre? (x) (if (num? x) Vrai Faux))
+(put 'Booleen? 'doc
+"Prédicat retournant `Vrai` si la valeur de son argument est un booleen,
+et `Faux` sinon.")
+(put 'Booleen? 'text "Prédicat `Booleen?`.")
+(de Booleen? (x) (if (or (== Vrai x) (== Faux x)) Vrai Faux))
+# Sans le suffixe '?'
+# Éviter le message « redefined »
+(setq = NIL)
+(setq < NIL)
+(setq <= NIL)
+(setq > NIL)
+(setq >= NIL)
+(put '= 'doc
+"Prédicat retournant `Vrai` si les valeurs de ses deux arguments sont égales,
+et `Faux` sinon.")
+(put '= 'text "Prédicat `=`.")
+(de = (x y) (ifn (<> x y) Vrai Faux))
+(put '=/ 'doc
+"Prédicat retournant `Vrai` si les valeurs de ses deux arguments sont
+différentes, et `Faux` sinon.")
+(put '=/ 'text "Prédicat `=/`.")
+(de =/ (x y) (if (<> x y) Vrai Faux))
+(put '< 'doc
+"Prédicat retournant `Vrai` si les valeurs de ses deux arguments sont
+dans l’ordre croissant (strictement), et `Faux` sinon.")
+(put '< 'text "Prédicat `<`.")
+(de < (x y) (ifn (ge0 (- x y)) Vrai Faux))
+(put '<= 'doc
+"Prédicat retournant `Vrai` si les valeurs de ses deux arguments sont
+dans l’ordre croissant.")
+(put '<= 'text "Prédicat `<=`.")
+(de <= (x y) (if (le0 (- x y)) Vrai Faux))
+(put '> 'doc
+"Prédicat retournant `Vrai` si les valeurs de ses deux arguments sont
+dans l’ordre décroissant (strictement), et `Faux` sinon.")
+(put '> 'text "Prédicat `>`.")
+(de > (x y) (ifn (le0 (- x y)) Vrai Faux))
+(put '>= 'doc
+"Prédicat retournant `Vrai` si les valeurs de ses deux arguments sont
+dans l’ordre décroissant.")
+(put '>= 'text "Prédicat `>=`.")
+(de >= (x y) (if (ge0 (- x y)) Vrai Faux))
+(put 'Vide? 'doc
+"Prédicat retournant `Vrai` si l’argument est considéré comme vide.
+
+* **Textes** : le seul texte vide est `\"\"`.
+")
+(put 'Vide? 'text "Prédicat `Vide?`.")
+(de Vide? (obj)
+ (if (<> 0 (length obj)) Faux Vrai))
+
+# Rien
+(put 'Rien 'doc
+"Valeur de contenant aucune information, représentant l’absence de valeur.")
+(setq Rien 'Rien)
+
+# Ignorer les balises de la galerie (http://galerie.microalg.info) si utilisées
+# par inadvertance, ou une fois de trop dans la galerie.
+(de MicroAlg arg_lst
+ (Afficher
+ (pack "L’instruction `(MicroAlg ...)` est une instruction fantôme. ^J"
+ "Merci de la supprimer, elle ne sert que pour la galerie ^J"
+ "(<http://galerie.microalg.info>).") ) )
+(de /MicroAlg arg_lst
+ (Afficher
+ (pack "L’instruction `(/MicroAlg)` est une instruction fantôme. ^J"
+ "Merci de la supprimer, elle ne sert que pour la galerie ^J"
+ "(<http://galerie.microalg.info>).") ) )
diff --git a/input/microalg_export.l b/input/microalg_export.l
new file mode 100644
index 0000000..5f869d5
@@ -0,0 +1,9 @@
+(de proteger_litteraux src (proteger_litteraux_aux src))
+(de proteger_litteraux_aux (src)
+ (cond
+ ((num? src) (list 'Litteral src))
+ ((str? src) (list 'Litteral src))
+ ((sym? src) src)
+ (T (mapcar 'proteger_litteraux_aux src))
+ )
+)
\ No newline at end of file
diff --git a/input/microalg_export_blockly.l b/input/microalg_export_blockly.l
new file mode 100644
index 0000000..c91f4af
@@ -0,0 +1,95 @@
+(de Litteral (content)
+ (cond
+ ((num? content) (pack "<block type=\"nombre_litteral\"><field name=\"NUM\">"
+ content
+ "</field></block>"))
+ ((str? content) (pack "<block type=\"texte_litteral\"><field name=\"TEXT\">"
+ content
+ "</field></block>"))
+ (T "Littéral de type inconnu.")
+ ))
+(de insertion_next (src) (car (insertion_next_aux (reverse src))))
+(de insertion_next_aux (src)
+ (if (<= (length src) 1) src
+ # Déplacement de la tête, enfermée dans un (Next ),
+ # À la fin du deuxième élément.
+ # La queue restant inchangée.
+ (let (tete (car src)
+ deuxieme_instr (cadr src)
+ reste (cddr src))
+ (queue 'deuxieme_instr (list 'Next tete))
+ (insertion_next_aux
+ (cons
+ deuxieme_instr
+ reste)
+ )
+ )
+ ))
+(de Next (content)
+ (pack "<next>"
+ content
+ "</next>"))
+(de !!! (content next)
+ (pack "<block type=\"commentaire\"><field name=\"COMZ\">"
+ content
+ "</field>"
+ next
+ "</block>"))
+(de + (A B)
+ (pack "<block type=\"operations\"><field name=\"OP\">ADD</field>"
+ "<value name=\"A\">" A "</value>"
+ "<value name=\"B\">" B "</value>"
+ "</block>"))
+(de - (A B)
+ (pack "<block type=\"operations\"><field name=\"OP\">MINUS</field>"
+ "<value name=\"A\">" A "</value>"
+ "<value name=\"B\">" B "</value>"
+ "</block>"))
+(de * (A B)
+ (pack "<block type=\"operations\"><field name=\"OP\">MULTIPLY</field>"
+ "<value name=\"A\">" A "</value>"
+ "<value name=\"B\">" B "</value>"
+ "</block>"))
+(de / (A B)
+ (pack "<block type=\"operations\"><field name=\"OP\">DIVIDE</field>"
+ "<value name=\"A\">" A "</value>"
+ "<value name=\"B\">" B "</value>"
+ "</block>"))
+(de Afficher (content next)
+ (pack "<block type=\"afficher\">"
+ "<value name=\"VALUE\">"
+ content
+ "</value>"
+ next
+ "</block>"))
+(de Concatener inputs
+ (pack "<block type=\"concatener\">"
+ "<mutation items=\"" (length inputs) "\"></mutation>"
+ (mapcar '((i input) (pack "<value name=\"ADD" i "\">" (eval input) "</value>")) (range 0 (dec (length inputs))) inputs)
+ "</block>"))
+(de Demander ()
+ "<block type=\"demander\"></block>")
+(de Nombre (content)
+ (pack "<block type=\"nombre\">"
+ "<value name=\"VALUE\">"
+ content
+ "</value>"
+ "</block>"))
+(de Nombre? (content)
+ (pack "<block type=\"nombre?\">"
+ "<value name=\"VALUE\">"
+ content
+ "</value>"
+ "</block>"))
+(de Texte (content)
+ (pack "<block type=\"texte\">"
+ "<value name=\"VALUE\">"
+ content
+ "</value>"
+ "</block>"))
+(de Texte? (content)
+ (pack "<block type=\"texte?\">"
+ "<value name=\"VALUE\">"
+ content
+ "</value>"
+ "</block>"))
diff --git a/input/static/microalg_web/emulisp/emulisp_core.js b/input/static/microalg_web/emulisp/emulisp_core.js
index 0aee9ce..3987f15 100644
@@ -1,22 +1,23 @@
-/* 13may14jk
+/* 15sep14jk
* (c) Jon Kleiser
*/
var EMULISP_CORE = (function () {
-var VERSION = [2, 0, 0, 3],
+var VERSION = [2, 0, 2, 0],
+ MONLEN = [31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
BOXNAT_EXP = "Boxed native object expected",
BOOL_EXP = "Boolean expected", CELL_EXP = "Cell expected", LIST_EXP = "List expected",
NUM_EXP = "Number expected", SYM_EXP = "Symbol expected", VAR_EXP = "Variable expected",
EXEC_OR_NUM_EXP = "Executable or Number expected",
+ CHANNEL_NOT_SUPPORTED = "EmuLisp only supports the NIL channel",
BAD_ARG = "Bad argument", BAD_DOT = "Bad dotted pair", BAD_INPUT = "Bad input", DIV_0 = "Div/0",
NOT_MAK = "Not making", PROT_SYM = "Protected symbol", UNDEF = "Undefined",
JS_CTORNAME_EXP = "Constructor name expected", JS_RESERVED = "Reserved word";
-/** bla */
function getFileSync(fileUrl) {
var req = new XMLHttpRequest();
- var OK = fileUrl.match(/^https?:/) ? 200 : 200;
+ var OK = fileUrl.match(/^file:/) ? 0 : 200;
req.open("GET", fileUrl, false); // synchronous
if (req.overrideMimeType) req.overrideMimeType("text/plain; charset=utf-8");
req.send(null);
@@ -29,6 +30,12 @@ function getFileSync(fileUrl) {
var NILTYPE = 0, NUMBERTYPE = 1, SYMBOLTYPE = 2, CELLTYPE = 3, TRUETYPE = 4;
Number.prototype.TYPEVAL = NUMBERTYPE;
+Function.prototype.TYPEVAL = NUMBERTYPE;
+
+function logLisp(msg, x) {
+ console.log("%s: %s", msg, x.toString());
+ return x;
+}
function lispToStr(x) {
//if (!confirm("lispToStr: " + x.toString() + ", " + x.TYPEVAL)) throw new Error("lispToStr aborted");
@@ -92,14 +99,14 @@ Cell.prototype.toValueString = function() {
function Symbol(name, val) {
this.name = name;
this.trans = false;
- this.cdr = (val === undefined) ? NIL : val;
+ this.car = (val === undefined) ? NIL : val; // Ersatz-like
this.props = NIL;
}
function newTransSymbol(name) {
var ts = new Symbol(name);
ts.trans = true;
- ts.cdr = ts;
+ ts.car = ts; // Ersatz-like
return ts;
}
@@ -113,7 +120,7 @@ function box(val) {
Symbol.prototype.TYPEVAL = SYMBOLTYPE;
Symbol.prototype.getVal = function() {
- return this.cdr;
+ return this.car; // Ersatz-like
}
Symbol.prototype.valueOf = function() {
@@ -122,7 +129,7 @@ Symbol.prototype.valueOf = function() {
Symbol.prototype.setVal = function(val) {
if (this.lock) throw new Error(newErrMsg(PROT_SYM, this));
- this.cdr = val;
+ this.car = val; // Ersatz-like
}
// Internal symbol names can consist of any printable (non-whitespace) character,
@@ -130,6 +137,7 @@ Symbol.prototype.setVal = function(val) {
// It is possible, though, to include these special characters into symbol names
// by escaping them with a backslash '\'.
Symbol.prototype.escName = function() {
+ if (this.name instanceof Number) return this.name;
var eName = this.name.replace(/\\/g, "\\\\");
eName = eName.replace(/\"/g, "\\\"");
eName = eName.replace(/\^/g, "\\^");
@@ -154,13 +162,13 @@ Symbol.prototype.toValueString = function() {
Symbol.prototype.pushValue = function(val) {
if (this.stack === undefined) this.stack = [];
- this.stack.push(this.cdr);
- this.cdr = val;
+ this.stack.push(this.car); // Ersatz-like
+ this.car = val; // Ersatz-like
}
Symbol.prototype.popValue = function() {
- var pv = this.cdr;
- this.cdr = this.stack.pop();
+ var pv = this.car; // Ersatz-like
+ this.car = this.stack.pop(); // Ersatz-like
//if (this.stack.length === 0) delete this.stack;
return pv;
}
@@ -180,6 +188,21 @@ function setSymbolValue(s, val) {
s.setVal(val);
}
+function needVar(ex, x) {
+ if (x instanceof Number) throw new Error(newErrMsg(VAR_EXP, x)); // Ersatz-like
+ // TODO: handle ex
+}
+
+function indx(x, y) { // Ersatz-like
+ var i = 1, z = y;
+ while (y instanceof Cell) {
+ if (eqVal(x, y.car)) return i;
+ ++i;
+ if (z === (y = y.cdr)) return 0;
+ }
+ return 0;
+}
+
function Source(text, chars) {
this.src = text;
// character limitation for symbols
@@ -261,7 +284,7 @@ Source.prototype.getSymbolBeforePos = function(endPos) {
var NIL = new Symbol("NIL"); NIL.car = NIL; NIL.cdr = NIL; NIL.props = NIL;
NIL.lock = true; NIL.TYPEVAL = NILTYPE; NIL.bool = false;
-var T = new Symbol("T"); T.cdr = T; T.lock = true; T.TYPEVAL = TRUETYPE; T.bool = true;
+var T = new Symbol("T"); T.car = T; T.lock = true; T.TYPEVAL = TRUETYPE; T.bool = true;
var A1 = new Symbol("@", NIL), A2 = new Symbol("@@", NIL), A3 = new Symbol("@@@", NIL);
var ZERO = new Number(0), ONE = new Number(1);
var gEmptyObj = {};
@@ -282,20 +305,12 @@ function prepareNewState(optionalState) {
compExprArr: [], // sort expression stack
evFrames: NIL,
trcIndent: "",
- startupMillis: (new Date()).getTime()
+ startupMillis: Date.now()
};
QUOTE = getSymbol("quote");
getSymbol("*EMUENV").setVal(new Symbol(emuEnv()));
}
-//var gSym = {NIL: NIL, T: T, "@": A1, "@@": A2, "@@@": A3}; // dictionary/index for internal symbols
-//var gTrans = {}; // dictionary/index for transient symbols (strings)
-//var gParseCache = {};
-//var mk = []; // 'make' stack
-//var evFrames = NIL;
-//var gTrcIndent = "";
-//var startupMillis = (new Date()).getTime();
-
function mkNew() { cst.mk.unshift({h: NIL, t: NIL}); }
function linkc(c) {
if (cst.mk.length === 0) throw new Error(newErrMsg(NOT_MAK));
@@ -303,13 +318,18 @@ function linkc(c) {
if (cst.mk[0].h === NIL) { cst.mk[0].h = c; } else { cst.mk[0].t.cdr = c; }
while (c.cdr !== NIL) { c = c.cdr; }; cst.mk[0].t = c; return c.car;
}
-function link(x) {
- if (cst.mk.length === 0) throw new Error(newErrMsg(NOT_MAK));
+function mkResult() { return cst.mk.shift().h; }
+
+function List() {
+ this.list = NIL;
+ this.last = NIL;
+}
+
+List.prototype.link = function(x) {
var c = new Cell(x, NIL);
- if (cst.mk[0].h === NIL) { cst.mk[0].h = c; } else { cst.mk[0].t.cdr = c; }
- cst.mk[0].t = c; return x;
+ if (this.list === NIL) { this.list = c; } else { this.last.cdr = c; }
+ this.last = c;
}
-function mkResult() { return cst.mk.shift().h; }
function getString(str, editMode) {
var s = (str in gEmptyObj) ? undefined : cst.tSym[str];
@@ -322,12 +342,10 @@ function getString(str, editMode) {
function newErrMsg(msg, badValue) {
getSymbol("*Msg").setVal(newTransSymbol(msg));
- return (badValue === undefined) ? msg : lispToStr(badValue) + " -- " + msg;
+ return (badValue === undefined) ? msg + "" : lispToStr(badValue) + " -- " + msg;
}
-function aTrue(val) { if (val !== NIL) { A1.pushValue(val); return true; } else return false; }
-
-function aPop(val) { A1.popValue(); return val; }
+function aTrue(val) { if (val !== NIL) { A1.setVal(val); return true; } else return false; }
function car(c) { if (c.car) return c.car; else throw new Error(newErrMsg(LIST_EXP)); }
function cdr(c) { if ((c instanceof Cell) || (c === NIL)) return c.cdr;
@@ -338,6 +356,13 @@ function numeric(val) {
throw new Error(newErrMsg(NUM_EXP, val));
}
+function validTime1970(y, m, d) {
+ numeric(y); numeric(m); numeric(d);
+ if (m<1 || m>12 || d<1 || d>MONLEN[m] && (m!=2 || d!=29 || y%4!=0 || y%100==0 && y%400!=0)) return null;
+ var ms1970 = Date.UTC(y, m - 1, d);
+ return (y >= 100) ? ms1970 : ms1970 - 59958144000000;
+}
+
function nth(lst, n) {
if (lst instanceof Cell) {
if (n <= 0) return NIL;
@@ -373,9 +398,9 @@ function getAlg(c) {
do { s = s.cdr; } while ((s !== NIL) && (++k < 0));
}
} else {
- return NIL;
+ s = NIL;
}
- } else throw new Error(newErrMsg(SYM_EXP));
+ } else throw new Error(newErrMsg(SYM_EXP, s));
c = c.cdr;
}
return s;
@@ -399,7 +424,6 @@ function iter(c) {
if (cond) {
if (cMatch) {
v = prog(cv.cdr.cdr);
- if (cv.car === T) aPop(v);
return {v: v, m: true};
}
} else v = evalLisp(cv);
@@ -422,7 +446,7 @@ function div(c, divFn) {
}
function eqVal(a, b) {
- //alert("eqVal() " + a + ", " + b);
+ //console.log("eqVal(%s, %s)", a, b);
if (a.TYPEVAL === b.TYPEVAL) {
if (a === b) return true;
if (a.TYPEVAL === CELLTYPE) {
@@ -517,9 +541,9 @@ function idxDelete(owner, v) {
return tree;
}
-function idxLinkSorted(tree) {
+function idxLinkSorted(tree, resList) {
while (tree !== NIL)
- { idxLinkSorted(tree.cdr.car); link(tree.car); tree = tree.cdr.cdr; }
+ { idxLinkSorted(tree.cdr.car, resList); resList.link(tree.car); tree = tree.cdr.cdr; }
}
/*
@@ -589,14 +613,15 @@ function cachedTextParse(str) {
function unevalArgs(lst) {
// Putting elements of lst into anonymous symbols
- mkNew(); while (lst !== NIL) { link(box(lst.car)); lst = lst.cdr; }
- return mkResult();
+ var a = new List(); while (lst !== NIL) { a.link(box(lst.car)); lst = lst.cdr; }
+ return a.list;
}
function applyFn(rawFn, lst, more) {
+ if (! (lst instanceof Cell)) lst = NIL;
if (more !== NIL) {
- mkNew(); do { link(evalLisp(more.car)); more = more.cdr; } while (more !== NIL);
- cst.mk[0].t.cdr = lst; lst = mkResult();
+ var m = new List(); do { m.link(evalLisp(more.car)); more = more.cdr; } while (more !== NIL);
+ m.last.cdr = lst; lst = m.list;
}
var fn = evalLisp(rawFn); if (! (fn instanceof Symbol)) fn = box(fn);
return evalLisp(new Cell(fn, unevalArgs(lst)));
@@ -608,6 +633,19 @@ function printx(c, x) { var arr = [];
_stdPrint(arr.join(" ") + x); return c.car;
}
+function rand(c, picoSize) {
+ var r = Math.random(); // range 0.0 .. 1.0
+ if (c === NIL) {
+ if (picoSize) r = Math.floor((2 * r - 1) * picoSize);
+ return new Number(r);
+ }
+ var n = evalLisp(c.car);
+ if (n === T) return (r < 0.5) ? NIL : T;
+ r = (-numeric(n) + numeric(evalLisp(c.cdr.car)) + (picoSize ? 1 : 0)) * r + n;
+ if (picoSize) r = Math.floor(r);
+ return new Number(r);
+}
+
function ascending(a, b) { return ltVal(a, b) ? -1 : eqVal(a, b) ? 0 : 1; }
//function descending(a, b) { return ltVal(a, b) ? 1 : eqVal(a, b) ? 0 : -1; }
@@ -619,14 +657,21 @@ function CompExpr(fn) {
}
CompExpr.prototype.evalTrue = function(a, b) {
- this.arg1Sym.cdr = a; // faster than this.arg1Sym.setVal(a);
- this.arg2Sym.cdr = b;
+ this.arg1Sym.car = a; // Ersatz-like, faster than this.arg1Sym.setVal(a);
+ this.arg2Sym.car = b; // Ersatz-like
return (evalLisp(this.expr) === T);
}
function lispFnOrder(a, b) { return cst.compExprArr[0].evalTrue(a, b) ? -1 : 1; }
var coreFunctions = {
+ "and": function(c) { var v = NIL; while (c instanceof Cell) { v = evalLisp(c.car);
+ if (!aTrue(v)) return NIL; c = c.cdr; } return v;
+ },
+ "any": function(c) { var cv = evalLisp(c.car);
+ if (cv instanceof Symbol) return cachedTextParse(cv.valueOf()).car;
+ throw new Error(newErrMsg(SYM_EXP, cv));
+ },
"apply": function(c) { return applyFn(c.car, evalLisp(c.cdr.car), c.cdr.cdr); },
"arg": function(c) { var n = 0, f = cst.evFrames.car;
if (c !== NIL) {
@@ -636,11 +681,12 @@ var coreFunctions = {
return f.car;
},
"args": function(c) { return (cst.evFrames.car.cdr === NIL) ? NIL : T; },
- "bench": function(c) { var t0 = (new Date()).getTime(), r = prog(c);
- _stdPrint(((new Date()).getTime() - t0) / 1000 + " sec\n"); return r;
+ "atom": function(c) { return (evalLisp(c.car) instanceof Cell) ? NIL : T; },
+ "bench": function(c) { var t0 = Date.now(), r = prog(c);
+ _stdPrint((Date.now() - t0) / 1000 + " sec\n"); return r;
},
+ "bool": function(c) { return (evalLisp(c.car) === NIL) ? NIL : T; },
"box": function(c) { return box(evalLisp(c.car)); },
- /** bye */
"bye": function(c) { prog(getSymbol("*Bye").getVal());
if (emuEnv() == "nodejs") { var prv = evalLisp(c.car);
process.exit((prv instanceof Number) ? prv : 0); } else {
@@ -664,7 +710,7 @@ var coreFunctions = {
},
"cond": function(c) {
while (c.car instanceof Cell) {
- if (aTrue(evalLisp(c.car.car))) return aPop(prog(c.car.cdr));
+ if (aTrue(evalLisp(c.car.car))) return prog(c.car.cdr);
c = c.cdr;
}
return NIL;
@@ -674,18 +720,32 @@ var coreFunctions = {
while (c !== NIL) { var d = new Cell(t.cdr, evalLisp(c.car)); t.cdr = d; t = d; c = c.cdr; }
return r;
},
+ "date": function(c) { var MSPD = 86400000, D1970 = 719469, a1 = evalLisp(c.car), ms1970;
+ if ((c === NIL) || (a1 === T)) {
+ ms1970 = Date.now();
+ if (c === NIL) ms1970 -= (new Date()).getTimezoneOffset() * 60000; // local (non-UTC)
+ return new Number(Math.floor(ms1970 / MSPD) + D1970);
+ }
+ if (a1 instanceof Cell) {
+ ms1970 = validTime1970(a1.car, a1.cdr.car, a1.cdr.cdr.car);
+ return (ms1970 !== null) ? new Number(ms1970 / MSPD + D1970) : NIL;
+ }
+ if (a1 instanceof Number) {
+ if (c.cdr !== NIL) {
+ ms1970 = validTime1970(a1, evalLisp(c.cdr.car), evalLisp(c.cdr.cdr.car));
+ return (ms1970 !== null) ? new Number(ms1970 / MSPD + D1970) : NIL;
+ }
+ var d = new Date((a1 - D1970) * MSPD);
+ return new Cell(new Number(d.getUTCFullYear()), new Cell(new Number(d.getUTCMonth() + 1),
+ new Cell(new Number(d.getUTCDate()), NIL)));
+ }
+ return NIL;
+ },
"de": function(c) { var old = c.car.getVal();
setSymbolValue(c.car, c.cdr);
if ((old !== NIL) && !eqVal(c.cdr, old)) _warn("# " + c.car.valueOf() + " redefined");
return c.car;
},
- "def": function(c) {
- var name = evalLisp(c.car);
- var old = name.getVal();
- setSymbolValue(name, c.cdr);
- if ((old !== NIL) && !eqVal(c.cdr, old)) _warn("# " + name.valueOf() + " redefined");
- return name;
- },
"dec": function(c) {
if (c === NIL) return NIL;
var ns = evalLisp(c.car);
@@ -696,13 +756,13 @@ var coreFunctions = {
"delete": function(c) { var a = evalLisp(c.car), lst = evalLisp(c.cdr.car);
if (!(lst instanceof Cell)) return lst;
if (eqVal(a, lst.car)) return lst.cdr;
- mkNew(); link(lst.car); lst = lst.cdr;
+ var r = new List(); r.link(lst.car); lst = lst.cdr;
while (lst instanceof Cell) {
- if (eqVal(a, lst.car)) { cst.mk[0].t.cdr = lst.cdr; return mkResult(); }
- link(lst.car); lst = lst.cdr;
+ if (eqVal(a, lst.car)) { r.last.cdr = lst.cdr; return r.list; }
+ r.link(lst.car); lst = lst.cdr;
}
- cst.mk[0].t.cdr = lst; // taking care of dotted tail
- return mkResult();
+ r.last.cdr = lst; // taking care of dotted tail
+ return r.list;
},
"do": function(c) {
var n = evalLisp(c.car);
@@ -760,20 +820,41 @@ var coreFunctions = {
s.popValue(); if (s2 != null) s2.popValue();
return v;
},
+ "format": function(c) { var cv = evalLisp(c.car);
+ // Decimal and thousands separators not implemented yet:
+ // http://www.software-lab.de/doc/refF.html#format
+ if (cv instanceof Number) return newTransSymbol(cv);
+ if (cv.trans) {
+ return isNaN(cv.name)? NIL : new Number(parseFloat(cv.name));
+ }
+ return NIL;
+ },
+ "ge0": function(c) { var cv = evalLisp(c.car);
+ return ((cv instanceof Number) && (cv >= 0)) ? cv : NIL; },
"get": function(c) { return getAlg(evalArgs(c)); },
"getl": function(c) { var s = getAlg(evalArgs(c));
if (s instanceof Symbol) return s.props;
throw new Error(newErrMsg(SYM_EXP, s));
},
+ "gt0": function(c) { var cv = evalLisp(c.car);
+ return ((cv instanceof Number) && (cv > 0)) ? cv : NIL; },
"idx": function(c) { var s = evalLisp(c.car);
if (!(s instanceof Symbol)) return NIL;
- if (c.cdr === NIL) { mkNew(); idxLinkSorted(s.getVal()); return mkResult(); }
+ if (c.cdr === NIL) { var r = new List(); idxLinkSorted(s.getVal(), r); return r.list; }
var a = evalLisp(c.cdr.car);
if (c.cdr.cdr === NIL) return idxLookup(s, a);
return (evalLisp(c.cdr.cdr.car) === NIL) ? idxDelete(s, a) : idxInsert(s, a);
},
- "if": function(c) { return aTrue(evalLisp(c.car)) ? aPop(evalLisp(c.cdr.car)) : prog(c.cdr.cdr); },
- "ifn": function(c) { return aTrue(evalLisp(c.car)) ? aPop(prog(c.cdr.cdr)) : evalLisp(c.cdr.car); },
+ "if": function(c) { return aTrue(evalLisp(c.car)) ? evalLisp(c.cdr.car) : prog(c.cdr.cdr); },
+ "ifn": function(c) { return aTrue(evalLisp(c.car)) ? prog(c.cdr.cdr) : evalLisp(c.cdr.car); },
+ "in": function(c) { // For now only the NIL channel is supported, just for compat with the use of 'read'.
+ var chan = c.car;
+ if (chan === NIL) {
+ return prog(c.cdr);
+ } else {
+ throw new Error(newErrMsg(CHANNEL_NOT_SUPPORTED, chan));
+ }
+ },
"inc": function(c) {
if (c === NIL) return NIL;
var ns = evalLisp(c.car);
@@ -781,6 +862,11 @@ var coreFunctions = {
var v = new Number(ns.getVal() + ((c.cdr !== NIL) ? numeric(evalLisp(c.cdr.car)) : 1));
ns.setVal(v); return v;
},
+ "index": function(c) { var i = indx(evalLisp(c.car), evalLisp(c.cdr.car));
+ return (i === 0) ? NIL : new Number(i);
+ },
+ "le0": function(c) { var cv = evalLisp(c.car);
+ return ((cv instanceof Number) && (cv <= 0)) ? cv : NIL; },
"length": function(c) { var cv = evalLisp(c.car), v = 0;
if (cv instanceof Number) { v = cv.toString().length; }
else if (cv instanceof Symbol) { v = cv.lock ? cv.toValueString().length :
@@ -825,35 +911,40 @@ var coreFunctions = {
"loop": function(c) {
var v = NIL; while (true) { var r = iter(c); v = r.v; if (r.m) break; }; return v;
},
+ "lt0": function(c) { var cv = evalLisp(c.car);
+ return ((cv instanceof Number) && (cv < 0)) ? cv : NIL; },
"make": function(c) { mkNew(); prog(c); return mkResult(); },
"mapc": function(c) { var r = NIL, fn = evalLisp(c.car), ci = evalArgs(c.cdr);
if (! (fn instanceof Symbol)) fn = box(fn);
- while (ci.car !== NIL) { var cj = ci; mkNew();
- while (cj !== NIL) { link(cj.car.car); cj.car = cj.car.cdr; cj = cj.cdr; }
- r = evalLisp(new Cell(fn, unevalArgs(mkResult())));
+ while (ci.car !== NIL) { var cj = ci, a = new List();
+ while (cj !== NIL) { a.link(cj.car.car); cj.car = cj.car.cdr; cj = cj.cdr; }
+ r = evalLisp(new Cell(fn, unevalArgs(a.list)));
}
return r;
},
- "mapcar": function(c) { var fn = evalLisp(c.car), ci = evalArgs(c.cdr);
+ "mapcar": function(c) { var fn = evalLisp(c.car), ci = evalArgs(c.cdr), r = new List();
if (! (fn instanceof Symbol)) fn = box(fn);
- mkNew();
- while (ci.car !== NIL) { var cj = ci; mkNew();
- //if (!confirm(lispToStr(cj))) throw new Error("mapcar aborted");
- while (cj !== NIL) { link(cj.car.car); cj.car = cj.car.cdr; cj = cj.cdr; }
- link(evalLisp(new Cell(fn, unevalArgs(mkResult()))));
+ while (ci.car !== NIL) { var cj = ci, a = new List();
+ while (cj !== NIL) { a.link(cj.car.car); cj.car = cj.car.cdr; cj = cj.cdr; }
+ r.link(evalLisp(new Cell(fn, unevalArgs(a.list))));
}
- return mkResult();
+ return r.list;
},
"n0": function(c) { return eqVal(evalLisp(c.car), ZERO) ? NIL : T; },
"next": function(c) { cst.evFrames.car = cst.evFrames.car.cdr; return cst.evFrames.car.car; },
"not": function(c) { return (evalLisp(c.car) === NIL) ? T : NIL; },
+ "nT": function(c) { return (evalLisp(c.car) === T) ? NIL : T; },
"nth": function(c) { var lst = evalArgs(c); c = lst.cdr;
do { lst = nth(lst.car, numeric(c.car)); c = c.cdr; } while(c !== NIL); return lst; },
+ "num?": function(c) { var v = evalLisp(c.car); return (v instanceof Number) ? v : NIL; },
"or": function(c) { while (c instanceof Cell) { var v = evalLisp(c.car);
- if (v !== NIL) return v; c = c.cdr; } return NIL;
+ if (aTrue(v)) return v; c = c.cdr; } return NIL;
},
// pack has no support for circular lists, same as in PicoLisp
- "pack": function(c) { return (c !== NIL) ? newTransSymbol(valueToStr(evalArgs(c))) : NIL; },
+ "pack": function(c) {
+ if (c !== NIL) { var s = valueToStr(evalArgs(c)); if (s !== "") return newTransSymbol(s); }
+ return NIL;
+ },
"pass": function(c) { return applyFn(c.car, cst.evFrames.car.cdr, c.cdr); },
"pop": function(c) { var cv = evalLisp(c.car);
if (cv.getVal) {
@@ -864,6 +955,12 @@ var coreFunctions = {
}
throw new Error(newErrMsg(VAR_EXP, cv));
},
+ "pre?": function(c) {
+ var s1 = valueToStr(evalLisp(c.car)), v2 = evalLisp(c.cdr.car), s2 = valueToStr(v2);
+ if (s1 !== s2.substring(0, s1.length)) return NIL;
+ // Handling Cell and Number like PicoLisp, not like Ersatz ...
+ return ((v2 instanceof Cell) || (v2 instanceof Number)) ? newTransSymbol(s2) : v2;
+ },
"prin": function(c) {
c = evalArgs(c); _stdPrint(c.toValueString());
while (c.cdr !== NIL) { c = c.cdr; }; return c.car;
@@ -871,7 +968,7 @@ var coreFunctions = {
"prinl": function(c) {
c = evalArgs(c); _stdPrint(c.toValueString() + "\n");
while (c.cdr !== NIL) { c = c.cdr; }; return c.car;
- },
+ },
"print": function(c) { return printx(c, ""); },
"println": function(c) { return printx(c, "\n"); },
"printsp": function(c) { return printx(c, " "); },
@@ -884,10 +981,10 @@ var coreFunctions = {
throw new Error(newErrMsg(VAR_EXP, t));
},
"put": function(c) {
- var kc, vc;
- c = evalArgs(c); mkNew();
- do { link(c.car); kc = c.cdr; vc = kc.cdr; c = c.cdr; } while (vc.cdr !== NIL);
- var s = getAlg(mkResult()), k = kc.car;
+ var kc, vc, a = new List();
+ c = evalArgs(c);
+ do { a.link(c.car); kc = c.cdr; vc = kc.cdr; c = c.cdr; } while (vc.cdr !== NIL);
+ var s = getAlg(a.list), k = kc.car;
if (!(s instanceof Symbol)) throw new Error(newErrMsg(SYM_EXP, s));
if (s === NIL) throw new Error(newErrMsg(PROT_SYM, s));
if (eqVal(k, ZERO)) {
@@ -922,18 +1019,33 @@ var coreFunctions = {
throw new Error(newErrMsg(VAR_EXP, s));
},
"quote": function(c) { return c; },
- "rand": function(c) { var r = Math.random();
- if (c === NIL) return new Number(r); // range 0.0 .. 1.0
- var n = evalLisp(c.car);
- if (n === T) return (r < 0.5) ? NIL : T;
- return new Number((-numeric(n) + numeric(evalLisp(c.cdr.car))) * r + n);
+ "quit": function(c) {
+ var value = evalLisp(c.cdr.car);
+ if (value == NIL) throw new Error(newErrMsg(evalLisp(c.car)));
+ else throw new Error(newErrMsg(evalLisp(c.car), value));
},
+ "rand": function(c) { return rand(c, 2147483648); },
+ "randfloat": function(c) { return rand(c); }, // not std. PicoLisp
"range": function(c) {
var n = numeric(evalLisp(c.car)), n2 = numeric(evalLisp(c.cdr.car)), s = evalLisp(c.cdr.cdr.car);
if (s === NIL) { s = 1; } else if (numeric(s) <= 0) throw new Error(newErrMsg(BAD_ARG, s));
if (n > n2) s = -s;
- mkNew(); do { link(n); n = new Number(n + s); } while ((s > 0) ? (n <= n2) : (n >= n2));
- return mkResult();
+ var r = new List(); do { r.link(n); n = new Number(n + s); } while ((s > 0) ? (n <= n2) : (n >= n2));
+ return r.list;
+ },
+ "read": function(c) { // No support (yet) for the two parameters (non-split chars and comment char).
+ if (emuEnv() == 'nodejs') {
+ var readlinesync = require('readline-sync');
+ readlinesync.setPrompt("");
+ _stdPrompt = readlinesync.prompt;
+ } else {
+ if (typeof stdPrompt != "undefined") {
+ var _stdPrompt = stdPrompt;
+ } else {
+ var _stdPrompt = window.prompt;
+ }
+ }
+ return newTransSymbol(_stdPrompt());
},
"rest": function(c) { return cst.evFrames.car.cdr; },
"reverse": function(c) { var lst = evalLisp(c.car), r = NIL;
@@ -941,6 +1053,28 @@ var coreFunctions = {
do { r = new Cell(lst.car, r); lst = lst.cdr; } while (lst instanceof Cell);
return r;
},
+ "round": function(c) {
+ var len = evalLisp(c.cdr.car);
+ if (len == NIL) len = 3;
+ var power_of_ten = Math.pow(10, len);
+ var num = evalLisp(c.car);
+ return newTransSymbol((Math.round(num * power_of_ten) / power_of_ten).toString());
+ },
+ "run": function(c) { // TODO: binding env. offset cnt
+ c = evalLisp(c.car);
+ // Reuse prog here.
+ var v = NIL; while (c instanceof Cell) { v = evalLisp(c.car); c = c.cdr; }; return v;
+ },
+ "set": function(c) {
+ var v = NIL;
+ while (c instanceof Cell) {
+ v = (c.cdr instanceof Cell) ? evalLisp(c.cdr.car) : NIL;
+ needVar(c, c.car);
+ evalLisp(c.car).car = v;
+ c = (c.cdr instanceof Cell) ? c.cdr.cdr : NIL;
+ }
+ return v;
+ },
"setq": function(c) {
var v = NIL;
while (c instanceof Cell) {
@@ -949,7 +1083,7 @@ var coreFunctions = {
c = (c.cdr instanceof Cell) ? c.cdr.cdr : NIL;
}
return v;
- },
+ },
"sort": function(c) {
var lst = evalLisp(c.car);
if (lst instanceof Cell) {
@@ -967,6 +1101,26 @@ var coreFunctions = {
}
return lst;
},
+ "space": function(c) { var n = 1, s;
+ if (c.car !== NIL) n = numeric(evalLisp(c.car));
+ for (s = ""; s.length < n; s += " ") {}
+ if (s > "") _stdPrint(s);
+ return new Number(n);
+ },
+ "split": function(c) {
+ var lst = evalLisp(c.car);
+ if (lst instanceof Cell) {
+ var x = c.cdr, arr = []; while (x !== NIL) { arr.push(evalLisp(x.car)); x = x.cdr; }
+ var r1 = new List(), r2 = new List();
+ do { var i; for (i=0; i<arr.length && !eqVal(lst.car, arr[i]); i++) {}
+ if (i<arr.length) { r1.link(r2.list); r2 = new List(); } else r2.link(lst.car);
+ lst = lst.cdr;
+ } while (lst instanceof Cell);
+ r1.link(r2.list);
+ return r1.list;
+ }
+ return lst;
+ },
"str": function(c) {
var cv = evalLisp(c.car);
if (cv instanceof Symbol) {
@@ -982,7 +1136,9 @@ var coreFunctions = {
if (cv === NIL) return NIL;
throw new Error(newErrMsg(CELL_EXP, cv));
},
+ "str?": function(c) { var v = evalLisp(c.car); return ((v instanceof Symbol) && v.trans) ? v : NIL; },
"sym": function(c) { return newTransSymbol(evalLisp(c.car).toString()); },
+ "sym?": function(c) { return (evalLisp(c.car) instanceof Symbol) ? T : NIL; },
"tail": function(c) {
var cl = evalLisp(c.car), lst = evalLisp(c.cdr.car);
if (cl instanceof Cell) {
@@ -1024,9 +1180,13 @@ var coreFunctions = {
setSymbolValue(s, f);
return s;
},
- "usec": function(c) { return new Number(((new Date()).getTime() - cst.startupMillis) * 1000); },
+ "usec": function(c) { return new Number((Date.now() - cst.startupMillis) * 1000); },
+ "val": function(c) { var x = evalLisp(c.car); needVar(c, x); return x.car; },
"version": function(c) { if (!aTrue(evalLisp(c.car))) _stdPrint(VERSION.join(".") + " JS\n");
- mkNew(); for (var i=0; i<VERSION.length; i++) { link(VERSION[i]); }; return mkResult(); },
+ var v = new List(); for (var i=0; i<VERSION.length; i++) { v.link(VERSION[i]); }; return v.list; },
+ "while": function(c) {
+ var v = NIL; while (aTrue(evalLisp(c.car))) { v = prog(c.cdr); }; return v;
+ },
"yoke": function(c) { if (cst.mk.length === 0) throw new Error(newErrMsg(NOT_MAK));
var tn = (cst.mk[0].t === NIL);
do { var h = new Cell(evalLisp(c.car), cst.mk[0].h);
@@ -1071,10 +1231,13 @@ var coreFunctions = {
"/": function(c) { return div(c, function(a, b) { return a / b; }); }, // floating point division
"/t": function(c) { return div(c, function(a, b) { var d = a / b;
return (d >= 0) ? Math.floor(d) : Math.ceil(d); }); }, // truncated division
+ "%": function(c) { return div(c, function(a, b) { return a % b; }); },
"=": function(c) { var cv = evalLisp(c.car), d = c, dv;
while (d.cdr !== NIL) { d = d.cdr; dv = evalLisp(d.car); if (!eqVal(cv, dv)) return NIL; }; return T; },
+ "=0": function(c) { return eqVal(evalLisp(c.car), ZERO) ? ZERO : NIL; },
"==": function(c) { var cv = evalLisp(c.car), d = c, dv;
while (d.cdr !== NIL) { d = d.cdr; dv = evalLisp(d.car); if (cv !== dv) return NIL; }; return T; },
+ "=T": function(c) { return (evalLisp(c.car) === T) ? T : NIL; },
"<": function(c) { var cv = evalLisp(c.car), d = c, dv;
while (d.cdr !== NIL) {
d = d.cdr; dv = evalLisp(d.car); if (!ltVal(cv, dv)) return NIL;
@@ -1087,6 +1250,8 @@ var coreFunctions = {
cv = dv;
}; return T;
},
+ "<>": function(c) { var cv = evalLisp(c.car), d = c, dv;
+ while (d.cdr !== NIL) { d = d.cdr; dv = evalLisp(d.car); if (!eqVal(cv, dv)) return T; }; return NIL; },
">": function(c) { var cv = evalLisp(c.car), d = c, dv;
while (d.cdr !== NIL) {
d = d.cdr; dv = evalLisp(d.car); if (!ltVal(dv, cv)) return NIL;
@@ -1150,14 +1315,14 @@ function evalDef(def, inExprLst) {
}
function evalLisp(lst) {
- if (lst instanceof Symbol) return lst.cdr;
+ if (lst instanceof Symbol) return lst.car; // Ersatz-like
if (lst instanceof Cell) {
- if (typeof lst.car.cdr === "function") {
- return lst.car.cdr(lst.cdr);
+ if (typeof lst.car.car === "function") {
+ return lst.car.car(lst.cdr); // Ersatz-like
}
if (lst.car instanceof Symbol) {
- if (lst.car.cdr === NIL) throw new Error(newErrMsg(UNDEF, lst.car));
- return evalDef(lst.car.cdr, lst.cdr);
+ if (lst.car.car === NIL) throw new Error(newErrMsg(UNDEF, lst.car));
+ return evalDef(lst.car.car, lst.cdr); // Ersatz-like
}
if ((lst.car.car === QUOTE) && (lst.car.cdr instanceof Cell)) {
return evalDef(lst.car.cdr, lst.cdr);
@@ -1197,10 +1362,10 @@ function loadJavaScript(fileUrl) {
}
function _stdPrint(text) {
- if (typeof stdPrint === "function") stdPrint(text)
+ if (typeof stdPrint === "function") stdPrint(text, cst)
else // when function stdPrint is not available in front end
//if (!confirm("_stdPrint:\n" + text)) throw new Error("_stdPrint aborted");
- console.log(text.replace(/\n$/g,'')); // last new line offered by console.log
+ console.log(text);
}
function _warn(msg) {
@@ -1276,9 +1441,9 @@ function symbolRefUrl(symbolName) {
}
}
-var pub = {
+var pub = {
init: function(optionalState) { prepareNewState(optionalState); },
-
+
currentState: function() { return cst; },
forSymbolWithNameDefineFun: function(name, jsFn) {
@@ -1286,13 +1451,13 @@ var pub = {
var sym = new Symbol(name, jsFn);
cst.iSym[name] = sym;
},
-
+
forSymbolWithNamePushValue: function(name, value) {
var sym = getSymbol(name);
sym.pushValue(value);
return sym;
},
-
+
forSymbolWithNameSetValue: function(name, value) {
return getSymbol(name).setVal(value);
},
@@ -1309,9 +1474,13 @@ var pub = {
evalArgs: evalArgs, evalLisp: evalLisp, lispToStr: lispToStr, loadLisp: loadLisp, newErrMsg: newErrMsg,
newTransSymbol: newTransSymbol, prog: prog, valueToStr: valueToStr, Params: Params,
NIL: NIL, T: T,
+
+ getFileSync: getFileSync,
eval: function(code) {
- return prog(parseList(new Source(code))).toString();
+ var result = prog(parseList(new Source(code)));
+ A3.setVal(A2.getVal()); A2.setVal(A1.getVal()); A1.setVal(result);
+ return result.toString();
}
}
diff --git a/input/static/microalg_web/ide_injections.js b/input/static/microalg_web/ide_injections.js
index 6f99ca8..db8cba8 100644
@@ -1,3 +1,68 @@
+// Load microalg.l.
+// http://stackoverflow.com/questions/984510/what-is-my-script-src-url
+var this_script_url = (function(scripts) {
+ var scripts = document.getElementsByTagName('script'),
+ script = scripts[scripts.length - 1];
+ if (script.getAttribute.length !== undefined) {
+ return script.src
+ }
+ return script.getAttribute('src', -1)
+}());
+var this_script_path = 'static/microalg_web/ide_injections.js';
+var root_path = this_script_url.slice(0, -this_script_path.length);
+var microalg_l_src =
+ EMULISP_CORE.getFileSync(root_path + 'microalg.l');
+var microalg_export_src =
+ EMULISP_CORE.getFileSync(root_path + 'microalg_export.l');
+var microalg_export_blockly_src =
+ EMULISP_CORE.getFileSync(root_path + 'microalg_export_blockly.l');
+
+// Editor states are stored with key = div id to print
+var emulisp_states = {};
+
+// The marvellous PicoLisp prompt:
+var malg_prompt = ": ";
+
+function cleanTransient(text) {
+ text = text.replace(/\^J/g,'\n'); // PicoLisp control char
+ text = text.replace(/\\"/g,'"'); // unescape double quotes
+ text = text.replace(/\n$/,''); // remove last newline
+ if (text.charAt(0) == '"' && text.charAt(text.length-1) == '"') {
+ text = text.slice(1, -1); // remove enclosing quotes
+ }
+ return text;
+}
+
+function stdPrint(text, state) {
+ var target = $('#' + state.context.display_elt);
+ text = cleanTransient(text);
+ if (state.context.type == 'editor') {
+ if (target.html() == " " && text != "") {
+ target.html(""); // clean the target
+ }
+ if (typeof Showdown != 'undefined') {
+ text = new Showdown.converter().makeHtml(text);
+ }
+ target.html(target.html() + text);
+ }
+ if (state.context.type == 'repl') {
+ var repl_elt = $('#' + state.context.display_elt);
+ if (text !== undefined && text != '' && text != 'NIL') {
+ repl_elt.val(repl_elt.val() + "\n" + text);
+ }
+ }
+ if (state.context.type == 'jrepl') {
+ state.context.term.echo(text);
+ }
+}
+
+function stdPrompt() {
+ var last_line_displayed = cleanTransient(EMULISP_CORE.eval('*LastStdOut'));
+ var user_input = window.prompt(last_line_displayed);
+ if (user_input !== null) return user_input;
+ else throw new Error("Opération 'Demander' annulée.")
+}
+
function onCtrlEnter(elt, f) {
elt.keydown(function (e) {
if ((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey) {
@@ -6,13 +71,49 @@ function onCtrlEnter(elt, f) {
});
}
+function ide_action(editor_elt) {
+ // Compute the target HTML elt.
+ var elt_id = editor_elt.attr('id').slice(0, -('-malg-editor'.length));
+ var display_target_id = elt_id + '-displaytarget';
+ // Init the state and load it with MicroAlg.
+ EMULISP_CORE.init();
+ EMULISP_CORE.eval(microalg_l_src);
+ // Custom state for a custom display in the page.
+ EMULISP_CORE.currentState().context = {type: 'editor', display_elt: display_target_id};
+ // Process src.
+ var src = editor_elt.val();
+ // The editor is in a hiddable div,
+ // createRichInput put the editor in a sub div,
+ // that's why we use parent().parent().parent()
+ var error_elt = editor_elt.parent().parent().parent().find('.malg-error').first();
+ var display_elt = editor_elt.parent().parent().parent().find('.malg-display').first();
+ display_elt.html(' ');
+ try {
+ error_elt.text('');
+ EMULISP_CORE.eval(src);
+ } catch(e) {
+ error_elt.text(e.message);
+ }
+ EMULISP_CORE.eval('(setq *LastStdOut "?")');
+ if (typeof(Storage) !== "undefined") {
+ var key = 'microalg_src_' + elt_id;
+ localStorage[key] = src;
+ }
+}
+
function inject_microalg_editor_in(elt_id, config, msg) {
+ // Build the html and bind to ide_action.
+ var display_target_id = elt_id + '-displaytarget';
var script_container = $('#' + elt_id);
- var script_string = '<textarea id="' + elt_id + '-malg-editor" class="malg-editor" cols="80" rows="2" >' + msg + '</textarea>' +
+ var hidden = config.hidden ? ' style="display:none;"' : '';
+ var script_string = '<div ' + hidden + '><textarea id="' + elt_id + '-malg-editor" ' +
+ 'class="malg-editor" cols="80" rows="2"' +
+ 'spellcheck="false">' + msg + '</textarea></div>' +
+ '<input type="button" onclick="ide_action($(\'#' + elt_id + '-malg-editor\'))" value="OK" class="malg-ok"/>' +
'<div class="malg-error" style="color: red;"></div>' +
- '<div class="malg-display"> </div>';
+ '<div id="' + display_target_id + '" class="malg-display"> </div>';
script_container.html(script_string);
- var editor = script_container.find('.malg-editor').first();
+ var editor = $('#' + elt_id + '-malg-editor');
// Load local storage in the editor.
if (config.localStorage && typeof(Storage)!=="undefined") {
var key = 'microalg_src_' + elt_id;
@@ -22,64 +123,219 @@ function inject_microalg_editor_in(elt_id, config, msg) {
}
createRichInput(editor);
onCtrlEnter(editor, ide_action);
- function ide_action(editor_elt) {
- var src = editor_elt.val();
- // createRichInput put the editor in a sub div, that's why we use
- // parent().parent()
- var error_elt = editor_elt.parent().parent().find('.malg-error').first();
- var display_elt = editor_elt.parent().parent().find('.malg-display').first();
- display_elt.html(' ');
- try {
- EMULISP_CORE.eval(src).toString();
- error_elt.text('');
- } catch(e) {
- error_elt.text(e.toString());
- }
- var stdout = EMULISP_CORE.currentState().iSym['*StdOut'].cdr.name;
- if (stdout == '') {
- stdout = ' ';
- }
- display_elt.html(stdout);
- EMULISP_CORE.currentState().iSym['*StdOut'].cdr.name = '';
- if (config.localStorage && typeof(Storage)!=="undefined") {
- localStorage[key] = src;
+}
+
+function repl_action(repl_elt) {
+ // Fetch the relevant state.
+ EMULISP_CORE.init(emulisp_states[repl_elt.attr('id')]);
+ var result;
+ var repl_content = repl_elt.val();
+ var src = repl_content.slice(EMULISP_CORE.currentState().old_src.length,
+ repl_content.length);
+ try {
+ result = EMULISP_CORE.eval(src);
+ } catch(e) {
+ if (e.message == "Function 'bye' not supported") {
+ // Destroy the textarea (parent.parent is because of parenedit).
+ repl_elt.parent().parent().html('');
+ return;
+ } else {
+ repl_elt.val(repl_elt.val() + "\n" + e.message);
}
}
+ if (typeof result != "undefined" && result != '""') {
+ repl_elt.val(repl_elt.val() + "\n-> " + cleanTransient(result));
+ }
+ EMULISP_CORE.eval('(setq *LastStdOut "?")');
+ repl_elt.val(repl_elt.val() + "\n" + malg_prompt);
+ EMULISP_CORE.currentState().old_src = repl_elt.val();
}
function inject_microalg_repl_in(elt_id, msg) {
- var malg_prompt = ": ";
+ // Compute the target HTML elt.
+ var repl_id = elt_id + '-malg-repl';
+ // Init the state and load it with MicroAlg.
+ EMULISP_CORE.init();
+ EMULISP_CORE.eval(microalg_l_src);
+ // Custom state for a custom display in the REPL.
+ EMULISP_CORE.currentState().context = {type: 'repl', display_elt: repl_id};
+ emulisp_states[repl_id] = EMULISP_CORE.currentState();
+ // Build the html and bind to ide_action.
var repl_container = $('#' + elt_id);
- var repl_string = '<textarea id="malg-repl" class="malg-repl" rows="2" >' + malg_prompt + msg + '</textarea>';
+ var rows = msg.split('\n').length;
+ var repl_string = '<textarea id="' + repl_id + '" class="malg-repl" rows="' + (rows+2) + '" spellcheck="false">' + malg_prompt + msg + '</textarea>' +
+ '<input type="button" onclick="repl_action($(\'#' + elt_id + '-malg-repl\'))" value="OK" class="malg-ok"/>';
repl_container.html(repl_string);
- var repl = repl_container.find('.malg-repl').first();
+ var repl = $('#' + repl_id);
createRichInput(repl);
onCtrlEnter(repl, repl_action);
- var old_src = malg_prompt;
- function repl_action(repl_elt) {
- var result = '';
- var repl_content = repl_elt.val();
- var src = repl_content.slice(old_src.length, repl_content.length);
- try {
- result = EMULISP_CORE.eval(src).toString();
- } catch(e) {
- if (e.toString() == "Error: Function 'bye' not supported") {
- repl_container.html('');
- } else {
- repl_elt.val(repl_elt.val() + "\n" + e.toString());
+ EMULISP_CORE.currentState().old_src = malg_prompt;
+}
+
+function inject_microalg_jrepl_in(elt_id, msg) {
+ $('#' + elt_id).terminal(function(command, term) {
+ if (command !== '') {
+ // Fetch the relevant state.
+ EMULISP_CORE.init(emulisp_states[elt_id]);
+ try {
+ var result = EMULISP_CORE.eval(command);
+ if (result != '""') {
+ term.echo('-> ' + cleanTransient(result.toString()));
+ }
+ } catch(e) {
+ if (e.message == "Function 'bye' not supported") {
+ term.destroy();
+ } else {
+ term.error(e.message);
+ }
}
+ EMULISP_CORE.eval('(setq *LastStdOut "?")');
}
- if (result != '' && result != 'NIL') {
- repl_elt.val(repl_elt.val() + "\n-> " + result);
- $.modal('<div class="web-ide">' + result + '</div>',
- {onClose: function (dialog) {$.modal.close();repl_elt.focus();}});
- }
- var stdout = EMULISP_CORE.currentState().iSym['*StdOut'].cdr.name;
- if (stdout != '' && stdout != 'NIL') {
- repl_elt.val(repl_elt.val() + "\n" + stdout);
+ }, {
+ greetings: msg,
+ name: 'malg_repl',
+ height: 150,
+ prompt: ': ',
+ clear: false,
+ exit: false,
+ keypress: function(e, term) {
+ // http://stackoverflow.com/questions/23817604/how-to-hook-on-keypress-and-grab-the-current-content-of-the-terminal
+ setTimeout(function() {
+ if (false) console.log(term.html());
+ }, 5);
+ },
+ onInit: function(term) {
+ // Init the state and load it with MicroAlg.
+ EMULISP_CORE.init();
+ EMULISP_CORE.eval(microalg_l_src);
+ // Custom state for a custom display in the REPL.
+ EMULISP_CORE.currentState().context = {type: 'jrepl', term: term};
+ emulisp_states[elt_id] = EMULISP_CORE.currentState();
+ },
+ keydown: function(e) {
+ if (e.which === 76 && e.ctrlKey) { // CTRL+L
+ return true;
+ }
}
- repl_elt.val(repl_elt.val() + "\n" + malg_prompt);
- EMULISP_CORE.currentState().iSym['*StdOut'].cdr.name = '';
- old_src = repl_elt.val();
+ });
+}
+
+function malg2blockly(src) {
+ EMULISP_CORE.init();
+ EMULISP_CORE.eval(microalg_export_src);
+ var litteraux_proteges = EMULISP_CORE.eval("(proteger_litteraux " + src + ")");
+ EMULISP_CORE.eval(microalg_export_blockly_src);
+ var avec_des_next = EMULISP_CORE.eval("(insertion_next '" + litteraux_proteges + ")");
+ // Le car pour récupérer l’unique élément de la liste finale.
+ var xml = cleanTransient(EMULISP_CORE.eval('(pack (car ' + avec_des_next + ')'));
+ xml = '<xml xmlns="http://www.w3.org/1999/xhtml"><block type="programme"><value name="VALUE">' +
+ xml +
+ '</value></block></xml>';
+ EMULISP_CORE.init();
+ EMULISP_CORE.eval(microalg_l_src);
+ return xml;
+}
+
+function inject_microalg_blockly_in(elt_id, editor_id, msg) {
+ var blockly_container = $('#' + elt_id);
+ // Injection de HTML dans une iframe car besoin de plusieurs Blockly.
+ // http://stackoverflow.com/questions/13214419/alternatives-to-iframe-srcdoc
+ // Le code MicroAlg doit être sur une ligne pour passer dans le js généré:
+ if (typeof msg != "undefined") {
+ msg = msg.replace(/(\r\n|\n|\r)/gm, "");
+ } else {
+ msg = "";
+ }
+ // Ensuite le contenu de la toolbox:
+ var toolbox_string =
+ '<xml id="' + elt_id + '-toolbox" style="display: none">' +
+ ' <category name="Commandes">' +
+ ' <block type="commentaire"></block>' +
+ ' <block type="afficher"></block>' +
+ ' <block type="concatener"></block>' +
+ ' <block type="demander"></block>' +
+ ' <block type="operations"></block>' +
+ ' </category>' +
+ ' <category name="Autres">' +
+ ' <block type="texte_litteral"></block>' +
+ ' <block type="nombre_litteral"></block>' +
+ ' </category>' +
+ '</xml>';
+ // La page:
+ var content = '<!DOCTYPE html>' +
+'<html>\n' +
+' <head>\n' +
+' <meta charset="utf-8">\n' +
+' <script type="text/javascript" src="web/blockly/blockly_compressed.js"></script>\n' +
+' <script type="text/javascript" src="web/blockly_microalg.js"></script>\n' +
+' <style>\n' +
+' html, body {\n' +
+' background-color: #fff;\n' +
+' margin: 0;\n' +
+' padding: 0;\n' +
+' overflow: hidden;\n' +
+' height: 100%;\n' +
+' }\n' +
+' .blocklySvg {\n' +
+' height: 100%;\n' +
+' width: 100%;\n' +
+' }\n' +
+' </style>\n' +
+' <script>\n' +
+' function init() {\n' +
+' Blockly.inject(document.body,\n' +
+' {path: "../../web/blockly/",\n' +
+' comments: false,\n' +
+' disable: false,\n' +
+' toolbox: document.getElementById("' + elt_id + '-toolbox")});\n' +
+' // Let the top-level application know that Blockly is ready.\n' +
+' window.parent.blocklyLoaded(Blockly, "' + editor_id + '", \'' + msg + '\');\n' +
+' }\n' +
+' </script>\n' +
+' </head>\n' +
+' <body onload="init()">\n' + toolbox_string
+' </body>\n' +
+'</html>';
+ // Création de l’iframe et injection.
+ var iframe_id = elt_id + '-iframe';
+ var style = 'seamless class="malg-blockly-iframe" scrolling="no"';
+ blockly_container.html('<iframe id="' + iframe_id + '" ' + style + '></iframe>');
+ var iframeDocument = document.querySelector('#' + iframe_id).contentWindow.document;
+ iframeDocument.open('text/html', 'replace');
+ iframeDocument.write(content);
+ iframeDocument.close();
+ // La suite se passe dans blocklyLoaded ci-dessous, une fois que chaque
+ // iframe est chargée.
+}
+
+function blocklyLoaded(blockly, editor_id, msg) {
+ if (typeof msg != 'undefined') {
+ var xml_text = malg2blockly(msg);
+ var xml = blockly.Xml.textToDom(xml_text);
+ blockly.Xml.domToWorkspace(blockly.mainWorkspace, xml);
}
+ blockly.addChangeListener(function () {
+ var raw_src = blockly.MicroAlg.workspaceToCode();
+ // Ne garder que le code entre les marqueurs:
+ var src = /.*««««««««««([^]*)»»»»»»»»»».*/.exec(raw_src)[1];
+ var textarea = $('#' + editor_id);
+ textarea.val(src);
+ textarea.click(); // Trigger a parenedit redraw.
+ });
}
+
+// http://www.sitepoint.com/jquery-set-focus-character-range/
+$.fn.selectRange = function(start, end) {
+ return this.each(function() {
+ if (this.setSelectionRange) {
+ this.focus();
+ this.setSelectionRange(start, end);
+ } else if (this.createTextRange) {
+ var range = this.createTextRange();
+ range.collapse(true);
+ range.moveEnd('character', end);
+ range.moveStart('character', start);
+ range.select();
+ }
+ });
+};
diff --git a/input/static/microalg_web/jquery.simplemodal.1.4.4.min.js b/input/static/microalg_web/jquery.simplemodal.1.4.4.min.js
deleted file mode 100644
index 382c736..0000000
@@ -1,26 +0,0 @@
-/*
- * SimpleModal 1.4.4 - jQuery Plugin
- * http://simplemodal.com/
- * Copyright (c) 2013 Eric Martin
- * Licensed under MIT and GPL
- * Date: Sun, Jan 20 2013 15:58:56 -0800
- */
-(function(b){"function"===typeof define&&define.amd?define(["jquery"],b):b(jQuery)})(function(b){var j=[],n=b(document),k=navigator.userAgent.toLowerCase(),l=b(window),g=[],o=null,p=/msie/.test(k)&&!/opera/.test(k),q=/opera/.test(k),m,r;m=p&&/msie 6./.test(k)&&"object"!==typeof window.XMLHttpRequest;r=p&&/msie 7.0/.test(k);b.modal=function(a,h){return b.modal.impl.init(a,h)};b.modal.close=function(){b.modal.impl.close()};b.modal.focus=function(a){b.modal.impl.focus(a)};b.modal.setContainerDimensions=
-function(){b.modal.impl.setContainerDimensions()};b.modal.setPosition=function(){b.modal.impl.setPosition()};b.modal.update=function(a,h){b.modal.impl.update(a,h)};b.fn.modal=function(a){return b.modal.impl.init(this,a)};b.modal.defaults={appendTo:"body",focus:!0,opacity:50,overlayId:"simplemodal-overlay",overlayCss:{},containerId:"simplemodal-container",containerCss:{},dataId:"simplemodal-data",dataCss:{},minHeight:null,minWidth:null,maxHeight:null,maxWidth:null,autoResize:!1,autoPosition:!0,zIndex:1E3,
-close:!0,closeHTML:'<a class="modalCloseImg" title="Close"></a>',closeClass:"simplemodal-close",escClose:!0,overlayClose:!1,fixed:!0,position:null,persist:!1,modal:!0,onOpen:null,onShow:null,onClose:null};b.modal.impl={d:{},init:function(a,h){if(this.d.data)return!1;o=p&&!b.support.boxModel;this.o=b.extend({},b.modal.defaults,h);this.zIndex=this.o.zIndex;this.occb=!1;if("object"===typeof a){if(a=a instanceof b?a:b(a),this.d.placeholder=!1,0<a.parent().parent().size()&&(a.before(b("<span></span>").attr("id",
-"simplemodal-placeholder").css({display:"none"})),this.d.placeholder=!0,this.display=a.css("display"),!this.o.persist))this.d.orig=a.clone(!0)}else if("string"===typeof a||"number"===typeof a)a=b("<div></div>").html(a);else return alert("SimpleModal Error: Unsupported data type: "+typeof a),this;this.create(a);this.open();b.isFunction(this.o.onShow)&&this.o.onShow.apply(this,[this.d]);return this},create:function(a){this.getDimensions();if(this.o.modal&&m)this.d.iframe=b('<iframe src="javascript:false;"></iframe>').css(b.extend(this.o.iframeCss,
-{display:"none",opacity:0,position:"fixed",height:g[0],width:g[1],zIndex:this.o.zIndex,top:0,left:0})).appendTo(this.o.appendTo);this.d.overlay=b("<div></div>").attr("id",this.o.overlayId).addClass("simplemodal-overlay").css(b.extend(this.o.overlayCss,{display:"none",opacity:this.o.opacity/100,height:this.o.modal?j[0]:0,width:this.o.modal?j[1]:0,position:"fixed",left:0,top:0,zIndex:this.o.zIndex+1})).appendTo(this.o.appendTo);this.d.container=b("<div></div>").attr("id",this.o.containerId).addClass("simplemodal-container").css(b.extend({position:this.o.fixed?
-"fixed":"absolute"},this.o.containerCss,{display:"none",zIndex:this.o.zIndex+2})).append(this.o.close&&this.o.closeHTML?b(this.o.closeHTML).addClass(this.o.closeClass):"").appendTo(this.o.appendTo);this.d.wrap=b("<div></div>").attr("tabIndex",-1).addClass("simplemodal-wrap").css({height:"100%",outline:0,width:"100%"}).appendTo(this.d.container);this.d.data=a.attr("id",a.attr("id")||this.o.dataId).addClass("simplemodal-data").css(b.extend(this.o.dataCss,{display:"none"})).appendTo("body");this.setContainerDimensions();
-this.d.data.appendTo(this.d.wrap);(m||o)&&this.fixIE()},bindEvents:function(){var a=this;b("."+a.o.closeClass).bind("click.simplemodal",function(b){b.preventDefault();a.close()});a.o.modal&&a.o.close&&a.o.overlayClose&&a.d.overlay.bind("click.simplemodal",function(b){b.preventDefault();a.close()});n.bind("keydown.simplemodal",function(b){a.o.modal&&9===b.keyCode?a.watchTab(b):a.o.close&&a.o.escClose&&27===b.keyCode&&(b.preventDefault(),a.close())});l.bind("resize.simplemodal orientationchange.simplemodal",
-function(){a.getDimensions();a.o.autoResize?a.setContainerDimensions():a.o.autoPosition&&a.setPosition();m||o?a.fixIE():a.o.modal&&(a.d.iframe&&a.d.iframe.css({height:g[0],width:g[1]}),a.d.overlay.css({height:j[0],width:j[1]}))})},unbindEvents:function(){b("."+this.o.closeClass).unbind("click.simplemodal");n.unbind("keydown.simplemodal");l.unbind(".simplemodal");this.d.overlay.unbind("click.simplemodal")},fixIE:function(){var a=this.o.position;b.each([this.d.iframe||null,!this.o.modal?null:this.d.overlay,
-"fixed"===this.d.container.css("position")?this.d.container:null],function(b,e){if(e){var f=e[0].style;f.position="absolute";if(2>b)f.removeExpression("height"),f.removeExpression("width"),f.setExpression("height",'document.body.scrollHeight > document.body.clientHeight ? document.body.scrollHeight : document.body.clientHeight + "px"'),f.setExpression("width",'document.body.scrollWidth > document.body.clientWidth ? document.body.scrollWidth : document.body.clientWidth + "px"');else{var c,d;a&&a.constructor===
-Array?(c=a[0]?"number"===typeof a[0]?a[0].toString():a[0].replace(/px/,""):e.css("top").replace(/px/,""),c=-1===c.indexOf("%")?c+' + (t = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"':parseInt(c.replace(/%/,""))+' * ((document.documentElement.clientHeight || document.body.clientHeight) / 100) + (t = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"',a[1]&&(d="number"===typeof a[1]?
-a[1].toString():a[1].replace(/px/,""),d=-1===d.indexOf("%")?d+' + (t = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + "px"':parseInt(d.replace(/%/,""))+' * ((document.documentElement.clientWidth || document.body.clientWidth) / 100) + (t = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + "px"')):(c='(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (t = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"',
-d='(document.documentElement.clientWidth || document.body.clientWidth) / 2 - (this.offsetWidth / 2) + (t = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + "px"');f.removeExpression("top");f.removeExpression("left");f.setExpression("top",c);f.setExpression("left",d)}}})},focus:function(a){var h=this,a=a&&-1!==b.inArray(a,["first","last"])?a:"first",e=b(":input:enabled:visible:"+a,h.d.wrap);setTimeout(function(){0<e.length?e.focus():h.d.wrap.focus()},
-10)},getDimensions:function(){var a="undefined"===typeof window.innerHeight?l.height():window.innerHeight;j=[n.height(),n.width()];g=[a,l.width()]},getVal:function(a,b){return a?"number"===typeof a?a:"auto"===a?0:0<a.indexOf("%")?parseInt(a.replace(/%/,""))/100*("h"===b?g[0]:g[1]):parseInt(a.replace(/px/,"")):null},update:function(a,b){if(!this.d.data)return!1;this.d.origHeight=this.getVal(a,"h");this.d.origWidth=this.getVal(b,"w");this.d.data.hide();a&&this.d.container.css("height",a);b&&this.d.container.css("width",
-b);this.setContainerDimensions();this.d.data.show();this.o.focus&&this.focus();this.unbindEvents();this.bindEvents()},setContainerDimensions:function(){var a=m||r,b=this.d.origHeight?this.d.origHeight:q?this.d.container.height():this.getVal(a?this.d.container[0].currentStyle.height:this.d.container.css("height"),"h"),a=this.d.origWidth?this.d.origWidth:q?this.d.container.width():this.getVal(a?this.d.container[0].currentStyle.width:this.d.container.css("width"),"w"),e=this.d.data.outerHeight(!0),f=
-this.d.data.outerWidth(!0);this.d.origHeight=this.d.origHeight||b;this.d.origWidth=this.d.origWidth||a;var c=this.o.maxHeight?this.getVal(this.o.maxHeight,"h"):null,d=this.o.maxWidth?this.getVal(this.o.maxWidth,"w"):null,c=c&&c<g[0]?c:g[0],d=d&&d<g[1]?d:g[1],i=this.o.minHeight?this.getVal(this.o.minHeight,"h"):"auto",b=b?this.o.autoResize&&b>c?c:b<i?i:b:e?e>c?c:this.o.minHeight&&"auto"!==i&&e<i?i:e:i,c=this.o.minWidth?this.getVal(this.o.minWidth,"w"):"auto",a=a?this.o.autoResize&&a>d?d:a<c?c:a:f?
-f>d?d:this.o.minWidth&&"auto"!==c&&f<c?c:f:c;this.d.container.css({height:b,width:a});this.d.wrap.css({overflow:e>b||f>a?"auto":"visible"});this.o.autoPosition&&this.setPosition()},setPosition:function(){var a,b;a=g[0]/2-this.d.container.outerHeight(!0)/2;b=g[1]/2-this.d.container.outerWidth(!0)/2;var e="fixed"!==this.d.container.css("position")?l.scrollTop():0;this.o.position&&"[object Array]"===Object.prototype.toString.call(this.o.position)?(a=e+(this.o.position[0]||a),b=this.o.position[1]||b):
-a=e+a;this.d.container.css({left:b,top:a})},watchTab:function(a){if(0<b(a.target).parents(".simplemodal-container").length){if(this.inputs=b(":input:enabled:visible:first, :input:enabled:visible:last",this.d.data[0]),!a.shiftKey&&a.target===this.inputs[this.inputs.length-1]||a.shiftKey&&a.target===this.inputs[0]||0===this.inputs.length)a.preventDefault(),this.focus(a.shiftKey?"last":"first")}else a.preventDefault(),this.focus()},open:function(){this.d.iframe&&this.d.iframe.show();b.isFunction(this.o.onOpen)?
-this.o.onOpen.apply(this,[this.d]):(this.d.overlay.show(),this.d.container.show(),this.d.data.show());this.o.focus&&this.focus();this.bindEvents()},close:function(){if(!this.d.data)return!1;this.unbindEvents();if(b.isFunction(this.o.onClose)&&!this.occb)this.occb=!0,this.o.onClose.apply(this,[this.d]);else{if(this.d.placeholder){var a=b("#simplemodal-placeholder");this.o.persist?a.replaceWith(this.d.data.removeClass("simplemodal-data").css("display",this.display)):(this.d.data.hide().remove(),a.replaceWith(this.d.orig))}else this.d.data.hide().remove();
-this.d.container.hide().remove();this.d.overlay.hide();this.d.iframe&&this.d.iframe.hide().remove();this.d.overlay.remove();this.d={}}}}});
diff --git a/input/static/microalg_web/jquery.simplemodal.css b/input/static/microalg_web/jquery.simplemodal.css
deleted file mode 100644
index b77b88b..0000000
@@ -1,25 +0,0 @@
-#simplemodal-container {
- height:360px;
- width:600px;
- color: black;
- background-color: white;
- border:4px solid #444;
- padding:12px;
-}
-#simplemodal-container .simplemodal-data {
- padding:8px;
-}
-#simplemodal-container a.modalCloseImg {
- color: black;
- width:25px;
- height:29px;
- display:inline;
- z-index:3200;
- position:absolute;
- top: 0px;
- right: -10px;
- cursor:pointer;
-}
-#simplemodal-container a.modalCloseImg:before {
- content: "X";
-}
diff --git a/input/static/microalg_web/microalg_export.l b/input/static/microalg_web/microalg_export.l
new file mode 100644
index 0000000..5f869d5
@@ -0,0 +1,9 @@
+(de proteger_litteraux src (proteger_litteraux_aux src))
+(de proteger_litteraux_aux (src)
+ (cond
+ ((num? src) (list 'Litteral src))
+ ((str? src) (list 'Litteral src))
+ ((sym? src) src)
+ (T (mapcar 'proteger_litteraux_aux src))
+ )
+)
\ No newline at end of file
diff --git a/input/static/microalg_web/microalg_export_blockly.l b/input/static/microalg_web/microalg_export_blockly.l
new file mode 100644
index 0000000..c91f4af
@@ -0,0 +1,95 @@
+(de Litteral (content)
+ (cond
+ ((num? content) (pack "<block type=\"nombre_litteral\"><field name=\"NUM\">"
+ content
+ "</field></block>"))
+ ((str? content) (pack "<block type=\"texte_litteral\"><field name=\"TEXT\">"
+ content
+ "</field></block>"))
+ (T "Littéral de type inconnu.")
+ ))
+(de insertion_next (src) (car (insertion_next_aux (reverse src))))
+(de insertion_next_aux (src)
+ (if (<= (length src) 1) src
+ # Déplacement de la tête, enfermée dans un (Next ),
+ # À la fin du deuxième élément.
+ # La queue restant inchangée.
+ (let (tete (car src)
+ deuxieme_instr (cadr src)
+ reste (cddr src))
+ (queue 'deuxieme_instr (list 'Next tete))
+ (insertion_next_aux
+ (cons
+ deuxieme_instr
+ reste)
+ )
+ )
+ ))
+(de Next (content)
+ (pack "<next>"
+ content
+ "</next>"))
+(de !!! (content next)
+ (pack "<block type=\"commentaire\"><field name=\"COMZ\">"
+ content
+ "</field>"
+ next
+ "</block>"))
+(de + (A B)
+ (pack "<block type=\"operations\"><field name=\"OP\">ADD</field>"
+ "<value name=\"A\">" A "</value>"
+ "<value name=\"B\">" B "</value>"
+ "</block>"))
+(de - (A B)
+ (pack "<block type=\"operations\"><field name=\"OP\">MINUS</field>"
+ "<value name=\"A\">" A "</value>"
+ "<value name=\"B\">" B "</value>"
+ "</block>"))
+(de * (A B)
+ (pack "<block type=\"operations\"><field name=\"OP\">MULTIPLY</field>"
+ "<value name=\"A\">" A "</value>"
+ "<value name=\"B\">" B "</value>"
+ "</block>"))
+(de / (A B)
+ (pack "<block type=\"operations\"><field name=\"OP\">DIVIDE</field>"
+ "<value name=\"A\">" A "</value>"
+ "<value name=\"B\">" B "</value>"
+ "</block>"))
+(de Afficher (content next)
+ (pack "<block type=\"afficher\">"
+ "<value name=\"VALUE\">"
+ content
+ "</value>"
+ next
+ "</block>"))
+(de Concatener inputs
+ (pack "<block type=\"concatener\">"
+ "<mutation items=\"" (length inputs) "\"></mutation>"
+ (mapcar '((i input) (pack "<value name=\"ADD" i "\">" (eval input) "</value>")) (range 0 (dec (length inputs))) inputs)
+ "</block>"))
+(de Demander ()
+ "<block type=\"demander\"></block>")
+(de Nombre (content)
+ (pack "<block type=\"nombre\">"
+ "<value name=\"VALUE\">"
+ content
+ "</value>"
+ "</block>"))
+(de Nombre? (content)
+ (pack "<block type=\"nombre?\">"
+ "<value name=\"VALUE\">"
+ content
+ "</value>"
+ "</block>"))
+(de Texte (content)
+ (pack "<block type=\"texte\">"
+ "<value name=\"VALUE\">"
+ content
+ "</value>"
+ "</block>"))
+(de Texte? (content)
+ (pack "<block type=\"texte?\">"
+ "<value name=\"VALUE\">"
+ content
+ "</value>"
+ "</block>"))
diff --git a/input/static/microalg_web/parenedit.css b/input/static/microalg_web/parenedit.css
index 4db0e98..1bc4508 100644
@@ -36,7 +36,6 @@ input,.richtext {
input, textarea, .richtext > pre {
font-family: 'Courier New', Courier, monospace;
font-size: 100%;
- width: 100%;
line-height: 1.5;
}
#test:focus, input:focus, .fake_focus {
@@ -60,7 +59,7 @@ input, textarea, .richtext > pre {
background: #ffd;
}
.paren_4 {
- background: #cfc;
+ background: #dfb;
}
.paren_5 {
background: #cef;
diff --git a/input/static/microalg_web/showdown.js b/input/static/microalg_web/showdown.js
new file mode 100644
index 0000000..65ee602
@@ -0,0 +1,62 @@
+//
+// showdown.js -- A javascript port of Markdown.
+//
+// Copyright (c) 2007 John Fraser.
+//
+// Original Markdown Copyright (c) 2004-2005 John Gruber
+// <http://daringfireball.net/projects/markdown/>
+//
+// Redistributable under a BSD-style open source license.
+// See license.txt for more information.
+//
+// The full source distribution is at:
+//
+// A A L
+// T C A
+// T K B
+//
+// <http://www.attacklab.net/>
+//
+//
+// Wherever possible, Showdown is a straight, line-by-line port
+// of the Perl version of Markdown.
+//
+// This is not a normal parser design; it's basically just a
+// series of string substitutions. It's hard to read and
+// maintain this way, but keeping Showdown close to the original
+// design makes it easier to port new features.
+//
+// More importantly, Showdown behaves like markdown.pl in most
+// edge cases. So web applications can do client-side preview
+// in Javascript, and then build identical HTML on the server.
+//
+// This port needs the new RegExp functionality of ECMA 262,
+// 3rd Edition (i.e. Javascript 1.5). Most modern web browsers
+// should do fine. Even with the new regular expression features,
+// We do a lot of work to emulate Perl's regex functionality.
+// The tricky changes in this file mostly have the "attacklab:"
+// label. Major or self-explanatory changes don't.
+//
+// Smart diff tools like Araxis Merge will be able to match up
+// this file with markdown.pl in a useful way. A little tweaking
+// helps: in a copy of markdown.pl, replace "#" with "//" and
+// replace "$text" with "text". Be sure to ignore whitespace
+// and line endings.
+//
+//
+// Showdown usage:
+//
+// var text = "Markdown *rocks*.";
+//
+// var converter = new Showdown.converter();
+// var html = converter.makeHtml(text);
+//
+// alert(html);
+//
+// Note: move the sample code to the bottom of this
+// file before uncommenting it.
+//
+//
+// Showdown namespace
+//
+var Showdown={extensions:{}},forEach=Showdown.forEach=function(a,b){if(typeof a.forEach=="function")a.forEach(b);else{var c,d=a.length;for(c=0;c<d;c++)b(a[c],c,a)}},stdExtName=function(a){return a.replace(/[_-]||\s/g,"").toLowerCase()};Showdown.converter=function(a){var b,c,d,e=0,f=[],g=[];if(typeof module!="undefind"&&typeof exports!="undefined"&&typeof require!="undefind"){var h=require("fs");if(h){var i=h.readdirSync((__dirname||".")+"/extensions").filter(function(a){return~a.indexOf(".js")}).map(function(a){return a.replace(/\.js$/,"")});Showdown.forEach(i,function(a){var b=stdExtName(a);Showdown.extensions[b]=require("./extensions/"+a)})}}this.makeHtml=function(a){return b={},c={},d=[],a=a.replace(/~/g,"~T"),a=a.replace(/\$/g,"~D"),a=a.replace(/\r\n/g,"\n"),a=a.replace(/\r/g,"\n"),a="\n\n"+a+"\n\n",a=M(a),a=a.replace(/^[ \t]+$/mg,""),Showdown.forEach(f,function(b){a=k(b,a)}),a=z(a),a=m(a),a=l(a),a=o(a),a=K(a),a=a.replace(/~D/g,"$$"),a=a.replace(/~T/g,"~"),Showdown.forEach(g,function(b){a=k(b,a)}),a};if(a&&a.extensions){var j=this;Showdown.forEach(a.extensions,function(a){typeof a=="string"&&(a=Showdown.extensions[stdExtName(a)]);if(typeof a!="function")throw"Extension '"+a+"' could not be loaded. It was either not found or is not a valid extension.";Showdown.forEach(a(j),function(a){a.type?a.type==="language"||a.type==="lang"?f.push(a):(a.type==="output"||a.type==="html")&&g.push(a):g.push(a)})})}var k=function(a,b){if(a.regex){var c=new RegExp(a.regex,"g");return b.replace(c,a.replace)}if(a.filter)return a.filter(b)},l=function(a){return a+="~0",a=a.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|(?=~0))/gm,function(a,d,e,f,g){return d=d.toLowerCase(),b[d]=G(e),f?f+g:(g&&(c[d]=g.replace(/"/g,""")),"")}),a=a.replace(/~0/,""),a},m=function(a){a=a.replace(/\n/g,"\n\n");var b="p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del|style|section|header|footer|nav|article|aside",c="p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside";return a=a.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,n),a=a.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside)\b[^\r]*?<\/\2>[ \t]*(?=\n+)\n)/gm,n),a=a.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,n),a=a.replace(/(\n\n[ ]{0,3}<!(--[^\r]*?--\s*)+>[ \t]*(?=\n{2,}))/g,n),a=a.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,n),a=a.replace(/\n\n/g,"\n"),a},n=function(a,b){var c=b;return c=c.replace(/\n\n/g,"\n"),c=c.replace(/^\n/,""),c=c.replace(/\n+$/g,""),c="\n\n~K"+(d.push(c)-1)+"K\n\n",c},o=function(a){a=v(a);var b=A("<hr />");return a=a.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,b),a=a.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,b),a=a.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,b),a=x(a),a=y(a),a=E(a),a=m(a),a=F(a),a},p=function(a){return a=B(a),a=q(a),a=H(a),a=t(a),a=r(a),a=I(a),a=G(a),a=D(a),a=a.replace(/ +\n/g," <br />\n"),a},q=function(a){var b=/(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;return a=a.replace(b,function(a){var b=a.replace(/(.)<\/?code>(?=.)/g,"$1`");return b=N(b,"\\`*_"),b}),a},r=function(a){return a=a.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,s),a=a.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,s),a=a.replace(/(\[([^\[\]]+)\])()()()()()/g,s),a},s=function(a,d,e,f,g,h,i,j){j==undefined&&(j="");var k=d,l=e,m=f.toLowerCase(),n=g,o=j;if(n==""){m==""&&(m=l.toLowerCase().replace(/ ?\n/g," ")),n="#"+m;if(b[m]!=undefined)n=b[m],c[m]!=undefined&&(o=c[m]);else{if(!(k.search(/\(\s*\)$/m)>-1))return k;n=""}}n=N(n,"*_");var p='<a href="'+n+'"';return o!=""&&(o=o.replace(/"/g,"""),o=N(o,"*_"),p+=' title="'+o+'"'),p+=">"+l+"</a>",p},t=function(a){return a=a.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,u),a=a.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,u),a},u=function(a,d,e,f,g,h,i,j){var k=d,l=e,m=f.toLowerCase(),n=g,o=j;o||(o="");if(n==""){m==""&&(m=l.toLowerCase().replace(/ ?\n/g," ")),n="#"+m;if(b[m]==undefined)return k;n=b[m],c[m]!=undefined&&(o=c[m])}l=l.replace(/"/g,"""),n=N(n,"*_");var p='<img src="'+n+'" alt="'+l+'"';return o=o.replace(/"/g,"""),o=N(o,"*_"),p+=' title="'+o+'"',p+=" />",p},v=function(a){function b(a){return a.replace(/[^\w]/g,"").toLowerCase()}return a=a.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,function(a,c){return A('<h1 id="'+b(c)+'">'+p(c)+"</h1>")}),a=a.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,function(a,c){return A('<h2 id="'+b(c)+'">'+p(c)+"</h2>")}),a=a.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,function(a,c,d){var e=c.length;return A("<h"+e+' id="'+b(d)+'">'+p(d)+"</h"+e+">")}),a},w,x=function(a){a+="~0";var b=/^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;return e?a=a.replace(b,function(a,b,c){var d=b,e=c.search(/[*+-]/g)>-1?"ul":"ol";d=d.replace(/\n{2,}/g,"\n\n\n");var f=w(d);return f=f.replace(/\s+$/,""),f="<"+e+">"+f+"</"+e+">\n",f}):(b=/(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g,a=a.replace(b,function(a,b,c,d){var e=b,f=c,g=d.search(/[*+-]/g)>-1?"ul":"ol",f=f.replace(/\n{2,}/g,"\n\n\n"),h=w(f);return h=e+"<"+g+">\n"+h+"</"+g+">\n",h})),a=a.replace(/~0/,""),a};w=function(a){return e++,a=a.replace(/\n{2,}$/,"\n"),a+="~0",a=a.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,function(a,b,c,d,e){var f=e,g=b,h=c;return g||f.search(/\n{2,}/)>-1?f=o(L(f)):(f=x(L(f)),f=f.replace(/\n$/,""),f=p(f)),"<li>"+f+"</li>\n"}),a=a.replace(/~0/g,""),e--,a};var y=function(a){return a+="~0",a=a.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,function(a,b,c){var d=b,e=c;return d=C(L(d)),d=M(d),d=d.replace(/^\n+/g,""),d=d.replace(/\n+$/g,""),d="<pre><code>"+d+"\n</code></pre>",A(d)+e}),a=a.replace(/~0/,""),a},z=function(a){return a+="~0",a=a.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g,function(a,b,c){var d=b,e=c;return e=C(e),e=M(e),e=e.replace(/^\n+/g,""),e=e.replace(/\n+$/g,""),e="<pre><code"+(d?' class="'+d+'"':"")+">"+e+"\n</code></pre>",A(e)}),a=a.replace(/~0/,""),a},A=function(a){return a=a.replace(/(^\n+|\n+$)/g,""),"\n\n~K"+(d.push(a)-1)+"K\n\n"},B=function(a){return a=a.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(a,b,c,d,e){var f=d;return f=f.replace(/^([ \t]*)/g,""),f=f.replace(/[ \t]*$/g,""),f=C(f),b+"<code>"+f+"</code>"}),a},C=function(a){return a=a.replace(/&/g,"&"),a=a.replace(/</g,"<"),a=a.replace(/>/g,">"),a=N(a,"*_{}[]\\",!1),a},D=function(a){return a=a.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,"<strong>$2</strong>"),a=a.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,"<em>$2</em>"),a},E=function(a){return a=a.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,function(a,b){var c=b;return c=c.replace(/^[ \t]*>[ \t]?/gm,"~0"),c=c.replace(/~0/g,""),c=c.replace(/^[ \t]+$/gm,""),c=o(c),c=c.replace(/(^|\n)/g,"$1 "),c=c.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm,function(a,b){var c=b;return c=c.replace(/^ /mg,"~0"),c=c.replace(/~0/g,""),c}),A("<blockquote>\n"+c+"\n</blockquote>")}),a},F=function(a){a=a.replace(/^\n+/g,""),a=a.replace(/\n+$/g,"");var b=a.split(/\n{2,}/g),c=[],e=b.length;for(var f=0;f<e;f++){var g=b[f];g.search(/~K(\d+)K/g)>=0?c.push(g):g.search(/\S/)>=0&&(g=p(g),g=g.replace(/^([ \t]*)/g,"<p>"),g+="</p>",c.push(g))}e=c.length;for(var f=0;f<e;f++)while(c[f].search(/~K(\d+)K/)>=0){var h=d[RegExp.$1];h=h.replace(/\$/g,"$$$$"),c[f]=c[f].replace(/~K\d+K/,h)}return c.join("\n\n")},G=function(a){return a=a.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&"),a=a.replace(/<(?![a-z\/?\$!])/gi,"<"),a},H=function(a){return a=a.replace(/\\(\\)/g,O),a=a.replace(/\\([`*_{}\[\]()>#+-.!])/g,O),a},I=function(a){return a=a.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,'<a href="$1">$1</a>'),a=a.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,function(a,b){return J(K(b))}),a},J=function(a){var b=[function(a){return"&#"+a.charCodeAt(0)+";"},function(a){return"&#x"+a.charCodeAt(0).toString(16)+";"},function(a){return a}];return a="mailto:"+a,a=a.replace(/./g,function(a){if(a=="@")a=b[Math.floor(Math.random()*2)](a);else if(a!=":"){var c=Math.random();a=c>.9?b[2](a):c>.45?b[1](a):b[0](a)}return a}),a='<a href="'+a+'">'+a+"</a>",a=a.replace(/">.+:/g,'">'),a},K=function(a){return a=a.replace(/~E(\d+)E/g,function(a,b){var c=parseInt(b);return String.fromCharCode(c)}),a},L=function(a){return a=a.replace(/^(\t|[ ]{1,4})/gm,"~0"),a=a.replace(/~0/g,""),a},M=function(a){return a=a.replace(/\t(?=\t)/g," "),a=a.replace(/\t/g,"~A~B"),a=a.replace(/~B(.+?)~A/g,function(a,b,c){var d=b,e=4-d.length%4;for(var f=0;f<e;f++)d+=" ";return d}),a=a.replace(/~A/g," "),a=a.replace(/~B/g,""),a},N=function(a,b,c){var d="(["+b.replace(/([\[\]\\])/g,"\\$1")+"])";c&&(d="\\\\"+d);var e=new RegExp(d,"g");return a=a.replace(e,O),a},O=function(a,b){var c=b.charCodeAt(0);return"~E"+c+"E"}},typeof module!="undefined"&&(module.exports=Showdown),typeof define=="function"&&define.amd&&define("showdown",function(){return Showdown});
\ No newline at end of file
diff --git a/input/static/microalg_web/style.css b/input/static/microalg_web/style.css
index 831ce1c..20eda6f 100644
@@ -3,7 +3,7 @@ body.microalg {
margin: 0px auto;
font-family: Verdana, Arial, sans-serif;
color: black;
- background-color: white;
+ background-color: #D1D1D1;
}
.microalg a:link {color:#337;}
.microalg a:visited {color:#333;}
@@ -26,16 +26,29 @@ body.microalg {
white-space: nowrap;
}
.microalg pre code {
+ display: block;
white-space: pre;
position: relative;
}
-#script-container, #repl-container {
+.malg-container {
width: 95%;
margin: 0px auto;
}
+.malg-blockly-iframe {
+ height: 350px;
+ width: 100%;
+ border-style: solid;
+ border-width: 1px;
+ border-color: #aaa;
+}
.malg-editor, .malg-repl {
width: 100%;
}
+.malg-ok {
+ margin: 2px;
+ background-color: #ddd;
+ width: 100%;
+}
.malg-display {
border-color: black;
border-style: solid;
@@ -43,8 +56,20 @@ body.microalg {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
+ background-color: white;
+}
+.malg-display p {
+ margin: 0px;
+ margin-left: 3px;
}
-#links {
+.microalg .terminal, .microalg .cmd {
+ width: 93%;
+ margin: 0px auto;
+ color: black;
+ background-color: white;
+ font-family: 'Courier New', Courier, monospace;
+}
+.link-right {
text-align: right;
}
#bla {
@@ -54,3 +79,12 @@ body.microalg {
#bla h1 {
text-align: center;
}
+.navbar {
+ position: fixed;
+ top: 0;
+ right: 0;
+ margin: 1em;
+ padding: 1em;
+ z-index: 100;
+ background-color: #eee;
+}
diff --git a/macros.py b/macros.py
index 6ca402a..c33f314 100644
@@ -52,11 +52,9 @@ parenedit = """ <script src="static/microalg_web/parenedit.js" type="text/jav
microalg = """ <script src="static/microalg_web/emulisp/emulisp_core.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="static/microalg_web/style.css" />
<script type="text/javascript" src="static/microalg_web/ide_injections.js"></script>
- <!-- http://code.google.com/p/simplemodal/ -->
- <script type="text/javascript" src="static/microalg_web/jquery.simplemodal.1.4.4.min.js"></script>
- <link type="text/css" href="static/microalg_web/jquery.simplemodal.css" rel="stylesheet" />
<script type="text/javascript" src="static/microalg_web/parenedit.js"></script>
- <link type="text/css" href="static/microalg_web/parenedit.css" rel="stylesheet" />""",
+ <link type="text/css" href="static/microalg_web/parenedit.css" rel="stylesheet" />
+ <script type="text/javascript" src="static/microalg_web/showdown.js"></script>""",
timeline = """ <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-touch-fullscreen" content="yes">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">