type pdecl | Ptype of symbol * pxp (* id : expr; *) | Pexpr of symbol * pxp (* id = expr; *) | Pmacro of symbol * sexp list (* id * sexp; *)
Je renommerais Pmacro à Pmacrocall (ou Pmcall, ou ce qui te passe par la tête) pour clarifier qu'il s'agit d'un appel à une macro plutôt qu'une définition de macro.
Mis à part ça, ça m'a l'air OK. L'expansion de la macro renverra une Sexp qui peut être (re)parsée pour donner une "pdecl list".
BTW, j'ai un problème de design de la syntaxe pour vous:
La définition de fonction, dans sa forme la plus basique est:
f = lambda <args> -> <body>
mais il nous faudrait une forme plus pratique. Bien sûr on peut commencer avec
f <args> = <body>
et faire ce que fait OCaml:
f <args> = case <args> | <pat1> -> <body1> | <pat2> -> <body2>
mais si on veut faire une définition "par cas" sans répéter <args> c'est plus problématique. La version style Haskell
f <pat1> = <body1>; f <pat2> = <body2>
ne s'intègre pas bien parce que c'est parsé comme plusieurs déclarations séparées (donc on serait plus ou moins obligé d'ajouter cette fonctionnalité directement dans lexp_parse plutôt que dans une macro).
En SML la syntaxe est
fun f <pat1> = <body1> | f <pat2> = <body2>
Hmm... maintenant que je l'écrit je vois qu'on pourrait facilement définir une macro "fun_" qui accepte exactement cette syntaxe.
Et on pourrait aussi peut-être définir une macro "_|_" pour permettre une syntaxe telle que:
f <args> | <pat1> -> <body1> | <pat2> -> <body2>
qui aurait l'avantage d'utiliser moins de colonnes et d'éviter la répétition de "f" (et de donner un nom à chaque argument).
Hmm... OK... merci pour votre aide ;-)
Dans le code:
node : Sexp -> List Sexp -> Sexp; node = (lambda (op : Sexp) -> lambda (y : List Sexp) -> case y | nil => node_ op nil | _ => node_ (quote' (cons op nil)) (quote' y));
| uquote => node_ (symbol_ "node_") (cons (quote' op) (cons (reconstruire la liste en sexp) nil))
Je ne comprend pas comment la branche
uquote => node_ (symbol_ "node_") (cons (quote' op) (cons (reconstruire la liste en sexp) nil))
va permettre au élément unquote d'être effectivement remplacé par leur valeur dans l’environnement d'évaluation.
La valeur ne sera pas remplacée pendant l'expansion de macro.
L'expansion de macro va renvoyer un morceau de code et c'est ce morceau de code qui va calculer cette valeur et ensuite appeler "node_" (et autres) pour construire la sexp que l'on veut.
Pour te donner une comparaison en ELisp, l'expansion de:
`(a ,(+ 2 3) b) est (cons (quote a) (cons (+ 2 3) (quote (b))))
[ Comme le confirme M-: (macroexpand '`(a ,(+ 2 3) b)) RET ]
Si (comme Typer) ELisp n'avait pas `quote`, il aurait dû donner qqch comme
(cons (make-symbol "a") (cons (+ 2 3) (list (make-symbol "b"))))
mais l'important est que le (+ 2 3) n'est pas évalué à ce moment.
Stefan