2 Copyright (C) 2009 Maxim Ermilov <zaspire@rambler.ru>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "general.h" /* must always come first */
28 #include "js-parser/jstypes.h"
30 #include "js-parser/jsparse.h"
31 #include "js-parser/js-context.h"
32 #include "ctags-utils.h"
37 getTagPos (JSNode
*node
)
39 if (node
->pn_type
== TOK_NAME
)
44 #define PROTOTYPE ".prototype"
46 static GList
*symbols
= NULL
;
47 static GList
*tags
= NULL
;
50 get_member_list (JSContext
*my_cx
)
54 g_assert (my_cx
!= NULL
);
56 gint plen
= strlen (PROTOTYPE
);
58 for (i
= my_cx
->local_var
; i
; i
= g_list_next (i
))
62 Var
*t
= (Var
*)i
->data
;
65 len
= strlen (t
->name
);
68 if (tstr
= strstr (t
->name
, PROTOTYPE
), tstr
== NULL
)
70 if (strlen (tstr
) != plen
)
72 //TODO:puts (t->name);
77 JSNode
*node
= t
->node
;
80 g_assert (node
->pn_type
== TOK_RC
);
82 for (iter
= node
->pn_u
.list
.head
; iter
!= NULL
; iter
= iter
->pn_next
)
84 const gchar
* name
= js_node_get_name (iter
->pn_u
.binary
.left
);
85 const JSTokenPos
* pos
= getTagPos (iter
->pn_u
.binary
.left
);
87 g_assert_not_reached ();
90 gchar
*rname
= g_strndup (t
->name
, len
- plen
);
92 if (g_strcmp0 (name
, "__proto__") == 0 )
95 Type
*t
= js_context_get_node_type (my_cx
, JS_NODE (iter
->pn_u
.binary
.right
));
98 for (i
= tags
; i
!= NULL
; i
= g_list_next (i
))
99 if (g_strcmp0 (((tagEntryInfo
*)i
->data
)->name
, rname
) == 0)
101 gchar
*tn
= g_strdup (t
->name
), *tstr
;
102 if (tstr
= strstr (tn
, PROTOTYPE
), tstr
!= NULL
)
104 g_assert (strlen (tstr
) == plen
);
107 ((tagEntryInfo
*)i
->data
)->extensionFields
.inheritance
= tn
;
113 tagEntryInfo
*tag
= (tagEntryInfo
*)malloc (sizeof (tagEntryInfo
));
115 symbols
= g_list_append (symbols
, g_strdup (name
));
117 initTagEntry (tag
, name
);
118 tag
->isFileScope
= 1;
119 tag
->kindName
= "member";
121 get_file_pos (pos
->begin
, &tag
->filePosition
, File
.fp
);
122 tag
->lineNumber
= pos
->begin
;
123 tag
->extensionFields
.scope
[0]="class";
124 tag
->extensionFields
.scope
[1]=rname
;
125 JSNode
*node
= (JSNode
*)iter
->pn_u
.binary
.right
;
126 if (node
&& node
->pn_arity
== PN_FUNC
&& node
->pn_u
.func
.args
)
128 gchar
*str
= NULL
, *t
;
129 JSNode
*i
= node
->pn_u
.func
.args
;
130 g_assert (i
->pn_arity
== PN_LIST
);
131 for (i
= (JSNode
*)i
->pn_u
.list
.head
; i
; i
= (JSNode
*)i
->pn_next
)
134 g_assert (i
->pn_arity
== PN_NAME
);
135 name
= js_node_get_name (i
);
136 g_assert (name
!= NULL
);
138 str
= g_strdup_printf ("( %s", name
);
141 t
= g_strdup_printf ("%s, %s", str
, name
);
146 t
= g_strdup_printf ("%s)", str
);
149 tag
->extensionFields
.signature
= str
;
157 for (i
= my_cx
->childs
; i
; i
= g_list_next (i
))
159 JSContext
*t
= (JSContext
*)i
->data
;
165 static kindOption JsKinds
[] = {
166 { TRUE
, 'f', "function", "functions"},
167 { TRUE
, 'c', "class", "classes"},
168 { TRUE
, 'm', "method", "methods"},
169 { TRUE
, 'p', "property", "properties"},
170 { TRUE
, 'v', "variable", "global variables"}
174 initialize (const langType language
)
180 findTags (JSContext
*my_cx
)
183 g_assert (my_cx
!= NULL
);
184 if (my_cx
->func_name
)
186 const char *name
= my_cx
->func_name
;
187 gint line
= my_cx
->bline
;
190 tagEntryInfo
*tag
= (tagEntryInfo
*)malloc (sizeof (tagEntryInfo
));
191 initTagEntry (tag
, name
);
192 get_file_pos (line
, &tag
->filePosition
, File
.fp
);
193 tag
->lineNumber
= line
;
194 tag
->isFileScope
= 1;
195 tag
->kindName
= "class";
198 symbols
= g_list_append (symbols
, g_strdup (name
));
201 tag
->extensionFields
.returnType
= my_cx
->ret_type
->data
;
204 gchar
*str
= NULL
, *t
;
206 for (i
= my_cx
->func_arg
; i
; i
= g_list_next (i
))
208 g_assert (i
->data
!= NULL
);
209 if (i
== my_cx
->func_arg
)
210 str
= g_strdup_printf ("( %s", (gchar
*)i
->data
);
213 t
= g_strdup_printf ("%s, %s", str
, (gchar
*)i
->data
);
218 t
= g_strdup_printf ("%s)", str
);
221 tag
->extensionFields
.signature
= str
;
223 tags
= g_list_append (tags
, tag
);
226 for (i
= my_cx
->childs
; i
; i
= g_list_next (i
))
233 findGlobal (JSContext
*my_cx
)
235 static int depth
= 0;
238 g_assert (my_cx
!= NULL
);
239 g_assert (depth
<= 1);
241 for (i
= my_cx
->local_var
; i
; i
= g_list_next (i
))
243 const char *name
= ((Var
*)i
->data
)->name
;
244 gint line
= ((Var
*)i
->data
)->line
;
245 g_assert (name
!= NULL
);
247 if (g_strstr_len (name
, -1, PROTOTYPE
) != NULL
)
250 tagEntryInfo
*tag
= (tagEntryInfo
*)malloc (sizeof (tagEntryInfo
));
251 initTagEntry (tag
, name
);
252 get_file_pos (line
, &tag
->filePosition
, File
.fp
);
253 tag
->lineNumber
= line
;
254 tag
->isFileScope
= 1;
255 tag
->kindName
= "variable";
257 Type
*t
= js_context_get_node_type (my_cx
, ((Var
*)i
->data
)->node
);
260 tag
->extensionFields
.typeRef
[0] = "variable";
261 tag
->extensionFields
.typeRef
[1] = t
->name
;
265 tag
->extensionFields
.returnType
= my_cx
->ret_type
->data
;
266 if (g_list_find_custom (symbols
, name
, (GCompareFunc
)g_strcmp0
) == NULL
)
272 for (i
= my_cx
->childs
; i
; i
= g_list_next (i
))
274 findGlobal (i
->data
);
283 g_assert (symbols
== NULL
);
284 g_assert (tags
== NULL
);
286 JSNode
* global
= js_node_new_from_file (getInputFileName());
290 my_cx
= js_context_new_from_node (global
, &calls
);
295 get_member_list (my_cx
);
297 g_list_foreach (tags
, (GFunc
)makeTagEntry
, NULL
);
301 g_list_free (symbols
);
308 extern parserDefinition
*
309 JavaScriptParser (void)
311 static const char *const extensions
[] = { "js", NULL
};
312 parserDefinition
*const def
= parserNew ("JavaScript");
313 def
->extensions
= extensions
;
315 def
->kinds
= JsKinds
;
316 def
->kindCount
= KIND_COUNT (JsKinds
);
317 def
->parser
= findJsTags
;
318 def
->initialize
= initialize
;