When review our CC code, I see that the core type matching code is:
// find all other matches
std::queue<ParserComponent> components;
BreakUpComponents(actual_search, components);
m_LastAISearchWasGlobal = components.size() <= 1;
if (!components.empty())
m_LastAIGlobalSearch = components.front().component;
ResolveExpression(tree, components, *search_scope, result, caseSensitive, isPrefix);
if (s_DebugSmartSense)
CCLogger::Get()->DebugLog(F(_T("AI() AI leave, returned %d results"),result.size()));
return result.size();
The components is the statement when user write.
The ResolveExpression is in Nativeparser_base now. So, I think we can safely add the nativeparser_base to our parsertest project.
I see that the class Nativeparser_base is quite nice for testing. It does not contains UI related code. (simply remove #include <cbstyledtextctrl.h> in the cpp file)
I'm going to write the test for the ResolveExpression.(mostly after the parsing stage)
E.g.
class A
{
public:
int m_Member1;
int m_Member2;
};
class B:public A
{
};
B obj;
Now, we have a expression "obj.m_Member1".
The initial search scope is the -1 (the global namespace)
Running the function: ResolveExpression should return the one exact matches, which is the Token "m_Member1".
So, this is only the start point, later we can test more complex expressions or more classes in the hierarchy or template related code.
I'm starting the work on my local git repos. :) I will report any progress here in this thread.
Ok, it works nice.
Copy nativeparser_base.h and nativeparser_base.cpp to the parser folder.
I have add some code snippet in frame.cpp
//Here we are going to test the expression solving algorithm
NativeParserTest nativeParserTest;
wxString exp = _T("obj.m_Member1");
TokenIdxSet searchScope;
searchScope.insert(-1);
TokenIdxSet result;
TokensTree *tree = ParserTest::Get()->GetTokensTree();
nativeParserTest.TestExpression(exp,
tree,
searchScope,
result );
wxLogMessage(_T("Result have %d matches"), result.size());
for (TokenIdxSet::iterator it=result.begin(); it!=result.end(); ++it)
{
Token* token = tree->at(*it);
if (token)
{
wxString log;
log << token->GetTokenKindString() << _T(" ")
<< token->DisplayName() << _T("\t[")
<< token->m_Line << _T(",")
<< token->m_ImplLine << _T("]");
CCLogger::Get()->Log(log);
}
}
And here is the class declaration and implementation:
#ifndef NATIVEPARSERTEST_H
#define NATIVEPARSERTEST_H
#include "nativeparser_base.h"
class NativeParserTest : public NativeParserBase
{
public:
NativeParserTest();
~NativeParserTest();
bool TestExpression(wxString& expression,
TokensTree * tree,
const TokenIdxSet& searchScope,
TokenIdxSet& result);
};
#endif //NATIVEPARSERTEST_H
#include <sdk.h>
#ifndef CB_PRECOMP
#endif
#include "nativeparsertest.h"
#include "parser/cclogger.h"
#define CC_NATIVEPARSERTEST_DEBUG_OUTPUT 0
#if CC_GLOBAL_DEBUG_OUTPUT == 1
#undef CC_NATIVEPARSERTEST_DEBUG_OUTPUT
#define CC_NATIVEPARSERTEST_DEBUG_OUTPUT 1
#elif CC_GLOBAL_DEBUG_OUTPUT == 2
#undef CC_NATIVEPARSERTEST_DEBUG_OUTPUT
#define CC_NATIVEPARSERTEST_DEBUG_OUTPUT 2
#endif
#ifdef CC_PARSER_TEST
// #define ADDTOKEN(format, args...) \
// CCLogger::Get()->AddToken(F(format, ##args))
// #define TRACE(format, args...) \
// CCLogger::Get()->DebugLog(F(format, ##args))
// #define TRACE2(format, args...) \
// CCLogger::Get()->DebugLog(F(format, ##args))
#define ADDTOKEN(format, args...) \
wxLogMessage(F(format, ##args))
#define TRACE(format, args...) \
wxLogMessage(F(format, ##args))
#define TRACE2(format, args...) \
wxLogMessage(F(format, ##args))
#else
#if CC_NATIVEPARSERTEST_DEBUG_OUTPUT == 1
#define ADDTOKEN(format, args...) \
CCLogger::Get()->AddToken(F(format, ##args))
#define TRACE(format, args...) \
CCLogger::Get()->DebugLog(F(format, ##args))
#define TRACE2(format, args...)
#elif CC_NATIVEPARSERTEST_DEBUG_OUTPUT == 2
#define ADDTOKEN(format, args...) \
CCLogger::Get()->AddToken(F(format, ##args))
#define TRACE(format, args...) \
do \
{ \
if (g_EnableDebugTrace) \
CCLogger::Get()->DebugLog(F(format, ##args)); \
} \
while (false)
#define TRACE2(format, args...) \
CCLogger::Get()->DebugLog(F(format, ##args))
#else
#define ADDTOKEN(format, args...)
#define TRACE(format, args...)
#define TRACE2(format, args...)
#endif
#endif
extern bool s_DebugSmartSense;
NativeParserTest::NativeParserTest( )
{
}
NativeParserTest::~NativeParserTest()
{
}
bool NativeParserTest::TestExpression(wxString& expression,
TokensTree * tree,
const TokenIdxSet& searchScope,
TokenIdxSet& result)
{
// find all other matches
std::queue<ParserComponent> components;
BreakUpComponents(expression, components);
ResolveExpression(tree, components, searchScope, result, true, false);
if (s_DebugSmartSense)
CCLogger::Get()->DebugLog(F(_T("NativeParserTest::TestExpression , returned %d results"),result.size()));
return true;
}
The test code is in my previous post, and I can see the final result:
...
000033. NativeParserTest::TestExpression , returned 1 results
000034. variable int A::m_Member1 [5,0]
...
:) :) :)
EDIT:
I add the diff file, so it is test only patch.(Note, the diff file contains my other part of changes to CC, like adding some comments, re-direct the TRACE message to standard console, so I can still see these messages when the app hit a breakpoint.....)
The patch is generated by git, but I think using the patch command under msys, it can directly apply the change on a SVN trunk.
BTW: Maybe, some EOL should be changed after patching, because my git use Linux-style EOL.
For the record:
This works Ok currently.
Code:
class wxWindow
{
int aaaaa;
};
// The template parameter W must be a wxWindow-derived class.
template <class W>
class wxNavigationEnabled
{
public:
W m_T;
};
wxNavigationEnabled<wxWindow> ccccc;
Statement:
To solve the problem stated here:Re: CodeCompletion wxWidgets (http://forums.codeblocks.org/index.php/topic,16525.msg112192.html#msg112192), we need to solve below:
class wxWindow
{
int aaaaa;
};
// The template parameter W must be a wxWindow-derived class.
template <class W>
class wxNavigationEnabled : public W
{
public:
typedef W BaseWindowClass;
};
class wxPanelBase : public wxNavigationEnabled<wxWindow>
{
};
wxPanelBase ccccc;
Statement:
@Morten:
I think that the parsertest project should make as simple as possible, so I'm planning to remove the "codeblocks.dll" dependency, also, I think cbStyleTextCtrl is not necessary. :)
My plan is:
One file for test parsing(test.h)
class wxWindow
{
int aaaaa;
};
// The template parameter W must be a wxWindow-derived class.
template <class W>
class wxNavigationEnabled : public W
{
public:
typedef W BaseWindowClass;
};
class wxPanelBase : public wxNavigationEnabled<wxWindow>
{
};
wxPanelBase ccccc;
and one file for test resolving expression(test_expression.exp)
The expression file can contains something like:
expression:
ccccc.aaaaa
expected result:
variable int wxWindow::aaaaa
The only issue is that it can only test expression from "global namespace". ;) But I think it was just enough good if we have many testing files. Introducing the class cbStyleTextCtrl was just trying to find the which function the cursor was located in.
There is a question, I see test.h belong to cc_test.cbp
<Unit filename="cc_test\test.h">
<Option target="<{~None~}>" />
</Unit>
This may cause some issue. E.g. When you are testing a parser hang problem, you put some code snippet to test.h, then you open the cc_test.cbp in a C::B , as test.h belong to cbp, the parser in C::B will parse it, this will cause the host C::B hangs.
So, I think we should remove "test.h" from cc_test.cbp to avoid such hang issue.
You may not understand my idea.
...maybe I need to rre-phrase. As you see:
<Unit filename="cc_test\test.h">
<Option target="<{~None~}>" />
</Unit>
...although the file is in the project, it belongs to a the special target "{~None~}" which means in no target it is checked. I was under the impression hat only those files are parsed, that belong to a real target (like "default") and this file only in case it is being opened (which you don't need to do). How does CC collect its list of files to parse precisely? I'll have a look...
You may not understand my idea.
...maybe I need to rre-phrase. As you see:
<Unit filename="cc_test\test.h">
<Option target="<{~None~}>" />
</Unit>
...although the file is in the project, it belongs to a the special target "{~None~}" which means in no target it is checked. I was under the impression hat only those files are parsed, that belong to a real target (like "default") and this file only in case it is being opened (which you don't need to do). How does CC collect its list of files to parse precisely? I'll have a look...
I think CC just add all the files belong to the project, you can see below:
void NativeParser::AddProjectToParser(cbProject* project)
{
....
if (project)
{
size_t fileCount = 0;
for (FilesList::iterator it = project->GetFilesList().begin(); it != project->GetFilesList().end(); ++it)
{
ProjectFile* pf = *it;
if (pf && FileTypeOf(pf->relativeFilename) == ftHeader)
{
if (AddFileToParser(project, pf->file.GetFullPath(), parser))
++fileCount;
}
}
for (FilesList::iterator it = project->GetFilesList().begin(); it != project->GetFilesList().end(); ++it)
{
ProjectFile* pf = *it;
if (pf && FileTypeOf(pf->relativeFilename) == ftSource)
{
if (AddFileToParser(project, pf->file.GetFullPath(), parser))
fileCount++;
}
}
wxString log(F(_("Done adding %d files of project (%s) to parser."), fileCount, prj.wx_str()));
CCLogger::Get()->DebugLog(log);
}
...
BTW: I noticed that in our codeblocks.cbp, there are different targets which have the save class name "Token", CodeCompletion plugin target and debugger plugin target. Click on the "Token" and context menu select goto declaration will bring me to:
plugins\debuggergdb\parsewatchvalue.cpp
This is pretty annoying...... :(