2011-11-23 11 views
5

Mi piacerebbe essere in grado di catturare assegnazioni variabili da una valutazione Perl. Cioè, per determinare quali nomi di variabili sono stati assegnati all'interno del codice ed estrarne il valore.Cattura assegnazioni variabili in Perl eval

Per esempio se corro:

eval '$foo=42; $bar=3.14;' 

Il risultato della eval è 3.14 (l'ultimo valore valutata), ma vorrei anche essere in grado di determinare i nomi "$ pippo" e "$ barra "e i loro valori (senza conoscere i nomi in anticipo).

Ho letto un paio di modi per inserire variabili nel blocco eval, tramite Safe ed Eval :: Context, ma non ancora in alcun modo per estrarle. Ho più familiarità con Eval/exec di Python che ha supportato questo.

risposta

1

Ecco il mio tentativo di arricchire una soluzione basata su Safe, come suggerito da Eric Strom.

package main; 
use warnings; use strict; 
use Safe; 

my $cpt = new Safe; 

$cpt->permit_only(qw(sassign lineseq padany const rv2sv leaveeval)); 
my $name_space = $cpt->root; 

my $no_strict = 0; 
# 
# populate the clean symbol table 
# 
$cpt->reval('0'); 
die "safe compartment initialisation error: [email protected]" if [email protected]; 
my %symtab_clean = do {no strict 'refs'; %{$name_space.'::'} }; 

my $result = $cpt->reval('$foo=42; $bar=3.14;', $no_strict); 

if ([email protected]) { 
    warn "eval error: [email protected]"; 
} 
else { 
    # 
    # symbol table additions 
    # 
    my %symtab_dirty = do {no strict 'refs'; %{$name_space.'::'} }; 

    my @updated_variables = grep { ! exists $symtab_clean{$_} } (sort keys %symtab_dirty); 

    foreach my $variable (@updated_variables) { 
     my $value = do{ no strict 'refs'; ${$name_space.'::'.$variable} }; 
     print "variable $variable was set to: $value\n" 
    } 
} 

Note:

  1. Quanto sopra consente un insieme restrictve minimo di codici operativi SAF. Vedere perl opcodes
  2. Ho scelto di cercare le differenze prima e dopo l'esecuzione del comando
0

Bene, il valore di $ pippo sarà 42 dopo l'esecuzione di eval. Non c'è alcun cambiamento nello scope che rende $ foo invisibile.

Ma questo ovviamente presuppone la conoscenza dell'esistenza di $ pippo.

In ogni caso, questo funzionerà solo senza il set use strict, che è quasi certamente una cattiva idea. Con use strict in posizione, lo script non verrà compilato. Presumo che il tuo esempio sia più complesso e stai cercando le modifiche a un hash esistente eseguito dal tuo eval. Ma non è chiaro come il tuo eval non possa sapere cosa sta cambiando, a meno che non ci sia una sorta di iniezione dinamica del codice.

7

Qualsiasi variabile lessicale dichiarata all'interno di una valutazione verrà persa dopo la fine della valutazione. Per acquisire e isolare le variabili globali impostate all'interno di un'eval, è possibile esaminare l'utilizzo del modulo Safe per creare un nuovo spazio dei nomi globale. Qualcosa di simile a quanto segue:

use Safe; 

my $vars = Safe->new->reval(qq{ 
    $code_to_eval; 
    $code_to_search_the_symbol_table_for_declared_variables 
}); 

in cui il codice di ricerca è definita come qualcosa che cammina la nidificato tavolo %main:: simbolo alla ricerca di tutte le variabili di interesse. Puoi fare in modo che restituisca una struttura dati contenente le informazioni, e quindi puoi farne quello che ti piace.

Se siete preoccupati solo di variabili definite a livello di radice, si potrebbe scrivere qualcosa di simile:

use strict; 
use warnings; 

my $eval_code = '$foo=42; $bar=3.14;'; 

use Safe; 
my $vars = Safe->new->reval(
    $eval_code . q{; 
    my %vars; 
    for my $name (keys %main::) { 
     next if $name =~ /::$/ # exclude packages 
     or not $name =~ /[a-z]/; # and names without lc letters 

     my $glob = $main::{$name}; 
     for (qw($SCALAR @ARRAY %HASH)) { 
      my ($sigil, $type) = /(.)(.+)/; 
      if (my $ref = *$glob{$type}) { 
       $vars{$sigil.$name} = /\$/ ? $$ref : $ref 
      } 
     } 
    } 
    \%vars 
}); 

print "$_: $$vars{$_}\n" for keys %$vars; 
# $foo: 42 
# $bar: 3.14 

Il codice di ricerca potrebbe anche impiegare Padwalker per cercare la corrente scope lessicale per tutte le variabili definite utilizzando l'peek_my funzione.

+0

Quale versione ha Perl Iniziamo permettendo l'accesso a slot glob dalle stringhe? Avrei giurato che ricevevo un errore "non un errore" cercando di fare qualcosa del genere. Quindi, penso di averlo perso su qualche pagina delta. – Axeman

Problemi correlati