2016-06-02 24 views
5

Voglio che la mia macro procedurale sostituisca alcuni BinaryOps con i metodi. Come posso impostare gli span in modo che se si verificano degli errori i miei utenti non sono completamente confusi?Come gestire correttamente gli span nelle macro procedurali?

+0

Puoi fare un esempio? Vuoi che lo span evidenzi solo il BinaryOp, o l'intera espressione binaria? – kennytm

+0

Ogni Expr ha bisogno di un intervallo. Abbiamo l'originale 'BinaryOp'' Expr', l'operatore 'Expr's (che sono invariati, quindi mantengono il loro' Span's), il 'MethodCall' appena creato' Expr' con 'Span's per entrambi 'Espr' e' Ident' del metodo. Sono questi ultimi due "Span" a cui sono interessato. – llogiq

risposta

1

Dopo aver esaminato la fonte rustc, sono giunto alla conclusione che il modello "espansione" produce i risultati migliori. Quindi manteniamo l'originale Span ma per lo expn_id, che possiamo ottenere chiamando ExtCtxt::backtrace().

Sembra essere una buona idea impostarlo in entrambi i casi delineati nella domanda. L'operatore può essere visualizzato come espanso nel percorso (chiamata di funzione) e l'espressione binario originale nell'espressione espansa nella chiamata di funzione. Nel codice:

match expr.unwrap() { 
    .. 
    Expr { node: ExprKind::Binary(Spanned { node: Add, span: op }, l, r), span, .. } => { 
     let bt = self.cx.backtrace(); // get the expansion ID 
     let path = self.cx.path(Span { expn_id: bt, ..op }, vec![crate_name, trait_name, fn_name]); 
     let epath = self.cx.expr_path(path); // path expression 
     let args_expanded = self.fold_exprs(args); 
     self.cx.expr_call(Span { expn_id: bt, ..span }, epath, args_expanded) 
     //^outer expression 
    } 
    .. 
}