2009-09-14 3 views

Répondre

4

Vous pouvez obtenir un résultat suffisamment proche en utilisant des transformations d'analyse. Le parse_transform suivant recherche "atom1 ++ atom2" et le convertit en "atom1atom2" au moment de la compilation.

exemple le module

-module(z). 

-export([z/0]). 

-compile({parse_transform, zt}). 

z() -> concat ++ enate. 

compilation avec 'S' prouve qu'il est en effet concaténé au moment de la compilation:

{function, z, 0, 2}. 
    {label,1}. 
    {func_info,{atom,z},{atom,z},0}. 
    {label,2}. 
    {move,{atom,concatenate},{x,0}}. 
    return. 

fonctionne comme prévu:

1> z:z(). 
concatenate 

le module contenant le transformer la parse:

-module(zt). 

-export([parse_transform/2]). 

parse_transform(AST, _Options) -> 
    [parse(T) || T <- AST]. 

parse({function, _, _, _, _} = T) -> 
    erl_syntax_lib:map(fun hashhash/1, T); 
parse(T) -> T. 

hashhash(Tree) -> 
    erl_syntax:revert(
    case erl_syntax:type(Tree) of 
     infix_expr -> 
     Op = erl_syntax:infix_expr_operator(Tree), 
     Left = erl_syntax:infix_expr_left(Tree), 
     Right = erl_syntax:infix_expr_right(Tree), 
     case {erl_syntax:operator_name(Op), erl_syntax:type(Left), erl_syntax:type(Right)} of 
      {'++', atom, atom} -> 
      erl_syntax:atom(erl_syntax:atom_literal(Left) ++ erl_syntax:atom_literal(Right)); 
      _ -> 
      Tree 
     end; 
     _ -> 
     Tree 
    end 
). 

EDIT: édité pour "surcharger" l'opérateur infix ++. La version précédente utilisait la fonction "##".

+0

Cela a l'air génial! Je ne peux pas le compiler avec erlIDE: dois-je faire quelque chose de spécial? – jldupont

+1

erlc doit avoir accès à zt.beam lors de la compilation de z.erl, vous devez donc ajouter son chemin à erlc en utilisant l'option -pa, probablement: "erlc -pa.z.erl". Vous ne savez pas comment faire avec erlIDE. – Zed

+0

L'erlIDE n'est pas encore complet ... il ne permet pas de spécifier des chemins supplémentaires (comme avec l'option -pa). Existe-t-il un moyen de le faire avec une directive -compile? – jldupont

0

Je pense qu'il n'y en a pas. Et je pense à cause de cela, vous pouvez faire tout cela à l'exécution sans effets secondaires

+0

Je comprends que le compilateur est dit être vraiment bon mais comment peut-il y avoir aucun effet secondaire (par exemple les cycles consommés)? – jldupont

+0

Pouvez-vous donner un exemple de ce que vous voulez dire? –

1

Je ne suis pas sûr de comprendre ce que vous demandez, mais je vais essayer de le faire. Ou peut-être que vous vouliez dire cela?

-define(CATATOM(A, B), AB). 
NewAtom = ?CATATOM(atom1, atom2). % NewAtom is atom1atom2 

bien que je ne sois pas sûr de l'utilisation de la nouvelle seconde. Comme il serait plus simple d'écrire simplement atom1atom2 à la place de la macro.

Le second ne subira aucun effet secondaire d'exécution. La première entraînera des effets secondaires à l'exécution puisque le résultat de la macro est 3 fonctions à exécuter au moment de l'exécution.

+0

Le second donnerait très probablement "AB" variable "non lié". – Zed

+0

Votre proposition, en supposant qu'elle fonctionne, aboutirait à une évaluation de l'exécution: Je recherche une évaluation * compile-time *. – jldupont

0

Il y a le concept d'avoir des transformations d'analyse, qui vous permettraient de concaténer des atomes au moment de la compilation.

+2

Cela n'aide pas beaucoup si vous n'expliquez pas comment le faire avec une transformation d'analyse. –

1

Vous ne pouvez pas réellement faire quoi que ce soit dans une macro, c'est juste du texte pur, du bon niveau de jeton, de la substitution. N.B. vous travaillez sur le code source et ne l'évaluez pas. Si vous avez besoin de types de substitution plus complexes, vous devez utiliser une transformation d'analyse.

Si vous écrivez une macro de concaténation, vous pouvez toujours former la forme Arg pour obtenir l'argument sous forme de chaîne. Regardez la section du préprocesseur du manuel de référence en ligne.

Bien sûr, la question vraiment intéressante est pourquoi vous voudriez concaténer deux atomes à la compilation? Je suppose que c'est la sortie d'une autre macro, sinon il n'y aurait aucun intérêt à le faire.

+0

Je veux pouvoir "paramétrer" un module, par ex. -define (APP, app). -define (EXT, ext). -define (NOM,? APP ++? EXT). où l'opérateur '++' concaténerait les deux atomes() au moment de la compilation. – jldupont

0

Vous mentionnez dans une de vos réponses que vous souhaitez paramétrer les modules - cela peut être fait à l'exécution ...

Le document académique sur c'est here.

Mochiweb l'utilise.

+0

Pas tout à fait ce que je cherche mais merci. – jldupont

Questions connexes