2010-09-13 4 views
18

Sto lavorando su un DSL piccolo che utilizza il fallback nomethod per il sovraccarico per acquisire gli operatori utilizzati sui valori sovraccaricati. È simile alla funzione di symbolic calculator descritta nella documentazione di overload.C'è un modo per sovraccaricare l'operatore di regex binding `= ~` in Perl?

Questo funziona bene per gli operatori di confronto standard, ma considerare quanto segue:

my $ret = $overloaded =~ /regex/; 

In questo caso, nomethod viene chiamato a stringa i $overloaded, e dopo che il sovraccarico è perduto. Ho pensato di restituire una variabile legata, che mi consentirà almeno di portare in giro l'oggetto originale sovraccarico, ma che comunque si perderà durante l'esecuzione della regex.

Così, l'ultima domanda è se c'è qualche modo per estendere idea overload 's di una calcolatrice simbolica per includere l'operatori =~ e !~ vincolante regex, in modo che il codice di esempio sopra chiamerebbe nomethod con ($overloaded, qr/regex/, 0, '=~') o qualcosa di simile?

Ho anche esaminato brevemente l'overloading dell'operatore smartmatch ~~ ma questo non sembra aver risolto il problema (è sempre il valore predefinito di regex matching piuttosto che overloading).

Modifica: ho esaminato più ~~ e ho trovato che my $ret = $overloaded ~~ q/regex/ funziona a causa delle regole di smartmatching. Chiudi, ma non una soluzione ideale, e mi piacerebbe che funzionasse pre 5.10, quindi accolgo con favore altre risposte.

+0

Suppongo che fornire un wrapper al motore regex non funzionerebbe se si desidera che funzioni prima di 5.10. –

+0

Finisci la follia! Impara Python! – bukzor

+0

@bukzor: Sono abbastanza sicuro che non sia possibile sovraccaricare l'operatore di legame regex in Python, poiché non ne ha uno. Naturalmente, potresti scrivere una classe che ti darà funzionalità simili e limitate: http://code.activestate.com/recipes/302498-re-match-and-replace-through-operator-overloading/ –

risposta

2

Mi sembra che le DSL siano scritte meglio con source filters in perl. Puoi letteralmente fare TUTTO ciò che vuoi. ;-) Nel tuo esempio, puoi regex sostituire FOO = ~ BAR con myfunc (FOO, BAR) ed eseguire codice arbitrario.

Ecco una soluzione esempio:

# THE "MyLang" SOURCE FILTER 
package MyLang; 
use strict; 
use warnings; 
use Filter::Util::Call; 

sub import { 
    my ($type, @args) = @_; 
    my %p = @args; 
    no strict 'refs'; 
    my $caller = caller; 
    # Create the function to call 
    *{"${caller}::_mylang_defaultmethod"} = sub { 
     my ($a, $op, $b) = @_; 
     $p{nomethod}->($a, $b, 0, $op); 
    }; 
    my ($ref) = []; 
    filter_add(bless $ref); 
} 

sub filter { 
    my ($self) = @_; 
    my ($status); 
    if ($status = filter_read() > 0) { 
     $_ =~ s/([^=]+)(=~)([^;]+)/ _mylang_defaultmethod($1,'$2',$3)/g; 
    } 
    $status; 
} 

1; 

ESEMPIO UTILIZZO

use MyLang nomethod => \&mywrap; 

my $a = "foo"; 
my $b = "bar"; 
$x = $a =~ $b; 

sub mywrap { 
    my ($a, $b, $inv, $op) = @_; 
    print "$a\n"; 
} 

Ora il precedente stamperà "foo \ n" dal momento che è ciò che è nel "$ a" variabile. Ovviamente potresti voler eseguire un parsing leggermente più intelligente per la sostituzione regex nel filtro, ma questa è una semplice dimostrazione di concetto.

+0

Perché il downvote? –

+0

perché si succhia a ping pong – mkoryak

+0

Probabilmente perché in generale, i filtri di origine sono una soluzione fragile, specialmente quando il filtro ha confini sensibili al contesto. Il tuo esempio funziona nel caso di '$ x = $ a = ~ $ b', ma fallirà con' $ x = myfunc $ a = ~ $ b'. Ci sono troppi casi d'angolo per cui tali filtri sorgente siano mai veramente robusti. Inoltre, se si tenta di scrivere un filtro sorgente, si dovrebbe almeno usare 'Filtro :: Semplice' con il modificatore' code_no_comments' in modo tale che si stiano filtrando solo aree codificate, e non commenti, pod o stringhe tra virgolette. –