1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4
* Copyright (C) Eran Ifrah (Main file for CodeLite www.codelite.org/ )
5
* Copyright (C) Massimo Cora' 2009 <maxcvs@email.it>
7
* anjuta is free software: you can redistribute it and/or modify it
8
* under the terms of the GNU General Public License as published by the
9
* Free Software Foundation, either version 3 of the License, or
10
* (at your option) any later version.
12
* anjuta is distributed in the hope that it will be useful, but
13
* WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
* See the GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License along
18
* with this program. If not, see <http://www.gnu.org/licenses/>.
21
#include <libanjuta/anjuta-debug.h>
24
#include <libanjuta/interfaces/ianjuta-symbol-query.h>
25
#include <libanjuta/interfaces/ianjuta-symbol-manager.h>
27
#include "engine-parser-priv.h"
28
#include "engine-parser.h"
29
#include "flex-lexer-klass-tab.h"
30
#include "expression-parser.h"
31
#include "scope-parser.h"
32
#include "variable-parser.h"
33
#include "function-parser.h"
39
/* Singleton pattern. */
41
EngineParser::getInstance ()
45
s_engine = new EngineParser ();
51
EngineParser::EngineParser ()
53
_main_tokenizer = new CppTokenizer ();
54
_extra_tokenizer = new CppTokenizer ();
57
EngineParser::~EngineParser ()
59
delete _main_tokenizer;
60
delete _extra_tokenizer;
64
EngineParser::nextMainToken (string &out_token, string &out_delimiter)
70
while ( (type = _main_tokenizer->yylex()) != 0 )
79
out_delimiter = _main_tokenizer->YYText();
84
out_token.append (" ").append (_main_tokenizer->YYText());
93
out_token.append (" ").append (_main_tokenizer->YYText());
101
out_token.append (" ").append (_main_tokenizer->YYText());
105
out_token.append (" ").append (_main_tokenizer->YYText());
114
EngineParser::parseExpression(const string &in)
116
return parse_expression (in.c_str ());
120
EngineParser::unsetSymbolManager ()
123
g_object_unref (_query_scope);
127
g_object_unref (_query_search);
128
_query_search = NULL;
130
if (_query_search_in_scope)
131
g_object_unref (_query_search_in_scope);
132
_query_search_in_scope = NULL;
134
if (_query_parent_scope)
135
g_object_unref (_query_parent_scope);
136
_query_parent_scope = NULL;
140
EngineParser::setSymbolManager (IAnjutaSymbolManager *manager)
142
static IAnjutaSymbolField query_parent_scope_fields[] =
144
IANJUTA_SYMBOL_FIELD_ID, IANJUTA_SYMBOL_FIELD_NAME,
145
IANJUTA_SYMBOL_FIELD_KIND, IANJUTA_SYMBOL_FIELD_TYPE
147
static IAnjutaSymbolField query_search_fields[] =
149
IANJUTA_SYMBOL_FIELD_ID, IANJUTA_SYMBOL_FIELD_NAME,
150
IANJUTA_SYMBOL_FIELD_KIND
152
static IAnjutaSymbolField query_scope_fields[] =
154
IANJUTA_SYMBOL_FIELD_ID, IANJUTA_SYMBOL_FIELD_NAME,
155
IANJUTA_SYMBOL_FIELD_SIGNATURE, IANJUTA_SYMBOL_FIELD_TYPE
157
static IAnjutaSymbolField query_search_in_scope_fields[] =
159
IANJUTA_SYMBOL_FIELD_ID, IANJUTA_SYMBOL_FIELD_NAME,
160
IANJUTA_SYMBOL_FIELD_KIND, IANJUTA_SYMBOL_FIELD_RETURNTYPE,
161
IANJUTA_SYMBOL_FIELD_SIGNATURE, IANJUTA_SYMBOL_FIELD_TYPE_NAME
164
ianjuta_symbol_manager_create_query (manager,
165
IANJUTA_SYMBOL_QUERY_SEARCH,
166
IANJUTA_SYMBOL_QUERY_DB_PROJECT, NULL);
167
ianjuta_symbol_query_set_filters (_query_search,
169
(IANJUTA_SYMBOL_TYPE_SCOPE_CONTAINER |
170
IANJUTA_SYMBOL_TYPE_TYPEDEF), TRUE, NULL);
171
ianjuta_symbol_query_set_fields (_query_search,
172
G_N_ELEMENTS (query_search_fields),
173
query_search_fields, NULL);
175
ianjuta_symbol_manager_create_query (manager,
176
IANJUTA_SYMBOL_QUERY_SEARCH_SCOPE,
177
IANJUTA_SYMBOL_QUERY_DB_PROJECT, NULL);
178
ianjuta_symbol_query_set_fields (_query_scope,
179
G_N_ELEMENTS (query_scope_fields),
180
query_scope_fields, NULL);
181
_query_search_in_scope =
182
ianjuta_symbol_manager_create_query (manager,
183
IANJUTA_SYMBOL_QUERY_SEARCH_IN_SCOPE,
184
IANJUTA_SYMBOL_QUERY_DB_PROJECT, NULL);
185
ianjuta_symbol_query_set_fields (_query_search_in_scope,
186
G_N_ELEMENTS (query_search_in_scope_fields),
187
query_search_in_scope_fields, NULL);
188
_query_parent_scope =
189
ianjuta_symbol_manager_create_query (manager,
190
IANJUTA_SYMBOL_QUERY_SEARCH_PARENT_SCOPE,
191
IANJUTA_SYMBOL_QUERY_DB_PROJECT, NULL);
192
ianjuta_symbol_query_set_fields (_query_parent_scope,
193
G_N_ELEMENTS (query_parent_scope_fields),
194
query_parent_scope_fields, NULL);
198
EngineParser::trim (string& str, string trimChars /* = "{};\r\n\t\v " */)
200
string::size_type pos = str.find_last_not_of (trimChars);
202
if (pos != string::npos)
205
pos = str.find_first_not_of (trimChars);
206
if(pos != string::npos)
213
str.erase(str.begin(), str.end());
218
* @return NULL on global
221
EngineParser::getNearestClassInCurrentScopeChainByFileLine (const char* full_file_path,
222
unsigned long linenum,
223
string &out_type_name)
225
IAnjutaIterable *iter;
227
/* Find current scope of given file and line */
228
iter = ianjuta_symbol_query_search_scope (_query_scope, full_file_path,
233
/* FIXME: this method doesn't take into consideration
234
* classes with same name on multiple namespaces
240
IAnjutaIterable *parent_iter;
241
IAnjutaSymbol *node = IANJUTA_SYMBOL (iter);
242
DEBUG_PRINT ("sym_name = %s", ianjuta_symbol_get_string (node, IANJUTA_SYMBOL_FIELD_NAME, NULL));
243
if (ianjuta_symbol_get_sym_type (node, NULL) == IANJUTA_SYMBOL_TYPE_CLASS)
245
out_type_name = ianjuta_symbol_get_string (node, IANJUTA_SYMBOL_FIELD_NAME, NULL);
249
ianjuta_symbol_query_search_parent_scope (_query_parent_scope,
253
ianjuta_symbol_get_int (IANJUTA_SYMBOL (iter), IANJUTA_SYMBOL_FIELD_ID, NULL) ==
254
ianjuta_symbol_get_int (IANJUTA_SYMBOL (parent_iter), IANJUTA_SYMBOL_FIELD_ID, NULL))
256
g_object_unref (parent_iter);
260
g_object_unref (iter);
264
g_object_unref (iter);
269
EngineParser::getTypeNameAndScopeByToken (ExpressionResult &result,
272
const string& full_file_path,
273
unsigned long linenum,
274
const string& above_text,
275
string &out_type_name,
276
string &out_type_scope)
278
if (result.m_isaType)
280
DEBUG_PRINT ("*** Found a cast expression");
282
* Handle type (usually when casting is found)
284
if (result.m_isPtr && op == ".")
286
DEBUG_PRINT ("Did you mean to use '->' instead of '.' ?");
290
if (!result.m_isPtr && op == "->")
292
DEBUG_PRINT ("Can not use '->' operator on a non pointer object");
296
out_type_scope = result.m_scope.empty() ? "" : result.m_scope.c_str();
297
out_type_name = result.m_name.c_str();
300
else if (result.m_isThis)
302
DEBUG_PRINT ("*** Found 'this'");
304
/* special handle for 'this' keyword */
307
DEBUG_PRINT ("'this' can not be used with operator ::");
311
if (result.m_isPtr && op == ".")
313
DEBUG_PRINT ("Did you mean to use '->' instead of '.' ?");
317
if (!result.m_isPtr && op == "->")
319
DEBUG_PRINT ("Can not use '->' operator on a non pointer object");
323
/* reaching this point we are quite sure that the easiest tests about "this"
324
* calling are passed. Go on finding for the first symbol of type class that
325
* is reachable through the scopes chain.
328
/* will we find a good class scope? */
329
out_type_scope = result.m_scope.empty() ? "" : result.m_scope.c_str();
332
getNearestClassInCurrentScopeChainByFileLine (full_file_path.c_str (), linenum, out_type_name);
333
if (out_type_name.empty ())
335
DEBUG_PRINT ("'this' has not a type name");
343
out_type_name = token;
344
out_type_scope = result.m_scope.empty() ? "" : result.m_scope.c_str();
350
* Found an identifier (can be a local variable, a global one etc)
352
DEBUG_PRINT ("*** Found an identifier or local variable...");
354
/* optimize scope'll clear the scopes leaving the local variables */
355
string optimized_scope = optimizeScope(above_text);
358
std::map<std::string, std::string> ignoreTokens;
359
get_variables(optimized_scope, li, ignoreTokens, false);
361
/* here the trick is to start from the end of the found variables
362
* up to the begin. This because the local variable declaration should be found
363
* just above to the statement line
365
for (VariableList::reverse_iterator iter = li.rbegin(); iter != li.rend(); iter++)
367
Variable var = (*iter);
369
if (token == var.m_name)
371
DEBUG_PRINT ("We found the variable type to parse... it's \"%s"
372
"\" with typescope \"%s\"", var.m_type.c_str(), var.m_typeScope.c_str());
373
out_type_name = var.m_type;
374
out_type_scope = var.m_typeScope;
380
IAnjutaIterable* curr_scope_iter =
381
ianjuta_symbol_query_search_scope (_query_scope,
382
full_file_path.c_str (),
385
if (curr_scope_iter != NULL)
387
IAnjutaSymbol *node = IANJUTA_SYMBOL (curr_scope_iter);
389
/* try to get the signature from the symbol and test if the
390
* variable searched is found there.
392
const gchar * signature = ianjuta_symbol_get_string (node, IANJUTA_SYMBOL_FIELD_SIGNATURE, NULL);
393
if (signature == NULL)
395
g_object_unref (curr_scope_iter);
399
DEBUG_PRINT ("Signature is %s", signature);
401
get_variables(signature, li, ignoreTokens, false);
403
for (VariableList::reverse_iterator iter = li.rbegin(); iter != li.rend(); iter++)
405
Variable var = (*iter);
407
if (token == var.m_name)
409
DEBUG_PRINT ("We found the variable type to parse from signature... it's \"%s"
410
"\" with typescope \"%s\"", var.m_type.c_str (), var.m_typeScope.c_str ());
411
out_type_name = var.m_type;
412
out_type_scope = var.m_typeScope;
414
g_object_unref (curr_scope_iter);
419
g_object_unref (curr_scope_iter);
422
/* if we reach this point it's likely that we missed the right var type */
423
DEBUG_PRINT ("## Wrong detection of the variable type");
429
* Find a searchable scope (or container) from a type_name and type_scope strings.
430
* This function should usually be used to determine first token's scope.
433
EngineParser::getCurrentSearchableScope (string &type_name, string &type_scope)
435
// FIXME: case of more results now it's hardcoded to 1
436
IAnjutaIterable *curr_searchable_scope =
437
ianjuta_symbol_query_search (_query_search, type_name.c_str(), NULL);
439
if (curr_searchable_scope != NULL)
443
node = IANJUTA_SYMBOL (curr_searchable_scope);
445
const gchar *skind = ianjuta_symbol_get_string (node,
446
IANJUTA_SYMBOL_FIELD_KIND, NULL);
448
DEBUG_PRINT ("Current Searchable Scope name \"%s\" kind \"%s\" and id %d",
449
ianjuta_symbol_get_string (node, IANJUTA_SYMBOL_FIELD_NAME, NULL), skind,
450
ianjuta_symbol_get_int (node, IANJUTA_SYMBOL_FIELD_ID, NULL));
452
/* is it a typedef? In that case find the parent struct */
453
if (g_strcmp0 (ianjuta_symbol_get_string (node,
454
IANJUTA_SYMBOL_FIELD_KIND, NULL), "typedef") == 0)
456
DEBUG_PRINT ("It's a TYPEDEF... trying to find the associated struct...!");
458
curr_searchable_scope = switchTypedefToStruct (IANJUTA_ITERABLE (node));
460
node = IANJUTA_SYMBOL (curr_searchable_scope);
461
DEBUG_PRINT ("(NEW) Current Searchable Scope %s and id %d",
462
ianjuta_symbol_get_string (node, IANJUTA_SYMBOL_FIELD_NAME, NULL),
463
ianjuta_symbol_get_int (node, IANJUTA_SYMBOL_FIELD_ID, NULL));
468
DEBUG_PRINT ("Current Searchable Scope NULL");
471
return curr_searchable_scope;
475
* @param test Must be searched with SYMINFO_KIND
476
* @return or the same test iterator or a new struct. In that second case the input
477
* iterator test is unreffed.
481
EngineParser::switchTypedefToStruct (IAnjutaIterable * test,
482
IAnjutaSymbolField sym_info
483
/*= (SymExtraInfo)(SYMINFO_SIMPLE | SYMINFO_KIND)*/)
485
IAnjutaSymbol *node = IANJUTA_SYMBOL (test);
486
IAnjutaIterable *new_struct;
488
DEBUG_PRINT ("Switching TYPEDEF (%d) ==> to STRUCT",
489
ianjuta_symbol_get_int (node, IANJUTA_SYMBOL_FIELD_ID, NULL));
490
new_struct = ianjuta_symbol_query_search_parent_scope (_query_parent_scope,
493
if (new_struct != NULL)
495
/* kill the old one */
496
g_object_unref (test);
502
DEBUG_PRINT ("Couldn't find a parent for typedef. We'll return the same object");
509
EngineParser::switchMemberToContainer (IAnjutaIterable * test)
511
IAnjutaSymbol *node = IANJUTA_SYMBOL (test);
512
IAnjutaIterable *new_container;
513
const gchar* sym_type_name =
514
ianjuta_symbol_get_string (node, IANJUTA_SYMBOL_FIELD_TYPE_NAME, NULL);
516
DEBUG_PRINT ("Switching container with type_name %s", sym_type_name);
518
/* hopefully we'll find a new container for the type_name of test param */
519
new_container = ianjuta_symbol_query_search (_query_search,
520
sym_type_name, NULL);
521
if (new_container != NULL)
523
g_object_unref (test);
525
test = new_container;
527
DEBUG_PRINT (".. found new container with n items %d",
528
ianjuta_iterable_get_length (test, NULL));
532
DEBUG_PRINT ("Couldn't find a container to substitute sym_type_name %s",
539
/* FIXME TODO: error processing. Find out a way to notify the caller of the occurred
540
* error. The "cout" method cannot be used
543
EngineParser::processExpression(const string& stmt,
544
const string& above_text,
545
const string& full_file_path,
546
unsigned long linenum)
548
ExpressionResult result;
549
string current_token;
554
DEBUG_PRINT ("Setting text %s to the tokenizer", stmt.c_str ());
555
_main_tokenizer->setText (stmt.c_str ());
557
/* get the first token */
558
nextMainToken (current_token, op);
560
DEBUG_PRINT ("First main token \"%s\" with op \"%s\"", current_token.c_str (), op.c_str ());
562
/* parse the current sub-expression of a statement and fill up
563
* ExpressionResult object
565
result = parseExpression (current_token);
567
/* fine. Get the type name and type scope given the above result for the first
568
* and most important token.
569
* The type_scope is for instance 'std' in this statement:
570
* (std::foo_util)klass->
572
bool process_res = getTypeNameAndScopeByToken (result,
580
if (process_res == false)
582
DEBUG_PRINT ("Initial statement processing failed. "
583
"I cannot continue. ");
587
DEBUG_PRINT ("Searching for curr_searchable_scope with type_name \"%s\""
588
" and type_scope \"%s\"", type_name.c_str (), type_scope.c_str ());
590
/* at this time we're enough ready to issue a first query to our db.
591
* We absolutely need to find the searchable object scope of the first result
592
* type. By this one we can iterate the tree of scopes and reach a result.
594
IAnjutaIterable *curr_searchable_scope =
595
getCurrentSearchableScope (type_name, type_scope);
597
if (curr_searchable_scope == NULL)
599
DEBUG_PRINT ("curr_searchable_scope failed to process, check the problem please");
603
/* fine. Have we more tokens left? */
604
while (nextMainToken (current_token, op) == 1)
606
DEBUG_PRINT("Next main token \"%s\" with op \"%s\"",current_token.c_str (), op.c_str ());
608
/* parse the current sub-expression of a statement and fill up
609
* ExpressionResult object
611
result = parseExpression (current_token);
613
if (process_res == false || curr_searchable_scope == NULL)
615
DEBUG_PRINT ("No luck with the NEXT token, the NEXT token failed and then "
616
"I cannot continue. ");
618
if (curr_searchable_scope != NULL)
619
g_object_unref (curr_searchable_scope );
623
/* check if the name of the result is valuable or not */
625
IAnjutaIterable * iter;
627
node = IANJUTA_SYMBOL (curr_searchable_scope);
629
iter = ianjuta_symbol_query_search_in_scope (_query_search_in_scope,
630
result.m_name.c_str (),
635
DEBUG_PRINT ("Warning, the result.m_name %s "
636
"does not belong to scope (id %d)", result.m_name.c_str (),
637
ianjuta_symbol_get_int (node, IANJUTA_SYMBOL_FIELD_ID, NULL));
639
if (curr_searchable_scope != NULL)
640
g_object_unref (curr_searchable_scope );
647
DEBUG_PRINT ("Good element %s", result.m_name.c_str ());
649
node = IANJUTA_SYMBOL (iter);
650
sym_kind = (gchar*)ianjuta_symbol_get_string (node,
651
IANJUTA_SYMBOL_FIELD_KIND, NULL);
653
DEBUG_PRINT (".. it has sym_kind \"%s\"", sym_kind);
655
/* the same check as in the engine-core on sdb_engine_add_new_sym_type () */
656
if (g_strcmp0 (sym_kind, "member") == 0 ||
657
g_strcmp0 (sym_kind, "variable") == 0 ||
658
g_strcmp0 (sym_kind, "field") == 0)
660
iter = switchMemberToContainer (iter);
661
node = IANJUTA_SYMBOL (iter);
662
sym_kind = (gchar*)ianjuta_symbol_get_string (node,
663
IANJUTA_SYMBOL_FIELD_KIND, NULL);
666
/* check for any typedef */
667
if (g_strcmp0 (ianjuta_symbol_get_string (node,
668
IANJUTA_SYMBOL_FIELD_KIND, NULL),
671
iter = switchTypedefToStruct (iter);
672
node = IANJUTA_SYMBOL (iter);
673
sym_kind = (gchar*)ianjuta_symbol_get_string (node,
674
IANJUTA_SYMBOL_FIELD_KIND, NULL);
677
/* is it a function or a method? */
678
if (g_strcmp0 (sym_kind, "function") == 0 ||
679
g_strcmp0 (sym_kind, "method") == 0 ||
680
g_strcmp0 (sym_kind, "prototype") == 0)
683
string func_ret_type_name =
684
ianjuta_symbol_get_string (node, IANJUTA_SYMBOL_FIELD_RETURNTYPE, NULL);
686
string func_signature =
687
ianjuta_symbol_get_string (node, IANJUTA_SYMBOL_FIELD_SIGNATURE, NULL);
689
func_ret_type_name += " " + result.m_name + func_signature + "{}";
692
std::map<std::string, std::string> ignoreTokens;
693
get_functions (func_ret_type_name, li, ignoreTokens);
695
DEBUG_PRINT ("Functions found are...");
697
for (FunctionList::reverse_iterator func_iter = li.rbegin();
698
func_iter != li.rend();
701
Function var = (*func_iter);
706
g_object_unref (iter);
708
DEBUG_PRINT ("Going to look for the following function ret type %s",
709
func_ret_type_name.c_str ());
711
iter = getCurrentSearchableScope (li.front().m_returnValue.m_type,
715
/* remove the 'old' curr_searchable_scope and replace with
718
g_object_unref (curr_searchable_scope);
719
curr_searchable_scope = iter;
724
DEBUG_PRINT ("END of expression processing. Returning curr_searchable_scope");
725
return curr_searchable_scope;
729
* @return The visible scope until pchStopWord is encountered
732
EngineParser::optimizeScope(const string& srcString)
735
std::vector<std::string> scope_stack;
736
std::string currScope;
740
/* Initialize the scanner with the string to search */
741
const char * scannerText = srcString.c_str ();
742
_extra_tokenizer->setText (scannerText);
743
bool changedLine = false;
744
bool prepLine = false;
748
type = _extra_tokenizer->yylex();
753
if (!currScope.empty())
754
scope_stack.push_back(currScope);
758
/* eat up all tokens until next line */
759
if ( prepLine && _extra_tokenizer->lineno() == curline)
762
currScope += _extra_tokenizer->YYText();
768
/* Get the current line number, it will help us detect preprocessor lines */
769
changedLine = (_extra_tokenizer->lineno() > curline);
775
curline = _extra_tokenizer->lineno();
780
scope_stack.push_back(currScope);
785
scope_stack.push_back(currScope);
789
// Discard the current scope since it is completed
790
if ( !scope_stack.empty() ) {
791
currScope = scope_stack.back();
792
scope_stack.pop_back();
798
/* Discard the current scope since it is completed */
799
if ( !scope_stack.empty() ) {
800
currScope = scope_stack.back();
801
scope_stack.pop_back();
802
currScope += "\n{}\n";
809
/* We are at the start of a new line
810
* consume everything until new line is found or end of text
813
currScope += _extra_tokenizer->YYText();
819
currScope += _extra_tokenizer->YYText();
824
_extra_tokenizer->reset();
826
if (scope_stack.empty())
831
for (; i < scope_stack.size(); i++)
832
currScope += scope_stack.at(i);
834
/* if the current scope is not empty, terminate it with ';' and return */
835
if ( currScope.empty() == false ) {
837
return currScope.c_str();
843
/************ C FUNCTIONS ************/
846
engine_parser_init (IAnjutaSymbolManager * manager)
848
EngineParser::getInstance ()->setSymbolManager (manager);
852
engine_parser_deinit ()
854
EngineParser::getInstance ()->unsetSymbolManager ();
858
engine_parser_process_expression (const gchar *stmt, const gchar * above_text,
859
const gchar * full_file_path, gulong linenum)
863
IAnjutaIterable *iter =
864
EngineParser::getInstance ()->processExpression (stmt,
870
catch (const std::exception& error)
872
g_critical ("cxxparser error: %s", error.what());