2008-12-24 7 views
42

Il y a un analyseur JavaScript au moins en C et Java (Mozilla), JavaScript (Mozilla nouveau) et Ruby. Y en a-t-il actuellement pour Python?analyseur JavaScript Python

Je ne pas besoin d'un interpréteur JavaScript, en soi, juste un analyseur qui est conforme aux normes ECMA-262.

Une recherche rapide Google n'a révélé aucune réponse immédiate, donc je demande à la communauté SO.

Répondre

16

ANTLR, outil pour la langue une autre reconnaissance, est un outil linguistique qui fournit un cadre pour la construction d'analyseurs, des interprètes, des compilateurs et des traducteurs de descriptions grammaticales contenant des actions dans une variété de langues cibles.

Le site ANTLR fournit, y compris beaucoup de grammaires one for JavaScript.

En l'occurrence, il y a un Python API disponible - donc vous pouvez appeler le lexer (Recognizer) généré à partir de la grammaire directement à partir de Python (bonne chance).

+0

cela pourrait être exactement ce dont j'ai besoin, car je veux vraiment étendre la grammaire javascript standard. Merci! – Claudiu

+23

les deux grammaires ecmascript/javascript pour antlr3 sont cassées et non maintenues. c'est un hareng rouge. –

4

Vous pouvez essayer python-spidermonkey Il s'agit d'un wrapper sur spidermonkey qui est le nom de code pour l'implémentation C de javascript de Mozilla.

+1

Malheureusement, spidermonkey est mort en amont. –

11

Comme mentionné pib, pynarcissus est un tokenizer Javascript écrit en Python. Il semble avoir quelques aspérités, mais jusqu'ici cela a bien fonctionné pour ce que je veux accomplir.

Mise à jour: a pris une autre fissure à pynarcissus et au-dessous est une direction de travail pour l'utilisation PyNarcissus dans un motif de visiteur comme système. Malheureusement, mon client actuel a acheté la prochaine itération de mes expériences et a décidé de ne pas en faire une source publique. Une version plus propre du code ci-dessous est essentiel here

from pynarcissus import jsparser 
from collections import defaultdict 

class Visitor(object): 

    CHILD_ATTRS = ['thenPart', 'elsePart', 'expression', 'body', 'initializer'] 

def __init__(self, filepath): 
    self.filepath = filepath 
    #List of functions by line # and set of names 
    self.functions = defaultdict(set) 
    with open(filepath) as myFile: 
     self.source = myFile.read() 

    self.root = jsparser.parse(self.source, self.filepath) 
    self.visit(self.root) 


def look4Childen(self, node): 
    for attr in self.CHILD_ATTRS: 
     child = getattr(node, attr, None) 
     if child: 
      self.visit(child) 

def visit_NOOP(self, node): 
    pass 

def visit_FUNCTION(self, node): 
    # Named functions 
    if node.type == "FUNCTION" and getattr(node, "name", None): 
     print str(node.lineno) + " | function " + node.name + " | " + self.source[node.start:node.end] 


def visit_IDENTIFIER(self, node): 
    # Anonymous functions declared with var name = function() {}; 
    try: 
     if node.type == "IDENTIFIER" and hasattr(node, "initializer") and node.initializer.type == "FUNCTION": 
      print str(node.lineno) + " | function " + node.name + " | " + self.source[node.start:node.initializer.end] 
    except Exception as e: 
     pass 

def visit_PROPERTY_INIT(self, node): 

    # Anonymous functions declared as a property of an object 
    try: 
     if node.type == "PROPERTY_INIT" and node[1].type == "FUNCTION": 
      print str(node.lineno) + " | function " + node[0].value + " | " + self.source[node.start:node[1].end] 
    except Exception as e: 
     pass 


def visit(self, root): 

    call = lambda n: getattr(self, "visit_%s" % n.type, self.visit_NOOP)(n) 
    call(root) 
    self.look4Childen(root) 
    for node in root: 
     self.visit(node) 

filepath = r"C:\Users\dward\Dropbox\juggernaut2\juggernaut\parser\test\data\jasmine.js" 
outerspace = Visitor(filepath) 
+0

Cela ne peut pas émettre JavaScript à partir d'un AST analysé, n'est-ce pas? Je voulais modifier l'AST et émettre un nouveau JavaScript, mais il ne semble pas que cela puisse le faire. – gsingh2011

+0

@ gsingh2011 Non, il a un peu lutté avec l'analyse syntaxique, donc faire l'inverse est bien au-delà de ses capacités. – David

30

De nos jours, il y a au moins un meilleur outil, appelé slimit:

SLIMIT est un JavaScript minifier écrit en Python. Il compile en code JavaScript plus compact pour qu'il télécharge et exécute plus rapidement . SlimIt fournit également une bibliothèque qui inclut un analyseur syntaxique JavaScript, un fichier lexer , une jolie imprimante et un visiteur arborescente.

Démo:

Imaginez que nous avons le code javascript suivant:

$.ajax({ 
    type: "POST", 
    url: 'http://www.example.com', 
    data: { 
     email: '[email protected]', 
     phone: '9999999999', 
     name: 'XYZ' 
    } 
}); 

Et maintenant, nous avons besoin de email, phone et name valeurs de l'objet data.

L'idée serait d'instancier un analyseur slimit, visitez tous les noeuds, filtrer toutes les affectations et les mettre dans le dictionnaire:

from slimit import ast 
from slimit.parser import Parser 
from slimit.visitors import nodevisitor 


data = """ 
$.ajax({ 
    type: "POST", 
    url: 'http://www.example.com', 
    data: { 
     email: '[email protected]', 
     phone: '9999999999', 
     name: 'XYZ' 
    } 
}); 
""" 

parser = Parser() 
tree = parser.parse(data) 
fields = {getattr(node.left, 'value', ''): getattr(node.right, 'value', '') 
      for node in nodevisitor.visit(tree) 
      if isinstance(node, ast.Assign)} 

print fields 

Il imprime:

{'name': "'XYZ'", 
'url': "'http://www.example.com'", 
'type': '"POST"', 
'phone': "'9999999999'", 
'data': '', 
'email': "'[email protected]'"} 
+1

C'est génial! Vous pouvez également accéder à chaque valeur sous forme de dictionnaire, par exemple: 'print fields ['url']' – aesede

7

Je traduis esprima .js à Python:

https://github.com/PiotrDabkowski/pyjsparser

C'est une traduction manuelle donc c'est très rapide, il faut environ 1 seconde pour analyser le fichier angular.js (donc 100k caractères par seconde). Il prend en charge l'ensemble ECMAScript 5.1 et des parties de la version 6 - par exemple, les fonctions Flèche, const, let.

Vous pouvez également utiliser automated translation de la nouvelle version d'esprima à python qui fonctionne très bien et prend en charge l'ensemble de JavaScript 6!