Bonjour � tous,

Je d�veloppe un interpr�teur de classes et interfaces (style POO de PHP), le JSCN (JavaScript Class Notation).


Ce que j'ai d�j� fait (100% fonctionnel) :

  • Un simulacre de parser
  • Tout le syst�me de chargement, d'interpr�tation et construction des classes, en JS
  • Le type hinting via des constructeurs



Ce qui me reste � faire :

  • Le type hinting classique (void, int, double, etc.)
  • Les valeurs par d�faut des arguments de m�thodes
  • La gestion des erreurs personnalis�es, propres � mon interpr�teur (ParseError, li�es � l'h�ritages, etc.)
  • La finalisation de la gestion des interfaces
  • Un parser digne de ce nom, le moins gourmand possible



C'est donc pour d�velopper un parser digne de ce nom que je me tourne vers vous, car c'est tout ce qu'il me manque pour terminer mon projet.

Je recherche des conseils pr�cis sur l'approche de son fonctionnement, qui parse un code hybride PHP-JS.

Le but est donc, ici, de dresser une "ligne de conduite"...

Voici la source de mon simulacre de parser actuel :

Code : S�lectionner tout - Visualiser dans une fen�tre � part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
var parser;
parser={
    patterns:{
        blockStart:/\r?\n\t*\{/g,
        carriageReturn:/\r?\n/,
        commentLine:/^\s*\/\//,
        commentStart:/^\s*\/\*/,
        commentEnd:/\*\/\s*$/,
        trimLeft:/^\s+/,
        trimRight:/\s+$/,
        classHead:/^(?:(final|abstract)\s+)?class\s+([A-Z][\w\d]*(?:_[A-Z][\w\d]*)*)(?:\s+extends\s+([A-Z][\w\d]*(?:_[A-Z][\w\d]*)*))?(?:\s+implements\s+((?:(?:[A-Z][\w\d]*(?:_[A-Z][\w\d]*)*)(?:\s*,\s*)?)+)?)?\s*\{?/,
        interfaceHead:/^interface\s+([A-Z][\w\d]*(?:_[A-Z][\w\d]*)*)(?:\s+extends\s+([A-Z][\w\d]*(?:_[A-Z][\w\d]*)*))?\s*\{?/,
        interfaceNames:/\s*,\s*/g,
        property:/^(?:([A-Z][\w\d\$_]*)\s+)?(?:\s*(public|protected|private))(?:\s+(static))?(?:\s+(const))?\s+([a-z][\w\d\$_]*)(?:\s*=\s*(.+?))?\s*;/,
        classMethod:/^(?:\s*([A-Z][\w\d\$_]*)\s+)?(?:\s*(final)\s+)?(?:\s*(public|protected|private))(?:\s+(static))?\s+function\s+([a-z][\w\d\$_]*)\s*\(\s*([^\)]*)\s*\)\s*\{?/,
        interfaceMethod:/^(?:\s*([A-Z][\w\d\$_]*)\s+)?\s*public(?:\s+(static))?\s+function\s+([a-z][\w\d\$_]*)\s*\(\s*([^\)]*)\s*\)\s*;/,
        token:/^(?:\s*[A-Z][\w\d\$_]*\s+)?(?:\s*final\s+)?(?:\s*public|protected|private)/,
        argStr:/\s*(?:(?:([A-Z][\w\d\$\._]*)*\s+([a-z_][\w\d\$_]*))|([a-z_][\w\d\$_]*))+?/g
    },
    parse:function parse(name,type,source){
        var line,
            lines,
            iterator,
            length,
            matches,
            itemInfo,
            property,
            methodLines;
        lines=parser.stripComments(source.replace(parser.patterns.blockStart,'{').split(parser.patterns.carriageReturn));
        iterator=0;
        length=lines.length-1;
        if(type==='class'&&(matches=lines[0].match(parser.patterns.classHead))){
            itemInfo={
                type:type,
                source:source,
                ns:name.substring(name.lastIndexOf('_')+1),
                isFinal:matches[1]==='final',
                isAbstract:matches[1]==='abstract',
                name:matches[2],
                parent:matches[3]!==''?matches[3]:null,
                interfaces:matches[4]!==''?matches[4].split(parser.patterns.interfaceNames):null,
                properties:[],
                descriptor:{}
            };
        }
        else if(type==='interface'&&(matches=lines[0].match(parser.patterns.interfaceHead))){
            itemInfo={
                type:type,
                name:matches[1],
                ns:name.substring(name.lastIndexOf('_')+1),
                parent:matches[2]!==''?matches[2]:null,
                properties:[]
            };
        }
        while((iterator+=1)<length){
            line=lines[iterator];
            property=[];
            if((matches=line.match(parser.patterns.property))){
                property.name=matches[5];
                property.type=matches[1];
                property.visibility=matches[2];
                property.isStatic=!!matches[3];
                property.isConst=!!matches[4];
                property.value=matches[6];
            }
            else if(type==='class'&&(matches=line.match(parser.patterns.classMethod))){
                methodLines=[];
                property.name=matches[5];
                property.returnType=matches[1];
                property.isFinal=!!matches[2];
                property.visibility=matches[3];
                property.isStatic=!!matches[4];
                property.argStr=matches[6];
                while(!('body' in property)){
                    if(lines[iterator+2]!==void null&&!(parser.patterns.token.test(lines[iterator+1]))){
                        if(lines[iterator]!==line){
                            methodLines.push(lines[iterator]);
                        }
                        iterator+=1;
                    }
                    else{
                        property.body=methodLines.join('\n');
                    }
                }
            }
            else if(type==='interface'&&(matches=line.match(parser.patterns.interfaceMethod))){
                property.name=matches[3];
                property.returnType=matches[1];
                property.visibility='public';
                property.isStatic=!!matches[2];
                property.argStr=matches[4];
            }
            if(typeof property.name!=='undefined'){
                itemInfo.properties[property.name]=property;
            }
        }
        return itemInfo;
    },
    stripComments:function stripComments(lines){
        var line,
            length,
            patterns,
            newLines,
            iterator,
            level;
        newLines=[];
        iterator=-1;
        level=0;
        length=lines.length;
        while((iterator+=1)<length){
            line=lines[iterator];
            if(!(parser.patterns.commentLine.test(line))){
                if(parser.patterns.commentStart.test(line)){
                    level+=1;
                }
                if(level===0){
                    line=parser.trim(line);
                    if(line.length>0){
                        newLines.push(line);
                    }
                }
                else{
                    if(parser.patterns.commentEnd.test(line)){
                        level-=1;
                    }
                }
            }
        }
        return newLines;
    },
    trim:function trim(str){
        return str.replace(parser.patterns.trimLeft,'').replace(parser.patterns.trimRight,'');
    }
};
Au final, le parser doit pouvoir :

  • Lire la structure d'une classe/interface comme si elle �tait �crite en PHP
  • D�tecter les erreurs de syntaxe JS (dans les m�thodes)
  • Remplacer les r�f�rences au namespace, s'il y en a
  • "Enregistrer" les lignes, � des fins de debugging


Est-ce que quelqu'un pourrait me guider vers son optimisation, �tape par �tape, svp? (ne me renvoyez pas vers un tuto pour cr�er un parser en C, par exemple, je ne connais rien � ce langage, alors encore moins � ses outils).

PS : Je ne comprends strictement rien aux grammaires, je n'ai pas r�ussi � trouver un tuto d�taill� sur leur fonctionnement, avec des exemples pratiques... (genre "Cr�er un parser pour les nuls")