Does CC take scope into account? If so, the code
int main()
{
{
int fooBar = 0;
}
return foo //CC suggests "fooBar" here
}
says otherwise...
I think the hard part with this method would how to keep track of which child node the user is currently typing in.
Its pretty simple actually. Assuming you know the location of the current function's body you should collect locals and manage them in a stack.
A simple container like:
typedef std::map<wxString, TokenInfo> ScopedLocals; // TokenInfo represents here a class of your choice that holds into about a single local variable
typedef std::list<ScopedLocals> LocalsStack;
And then apply the following logic:
start:
stack.push_back( new ScopedLocals );
if found '{':
stack.push_back( new ScopedLocals );
if found '}':
delete stack.back(); // No longer relevant, free the allocated memory
stack.pop_back(); // Remove it from the stack
if found local:
stack.back()->insert(std::make_pair<wxString, TokenInfo>(token.Name(), token);
When you hit the end of your parsing, whatever left in the stack are your visible locals.
Special exceptions that should be handled:
- Variable defined inside 'catch()'
- Variable defined inside 'for(..)'
Eran
it is in your Bison(yacc) based parser, right?
Actually, I don't parse locals until they are needed (e.g. user is trying to code complete something).
I wrote a lexer for this purpose (bison is not really needed here, I managed to do it with flex only)
http://codelite.svn.sourceforge.net/viewvc/codelite/trunk/ScopeOptimizer/ScopeOptimizer/scope_optimizer.l?revision=5183&view=markup (http://codelite.svn.sourceforge.net/viewvc/codelite/trunk/ScopeOptimizer/ScopeOptimizer/scope_optimizer.l?revision=5183&view=markup)
What this lexer does, its actually "optimize the scope", that means that it will remove all hidden blocks so the parser won't have to deal with them,
so this:
int main(int argc,char **argv) {
{
int member;
}
int another_variable;
| // caret is here
will become this:
int main(int argc,char **argv) {
{}
int another_variable;
note that this code is very independent (it comes with its own codelite workspace) and it expose a very simple API:
int OptimizeScope(const std::string &inputScope, std::string &optimizedScope)
The first argument is the buffer you want to optimize while the later is the result (the output).
Eran
Here is a possible scope optimizer for CC. If anyone has time to test, let me know how well it works.
Index: src/plugins/codecompletion/nativeparser.cpp
===================================================================
--- src/plugins/codecompletion/nativeparser.cpp (revision 8571)
+++ src/plugins/codecompletion/nativeparser.cpp (working copy)
@@ -1826,7 +1826,7 @@
if (blockStart != -1)
{
++blockStart; // skip {
- const int pos = caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos;
+ const int pos = (caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos);
const int line = searchData->control->LineFromPosition(pos);
const int blockEnd = searchData->control->GetLineEndPosition(line);
if (blockEnd < 0 || blockEnd > searchData->control->GetLength())
@@ -1842,7 +1842,29 @@
if (blockStart >= blockEnd)
blockStart = blockEnd;
- wxString buffer = searchData->control->GetTextRange(blockStart, blockEnd);
+ wxString buffer; // = searchData->control->GetTextRange(blockStart, blockEnd);
+ // condense out-of-scope braces {...}
+ int scanPos = blockEnd;
+ for (int i = pos; i > blockStart; --i)
+ {
+ if (searchData->control->GetCharAt(i) != wxT('}'))
+ continue;
+ const int style = searchData->control->GetStyleAt(i);
+ if ( searchData->control->IsString(style)
+ || searchData->control->IsCharacter(style)
+ || searchData->control->IsComment(style))
+ {
+ continue;
+ }
+ const int scopeStart = searchData->control->BraceMatch(i);
+ if (scopeStart < blockStart)
+ break;
+ buffer.Prepend(searchData->control->GetTextRange(i, scanPos));
+ scanPos = scopeStart + 1;
+ i = scopeStart;
+ }
+ buffer.Prepend(searchData->control->GetTextRange(blockStart, scanPos));
+
buffer.Trim();
if ( !buffer.IsEmpty()
&& !m_Parser->ParseBuffer(buffer, false, false, true, searchData->file, m_LastFuncTokenIdx, initLine) )
Here is a possible scope optimizer for CC. If anyone has time to test, let me know how well it works.
Index: src/plugins/codecompletion/nativeparser.cpp
===================================================================
--- src/plugins/codecompletion/nativeparser.cpp (revision 8571)
+++ src/plugins/codecompletion/nativeparser.cpp (working copy)
@@ -1826,7 +1826,7 @@
if (blockStart != -1)
{
++blockStart; // skip {
- const int pos = caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos;
+ const int pos = (caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos);
const int line = searchData->control->LineFromPosition(pos);
const int blockEnd = searchData->control->GetLineEndPosition(line);
if (blockEnd < 0 || blockEnd > searchData->control->GetLength())
@@ -1842,7 +1842,29 @@
if (blockStart >= blockEnd)
blockStart = blockEnd;
- wxString buffer = searchData->control->GetTextRange(blockStart, blockEnd);
+ wxString buffer; // = searchData->control->GetTextRange(blockStart, blockEnd);
+ // condense out-of-scope braces {...}
+ int scanPos = blockEnd;
+ for (int i = pos; i > blockStart; --i)
+ {
+ if (searchData->control->GetCharAt(i) != wxT('}'))
+ continue;
+ const int style = searchData->control->GetStyleAt(i);
+ if ( searchData->control->IsString(style)
+ || searchData->control->IsCharacter(style)
+ || searchData->control->IsComment(style))
+ {
+ continue;
+ }
+ const int scopeStart = searchData->control->BraceMatch(i);
+ if (scopeStart < blockStart)
+ break;
+ buffer.Prepend(searchData->control->GetTextRange(i, scanPos));
+ scanPos = scopeStart + 1;
+ i = scopeStart;
+ }
+ buffer.Prepend(searchData->control->GetTextRange(blockStart, scanPos));
+
buffer.Trim();
if ( !buffer.IsEmpty()
&& !m_Parser->ParseBuffer(buffer, false, false, true, searchData->file, m_LastFuncTokenIdx, initLine) )
The logic seems good to me.
So, for a simple code:
void ffff()
{
int a;
{
int b;
{
int c;
}
}
for (....)
{
int d;
{
int e;
////////// caret here;
}
}
}
It should have only variable statement "e, d, a" in the buffer.
I'm going to test it in tonight. :)
1, if you remove the whole "{" block, you will remove all the EOL characters "\n", so after parsing the buffer, you variable location (line information) may be changed.
I never thought of that... I will see what I can do.
2, if you remove the "{" block directly, which means:
The posted patch already deals with this.
+ buffer.Prepend(searchData->control->GetTextRange(i, scanPos));
+ scanPos = scopeStart + 1;
i is the position of a "}" brace, and the + 1 includes the matching "{" brace in scanPos, so
currently becomes
Yes, this patch did conflict with the one for parsing of for loops. But sorry those days I'm a little busy, so I have no time to deeply test and merge those two patches. :(
...maybe ALPHA can do it - what I meant is this:
http://developer.berlios.de/patch/?func=detailpatch&patch_id=3345&group_id=5358
Have not looked at that patch yet, but if it is not too complicated, I will merge them.
1, if you remove the whole "{" block, you will remove all the EOL characters "\n", so after parsing the buffer, you variable location (line information) may be changed.
I never thought of that... I will see what I can do.
This should deal with it:
Index: src/plugins/codecompletion/nativeparser.cpp
===================================================================
--- src/plugins/codecompletion/nativeparser.cpp (revision 8585)
+++ src/plugins/codecompletion/nativeparser.cpp (working copy)
@@ -1857,7 +1857,33 @@
if (blockStart >= blockEnd)
blockStart = blockEnd;
- wxString buffer = searchData->control->GetTextRange(blockStart, blockEnd);
+ wxString buffer; // = searchData->control->GetTextRange(blockStart, blockEnd);
+ // condense out-of-scope braces {...}
+ int scanPos = blockEnd;
+ for (int curPos = pos; curPos > blockStart; --curPos)
+ {
+ if (searchData->control->GetCharAt(curPos) != wxT('}'))
+ continue;
+ const int style = searchData->control->GetStyleAt(curPos);
+ if ( searchData->control->IsString(style)
+ || searchData->control->IsCharacter(style)
+ || searchData->control->IsComment(style))
+ {
+ continue;
+ }
+ const int scopeStart = searchData->control->BraceMatch(curPos);
+ if (scopeStart < blockStart)
+ break;
+ buffer.Prepend(searchData->control->GetTextRange(curPos, scanPos));
+ const int startLn = searchData->control->LineFromPosition(scopeStart);
+ const int endLn = searchData->control->LineFromPosition(curPos);
+ if (startLn < endLn) // maintain correct line numbers for parsed tokens
+ buffer.Prepend( wxString(wxT('\n'), endLn - startLn) );
+ scanPos = scopeStart + 1;
+ curPos = scopeStart;
+ }
+ buffer.Prepend(searchData->control->GetTextRange(blockStart, scanPos));
+
buffer.Trim();
if ( !buffer.IsEmpty()
&& !m_Parser->ParseBuffer(buffer, false, false, true, searchData->file, m_LastFuncTokenIdx, initLine) )
Yes, this patch did conflict with the one for parsing of for loops. But sorry those days I'm a little busy, so I have no time to deeply test and merge those two patches. :(
...maybe ALPHA can do it - what I meant is this:
http://developer.berlios.de/patch/?func=detailpatch&patch_id=3345&group_id=5358
Have not looked at that patch yet, but if it is not too complicated, I will merge them.
The only conflict I can see (are there other conflicts I have missed?) is that:
int main()
{
for (int var_it = 0; var_it < 5; ++var_it)
{
int fooBar = var_it;
}
// "fooBar" correctly does not exist here (with the above patch)
// but "var_it" does exist (from loop declaration patch)
return 0;
}
When modifying buffer, I think the proper way to condense for loop arguments is:
for (int var_it = 0; var_it < 5; ++var_it)
{
// stuff...
}
to:
However, I am not certain about the other cases that the loop declaration patch handles; any suggestions?