2015-12-30 32 views
7

Ho un codice JavaScript, dal quale ho bisogno di trovare gli indici start + end di ogni espressione regolare letterale.Enumera le espressioni regolari tramite UglifyJS

Come possono essere estratte tali informazioni da UglifyJS?

var uglify = require('uglify-js'); 
var code = "func(1/2, /hello/);"; 
var parsed = uglify.parse(code); 

La struttura che sto entrando nella variabile parsed è molto complessa. E tutto ciò di cui ho bisogno è un array di [{startIdx, endIdx}, {startIdx, endIdx}] di ogni espressione regolare letterale.

P.S. Se qualcuno pensa che lo stesso compito possa essere realizzato in un modo che è meglio di quello di UglifyJS, sei invitato a suggerire!

UPDATE

lo so se mi scavare più in profondità nella struttura analizzata, allora per ogni espressione regolare che posso trovare oggetto:

AST_Token { 
    raw: '/hello/', 
    file: null, 
    comments_before: [], 
    nlb: false, 
    endpos: 17, 
    endcol: 17, 
    endline: 1, 
    pos: 10, 
    col: 10, 
    line: 1, 
    value: /hello/, 
    type: 'regexp' 
} 

ho bisogno di capire come tirare tutti gli oggetti dalla struttura analizzata, così posso compilare la lista degli indici di posizione.

+0

Hai mai intenzione di dirci cosa hai intenzione di fare con queste espressioni regolari estratte o stringhe o i loro indici una volta che li hai estratti? –

+0

@torazaburo fa parte di un altro parser che è già terminato, ad eccezione del supporto corretto delle espressioni regolari. Sono riuscito a isolare circa il 99% di tutti i casi, ma l'ultimo 1% sembra impossibile senza una valutazione completa delle espressioni. Ho solo bisogno di sapere dove si trovano le espressioni regolari all'interno di una determinata riga di codice. –

risposta

1

Ho questo ultimamente utile link to the UglifyJS author's blog post, che mi ha indirizzato nella giusta direzione. Sulla base di quel blog sono stato in grado di modificare il mio codice di enumerazione al seguente:

function enumRegEx(parsed) { 
    var result = []; 
    parsed.walk(new uglify.TreeWalker(function (obj) { 
     if (obj instanceof uglify.AST_RegExp) { 
      result.push({ 
       startIdx: obj.end.col, 
       endIdx: obj.end.endcol 
      }); 
     } 
    })); 
    return result; 
} 

Non solo questa cosa è più breve e funziona lo stesso, ma la sua velocità di elaborazione è quasi immediato, entro 10 ms, che mette il risultato precedente (430 ms) da vergognare.

Questo è il risultato che stavo cercando! :)

UPDATE: Alla fine, però, ho scoperto che per questo particolare compito esprima è una scelta molto migliore. È molto più veloce e ha pieno supporto per ES6, a differenza di UglifyJS.

La stessa operazione fatta tramite esprima, grazie all'ottimo sostegno di Ariya Hidayat:

function parseRegEx(originalCode) { 
    var result = []; 
    esprima.tokenize(originalCode, {loc: true, range: true}, function (obj) { 
     if (obj.type === 'RegularExpression') { 
      result.push({ 
       startIdx: obj.range[0], 
       endIdx: obj.range[1] 
      }); 
     } 
    }); 
    return result; 
} 

Come si può vedere, con esprima non hai nemmeno bisogno di analizzare il codice, si passa nel codice originale al contrario, con il numero esprima verrà eseguito il tokenize, che è molto più veloce.

+0

Felice di aver trovato una soluzione. Dovresti inoltre contrassegnare la tua risposta come accettata :) –

+0

@HenriqueBarcelos StackOverflow non consente di accettare le proprie risposte per 2 giorni dopo la risposta. –

+0

Ma esprima è stato esplicitamente suggerito come la migliore soluzione in una domanda correlata che hai postato, e IIRC l'hai liquidato come eccessivo. –

0

Poiché nessuno ha ancora risposto, sono riuscito a trovare una soluzione frontale che funzioni, anche se forse non la migliore.

function enumRegEx(parsed) { 
    var result = []; 

    function loop(obj) { 

     if (obj && typeof obj === 'object') { 
      if (obj.used) { 
       return; 
      } else { 
       obj.used = true; 
      } 
      if (obj instanceof Array) { 
       obj.forEach(function (d) { 
        loop(d); 
       }); 
      } else { 
       if (obj instanceof uglify.AST_Node) { 
        for (var v in obj) { 
         loop(obj[v]); 
        } 
       } else { 
        if (obj instanceof uglify.AST_Token) { 
         if (obj.type === 'regexp') { 
          result.push({ 
           startIdx: obj.col, 
           endIdx: obj.endcol 
          }); 
         } 
        } 
       } 
      } 
     } 
    } 

    loop(parsed); 
    return result; 
} 

Le cose che non mi piace di questo approccio:

  • sto usando contro un enorme, 30.000 linee di file JavaScript, che viene analizzati da UglifyJS in 240ms, e poi il mio l'algoritmo prende altri 430 ms solo per enumerare le espressioni regolari. Questo sembra abbastanza inefficiente.

  • Devo modificare gli oggetti originali con la proprietà used perché la struttura analizzata utilizza riferimenti reciproci, che altrimenti generano cicli infiniti e esauriscono lo stack di chiamate. Anche se non mi preoccupo molto di questo, dal momento che non sto usando i dati analizzati per nient'altro.

Se si conosce un approccio migliore, si prega di inserirlo! A questo punto sono principalmente interessato a migliorare le prestazioni della mia enumerazione, che al momento è piuttosto lenta, rispetto al parsing attuale.