mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
libclang ide #94
- Assist/Autocomplete refactored to use libclang Other minor changes: - Removed CoWork Pipe - .dli runtime loading of dynamic libraries now supports path to library in access function - EditField::SetBackground - RichTextView::GotoLabel variant with Gate for matching - RichEdit::GotoLabel variant with Gate for matching
This commit is contained in:
parent
b1617ed3d3
commit
e8035690b9
147 changed files with 8943 additions and 11172 deletions
|
|
@ -82,6 +82,7 @@ private:
|
|||
bool ignored_next_edit;
|
||||
int next_age;
|
||||
int active_annotation;
|
||||
Vector<Color> animate;
|
||||
|
||||
String& PointBreak(int& y);
|
||||
void sPaintImage(Draw& w, int y, int fy, const Image& img);
|
||||
|
|
@ -136,6 +137,8 @@ public:
|
|||
bool IsHiliteIfEndif() const { return hilite_if_endif; }
|
||||
|
||||
int GetActiveAnnotationLine() const { return active_annotation; }
|
||||
|
||||
void SetAnimate(const Vector<Color>& a) { if(a != animate) { animate = clone(a); Refresh(); } }
|
||||
|
||||
EditorBar();
|
||||
virtual ~EditorBar();
|
||||
|
|
@ -509,15 +512,16 @@ public:
|
|||
void SetAnnotation(int i, const Image& icon, const String& a) { bar.SetAnnotation(i, icon, a); }
|
||||
String GetAnnotation(int i) const { return bar.GetAnnotation(i); }
|
||||
int GetActiveAnnotationLine() const { return bar.GetActiveAnnotationLine(); }
|
||||
|
||||
Size GetBarSize() const { return bar.GetSize(); }
|
||||
void HideBar() { bar.Hide(); }
|
||||
void AnimateBar(const Vector<Color>& a) { bar.SetAnimate(a); }
|
||||
|
||||
void SyncTip();
|
||||
void CloseTip() { if(tip.IsOpen()) tip.Close(); tip.d = NULL; }
|
||||
|
||||
void Illuminate(const WString& text);
|
||||
WString GetIlluminated() const { return illuminated; }
|
||||
|
||||
|
||||
void Zoom(int d);
|
||||
|
||||
One<EditorSyntax> GetSyntax(int line);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ void EditorBar::Paint(Draw& w)
|
|||
Color bg = IsDarkTheme() ? GrayColor(70) : SColorLtFace();
|
||||
Size sz = GetSize();
|
||||
w.DrawRect(0, 0, sz.cx, sz.cy, bg);
|
||||
for(int i = 0; i < animate.GetCount(); i++)
|
||||
w.DrawRect(i, 0, 1, sz.cy, animate[i]);
|
||||
if(!editor) return;
|
||||
int fy = editor->GetFontSize().cy;
|
||||
int hy = fy >> 1;
|
||||
|
|
|
|||
|
|
@ -311,36 +311,6 @@ void CoWork::SetPoolSize(int n)
|
|||
p.InitThreads(n);
|
||||
}
|
||||
|
||||
void CoWork::Pipe(int stepi, Function<void ()>&& fn)
|
||||
{
|
||||
Mutex::Lock __(stepmutex);
|
||||
auto& q = step.At(stepi);
|
||||
LLOG("Step " << stepi << ", count: " << q.GetCount() << ", running: " << steprunning.GetCount());
|
||||
q.AddHead(pick(fn));
|
||||
if(!steprunning.At(stepi, false)) {
|
||||
steprunning.At(stepi) = true;
|
||||
*this & [=]() {
|
||||
LLOG("Starting step " << stepi << " processor");
|
||||
stepmutex.Enter();
|
||||
for(;;) {
|
||||
Function<void ()> f;
|
||||
auto& q = step[stepi];
|
||||
LLOG("StepWork " << stepi << ", todo:" << q.GetCount());
|
||||
if(q.GetCount() == 0)
|
||||
break;
|
||||
f = pick(q.Tail());
|
||||
q.DropTail();
|
||||
stepmutex.Leave();
|
||||
f();
|
||||
stepmutex.Enter();
|
||||
}
|
||||
steprunning.At(stepi) = false;
|
||||
stepmutex.Leave();
|
||||
LLOG("Exiting step " << stepi << " processor");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void CoWork::Reset()
|
||||
{
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -57,11 +57,6 @@ public:
|
|||
|
||||
Atomic index;
|
||||
|
||||
// experimental pipe support
|
||||
Mutex stepmutex;
|
||||
Array<BiVector<Function<void ()>>> step;
|
||||
Vector<bool> steprunning;
|
||||
|
||||
public:
|
||||
static bool TrySchedule(Function<void ()>&& fn);
|
||||
static bool TrySchedule(const Function<void ()>& fn) { return TrySchedule(clone(fn)); }
|
||||
|
|
@ -83,7 +78,6 @@ public:
|
|||
int Next() { return ++index - 1; }
|
||||
|
||||
int GetScheduledCount() const { return todo; }
|
||||
void Pipe(int stepi, Function<void ()>&& lambda); // experimental
|
||||
|
||||
static void FinLock();
|
||||
|
||||
|
|
|
|||
|
|
@ -419,13 +419,11 @@ NTL_MOVEABLE(RECT)
|
|||
|
||||
//Place it to the begining of each file to be the first function called in whole executable...
|
||||
//This is now backup to init_priority attribute in heapdbg.cpp
|
||||
//$-
|
||||
struct MemDiagCls {
|
||||
MemDiagCls();
|
||||
~MemDiagCls();
|
||||
};
|
||||
static const MemDiagCls sMemDiagHelper__upp__;
|
||||
//$+
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ const char *PeFile::FindExportRaw(const char *name, bool case_sensitive) const
|
|||
HMODULE CheckDll__(const char *fn, const char *const *names, UPP::Vector<void *>& plist)
|
||||
{
|
||||
HMODULE hmod = LoadLibrary(fn);
|
||||
|
||||
|
||||
if(!hmod)
|
||||
return 0;
|
||||
|
||||
|
|
@ -154,18 +154,10 @@ void FreeDll__(HMODULE hmod)
|
|||
|
||||
void *CheckDll__(const char *fn, const char *const *names, UPP::Vector<void *>& plist)
|
||||
{
|
||||
Upp::MemoryIgnoreLeaksBlock __;
|
||||
void *hmod = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL);
|
||||
if(!hmod) {
|
||||
RLOG("Error loading library " << fn << ": " << dlerror());
|
||||
/*
|
||||
for(int i = 0; i < 100; i++) {
|
||||
hmod = dlopen(fn + ("." + UPP::AsString(i)), RTLD_LAZY | RTLD_GLOBAL);
|
||||
if(hmod)
|
||||
break;
|
||||
}
|
||||
if(!hmod)
|
||||
*/ return 0;
|
||||
}
|
||||
if(!hmod)
|
||||
return 0;
|
||||
|
||||
int missing = 0;
|
||||
for(const char *const *p = names; *p; p++) {
|
||||
|
|
@ -175,15 +167,15 @@ void *CheckDll__(const char *fn, const char *const *names, UPP::Vector<void *>&
|
|||
void *proc = dlsym(hmod, exp);
|
||||
if(!proc && !optional) {
|
||||
if(!missing) {
|
||||
RLOG(fn << " missing exports:");
|
||||
LOG(fn << " missing exports:");
|
||||
}
|
||||
RLOG(exp);
|
||||
LOG(exp);
|
||||
}
|
||||
plist.Add(proc);
|
||||
}
|
||||
|
||||
if(missing) {
|
||||
RLOG(missing << " missing symbols total");
|
||||
LOG(missing << " missing symbols total");
|
||||
dlclose(hmod);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@
|
|||
#undef max
|
||||
#endif
|
||||
|
||||
//$-template <class T> inline constexpr const T& min(const T& a, const T& b, ...);
|
||||
//$-template <class T> inline constexpr const T& max(const T& a, const T& b, ...);
|
||||
|
||||
template <class T>
|
||||
constexpr const T& min(const T& a, const T& b)
|
||||
{
|
||||
|
|
@ -33,16 +30,12 @@ constexpr const T& max(const T& a, const T& b, const Args& ...args)
|
|||
return max(a, max(b, args...));
|
||||
}
|
||||
|
||||
//$+
|
||||
|
||||
template <class T>
|
||||
constexpr T clamp(const T& x, const T& min_, const T& max_)
|
||||
{
|
||||
return min(max(x, min_), max_);
|
||||
}
|
||||
|
||||
//$-constexpr int findarg(const T& x, const T1& p0, ...);
|
||||
|
||||
template <class T, class K>
|
||||
constexpr int findarg(const T& x, const K& k)
|
||||
{
|
||||
|
|
@ -58,8 +51,6 @@ constexpr int findarg(const T& sel, const K& k, const L& ...args)
|
|||
return q >= 0 ? q + 1 : -1;
|
||||
}
|
||||
|
||||
//$-constexpr auto decode(const T& x, const T1& p0, const V1& v0, ...);
|
||||
|
||||
template <class T>
|
||||
constexpr const char *decode_chr_(const T& sel, const char *def)
|
||||
{
|
||||
|
|
@ -90,8 +81,6 @@ constexpr V decode(const T& sel, const K& k, const V& v, const L& ...args)
|
|||
return sel == k ? v : (V)decode(sel, args...);
|
||||
}
|
||||
|
||||
//$-constexpr T get_i(int i, const T& p0, const T1& p1, ...);
|
||||
|
||||
template <typename A, typename... T>
|
||||
constexpr A get_i(int i, const A& p0, const T& ...args)
|
||||
{
|
||||
|
|
@ -106,8 +95,6 @@ constexpr const P *get_i(int i, const P* p0, const T& ...args)
|
|||
return list[clamp(i, 0, (int)sizeof...(args))];
|
||||
}
|
||||
|
||||
//$-void foreach_arg(F fn, const T& p0, const T1& p1, ...);
|
||||
|
||||
template <class F, class V>
|
||||
void foreach_arg(F fn, V&& v)
|
||||
{
|
||||
|
|
@ -121,8 +108,6 @@ void foreach_arg(F fn, V&& v, Args&& ...args)
|
|||
foreach_arg(fn, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
//$+
|
||||
|
||||
template <class I, typename... Args>
|
||||
void iter_set(I t, Args&& ...args)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ Mutex vm; //a common access synchronizer
|
|||
#endif
|
||||
#endif
|
||||
|
||||
//to sMain: an Application can start more than one thread, without having *any* one of them called Run() of any Thread instace
|
||||
//to sMain: an Application can start more than one thread, without having *any* one of them called Run() of any Thread instance
|
||||
//when Run() is called *anytime*, it means, the term of *MainThread* has to be running anyway,
|
||||
//otherwise no child threads could run. they are created by main.
|
||||
//now each thread, having any Thread instance can start a first Run()
|
||||
|
|
@ -243,11 +243,36 @@ void Thread::EndShutdownThreads()
|
|||
sShutdown--;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Document this
|
||||
|
||||
static StaticMutex mtx;
|
||||
|
||||
static Vector<void (*)()>& sShutdownFns()
|
||||
{
|
||||
static Vector<void (*)()> m;
|
||||
return m;
|
||||
}
|
||||
|
||||
void Thread::AtShutdown(void (*shutdownfn)())
|
||||
{
|
||||
Mutex::Lock __(mtx);
|
||||
sShutdownFns().Add(shutdownfn);
|
||||
}
|
||||
|
||||
void Thread::TryShutdownThreads()
|
||||
{
|
||||
for(auto fn : sShutdownFns())
|
||||
(*fn)();
|
||||
}
|
||||
|
||||
void Thread::ShutdownThreads()
|
||||
{
|
||||
BeginShutdownThreads();
|
||||
while(GetCount())
|
||||
while(GetCount()) {
|
||||
TryShutdownThreads();
|
||||
Sleep(100);
|
||||
}
|
||||
EndShutdownThreads();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ public:
|
|||
static bool IsUpp();
|
||||
static int GetCount();
|
||||
static void BeginShutdownThreads();
|
||||
static void AtShutdown(void (*shutdownfn)());
|
||||
static void TryShutdownThreads();
|
||||
static void EndShutdownThreads();
|
||||
static void ShutdownThreads();
|
||||
static bool IsShutdownThreads();
|
||||
|
|
@ -415,7 +417,7 @@ typedef StaticMutex StaticCriticalSection;
|
|||
#endif
|
||||
|
||||
// Auxiliary multithreading - this is not using/cannot use U++ heap, so does not need cleanup.
|
||||
// Used to resolve some host platform issues.
|
||||
// Used to resolve some host platform issues. Do not use.
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
#define auxthread_t DWORD
|
||||
|
|
|
|||
|
|
@ -19,27 +19,6 @@ Vector<WString> Split(const wchar *s, const wchar *text, bool ignoreempty = true
|
|||
String Join(const Vector<String>& im, const String& delim, bool ignoreempty = false);
|
||||
WString Join(const Vector<WString>& im, const WString& delim, bool ignoreempty = false);
|
||||
|
||||
//$ bool SplitTo(const char *s, int delim, bool ignoreempty, String& p1...);
|
||||
//$ bool SplitTo(const char *s, int delim, String& p1...);
|
||||
//$ bool SplitTo(const char *s, int (*filter)(int), String& p1...);
|
||||
//$ bool SplitTo(const char *s, int (*filter)(int), String& p1...);
|
||||
//$ bool SplitTo(const char *s, const char *delim, bool ignoreempty, String& p1...);
|
||||
//$ bool SplitTo(const char *s, const char *delim, String& p1...);
|
||||
|
||||
//$ bool SplitTo(const wchar *s, int delim, bool ignoreempty, WString& p1...);
|
||||
//$ bool SplitTo(const wchar *s, int delim, WString& p1...);
|
||||
//$ bool SplitTo(const wchar *s, int (*filter)(int), WString& p1...);
|
||||
//$ bool SplitTo(const wchar *s, int (*filter)(int), WString& p1...);
|
||||
//$ bool SplitTo(const wchar *s, const wchar *delim, bool ignoreempty, WString& p1...);
|
||||
//$ bool SplitTo(const wchar *s, const wchar *delim, WString& p1...);
|
||||
|
||||
//$ String Merge(const char *delim, String& p1...);
|
||||
//$ WString Merge(const wchar *delim, WString& p1...);
|
||||
|
||||
//$ void MergeWith(String& dest, const char *delim, String& p1...);
|
||||
//$ void MergeWith(WString& dest, const wchar *delim, WString& p1...);
|
||||
|
||||
//$-
|
||||
template <typename... Args>
|
||||
bool SplitTo(const char *s, int delim, bool ignoreempty, Args& ...args)
|
||||
{
|
||||
|
|
@ -151,5 +130,3 @@ WString Merge(const wchar *delim, const Args& ...args)
|
|||
MergeWith(r, delim, args...);
|
||||
return r;
|
||||
}
|
||||
|
||||
//$-
|
||||
|
|
|
|||
|
|
@ -429,29 +429,6 @@ hash_t memhash(const void *ptr, size_t size);
|
|||
template <class T>
|
||||
inline hash_t GetHashValue(const T& x) { return x.GetHashValue(); }
|
||||
|
||||
struct CombineHash {
|
||||
hash_t hash;
|
||||
|
||||
template <class T> CombineHash& Do(const T& x) { Put(GetHashValue(x)); return *this; }
|
||||
|
||||
public:
|
||||
CombineHash& Put(hash_t h) { hash = HASH_CONST2 * hash + h; return *this; }
|
||||
|
||||
operator hash_t() const { return hash; }
|
||||
|
||||
CombineHash() { hash = HASH_CONST1; }
|
||||
template <class T>
|
||||
CombineHash(const T& h1) { hash = HASH_CONST1; Do(h1); }
|
||||
template <class T, class U>
|
||||
CombineHash(const T& h1, const U& h2) { hash = HASH_CONST1; Do(h1); Do(h2); }
|
||||
template <class T, class U, class V>
|
||||
CombineHash(const T& h1, const U& h2, const V& h3) { hash = HASH_CONST1; Do(h1); Do(h2); Do(h3); }
|
||||
template <class T, class U, class V, class W>
|
||||
CombineHash(const T& h1, const U& h2, const V& h3, const W& h4) { hash = HASH_CONST1; Do(h1); Do(h2); Do(h3); Do(h4); }
|
||||
|
||||
template <class T> CombineHash& operator<<(const T& x) { Do(x); return *this; }
|
||||
};
|
||||
|
||||
template<> inline hash_t GetHashValue(const char& a) { return (hash_t)a; }
|
||||
template<> inline hash_t GetHashValue(const signed char& a) { return (const hash_t)a; }
|
||||
template<> inline hash_t GetHashValue(const unsigned char& a) { return (const hash_t)a; }
|
||||
|
|
@ -478,12 +455,35 @@ template<> inline hash_t GetHashValue(const double& a) { return memhash(
|
|||
#ifdef CPU_32
|
||||
inline hash_t GetPtrHashValue(const void *a) { return (int)a; }
|
||||
#else
|
||||
inline hash_t GetPtrHashValue(const void *a) { return CombineHash((hash_t)(uintptr_t)a); }
|
||||
inline hash_t GetPtrHashValue(const void *a) { return (hash_t)(uintptr_t)a; }
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline hash_t GetHashValue(T *ptr) { return GetPtrHashValue(reinterpret_cast<const void *>(ptr)); }
|
||||
|
||||
struct CombineHash {
|
||||
hash_t hash;
|
||||
|
||||
template <class T> CombineHash& Do(const T& x) { Put(GetHashValue(x)); return *this; }
|
||||
|
||||
public:
|
||||
CombineHash& Put(hash_t h) { hash = HASH_CONST2 * hash + h; return *this; }
|
||||
|
||||
operator hash_t() const { return hash; }
|
||||
|
||||
CombineHash() { hash = HASH_CONST1; }
|
||||
template <class T>
|
||||
CombineHash(const T& h1) { hash = HASH_CONST1; Do(h1); }
|
||||
template <class T, class U>
|
||||
CombineHash(const T& h1, const U& h2) { hash = HASH_CONST1; Do(h1); Do(h2); }
|
||||
template <class T, class U, class V>
|
||||
CombineHash(const T& h1, const U& h2, const V& h3) { hash = HASH_CONST1; Do(h1); Do(h2); Do(h3); }
|
||||
template <class T, class U, class V, class W>
|
||||
CombineHash(const T& h1, const U& h2, const V& h3, const W& h4) { hash = HASH_CONST1; Do(h1); Do(h2); Do(h3); Do(h4); }
|
||||
|
||||
template <class T> CombineHash& operator<<(const T& x) { Do(x); return *this; }
|
||||
};
|
||||
|
||||
template <int size>
|
||||
struct Data_S_ : Moveable< Data_S_<size> >
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,10 +25,10 @@ public:
|
|||
};
|
||||
|
||||
struct TimeStopper {
|
||||
const char *name;
|
||||
String name;
|
||||
TimeStop tm;
|
||||
|
||||
TimeStopper(const char *name) : name(name) {}
|
||||
TimeStopper(const String& name) : name(name) {}
|
||||
~TimeStopper() { RLOG(name << " " << tm); }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ private:
|
|||
// ---------
|
||||
|
||||
DLLTYPE& DLIMODULE();
|
||||
DLLTYPE& DLIMODULE(const char *path);
|
||||
DLLTYPE& COMBINE(DLIMODULE, _)();
|
||||
|
||||
#endif
|
||||
|
|
@ -91,6 +92,13 @@ DLLTYPE& DLIMODULE()
|
|||
return out;
|
||||
}
|
||||
|
||||
DLLTYPE& DLIMODULE(const char *path)
|
||||
{
|
||||
DLLTYPE& out = COMBINE(DLIMODULE, _)();
|
||||
out.Load(path);
|
||||
return out;
|
||||
}
|
||||
|
||||
DLLTYPE::DLLTYPE()
|
||||
{
|
||||
checked = false;
|
||||
|
|
|
|||
|
|
@ -1,103 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
#define LLOG(x)
|
||||
#define LTIMING(x) DTIMING(x)
|
||||
|
||||
void CppItem::Serialize(Stream& s)
|
||||
{
|
||||
s % kind % access
|
||||
% item % name % natural % at % tparam % param % pname
|
||||
% tname % ctname % type % ptype % virt % filetype % file % line % impl
|
||||
% using_namespaces;
|
||||
}
|
||||
|
||||
struct CmpItem {
|
||||
bool operator()(const CppItem& a, const String& b) const
|
||||
{
|
||||
return a.qitem < b;
|
||||
}
|
||||
};
|
||||
|
||||
int FindItem(const Array<CppItem>& x, const String& qitem)
|
||||
{
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
if(x[i].qitem == qitem)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FindNext(const Array<CppItem>& x, int i)
|
||||
{
|
||||
if(i >= x.GetCount())
|
||||
return i;
|
||||
String q = x[i].qitem;
|
||||
while(i < x.GetCount() && x[i].qitem == q)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
int GetCount(const Array<CppItem>& x, int i)
|
||||
{
|
||||
return FindNext(x, i) - i;
|
||||
}
|
||||
|
||||
int FindName(const Array<CppItem>& x, const String& name, int i)
|
||||
{
|
||||
while(i < x.GetCount()) {
|
||||
if(x[i].name == name)
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CppBase::IsType(int i) const
|
||||
{
|
||||
return GetKey(i).GetCount();
|
||||
}
|
||||
|
||||
void CppBase::Dump(Stream& s)
|
||||
{
|
||||
for(int i = 0; i < GetCount(); i++) {
|
||||
s << Nvl(GetKey(i), "<<GLOBALS>>") << "\n";
|
||||
const Array<CppItem>& m = (*this)[i];
|
||||
for(int j = 0; j < m.GetCount(); j++)
|
||||
s << '\t' << m[j] << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void CppBase::Sweep(const Index<int>& file, bool keep)
|
||||
{
|
||||
Vector<int> remove;
|
||||
for(int ni = 0; ni < GetCount(); ni++) {
|
||||
Array<CppItem>& n = (*this)[ni];
|
||||
Vector<int> nr;
|
||||
for(int i = 0; i < n.GetCount(); i++)
|
||||
if((file.Find(n[i].file) < 0) == keep)
|
||||
nr.Add(i);
|
||||
if(nr.GetCount() == n.GetCount())
|
||||
remove.Add(ni); // remove whole array (later)
|
||||
else
|
||||
n.Remove(nr); // only remove some items
|
||||
}
|
||||
Remove(remove);
|
||||
}
|
||||
|
||||
void CppBase::Append(CppBase&& base)
|
||||
{
|
||||
for(int i = 0; i < base.GetCount(); i++)
|
||||
GetAdd(base.GetKey(i)).Append(pick(base[i]));
|
||||
}
|
||||
|
||||
void CppBase::RemoveFile(int filei)
|
||||
{
|
||||
Index<int> h;
|
||||
h.Add(filei);
|
||||
RemoveFiles(h);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,308 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
#define LLOG(x) // DLOG(x)
|
||||
|
||||
namespace Upp {
|
||||
|
||||
void Parser::Locals(const String& type)
|
||||
{
|
||||
Line();
|
||||
Array<Parser::Decl> d = Declaration(true, true, Null, Null);
|
||||
for(int i = 0; i < d.GetCount(); i++) {
|
||||
Local& l = local.Add(d[i].name);
|
||||
l.type = *type == '*' ? d[i].type : type;
|
||||
l.isptr = d[i].isptr;
|
||||
l.line = line + 1;
|
||||
LLOG("== Local variable " << d[i].name << ": " << l.type);
|
||||
}
|
||||
}
|
||||
|
||||
bool Parser::TryDecl()
|
||||
{ // attempt to interpret code as local variable declaration
|
||||
for(;;) {
|
||||
if(findarg(lex[0], tk_static, tk_const, tk_register, tk_volatile) >= 0)
|
||||
++lex;
|
||||
else
|
||||
if(!VCAttribute())
|
||||
break;
|
||||
}
|
||||
int t = lex[0];
|
||||
int q = 0;
|
||||
if(t == tk_int || t == tk_bool || t == tk_float || t == tk_double || t == tk_void ||
|
||||
t == tk_long || t == tk_signed || t == tk_unsigned || t == tk_short ||
|
||||
t == tk_char || t == tk___int8 || t == tk___int16 || t == tk___int32 || t == tk___int64 ||
|
||||
t == tk_auto) {
|
||||
q++;
|
||||
if(findarg(lex[q], tk_long, tk_int, tk_char) >= 0)
|
||||
q++;
|
||||
if(findarg(lex[q], tk_long, tk_int, tk_char) >= 0)
|
||||
q++;
|
||||
while(findarg(lex[q], '*', '&', t_and, tk_const) >= 0) // t_and is r-value here
|
||||
q++;
|
||||
if(!lex.IsId(q))
|
||||
return false;
|
||||
static String aut("*"), empty;
|
||||
Locals(t == tk_auto ? aut : empty);
|
||||
return true;
|
||||
}
|
||||
String type;
|
||||
if(t == tk_decltype && lex[q + 1] == '(') {
|
||||
q += 2;
|
||||
int q0 = q;
|
||||
int lvl = 1;
|
||||
for(;;) {
|
||||
if(lex[q] == t_eof)
|
||||
break;
|
||||
if(lex[q] == '(')
|
||||
lvl++;
|
||||
else
|
||||
if(lex[q] == ')' && --lvl == 0) {
|
||||
Locals("@" + String(lex.Pos(q0), lex.Pos(q)));
|
||||
return true;
|
||||
}
|
||||
++q;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(lex[q] == t_dblcolon) {
|
||||
type << "::";
|
||||
q++;
|
||||
}
|
||||
if(lex.IsId(q)) {
|
||||
type << lex.Id(q++);
|
||||
type << Tparam(q);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
while(lex[q] == t_dblcolon) {
|
||||
type << "::";
|
||||
if(lex.IsId(++q))
|
||||
type << lex.Id(q++);
|
||||
else
|
||||
return false;
|
||||
type << Tparam(q);
|
||||
}
|
||||
while(lex[q] == '*' || lex[q] == '&' || lex[q] == t_and) // t_and is r-value here
|
||||
q++;
|
||||
if(!lex.IsId(q))
|
||||
return false;
|
||||
type = qualify(current_scope, type, context.namespace_using);
|
||||
if(type.GetCount()) {
|
||||
Locals(type);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Parser::MatchPars()
|
||||
{
|
||||
int level = 1;
|
||||
while(level && lex != t_eof) {
|
||||
if(Key('(')) level++;
|
||||
else
|
||||
if(Key(')')) level--;
|
||||
else
|
||||
++lex;
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::Statement()
|
||||
{
|
||||
RecursionCounter recursionCounter(currentScopeDepth, lex == '{' ? 0 : 1);
|
||||
maxScopeDepth = max(maxScopeDepth, currentScopeDepth);
|
||||
|
||||
if(Key(tk_case)) {
|
||||
if(lex.IsId())
|
||||
++lex;
|
||||
Key(':');
|
||||
}
|
||||
if(Key(tk_default))
|
||||
Key(':');
|
||||
if(lex.IsId() && lex[1] == ':') {
|
||||
++lex;
|
||||
++lex;
|
||||
}
|
||||
if(Key('{')) {
|
||||
Context cc;
|
||||
cc <<= context;
|
||||
int l = local.GetCount();
|
||||
while(!Key('}')) {
|
||||
if(lex == t_eof)
|
||||
ThrowError("eof");
|
||||
Statement();
|
||||
}
|
||||
context <<= cc;
|
||||
local.Trim(l);
|
||||
}
|
||||
else
|
||||
if(Key(tk_if)) {
|
||||
int l = local.GetCount();
|
||||
Key('(');
|
||||
TryDecl();
|
||||
MatchPars();
|
||||
Statement();
|
||||
if(Key(tk_else))
|
||||
Statement();
|
||||
local.Trim(l);
|
||||
}
|
||||
else
|
||||
if(Key(tk_for)) {
|
||||
int l = local.GetCount();
|
||||
Key('(');
|
||||
TryDecl();
|
||||
MatchPars();
|
||||
Statement();
|
||||
local.Trim(l);
|
||||
}
|
||||
else
|
||||
if(Key(tk_while)) {
|
||||
int l = local.GetCount();
|
||||
Key('(');
|
||||
TryDecl();
|
||||
MatchPars();
|
||||
Statement();
|
||||
local.Trim(l);
|
||||
}
|
||||
else
|
||||
if(Key(tk_try))
|
||||
Statement();
|
||||
else
|
||||
if(Key(tk_catch)) {
|
||||
Key('(');
|
||||
MatchPars();
|
||||
Statement();
|
||||
}
|
||||
else
|
||||
if(Key(tk_do)) {
|
||||
Statement();
|
||||
Key(tk_while);
|
||||
Key('(');
|
||||
MatchPars();
|
||||
}
|
||||
else
|
||||
if(Key(tk_switch)) {
|
||||
int l = local.GetCount();
|
||||
Key('(');
|
||||
TryDecl();
|
||||
MatchPars();
|
||||
Statement();
|
||||
local.Trim(l);
|
||||
}
|
||||
else
|
||||
if(UsingNamespace())
|
||||
;
|
||||
else
|
||||
if(TryDecl())
|
||||
Key(';');
|
||||
else
|
||||
for(;;) {
|
||||
if(lex == t_eof)
|
||||
ThrowError("");
|
||||
TryLambda();
|
||||
if(Key(';') || lex == '{' || lex == '}' || lex >= tk_if && lex <= tk_do)
|
||||
break;
|
||||
++lex;
|
||||
}
|
||||
}
|
||||
|
||||
bool Parser::Skipars(int& q)
|
||||
{
|
||||
int par = lex[q];
|
||||
q++;
|
||||
int lvl = 1;
|
||||
while(lex[q] != t_eof) {
|
||||
int c = lex[q++];
|
||||
if(c == '(' || c == '[' || c == '{')
|
||||
lvl++;
|
||||
else
|
||||
if(c == ')' || c == ']' || c == '}') {
|
||||
lvl--;
|
||||
if(lvl == 0)
|
||||
return c == decode(par, '(', ')', '[', ']', '{', '}', 0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Parser::TryLambda()
|
||||
{
|
||||
if(lex != '[' || !dobody)
|
||||
return;
|
||||
int q = 0;
|
||||
if(!Skipars(q))
|
||||
return;
|
||||
int params = q;
|
||||
if(lex[q] == '(')
|
||||
if(!Skipars(q))
|
||||
return;
|
||||
if(lex[q] == tk_mutable)
|
||||
q++;
|
||||
if(lex[q] == t_arrow) {
|
||||
q++; // TODO: auto declaration could assign a return type here
|
||||
for(;;) {
|
||||
if(lex[q] == ';' || lex[q] == t_eof)
|
||||
return;
|
||||
if(lex[q] == '{')
|
||||
break;
|
||||
q++;
|
||||
}
|
||||
}
|
||||
if(lex[q] == '{') {
|
||||
int n = local.GetCount();
|
||||
lex.Get(params);
|
||||
if(Key('(')) {
|
||||
Decl d;
|
||||
Line();
|
||||
ParamList(d);
|
||||
}
|
||||
while(lex != '{' && lex != t_eof)
|
||||
++lex;
|
||||
Statement();
|
||||
local.Trim(n);
|
||||
}
|
||||
}
|
||||
|
||||
bool Parser::EatBody()
|
||||
{
|
||||
if(lex == t_eof)
|
||||
return false;
|
||||
if(lex != '{') {
|
||||
local.Clear();
|
||||
return false;
|
||||
}
|
||||
lex.BeginBody();
|
||||
maxScopeDepth = currentScopeDepth = dobody ? 0 : 1;
|
||||
if(dobody) {
|
||||
inbody = true;
|
||||
Statement();
|
||||
inbody = false;
|
||||
local.Clear();
|
||||
}
|
||||
else {
|
||||
Key('{');
|
||||
int level = 1;
|
||||
while(level && lex != t_eof) {
|
||||
if(Key('{')) level++;
|
||||
else
|
||||
if(Key('}')) level--;
|
||||
else
|
||||
++lex;
|
||||
maxScopeDepth = max(level, maxScopeDepth);
|
||||
}
|
||||
}
|
||||
lex.EndBody();
|
||||
return true;
|
||||
}
|
||||
|
||||
String Parser::ResolveAutoType()
|
||||
{
|
||||
Vector<String> xp = MakeXP(lex.Pos());
|
||||
if(lex == ':') // resolve for declaration, like 'for(auto i: vector)'
|
||||
xp << "." << "begin" << "()" << "->"; // incorrect, should rather use operator*(), but sufficient for now
|
||||
Index<String> s = GetExpressionType(*base, *this, xp);
|
||||
int i = FindMax(s); // Ugly hack: we are not resolving overloading at all, so just choose stable type if there are more, not Null
|
||||
return i < 0 ? String() : s[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
Copyright (c) 1998, 2022, The U++ Project
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -1,260 +0,0 @@
|
|||
#ifndef DOCPP_H
|
||||
#define DOCPP_H
|
||||
|
||||
#include <Core/Core.h>
|
||||
|
||||
namespace Upp {
|
||||
|
||||
// These functions can only but executed by single thread, unless said otherwise
|
||||
|
||||
bool IsCPPFile(const String& file);
|
||||
bool IsHFile(const String& path);
|
||||
|
||||
String GetStdDefs();
|
||||
|
||||
void SetPPDefs(const String& defs);
|
||||
|
||||
void InvalidatePPCache();
|
||||
|
||||
void PPSync(const String& include_path);
|
||||
|
||||
enum Kind {
|
||||
STRUCT,
|
||||
STRUCTTEMPLATE,
|
||||
TYPEDEF,
|
||||
CONSTRUCTOR,
|
||||
DESTRUCTOR,
|
||||
FUNCTION,
|
||||
INSTANCEFUNCTION,
|
||||
CLASSFUNCTION,
|
||||
FUNCTIONTEMPLATE,
|
||||
INSTANCEFUNCTIONTEMPLATE,
|
||||
CLASSFUNCTIONTEMPLATE,
|
||||
INLINEFRIEND,
|
||||
VARIABLE,
|
||||
INSTANCEVARIABLE,
|
||||
CLASSVARIABLE,
|
||||
ENUM,
|
||||
MACRO,
|
||||
FRIENDCLASS,
|
||||
NAMESPACE,
|
||||
FLAGTEST,
|
||||
};
|
||||
|
||||
inline bool IsCppType(int i)
|
||||
{
|
||||
return i >= STRUCT && i <= TYPEDEF || i == FRIENDCLASS;
|
||||
}
|
||||
|
||||
inline bool IsCppCode(int i) {
|
||||
return i >= CONSTRUCTOR && i <= INLINEFRIEND;
|
||||
};
|
||||
|
||||
inline bool IsCppData(int i) {
|
||||
return i >= VARIABLE && i <= ENUM;
|
||||
}
|
||||
|
||||
inline bool IsCppMacro(int i) {
|
||||
return i == MACRO;
|
||||
}
|
||||
|
||||
inline bool IsCppTemplate(int i) {
|
||||
return i == STRUCTTEMPLATE || i >= FUNCTIONTEMPLATE && i <= CLASSFUNCTIONTEMPLATE;
|
||||
}
|
||||
|
||||
void CleanPP();
|
||||
void SerializePPFiles(Stream& s);
|
||||
void SweepPPFiles(const Index<String>& keep);
|
||||
|
||||
void InvalidateFileTimeCache();
|
||||
void InvalidateFileTimeCache(const String& path);
|
||||
Time GetFileTimeCached(const String& path);
|
||||
|
||||
String NormalizeSourcePath(const String& path, const String& currdir);
|
||||
String NormalizeSourcePath(const String& path);
|
||||
|
||||
void ClearSources();
|
||||
const Index<String>& GetAllSources();
|
||||
void GatherSources(const String& path);
|
||||
String GetMasterFile(const String& file);
|
||||
const VectorMap<String, String>& GetAllSourceMasters();
|
||||
|
||||
const char **CppKeyword();
|
||||
|
||||
enum CppAccess {
|
||||
PUBLIC,
|
||||
PROTECTED,
|
||||
PRIVATE,
|
||||
};
|
||||
|
||||
enum FileTypeEnum {
|
||||
FILE_H,
|
||||
FILE_HPP,
|
||||
FILE_CPP,
|
||||
FILE_C,
|
||||
FILE_OTHER,
|
||||
};
|
||||
|
||||
struct CppItem {
|
||||
String qitem;
|
||||
String item;
|
||||
String name;
|
||||
String uname;
|
||||
String natural;
|
||||
String type;
|
||||
String qtype;
|
||||
String tparam; // complete template parameters list, like '<class T>'
|
||||
String param;
|
||||
String pname;
|
||||
String ptype; // fn: types of parameters, struct: base classes
|
||||
String qptype;
|
||||
String tname;
|
||||
String ctname;
|
||||
String using_namespaces;
|
||||
byte access = PUBLIC;
|
||||
byte kind = STRUCT;
|
||||
int16 at = 0;
|
||||
bool virt = false;
|
||||
|
||||
bool decla = false;
|
||||
bool lvalue = false;
|
||||
bool isptr = false;
|
||||
|
||||
byte filetype = FILE_OTHER;
|
||||
bool impl = false;
|
||||
int file = 0;
|
||||
int line = 0;
|
||||
|
||||
bool qualify = true;
|
||||
|
||||
bool IsType() const { return IsCppType(kind); }
|
||||
bool IsCode() const { return IsCppCode(kind); }
|
||||
bool IsData() const { return IsCppData(kind); }
|
||||
bool IsMacro() const { return IsCppMacro(kind); }
|
||||
bool IsFlagTest() const { return kind == FLAGTEST; }
|
||||
bool IsTemplate() const { return IsCppTemplate(kind); }
|
||||
|
||||
void Serialize(Stream& s);
|
||||
|
||||
void Dump(Stream& s) const;
|
||||
String ToString() const;
|
||||
};
|
||||
|
||||
int FindItem(const Array<CppItem>& x, const String& qitem);
|
||||
int FindName(const Array<CppItem>& x, const String& name, int i = 0);
|
||||
|
||||
struct CppBase : ArrayMap<String, Array<CppItem> > {
|
||||
String types_md5;
|
||||
Index<String> namespaces;
|
||||
|
||||
bool IsType(int i) const;
|
||||
void Sweep(const Index<int>& file, bool keep = true);
|
||||
void RemoveFiles(const Index<int>& remove_file) { Sweep(remove_file, false); }
|
||||
void RemoveFile(int filei);
|
||||
void Append(CppBase&& base);
|
||||
|
||||
void Dump(Stream& s);
|
||||
};
|
||||
|
||||
class ScopeInfo { // information about scope
|
||||
bool bvalid; // baselist is valid
|
||||
bool nvalid; // scopes is valid
|
||||
Vector<String> baselist; // list of all base classes of scope
|
||||
Vector<String> scopes; // list of scopes (Upp::String::Init::, Upp::String::, Upp::)
|
||||
int scopei; // index of this scope in base
|
||||
String usings; // using namespaces contained in scopes
|
||||
|
||||
void Bases(int i, Vector<int>& g);
|
||||
void Init();
|
||||
|
||||
public:
|
||||
const CppBase& base;
|
||||
VectorMap<String, String> cache;
|
||||
|
||||
const Vector<String>& GetBases();
|
||||
const Vector<String>& GetScopes(const String& usings);
|
||||
int GetScope() const { return scopei; }
|
||||
void NoBases() { baselist.Clear(); bvalid = true; }
|
||||
|
||||
ScopeInfo(const CppBase& base, int scopei = -1);
|
||||
ScopeInfo(int scopei, const CppBase& base);
|
||||
ScopeInfo(const CppBase& base, const String& scope);
|
||||
ScopeInfo(const ScopeInfo& f);
|
||||
};
|
||||
|
||||
struct ParserContext {
|
||||
struct Context {
|
||||
String ns;
|
||||
String scope;
|
||||
String ctname;
|
||||
Vector<int> tparam;
|
||||
Index<int> typenames;
|
||||
int access;
|
||||
String namespace_using;
|
||||
|
||||
void operator<<=(const Context& t);
|
||||
|
||||
String Dump() const;
|
||||
|
||||
Context() {}
|
||||
rval_default(Context);
|
||||
};
|
||||
|
||||
Context context;
|
||||
String current_scope;
|
||||
String current_key;
|
||||
String current_name;
|
||||
CppItem current;
|
||||
bool inbody;
|
||||
|
||||
struct Local : Moveable<Local> {
|
||||
String type;
|
||||
bool isptr;
|
||||
int line;
|
||||
};
|
||||
|
||||
VectorMap<String, Local> local;
|
||||
|
||||
Vector<String> GetNamespaces() const;
|
||||
bool IsInBody() const { return inbody; }
|
||||
};
|
||||
|
||||
// Parse CAN be run in parallel
|
||||
void Parse(CppBase& base, const String& src, int file, int filetype, const String& path,
|
||||
Event<int, const String&> error, const Vector<String>& namespace_stack,
|
||||
const Index<String>& namespace_using);
|
||||
|
||||
|
||||
String NoTemplatePars(const String& type);
|
||||
|
||||
// PreprocessParse CAN be run in parallel
|
||||
void PreprocessParse(CppBase& base, Stream& in, int file, const String& path,
|
||||
Event<int, const String&> error);
|
||||
String PreprocessCpp(const String& src, const String& path);
|
||||
|
||||
ParserContext AssistParse(const String& src, const String& path_, Event<int, const String&> error,
|
||||
Function<String(String, String, String)> qualify);
|
||||
|
||||
void SimpleParse(CppBase& cpp, const String& txt, const String& cls);
|
||||
|
||||
void Qualify(CppBase& base);
|
||||
|
||||
String Qualify(const CppBase& base, const String& scope, const String& type, const String& usings);
|
||||
|
||||
String ResolveTParam(const CppBase& codebase, const String& type, const Vector<String>& tparam);
|
||||
void ResolveTParam(const CppBase& codebase, Vector<String>& type, const Vector<String>& tparam);
|
||||
|
||||
String ParseTemplatedType(const String& type, Vector<String>& tparam);
|
||||
|
||||
bool HasCPPFileKeyword(const String& path, const String& id);
|
||||
|
||||
String GetPPMD5(const String& fn);
|
||||
|
||||
// GetDependeciesMD5 CAN be run in parallel
|
||||
String GetDependeciesMD5(const String& path, Index<String>& visited);
|
||||
|
||||
Index<String> GetExpressionType(const CppBase& codebase, const ParserContext& parser, const Vector<String>& xp);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
description "Partly heurestic (imprecise) C++ parser for purposes of Assist++ (intellisense)\377";
|
||||
|
||||
uses
|
||||
Core;
|
||||
|
||||
file
|
||||
CppBase.h options(BUILDER_OPTION) PCH,
|
||||
Internal.h,
|
||||
keyword.i,
|
||||
ppconfig.cpp,
|
||||
macro.cpp,
|
||||
util.cpp,
|
||||
ppfile.cpp,
|
||||
srcfiles.cpp,
|
||||
cpp.cpp,
|
||||
Pre.cpp,
|
||||
cpplex.cpp,
|
||||
Parser.cpp,
|
||||
Body.cpp,
|
||||
Base.cpp,
|
||||
ScopeInfo.cpp,
|
||||
Qualify.cpp,
|
||||
CppItem.cpp,
|
||||
Expression.cpp,
|
||||
Iface.cpp,
|
||||
Info readonly separator,
|
||||
Copying;
|
||||
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
String CppItem::ToString() const
|
||||
{
|
||||
StringStream ss;
|
||||
Dump(ss);
|
||||
return ss;
|
||||
}
|
||||
|
||||
String CppItemKindAsString(int kind)
|
||||
{
|
||||
return decode(kind,
|
||||
STRUCT, "STRUCT",
|
||||
STRUCTTEMPLATE, "STRUCTTEMPLATE",
|
||||
TYPEDEF, "TYPEDEF",
|
||||
CONSTRUCTOR, "CONSTRUCTOR",
|
||||
DESTRUCTOR, "DESTRUCTOR",
|
||||
FUNCTION, "FUNCTION",
|
||||
INSTANCEFUNCTION, "INSTANCEFUNCTION",
|
||||
CLASSFUNCTION, "CLASSFUNCTION",
|
||||
FUNCTIONTEMPLATE, "FUNCTIONTEMPLATE",
|
||||
INSTANCEFUNCTIONTEMPLATE, "INSTANCEFUNCTIONTEMPLATE",
|
||||
CLASSFUNCTIONTEMPLATE, "CLASSFUNCTIONTEMPLATE",
|
||||
INLINEFRIEND, "INLINEFRIEND",
|
||||
VARIABLE, "VARIABLE",
|
||||
INSTANCEVARIABLE, "INSTANCEVARIABLE",
|
||||
CLASSVARIABLE, "CLASSVARIABLE",
|
||||
ENUM, "ENUM",
|
||||
MACRO, "MACRO",
|
||||
FRIENDCLASS, "FRIENDCLASS",
|
||||
NAMESPACE, "NAMESPACE",
|
||||
"?kind:" + AsString(kind));
|
||||
}
|
||||
|
||||
void CppItem::Dump(Stream& s) const
|
||||
{
|
||||
s << Nvl(qitem, "?") << ' ';
|
||||
s << CppItemKindAsString(kind) << ' '
|
||||
<< decode(access,
|
||||
PUBLIC, "PUBLIC",
|
||||
PROTECTED, "PROTECTED",
|
||||
PRIVATE, "PRIVATE",
|
||||
"?access:" + AsString(access)) << ' '
|
||||
<< decode(filetype,
|
||||
FILE_H, "FILE_H",
|
||||
FILE_HPP, "FILE_HPP",
|
||||
FILE_CPP, "FILE_CPP",
|
||||
FILE_C, "FILE_C",
|
||||
FILE_OTHER, "FILE_OTHER",
|
||||
"?filetype:" + AsString(filetype))
|
||||
;
|
||||
#define PUT(x) if(x) s << ' ' << #x;
|
||||
PUT(virt);
|
||||
PUT(decla);
|
||||
PUT(lvalue);
|
||||
PUT(isptr);
|
||||
PUT(impl);
|
||||
PUT(qualify);
|
||||
#undef PUT
|
||||
s << ' ' << line << '\n';
|
||||
#define PUT(x) if(x.GetCount()) s << " " << #x << ": " << x << '\n';
|
||||
PUT(item);
|
||||
PUT(name);
|
||||
PUT(uname);
|
||||
PUT(natural);
|
||||
PUT(type);
|
||||
PUT(qtype);
|
||||
PUT(tparam);
|
||||
PUT(param);
|
||||
PUT(pname);
|
||||
PUT(ptype);
|
||||
PUT(qptype);
|
||||
PUT(tname);
|
||||
PUT(ctname);
|
||||
PUT(using_namespaces);
|
||||
#undef PUT
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,546 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
#if 0
|
||||
#define LDUMP(x) DDUMP(x)
|
||||
#define LDUMPC(x) DDUMPC(x)
|
||||
#define LLOG(x) DLOG(x)
|
||||
#else
|
||||
#define LDUMP(x)
|
||||
#define LDUMPC(x)
|
||||
#define LLOG(x)
|
||||
#endif
|
||||
|
||||
#define LTIMING(x) // DTIMING(x)
|
||||
|
||||
namespace Upp {
|
||||
|
||||
const Array<CppItem>& GetTypeItems(const CppBase& codebase, const String& type)
|
||||
{
|
||||
static Array<CppItem> sEmpty;
|
||||
int q = codebase.Find(type);
|
||||
if(q < 0)
|
||||
return sEmpty;
|
||||
return codebase[q];
|
||||
}
|
||||
|
||||
String ParseTemplatedType(const String& type, Vector<String>& tparam)
|
||||
{
|
||||
const char *s = type;
|
||||
String r;
|
||||
while(*s) {
|
||||
if(*s == '<') {
|
||||
s++;
|
||||
int lvl = 0;
|
||||
String t;
|
||||
while(*s) {
|
||||
int c = *s++;
|
||||
if(c == ',' && lvl == 0) {
|
||||
tparam.Add(t);
|
||||
t.Clear();
|
||||
}
|
||||
else {
|
||||
if(c == '>') {
|
||||
if(lvl == 0)
|
||||
break;
|
||||
lvl--;
|
||||
}
|
||||
if(c == '<')
|
||||
lvl++;
|
||||
t.Cat(c);
|
||||
}
|
||||
}
|
||||
tparam.Add(t);
|
||||
}
|
||||
else
|
||||
r.Cat(*s++);
|
||||
}
|
||||
LLOG("ParseTemplatedType " << type << " -> " << r);
|
||||
LDUMPC(tparam);
|
||||
return r;
|
||||
}
|
||||
|
||||
String ResolveTParam(const CppBase& codebase, const String& type, const Vector<String>& tparam)
|
||||
{
|
||||
LLOG("ResolveTParam " << type << ' ' << tparam);
|
||||
String r;
|
||||
const char *s = type;
|
||||
while(*s) {
|
||||
if(IsDigit(*s)) {
|
||||
int i = *s++ - '0';
|
||||
if(i >= 0 && i < tparam.GetCount())
|
||||
r.Cat(tparam[i]);
|
||||
}
|
||||
else
|
||||
if(iscib(*s))
|
||||
while(iscid(*s))
|
||||
r.Cat(*s++);
|
||||
else
|
||||
r.Cat(*s++);
|
||||
}
|
||||
LLOG("Resolved " << type << " -> " << r);
|
||||
const Array<CppItem>& x = GetTypeItems(codebase, r);
|
||||
if(x.GetCount() && x[0].kind == TYPEDEF) {
|
||||
LLOG("Is typedef " << x[0].qtype << ", unqualified " << x[0].type << ", natural " << x[0].natural);
|
||||
String h = x[0].qtype;
|
||||
if(h != type && h != r)
|
||||
return ResolveTParam(codebase, h, tparam);
|
||||
return h;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void ResolveTParam(const CppBase& codebase, Vector<String>& type, const Vector<String>& tparam)
|
||||
{
|
||||
for(int i = 0; i < type.GetCount(); i++)
|
||||
type[i] = ResolveTParam(codebase, type[i], tparam);
|
||||
}
|
||||
|
||||
struct ExpressionTyper {
|
||||
const CppBase& codebase;
|
||||
int scan_counter; // limit permutations
|
||||
String context_type;
|
||||
String usings;
|
||||
const Vector<String>& xp;
|
||||
Index<String> typeset;
|
||||
const ParserContext& parser;
|
||||
|
||||
Vector<String> GetTypeBases(const String& type);
|
||||
String ResolveReturnType(const CppItem& m, const Vector<String>& tparam);
|
||||
|
||||
void ExpressionType(bool isptr, const String& ttype, int ii,
|
||||
bool variable, bool can_shortcut_operator,
|
||||
Index<String>& visited_bases, int lvl);
|
||||
void ExpressionType(bool isptr, const String& ttype, int ii, bool variable, int lvl);
|
||||
|
||||
Index<String> ExpressionType();
|
||||
|
||||
enum { MAX_COUNT = 1000 };
|
||||
|
||||
ExpressionTyper(const CppBase& codebase, const ParserContext& parser, const Vector<String>& xp);
|
||||
};
|
||||
|
||||
ExpressionTyper::ExpressionTyper(const CppBase& codebase, const ParserContext& parser, const Vector<String>& xp)
|
||||
: codebase(codebase), xp(xp), parser(parser)
|
||||
{
|
||||
scan_counter = 0;
|
||||
context_type = parser.current_scope;
|
||||
usings = parser.context.namespace_using;
|
||||
}
|
||||
|
||||
Vector<String> ExpressionTyper::GetTypeBases(const String& type)
|
||||
{
|
||||
const Array<CppItem>& n = GetTypeItems(codebase, type);
|
||||
String bases;
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
const CppItem& im = n[i];
|
||||
if(im.IsType())
|
||||
bases << im.qptype << ';';
|
||||
}
|
||||
Index<String> r;
|
||||
Vector<String> h = Split(bases, ';');
|
||||
for(int i = 0; i < h.GetCount(); i++)
|
||||
r.FindAdd(h[i]);
|
||||
return r.PickKeys();
|
||||
}
|
||||
|
||||
String ExpressionTyper::ResolveReturnType(const CppItem& m, const Vector<String>& tparam)
|
||||
{
|
||||
if(m.tparam.GetCount()) {
|
||||
int q = InScListIndex(m.qtype, m.tname);
|
||||
if(q >= 0 && q < tparam.GetCount())
|
||||
return tparam[q];
|
||||
}
|
||||
return m.qtype;
|
||||
}
|
||||
|
||||
Vector<String> SplitTScope(const char *s)
|
||||
{
|
||||
Vector<String> r;
|
||||
const char *b = s;
|
||||
while(*s) {
|
||||
if(*s == '<') {
|
||||
s++;
|
||||
int lvl = 0;
|
||||
while(*s) {
|
||||
int c = *s++;
|
||||
if(c == '>') {
|
||||
if(lvl == 0)
|
||||
break;
|
||||
lvl--;
|
||||
}
|
||||
if(c == '<')
|
||||
lvl++;
|
||||
}
|
||||
}
|
||||
else
|
||||
if(*s == ':') {
|
||||
if(s > b)
|
||||
r.Add(String(b, s));
|
||||
while(*s == ':')
|
||||
s++;
|
||||
b = s;
|
||||
}
|
||||
else
|
||||
s++;
|
||||
}
|
||||
if(s > b)
|
||||
r.Add(String(b, s));
|
||||
return r;
|
||||
}
|
||||
|
||||
String AddTParams(const String& type, const String& ttype)
|
||||
{ // Upp::Vector::Foo, Upp::Vector<Upp::String>::Bar -> Upp::Vector<Upp::String>::Foo
|
||||
if(ttype.Find('<') < 0)
|
||||
return type;
|
||||
Vector<String> t = SplitTScope(type);
|
||||
Vector<String> tt = SplitTScope(ttype);
|
||||
int i = 0;
|
||||
String r;
|
||||
while(i < t.GetCount() && i < tt.GetCount()) {
|
||||
int q = tt[i].Find('<');
|
||||
if(q < 0)
|
||||
q = tt[i].GetLength();
|
||||
if(tt[i].Mid(0, q) != t[i])
|
||||
break;
|
||||
if(i)
|
||||
r << "::";
|
||||
r << tt[i];
|
||||
i++;
|
||||
}
|
||||
while(i < t.GetCount()) {
|
||||
if(i)
|
||||
r << "::";
|
||||
r << t[i];
|
||||
i++;
|
||||
}
|
||||
LLOG("AddTParam " << type << ", " << ttype << " -> " << r);
|
||||
return r;
|
||||
}
|
||||
|
||||
void ExpressionTyper::ExpressionType(bool isptr, const String& ttype, int ii,
|
||||
bool variable, bool can_shortcut_operator,
|
||||
Index<String>& visited_bases, int lvl)
|
||||
{
|
||||
LLOG("--- ExpressionType " << scan_counter << ", lvl " << lvl << ", ttype " << ttype << ", isptr " << isptr
|
||||
<< ", ii: " << ii << ", " << (ii < xp.GetCount() ? xp[ii] : "<end>"));
|
||||
if(++scan_counter >= MAX_COUNT || lvl > 100) // sort of ugly limitation of parsing permutations
|
||||
return;
|
||||
LDUMP(can_shortcut_operator);
|
||||
Vector<String> tparam;
|
||||
String type = ParseTemplatedType(ttype, tparam);
|
||||
int c0 = typeset.GetCount();
|
||||
const Array<CppItem>& n = GetTypeItems(codebase, type);
|
||||
LDUMP(type);
|
||||
LDUMP(tparam);
|
||||
|
||||
// STL/NTL is too much to parse for now, so until we have better expression resolver, let us play dirty
|
||||
static Index<String> std_container;
|
||||
static Index<String> std_pair_container;
|
||||
static Index<String> std_container_iterator;
|
||||
static Index<String> std_pair_container_iterator;
|
||||
static Index<String> upp_container;
|
||||
static Index<String> upp_container_iterator;
|
||||
static Index<String> upp_map_container;
|
||||
static Index<String> upp_map_container_iterator;
|
||||
static Index<String> upp_map_container_key_iterator;
|
||||
ONCELOCK {
|
||||
Vector<String> a = Split("array;vector;deque;forward_list;list;stack;queue;priority_queue;"
|
||||
"set;multiset;unordered_set;unordered_multiset", ';');
|
||||
for(int i = 0; i < a.GetCount(); i++) {
|
||||
std_container.Add("std::" + a[i]);
|
||||
std_container_iterator.Add("std::" + a[i] + "::iterator");
|
||||
}
|
||||
a = Split("map;multimap;unordered_map;unordered_multimap", ';');
|
||||
for(int i = 0; i < a.GetCount(); i++) {
|
||||
std_container.Add("std::" + a[i]);
|
||||
std_pair_container_iterator.Add("std::" + a[i] + "::iterator");
|
||||
}
|
||||
a = Split("VectorMap;ArrayMap;SortedVectorMap;SortedArrayMap", ';');
|
||||
for(int i = 0; i < a.GetCount(); i++) {
|
||||
upp_map_container.Add("Upp::" + a[i]);
|
||||
upp_map_container_iterator.Add("Upp::" + a[i] + "::iterator");
|
||||
upp_map_container_iterator.Add("Upp::" + a[i] + "::Iterator");
|
||||
upp_map_container_key_iterator.Add("Upp::" + a[i] + "::KeyIterator");
|
||||
}
|
||||
a = Split("Index;ArrayIndex;InVector;InArray;SortedIndex", ';');
|
||||
for(int i = 0; i < a.GetCount(); i++) {
|
||||
upp_container.Add("Upp::" + a[i]);
|
||||
upp_container_iterator.Add("Upp::" + a[i] + "::iterator");
|
||||
upp_container_iterator.Add("Upp::" + a[i] + "::Iterator");
|
||||
}
|
||||
}
|
||||
if(tparam.GetCount() > 0 && std_container_iterator.Find(type) >= 0) {
|
||||
LLOG("# nasty iterator");
|
||||
typeset.Clear();
|
||||
ExpressionType(false, tparam[0], ii, variable, can_shortcut_operator, visited_bases, lvl + 1);
|
||||
scan_counter = MAX_COUNT;
|
||||
return;
|
||||
}
|
||||
if(tparam.GetCount() > 1 && std_pair_container_iterator.Find(type) >= 0) {
|
||||
LLOG("# nasty pair iterator");
|
||||
typeset.Clear();
|
||||
ExpressionType(false, "std::pair<" + tparam[0] + "," + tparam[1] + ">",
|
||||
ii, variable, can_shortcut_operator, visited_bases, lvl + 1);
|
||||
scan_counter = MAX_COUNT;
|
||||
return;
|
||||
}
|
||||
if(tparam.GetCount() > 0 && upp_container_iterator.Find(type) >= 0) {
|
||||
LLOG("# Upp nasty iterator");
|
||||
typeset.Clear();
|
||||
ExpressionType(false, tparam[0], ii, variable, can_shortcut_operator, visited_bases, lvl + 1);
|
||||
scan_counter = MAX_COUNT;
|
||||
return;
|
||||
}
|
||||
if(tparam.GetCount() > 1 && upp_map_container_iterator.Find(type) >= 0) {
|
||||
LLOG("# Upp map nasty iterator");
|
||||
typeset.Clear();
|
||||
ExpressionType(false, tparam[1], ii, variable, can_shortcut_operator, visited_bases, lvl + 1);
|
||||
scan_counter = MAX_COUNT;
|
||||
return;
|
||||
}
|
||||
if(tparam.GetCount() > 1 && upp_map_container_key_iterator.Find(type) >= 0) {
|
||||
LLOG("# Upp map nasty key iterator");
|
||||
typeset.Clear();
|
||||
ExpressionType(false, tparam[0], ii, variable, can_shortcut_operator, visited_bases, lvl + 1);
|
||||
scan_counter = MAX_COUNT;
|
||||
return;
|
||||
}
|
||||
|
||||
if(codebase.namespaces.Find(ttype) < 0 && ttype.GetCount()) // do not search for namespace typedefs
|
||||
for(int i = 0; i < n.GetCount(); i++)
|
||||
if(n[i].kind == TYPEDEF) {
|
||||
LLOG("typedef -> " << n[i].qtype);
|
||||
ExpressionType(false, AddTParams(ResolveTParam(codebase, n[i].qtype, tparam), ttype), ii, variable, can_shortcut_operator, visited_bases, lvl + 1);
|
||||
return;
|
||||
}
|
||||
if(ii >= xp.GetCount()) {
|
||||
LLOG("==== Final type: " << ttype);
|
||||
typeset.FindAdd(ttype);
|
||||
return;
|
||||
}
|
||||
String id = xp[ii];
|
||||
|
||||
// More nasty tricks to make things work with containers (hopefully temporary)
|
||||
if((id == "begin" || id == "end") && std_container.Find(type) >= 0) {
|
||||
LLOG("# nasty begin/end");
|
||||
typeset.Clear();
|
||||
ExpressionType(false, ttype + "::iterator", ii + 1, variable, can_shortcut_operator, visited_bases, lvl + 1);
|
||||
scan_counter = MAX_COUNT;
|
||||
return;
|
||||
}
|
||||
if(findarg(id, "begin", "end", "Begin", "End") >= 0 &&
|
||||
(upp_map_container.Find(type) >= 0 || upp_container.Find(type) >= 0)) {
|
||||
LLOG("# nasty Upp begin/end");
|
||||
typeset.Clear();
|
||||
ExpressionType(false, ttype + "::Iterator", ii + 1, variable, can_shortcut_operator, visited_bases, lvl + 1);
|
||||
scan_counter = MAX_COUNT;
|
||||
return;
|
||||
}
|
||||
if(findarg(id, "KeyBegin", "KeyEnd") >= 0 && upp_map_container.Find(type) >= 0) {
|
||||
LLOG("# nasty Upp KeyBegin/KeyEnd");
|
||||
typeset.Clear();
|
||||
ExpressionType(false, ttype + "::KeyIterator", ii + 1, variable, can_shortcut_operator, visited_bases, lvl + 1);
|
||||
scan_counter = MAX_COUNT;
|
||||
return;
|
||||
}
|
||||
|
||||
int q = id.ReverseFind(':');
|
||||
if(q > 0 && id[q - 1] == ':') {
|
||||
type = ResolveTParam(codebase, Qualify(codebase, ttype, id.Mid(0, q - 1), usings), tparam);
|
||||
id = id.Mid(q + 1);
|
||||
}
|
||||
if(id.Find('<') >= 0) // as in Single<Display>
|
||||
id = ParseTemplatedType(id, tparam);
|
||||
LLOG("ExpressionType " << type << " ii: " << ii << " id:" << id << " variable:" << variable);
|
||||
|
||||
for(int i = 0; i < tparam.GetCount(); i++) // need to qualify template parameters
|
||||
tparam[i] = Qualify(codebase, context_type, tparam[i], usings);
|
||||
|
||||
bool shortcut_oper = false;
|
||||
if(!iscid(*id) && *id != '.' && !isptr) {
|
||||
shortcut_oper = can_shortcut_operator;
|
||||
id = "operator" + id;
|
||||
LLOG("id as: " << id);
|
||||
}
|
||||
if(*id == '.' || (!variable && !iscid(*id))) {
|
||||
LLOG(". " << ttype);
|
||||
ExpressionType(isptr, ttype, ii + 1, false, lvl + 1);
|
||||
return;
|
||||
}
|
||||
LDUMP(id);
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
const CppItem& m = n[i];
|
||||
if(m.name == id) {
|
||||
String t = AddTParams(ResolveReturnType(m, tparam), ttype);
|
||||
bool skipfnpars = m.IsCode() && ii + 1 < xp.GetCount() && xp[ii + 1] == "()";
|
||||
ExpressionType(m.isptr, ResolveTParam(codebase, t, tparam), ii + skipfnpars + 1,
|
||||
m.IsData() && !m.isptr, lvl + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(typeset.GetCount() == c0 && type.GetCount()) { // try to find id in type - Class::Method case
|
||||
String type2 = ParseTemplatedType(type, tparam);
|
||||
const Array<CppItem>& n = GetTypeItems(codebase, type2);
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
const CppItem& m = n[i];
|
||||
if(m.name == id) {
|
||||
String t = AddTParams(ResolveReturnType(m, tparam), type);
|
||||
bool skipfnpars = m.IsCode() && ii + 1 < xp.GetCount() && xp[ii + 1] == "()";
|
||||
ExpressionType(m.isptr, ResolveTParam(codebase, t, tparam), ii + skipfnpars + 1,
|
||||
m.IsData() && !m.isptr, lvl + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(typeset.GetCount() != c0 || IsNull(type))
|
||||
return;
|
||||
Vector<String> base = GetTypeBases(type);
|
||||
LDUMPC(base);
|
||||
ResolveTParam(codebase, base, tparam);
|
||||
LDUMPC(base);
|
||||
for(int i = 0; i < base.GetCount(); i++)
|
||||
if(visited_bases.Find(base[i]) < 0) {
|
||||
visited_bases.Add(base[i]);
|
||||
ExpressionType(isptr, base[i], ii, variable, false, visited_bases, lvl + 1);
|
||||
if(typeset.GetCount() != c0)
|
||||
return;
|
||||
}
|
||||
|
||||
if(shortcut_oper) {
|
||||
LLOG("Shortcut " << xp[ii] << ", ttype " << ttype);
|
||||
ExpressionType(false, ttype, ii + 1, false, lvl + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionTyper::ExpressionType(bool isptr, const String& ttype, int ii, bool variable, int lvl)
|
||||
{
|
||||
Index<String> bases;
|
||||
ExpressionType(isptr, ttype, ii, false, true, bases, 0);
|
||||
}
|
||||
|
||||
Index<String> ExpressionTyper::ExpressionType()
|
||||
{
|
||||
LLOG("------------------------------------------------------");
|
||||
LLOG("**** ExpressionType " << xp);
|
||||
String type;
|
||||
if(xp.GetCount() == 0)
|
||||
return pick(typeset);
|
||||
if(xp[0] == "this") {
|
||||
LLOG("this: " << type);
|
||||
ExpressionType(false, context_type, 1, false, 0);
|
||||
return pick(typeset);
|
||||
}
|
||||
int q = parser.local.FindLast(xp[0]);
|
||||
if(q >= 0) {
|
||||
String type = Qualify(codebase, context_type, parser.local[q].type, parser.context.namespace_using);
|
||||
LLOG("Found type local: " << type << " in scope: " << context_type << ", isptr: " << parser.local[q].isptr);
|
||||
ExpressionType(parser.local[q].isptr, type, 1, !parser.local[q].isptr, 0);
|
||||
return pick(typeset);
|
||||
}
|
||||
if(context_type.GetCount()) {
|
||||
ExpressionType(false, context_type, 0, false, 0);
|
||||
if(typeset.GetCount())
|
||||
return pick(typeset);
|
||||
}
|
||||
if(xp.GetCount() >= 2 && xp[1] == "()") {
|
||||
Vector<String> usings = Split(parser.context.namespace_using, ';');
|
||||
usings.Add("");
|
||||
for(int i = 0; i < usings.GetCount(); i++) {
|
||||
String qtype = Qualify(codebase, context_type, Merge("::", usings[i], xp[0]), parser.context.namespace_using);
|
||||
Vector<String> tparam;
|
||||
if(codebase.Find(ParseTemplatedType(qtype, tparam)) >= 0) {
|
||||
LLOG("Is constructor " << qtype);
|
||||
ExpressionType(false, qtype, 2, false, 0);
|
||||
}
|
||||
}
|
||||
if(typeset.GetCount())
|
||||
return pick(typeset);
|
||||
}
|
||||
Vector<String> ns = parser.GetNamespaces();
|
||||
for(int i = 0; i < ns.GetCount(); i++)
|
||||
ExpressionType(false, ns[i], 0, false, 0);
|
||||
return pick(typeset);
|
||||
}
|
||||
|
||||
Index<String> GetExpressionType(const CppBase& codebase, const ParserContext& parser, const Vector<String>& xp)
|
||||
{ // xp is a list of meaningful parts like "foo", "." , "Fn", "()", "->", "m", "[]"
|
||||
return ExpressionTyper(codebase, parser, xp).ExpressionType();
|
||||
}
|
||||
|
||||
void SkipPars(CParser& p)
|
||||
{
|
||||
int lvl = 1;
|
||||
while(lvl && !p.IsEof())
|
||||
if(p.Char('(') || p.Char('['))
|
||||
lvl++;
|
||||
else
|
||||
if(p.Char(')') || p.Char(']'))
|
||||
lvl--;
|
||||
else
|
||||
p.SkipTerm();
|
||||
}
|
||||
|
||||
Vector<String> MakeXP(const char *s)
|
||||
{
|
||||
Vector<String> xp;
|
||||
try {
|
||||
CParser p(s);
|
||||
while(!p.IsChar2(':', ':') && !p.IsId() && !p.IsEof())
|
||||
p.SkipTerm();
|
||||
while(!p.IsEof()) {
|
||||
String id;
|
||||
if(p.IsChar2(':', ':') || p.IsId()) {
|
||||
for(;;)
|
||||
if(p.Char2(':', ':'))
|
||||
id.Cat("::");
|
||||
else
|
||||
if(p.IsId())
|
||||
id.Cat(p.ReadId());
|
||||
else
|
||||
break;
|
||||
const char *s = p.GetPtr();
|
||||
if(p.Char('<')) {
|
||||
int lvl = 1;
|
||||
while(lvl && !p.IsEof()) {
|
||||
if(p.Char('<'))
|
||||
lvl++;
|
||||
else
|
||||
if(p.Char('>'))
|
||||
lvl--;
|
||||
else
|
||||
p.SkipTerm();
|
||||
}
|
||||
while(s < p.GetPtr()) {
|
||||
if((byte)*s > ' ')
|
||||
id.Cat(*s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
xp.Add(id);
|
||||
}
|
||||
else
|
||||
if(p.Char('(')) {
|
||||
xp.Add("()");
|
||||
SkipPars(p);
|
||||
}
|
||||
else
|
||||
if(p.Char('[')) {
|
||||
xp.Add("[]");
|
||||
SkipPars(p);
|
||||
}
|
||||
else
|
||||
if(p.Char2('-', '>'))
|
||||
xp.Add("->");
|
||||
else
|
||||
if(p.Char('.'))
|
||||
xp.Add(".");
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
return xp;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
bool HasCPPFileKeyword(const String& path, const String& id)
|
||||
{
|
||||
const PPFile& f = GetPPFile(NormalizeSourcePath(path));
|
||||
return FindIndex(f.keywords, id) >= 0;
|
||||
}
|
||||
|
||||
String GetDependeciesMD5(const String& path, Index<String>& visited)
|
||||
{
|
||||
Cpp pp;
|
||||
FileIn in(path);
|
||||
String npath = NormalizeSourcePath(path);
|
||||
pp.Preprocess(npath, in, GetMasterFile(npath), true);
|
||||
String md5 = pp.GetDependeciesMd5(GetPPFile(path).keywords);
|
||||
visited = pick(pp.visited);
|
||||
return md5;
|
||||
}
|
||||
|
||||
String GetPPMD5(const String& fn)
|
||||
{
|
||||
return GetPPFile(fn).md5sum;
|
||||
}
|
||||
|
||||
void Parse(CppBase& base,
|
||||
const String& src, int file, int filetype, const String& path,
|
||||
Event<int, const String&> error, const Vector<String>& namespace_stack,
|
||||
const Index<String>& namespace_using)
|
||||
{
|
||||
StringStream pin(src);
|
||||
Parser p;
|
||||
p.Do(pin, base, file, filetype, GetFileName(path), error, Vector<String>(),
|
||||
namespace_stack, namespace_using);
|
||||
}
|
||||
|
||||
void PreprocessParse(CppBase& base, Stream& in, int file, const String& path,
|
||||
Event<int, const String&> error)
|
||||
{
|
||||
Cpp cpp;
|
||||
cpp.Preprocess(path, in, GetMasterFile(path));
|
||||
int filetype = decode(ToLower(GetFileExt(path)), ".h", FILE_H, ".hpp", FILE_HPP,
|
||||
".cpp", FILE_CPP, ".icpp", FILE_CPP, ".c", FILE_C, FILE_OTHER);
|
||||
Parse(base, cpp.output, file, filetype, path, error, cpp.namespace_stack, cpp.namespace_using);
|
||||
}
|
||||
|
||||
String PreprocessCpp(const String& src, const String& path)
|
||||
{
|
||||
Cpp cpp;
|
||||
StringStream in(src);
|
||||
String p = NormalizeSourcePath(path);
|
||||
cpp.Preprocess(p, in, GetMasterFile(p));
|
||||
return cpp.output;
|
||||
}
|
||||
|
||||
ParserContext AssistParse(const String& src, const String& path_, Event<int, const String&> error,
|
||||
Function<String(String, String, String)> qualify)
|
||||
{
|
||||
String path = NormalizeSourcePath(path_);
|
||||
Cpp cpp;
|
||||
StringStream ss(src);
|
||||
cpp.Preprocess(path, ss, GetMasterFile(path));
|
||||
Parser parser;
|
||||
parser.dobody = true; // will do bodies and not write anything to base
|
||||
parser.qualify = qualify;
|
||||
StringStream pin(cpp.output);
|
||||
CppBase dummy;
|
||||
parser.Do(pin, dummy, Null, Null, GetFileTitle(path), error,
|
||||
Vector<String>(), cpp.namespace_stack, cpp.namespace_using); // needs CodeBase to identify type names
|
||||
return pick(parser);
|
||||
}
|
||||
|
||||
void SimpleParse(CppBase& cpp, const String& txt, const String& cls)
|
||||
{
|
||||
Parser parser; // we do not need/want preprocessing here
|
||||
StringStream ss(txt);
|
||||
parser.Do(ss, cpp, Null, Null, Null, CNULL, Split(cls, ':'),
|
||||
Vector<String>(), Index<String>());
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -1,450 +0,0 @@
|
|||
#ifndef _CppBase_Internal_h_
|
||||
#define _CppBase_Internal_h_
|
||||
|
||||
namespace Upp {
|
||||
|
||||
const char *SkipString(const char *s);
|
||||
|
||||
void RemoveComments(String& l, bool& incomment);
|
||||
|
||||
const VectorMap<String, String>& GetNamespaceMacros();
|
||||
const Index<String>& GetNamespaceEndMacros();
|
||||
|
||||
struct CppMacro : Moveable<CppMacro> {
|
||||
String param;
|
||||
String body;
|
||||
byte md5[16];
|
||||
|
||||
String Define(const char *s);
|
||||
void SetUndef() { body = "\x7f"; }
|
||||
bool IsUndef() const { return body[0] == '\x7f' && body[1] == '\0'; }
|
||||
|
||||
String Expand(const Vector<String>& p, const Vector<String>& ep) const;
|
||||
|
||||
void Serialize(Stream& s);
|
||||
|
||||
String ToString() const;
|
||||
};
|
||||
|
||||
enum PPItemType {
|
||||
PP_DEFINES,
|
||||
PP_INCLUDE,
|
||||
PP_USING,
|
||||
PP_NAMESPACE,
|
||||
PP_NAMESPACE_END
|
||||
};
|
||||
|
||||
struct PPItem {
|
||||
int type;
|
||||
String text;
|
||||
int segment_id;
|
||||
|
||||
void Serialize(Stream& s) { s % type % text % segment_id; }
|
||||
};
|
||||
|
||||
struct PPMacro : Moveable<PPMacro> {
|
||||
CppMacro macro;
|
||||
int segment_id; // a group of macros in single file, between other elements (include, namespace. using, undef...)
|
||||
int line; // line in file
|
||||
int undef_segment_id; // macro has matching undef in the same file within this segment
|
||||
|
||||
void Serialize(Stream& s) { s % macro % segment_id % line % undef_segment_id; }
|
||||
String ToString() const { return AsString(macro) + " " + AsString(segment_id); }
|
||||
|
||||
PPMacro() { segment_id = undef_segment_id = 0; }
|
||||
};
|
||||
|
||||
struct PPFile { // contains "macro extract" of file, only info about macros defined and namespaces
|
||||
Time filetime;
|
||||
Array<PPItem> item;
|
||||
Index<String> includes;
|
||||
Vector<String> keywords;
|
||||
String md5sum;
|
||||
|
||||
void Parse(Stream& in);
|
||||
void Serialize(Stream& s) { s % filetime % item % includes % keywords % md5sum; }
|
||||
void Dump() const;
|
||||
|
||||
private:
|
||||
Vector<int> ppmacro; // indicies of macros in sAllMacros
|
||||
|
||||
void CheckEndNamespace(Vector<int>& namespace_block, int level, Md5Stream& md5);
|
||||
};
|
||||
|
||||
PPMacro *FindPPMacro(const String& id, Index<int>& segment_id, int& segmenti);
|
||||
const CppMacro *FindMacro(const String& id, Index<int>& segment_id, int& segmenti);
|
||||
|
||||
String GetIncludePath();
|
||||
|
||||
String GetSegmentFile(int segment_id);
|
||||
|
||||
void MakePP(const Index<String>& paths); // this is the only place to change PPFile info, cannot be run concurrently with anything else
|
||||
|
||||
const PPFile& GetPPFile(const char *path); // only returns information created by MakePP
|
||||
|
||||
String GetIncludePath(const String& s, const String& filedir);
|
||||
bool IncludesFile(const String& parent_path, const String& header_path);
|
||||
|
||||
struct FlatPP {
|
||||
Index<int> segment_id;
|
||||
Index<String> usings;
|
||||
};
|
||||
|
||||
const FlatPP& GetFlatPPFile(const char *path); // with #includes resolved
|
||||
|
||||
struct Cpp {
|
||||
static Index<String> kw;
|
||||
|
||||
bool incomment;
|
||||
bool done;
|
||||
|
||||
Index<String> visited;
|
||||
|
||||
Index<int> segment_id; // segments of included macros
|
||||
VectorMap<String, PPMacro> macro; // macros defined
|
||||
int std_macros; // standard macros (keywords and trick - fixed)
|
||||
Index<String> notmacro; // accelerator / expanding helper
|
||||
String prefix_macro; // for handling multiline macros
|
||||
|
||||
String output; // preprocessed file
|
||||
// Index<String> usedmacro;
|
||||
Index<String> namespace_using; // 'using namespace' up to start of file
|
||||
Vector<String> namespace_stack; // namspace up to start of file
|
||||
|
||||
Md5Stream md5;
|
||||
|
||||
void Define(const char *s);
|
||||
|
||||
void ParamAdd(Vector<String>& param, const char *b, const char *e);
|
||||
String Expand(const char *s);
|
||||
void DoFlatInclude(const String& header_path);
|
||||
void Do(const String& sourcefile, Stream& in, const String& currentfile, bool get_macros);
|
||||
|
||||
bool Preprocess(const String& sourcefile, Stream& in, const String& currentfile,
|
||||
bool just_get_macros = false);
|
||||
|
||||
String GetDependeciesMd5(const Vector<String>& m);
|
||||
|
||||
typedef Cpp CLASSNAME;
|
||||
};
|
||||
|
||||
enum tk_Keywords {
|
||||
Tmarker_before_first = 255,
|
||||
#define CPPID(x) tk_##x,
|
||||
#include "keyword.i"
|
||||
#undef CPPID
|
||||
};
|
||||
|
||||
enum t_Terms {
|
||||
t_eof,
|
||||
t_string = -200,
|
||||
t_integer,
|
||||
t_double,
|
||||
t_character,
|
||||
t_dblcolon, // ::
|
||||
t_mulass, // *=
|
||||
t_divass, // /=
|
||||
t_modass, // %=
|
||||
t_xorass, // ^=
|
||||
t_neq, // <>
|
||||
t_dot_asteriks, // .*
|
||||
t_elipsis, // ...
|
||||
t_inc, // ++
|
||||
t_addass, // +=
|
||||
t_dec, // -
|
||||
t_arrow_asteriks, // ->*
|
||||
t_arrow, // ->
|
||||
t_subass, // -=
|
||||
t_and, // &
|
||||
t_andass, // &=
|
||||
t_or, // |
|
||||
t_orass, // |=
|
||||
t_eq, // ==
|
||||
t_shl, // <<
|
||||
t_shlass, // <<=
|
||||
t_le, // <=
|
||||
t_shr, // >>
|
||||
t_shrass, // >>=
|
||||
t_ge, // >=
|
||||
te_integeroverflow,
|
||||
te_badcharacter,
|
||||
te_badstring,
|
||||
};
|
||||
|
||||
class LexSymbolStat
|
||||
{
|
||||
public:
|
||||
LexSymbolStat();
|
||||
void Reset(int minSymbol, int maxSymbol);
|
||||
void IncStat(int symbol);
|
||||
int GetStat(int symbol) const;
|
||||
int SumStat(const Vector<int> & symbols) const;
|
||||
void Merge(const LexSymbolStat & other);
|
||||
|
||||
private:
|
||||
Vector<int> v;
|
||||
int minSymbol;
|
||||
};
|
||||
|
||||
|
||||
class Lex {
|
||||
#ifdef _DEBUG
|
||||
const char *pp;
|
||||
#endif
|
||||
const char *ptr;
|
||||
const char *pos;
|
||||
|
||||
Index<String> id;
|
||||
int endkey;
|
||||
int braceslevel;
|
||||
|
||||
struct Term : Moveable<Term>{
|
||||
const char *ptr;
|
||||
int code;
|
||||
String text;
|
||||
double number;
|
||||
bool grounding;
|
||||
|
||||
Term() { grounding = false; }
|
||||
};
|
||||
|
||||
bool statsCollected;
|
||||
LexSymbolStat symbolStat;
|
||||
BiVector<Term> term;
|
||||
int body;
|
||||
bool grounding;
|
||||
|
||||
bool Char(int c) { if(*ptr == c) { ptr++; return true; } else return false; }
|
||||
void AddCode(int code) { Term& tm = term.AddTail(); tm.code = code; tm.ptr = pos; tm.grounding = grounding; }
|
||||
void AssOp(int noass, int ass) { AddCode(Char('=') ? ass : noass); }
|
||||
void Next();
|
||||
bool Prepare(int pos);
|
||||
int GetCharacter();
|
||||
void ThrowError(const char *e);
|
||||
|
||||
public:
|
||||
Event<const String&> WhenError;
|
||||
|
||||
struct Grounding {};
|
||||
|
||||
int Code(int pos = 0);
|
||||
bool IsId(int pos = 0);
|
||||
String Id(int pos = 0);
|
||||
int Int(int pos = 0);
|
||||
double Double(int pos = 0);
|
||||
int Chr(int pos = 0);
|
||||
String Text(int pos = 0);
|
||||
|
||||
void Get(int n = 1);
|
||||
int GetCode() { int q = Code(); Get(); return q; }
|
||||
String GetId() { String q = Id(); Get(); return q; }
|
||||
int GetInt() { int q = Int(); Get(); return q; }
|
||||
double GetDouble() { double q = Double(); Get(); return q; }
|
||||
int GetChr() { int q = Chr(); Get(); return q; }
|
||||
String GetText() { String q = Text(); Get(); return q; }
|
||||
|
||||
int Id(const String& s) { return id.FindAdd(s) + 256; }
|
||||
|
||||
int GetBracesLevel() const { return braceslevel; }
|
||||
void ClearBracesLevel() { braceslevel = 0; }
|
||||
|
||||
void BeginBody() { body++; }
|
||||
void EndBody() { body--; }
|
||||
void ClearBody() { body = 0; }
|
||||
bool IsBody() const { return body; }
|
||||
bool IsGrounded() { Code(); return term.GetCount() && term[0].grounding; }
|
||||
void SkipToGrounding();
|
||||
|
||||
const char *Pos(int pos = 0);
|
||||
int operator[](int pos) { return Code(pos); }
|
||||
operator int() { return Code(0); }
|
||||
void operator++() { return Get(); }
|
||||
|
||||
void Dump(int pos);
|
||||
|
||||
void Init(const char *s);
|
||||
void StartStatCollection();
|
||||
const LexSymbolStat & FinishStatCollection();
|
||||
|
||||
Lex();
|
||||
};
|
||||
|
||||
struct SrcFile {
|
||||
SrcFile();
|
||||
rval_default(SrcFile);
|
||||
|
||||
String text;
|
||||
Vector<int> linepos;
|
||||
int preprocessorLinesRemoved;
|
||||
int blankLinesRemoved;
|
||||
int commentLinesRemoved;
|
||||
};
|
||||
|
||||
struct Parser;
|
||||
|
||||
SrcFile PreProcess(Stream& in, Parser& parser);
|
||||
|
||||
String CppItemKindAsString(int kind);
|
||||
|
||||
struct Parser : ParserContext {
|
||||
struct Decla {
|
||||
bool s_static = false;
|
||||
bool s_extern = false;
|
||||
bool s_register = false;
|
||||
bool s_mutable = false;
|
||||
bool s_explicit = false;
|
||||
bool s_virtual = false;
|
||||
String name;
|
||||
bool function = false;
|
||||
bool type_def = false;
|
||||
bool isfriend = false;
|
||||
bool istemplate = false;
|
||||
bool istructor = false;
|
||||
bool isdestructor = false;
|
||||
bool isptr = false;
|
||||
bool nofn = false;
|
||||
bool oper = false;
|
||||
bool castoper = false;
|
||||
|
||||
String tnames;
|
||||
String type;
|
||||
String natural;
|
||||
};
|
||||
|
||||
struct Decl : Decla {
|
||||
Array<Decl> param;
|
||||
|
||||
rval_default(Decl);
|
||||
Decl() {}
|
||||
};
|
||||
|
||||
struct RecursionCounter
|
||||
{
|
||||
int change;
|
||||
int &count;
|
||||
RecursionCounter(int &count_i, int change_i = 1) :
|
||||
change(change_i), count(count_i)
|
||||
{
|
||||
count += change;
|
||||
}
|
||||
~RecursionCounter() { count -= change; }
|
||||
};
|
||||
|
||||
SrcFile file;
|
||||
Lex lex;
|
||||
int filei;
|
||||
byte filetype;
|
||||
String title;
|
||||
int struct_level;
|
||||
|
||||
Event<int, const String&> err;
|
||||
|
||||
int lpos, line;
|
||||
|
||||
CppBase *base;
|
||||
|
||||
int RPtr();
|
||||
|
||||
bool Key(int code);
|
||||
bool EatBody();
|
||||
String ResolveAutoType();
|
||||
void TryLambda();
|
||||
bool Skipars(int& q);
|
||||
|
||||
void Cv();
|
||||
String TType();
|
||||
String ReadType(Decla& d, const String& tname, const String& tparam);
|
||||
void Qualifier(bool override_final = false);
|
||||
void ParamList(Decl& d);
|
||||
void Declarator(Decl& d, const char *p);
|
||||
void EatInitializers();
|
||||
void Vars(Array<Decl>& r, const char *p, bool type_def, bool more);
|
||||
void ReadMods(Decla& d);
|
||||
Array<Decl> Declaration0(bool l0, bool more, const String& tname, const String& tparam);
|
||||
Array<Decl> Declaration(bool l0/* = false*/, bool more/* = false*/, const String& tname, const String& tparam);
|
||||
bool IsParamList(int q);
|
||||
void Elipsis(Decl& d);
|
||||
Decl& Finish(Decl& d, const char *p);
|
||||
void AddNamespace(const String& n, const String& name);
|
||||
bool Scope(const String& tp, const String& tn);
|
||||
|
||||
String TemplateParams(String& pnames);
|
||||
String TemplateParams();
|
||||
String TemplatePnames();
|
||||
String Name(String& h, bool& castoper, bool& oper);
|
||||
String Name(bool& castoper, bool& oper);
|
||||
String Constant();
|
||||
String ReadOper(bool& castoper);
|
||||
|
||||
int GetLine(const char *pos);
|
||||
void Line();
|
||||
void Check(bool b, const char *err);
|
||||
void CheckKey(int c);
|
||||
|
||||
void ClassEnum(const String& clss);
|
||||
bool IsEnum(int i);
|
||||
bool UsingNamespace();
|
||||
void SetScopeCurrent();
|
||||
void ScopeBody();
|
||||
void DoNamespace();
|
||||
void Do();
|
||||
String AnonymousName();
|
||||
String StructDeclaration(const String& tp, const String& tn);
|
||||
void Enum(bool vars);
|
||||
|
||||
CppItem& Item(const String& scope, const String& using_namespace, const String& item,
|
||||
const String& name, bool impl);
|
||||
CppItem& Item(const String& scope, const String& using_namespace, const String& item,
|
||||
const String& name);
|
||||
|
||||
CppItem& Fn(const Decl& d, const String& templ, bool body,
|
||||
const String& tname, const String& tparam);
|
||||
|
||||
struct Error {};
|
||||
|
||||
void ThrowError(const String& e);
|
||||
void Resume(int bl);
|
||||
|
||||
void MatchPars();
|
||||
bool VCAttribute();
|
||||
bool TryDecl();
|
||||
void Statement();
|
||||
void Locals(const String& type);
|
||||
String Tparam(int& q);
|
||||
bool IsNamespace(const String& scope);
|
||||
|
||||
friend class Lex; // Fix to make Lex::ThrowError
|
||||
|
||||
typedef Parser CLASSNAME;
|
||||
|
||||
public:
|
||||
void AddMacro(int lineno, const String& macro, int kind = MACRO);
|
||||
|
||||
bool dobody;
|
||||
Function<String(String, String, String)> qualify; // used to qualify local variable names (needs main codebase and its mutex)
|
||||
int currentScopeDepth;
|
||||
int maxScopeDepth;
|
||||
|
||||
String namespace_info;
|
||||
|
||||
const SrcFile &getPreprocessedFile() { return file; }
|
||||
|
||||
void Do(Stream& in, CppBase& _base, int file, int filetype,
|
||||
const String& title, Event<int, const String&> _err,
|
||||
const Vector<String>& typenames,
|
||||
const Vector<String>& namespace_stack,
|
||||
const Index<String>& namespace_using);
|
||||
|
||||
Parser() : dobody(false) { lex.WhenError = THISBACK(ThrowError); }
|
||||
};
|
||||
|
||||
void QualifyTypes(CppBase& base, const String& scope, CppItem& m);
|
||||
String QualifyKey(const CppBase& base, const String& scope, const String& type, const String& usings);
|
||||
|
||||
const Array<CppItem>& GetTypeItems(const CppBase& codebase, const String& type);
|
||||
|
||||
Vector<String> MakeXP(const char *s);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,188 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
#define LTIMING(x) // DTIMING(x)
|
||||
|
||||
namespace Upp {
|
||||
|
||||
void SLPos(SrcFile& res)
|
||||
{
|
||||
res.linepos.Add(res.text.GetLength());
|
||||
}
|
||||
|
||||
SrcFile::SrcFile() :
|
||||
preprocessorLinesRemoved(0),
|
||||
blankLinesRemoved(0),
|
||||
commentLinesRemoved(0)
|
||||
{
|
||||
}
|
||||
|
||||
SrcFile PreProcess(Stream& in, Parser& parser) // This is not really C preprocess, only removes (or processes) comments and directives
|
||||
{
|
||||
SrcFile res;
|
||||
bool include = true;
|
||||
int lineno = 0;
|
||||
while(!in.IsEof()) {
|
||||
String ln = in.GetLine();
|
||||
lineno++;
|
||||
SLPos(res);
|
||||
while(*ln.Last() == '\\') {
|
||||
ln.Trim(ln.GetLength() - 1);
|
||||
ln.Cat(in.GetLine());
|
||||
SLPos(res);
|
||||
}
|
||||
const char *rm = ln;
|
||||
if(IsAlNum(*rm)) {
|
||||
const char *s = ln;
|
||||
bool islbl = false;
|
||||
bool wassemi = false;
|
||||
while(*s && iscid(*s) || findarg(*s, '\t', ' ', ':') >= 0) { // check for label, labeled lines are not grounded
|
||||
if(*s == ':' && !wassemi) {
|
||||
islbl = true;
|
||||
wassemi = true; // second ':' cancels label
|
||||
}
|
||||
else
|
||||
if(*s != '\t' && *s != ' ')
|
||||
islbl = false; // something was after the label, e.g. void Foo::Bar()
|
||||
s++;
|
||||
}
|
||||
if(!islbl)
|
||||
res.text << '\2';
|
||||
}
|
||||
else
|
||||
if(*rm == '\x1f') // line started with macro
|
||||
res.text << '\2';
|
||||
while(*rm == ' ' || *rm == '\t') rm++;
|
||||
if(*rm == '\0')
|
||||
res.blankLinesRemoved++;
|
||||
else
|
||||
if(*rm == '#') {
|
||||
const char *s = rm + 1;
|
||||
while(*s == ' ' || *s == '\t')
|
||||
s++;
|
||||
if(s[0] == 'd' && s[1] == 'e' && s[2] == 'f' &&
|
||||
s[3] == 'i' && s[4] == 'n' && s[5] == 'e' && !iscid(s[6])) {
|
||||
s += 6;
|
||||
while(*s == ' ' || *s == '\t') s++;
|
||||
const char *b = s;
|
||||
while(iscid(*s))
|
||||
s++;
|
||||
String macro(b, s);
|
||||
if(*s == '(') {
|
||||
b = s;
|
||||
while(*s != ')' && *s)
|
||||
s++;
|
||||
macro.Cat(b, s);
|
||||
macro << ')';
|
||||
}
|
||||
if(include)
|
||||
parser.AddMacro(lineno, macro);
|
||||
}
|
||||
else
|
||||
if(s[0] == 'i' && s[1] == 'f') {
|
||||
CParser p(s + 2);
|
||||
try {
|
||||
while(!p.IsEof()) {
|
||||
if(p.IsId()) {
|
||||
String id = p.ReadId();
|
||||
if(id.StartsWith("flag"))
|
||||
parser.AddMacro(lineno, id, FLAGTEST);
|
||||
}
|
||||
else
|
||||
p.SkipTerm();
|
||||
}
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
}
|
||||
res.preprocessorLinesRemoved++;
|
||||
}
|
||||
else {
|
||||
bool lineContainsComment = false;
|
||||
bool lineContainsNonComment = false;
|
||||
String cmd;
|
||||
while(*rm) {
|
||||
if(*rm == '\"') {
|
||||
lineContainsNonComment = true;
|
||||
res.text << '\"';
|
||||
rm++;
|
||||
while((byte)*rm && *rm != '\r' && *rm != '\n') {
|
||||
if(*rm == '\"') {
|
||||
res.text << '\"';
|
||||
rm++;
|
||||
break;
|
||||
}
|
||||
if(*rm == '\\' && rm[1]) {
|
||||
if(include)
|
||||
res.text.Cat(*rm);
|
||||
rm++;
|
||||
}
|
||||
if(include)
|
||||
res.text.Cat(*rm);
|
||||
rm++;
|
||||
}
|
||||
}
|
||||
else
|
||||
if(*rm == '\\' && rm[1]) {
|
||||
lineContainsNonComment = true;
|
||||
if(include) {
|
||||
res.text.Cat(*rm++);
|
||||
res.text.Cat(*rm++);
|
||||
}
|
||||
else
|
||||
rm += 2;
|
||||
}
|
||||
else
|
||||
if(rm[0] == '/' && rm[1] == '/') {
|
||||
cmd = rm + 2;
|
||||
if(!lineContainsNonComment)
|
||||
res.commentLinesRemoved++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
if(rm[0] == '/' && rm[1] == '*') {
|
||||
lineContainsComment = true;
|
||||
rm += 2;
|
||||
for(;;) {
|
||||
if(*rm == '\0') {
|
||||
if(!lineContainsNonComment)
|
||||
res.commentLinesRemoved++;
|
||||
if(in.IsEof()) break;
|
||||
SLPos(res);
|
||||
ln = in.GetLine();
|
||||
rm = ~ln;
|
||||
lineContainsNonComment = false;
|
||||
}
|
||||
if(rm[0] == '*' && rm[1] == '/') {
|
||||
rm += 2;
|
||||
break;
|
||||
}
|
||||
rm++;
|
||||
}
|
||||
if(include)
|
||||
res.text.Cat(' ');
|
||||
}
|
||||
else {
|
||||
lineContainsNonComment = true;
|
||||
if(include)
|
||||
res.text.Cat(*rm);
|
||||
rm++;
|
||||
}
|
||||
}
|
||||
if(include)
|
||||
res.text << ' ';
|
||||
if(cmd[0] == '$') {
|
||||
if(cmd[1] == '-') include = false;
|
||||
if(cmd[1] == '+') include = true;
|
||||
if(cmd[1]) {
|
||||
res.text.Cat(~cmd + 2);
|
||||
res.text.Cat(' ');
|
||||
}
|
||||
}
|
||||
if(lineContainsComment && !lineContainsNonComment)
|
||||
res.commentLinesRemoved++;
|
||||
}
|
||||
}
|
||||
return pick(res);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,315 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
#define LLOG(x) // DLOG(x)
|
||||
#define LTIMING(x) // DTIMING(x)
|
||||
|
||||
bool DoQualify(ScopeInfo& nf, const String& type, const String& usings, String& qt);
|
||||
|
||||
bool Qualify0(ScopeInfo& nf, const String& type, const String& usings, String& qt)
|
||||
{ // Qualify single type based on scoping information
|
||||
const Vector<String>& nd = nf.GetScopes(usings);
|
||||
if(nd.GetCount()) {
|
||||
LTIMING("First test");
|
||||
qt = nd[0] + type;
|
||||
if(nf.base.Find(qt) >= 0)
|
||||
return true;
|
||||
}
|
||||
if(nf.GetScope() >= 0) {
|
||||
int q = type.ReverseFind(':');
|
||||
if(q > 0) {
|
||||
LTIMING("Qualifying qualification");
|
||||
ScopeInfo hnf(nf);
|
||||
hnf.NoBases();
|
||||
String qn;
|
||||
String qs = type.Mid(0, q - 1);
|
||||
if(IsDigit(*qs)) {
|
||||
qt = type;
|
||||
return true;
|
||||
}
|
||||
if(DoQualify(hnf, qs, usings, qn)) {
|
||||
String tp = type.Mid(q + 1);
|
||||
if(nf.base.Find(qn) >= 0) {
|
||||
qt = qn + "::" + tp;
|
||||
return true;
|
||||
}
|
||||
int scopei = nf.base.Find(qn);
|
||||
if(scopei >= 0) {
|
||||
ScopeInfo nnf(nf.base, scopei);
|
||||
const Vector<String>& bs = nnf.GetBases();
|
||||
for(int i = 0; i < bs.GetCount(); i++) {
|
||||
qt = bs[i] + tp;
|
||||
if(nf.base.Find(qt) >= 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(nf.base.Find(qs) >= 0) {
|
||||
qt = qs;
|
||||
return true;
|
||||
}
|
||||
qt = type;
|
||||
if(nf.base.Find(qt) >= 0) // e.g. std::string
|
||||
return true;
|
||||
qt = type.Mid(q + 1);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
LTIMING("Bases");
|
||||
const Vector<String>& bs = nf.GetBases();
|
||||
for(int i = 0; i < bs.GetCount(); i++) {
|
||||
qt = bs[i] + type;
|
||||
if(nf.base.Find(qt) >= 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(type[0] != ':') {
|
||||
LTIMING("Testing scopes");
|
||||
for(int i = 1; i < nd.GetCount(); i++) {
|
||||
qt = nd[i] + type;
|
||||
if(nf.base.Find(qt) >= 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
int q = type.Find(':');
|
||||
if(q < 0)
|
||||
return false;
|
||||
return Qualify0(nf, type.Mid(q + 1), usings, qt);
|
||||
}
|
||||
|
||||
bool DoQualify(ScopeInfo& nf, const String& type, const String& usings, String& qt)
|
||||
{
|
||||
LTIMING("Qualify");
|
||||
int q = nf.cache.Find(type);
|
||||
if(q >= 0) {
|
||||
qt = nf.cache[q];
|
||||
return true;
|
||||
}
|
||||
LTIMING("Qualify0");
|
||||
if(!Qualify0(nf, type, usings, qt))
|
||||
return false;
|
||||
nf.cache.Add(type, qt);
|
||||
return true;
|
||||
}
|
||||
|
||||
String DoQualify(ScopeInfo& nf, const String& type, const String& usings)
|
||||
{
|
||||
String qt;
|
||||
return DoQualify(nf, type, usings, qt) ? qt : type;
|
||||
}
|
||||
|
||||
static String s_int("int");
|
||||
static String s_void("void");
|
||||
static String s_double("double");
|
||||
static String s_char("char");
|
||||
static String s_float("float");
|
||||
static String s_long("long");
|
||||
static String s_const("const");
|
||||
static String s_struct("struct");
|
||||
static String s_class("class");
|
||||
static String s_unsigned("unsigned");
|
||||
|
||||
inline void Qualify(String& r, ScopeInfo& nf, const char *b, const char *s, const String& usings)
|
||||
{
|
||||
String type(b, s);
|
||||
if(type.GetCount() == 0 || type == s_const ||
|
||||
type == s_int || type == s_double || type == s_char ||
|
||||
type == s_long || type == s_unsigned || type == s_struct || type == s_class ||
|
||||
type == s_float) {
|
||||
r << type;
|
||||
return;
|
||||
}
|
||||
r << DoQualify(nf, type, usings);
|
||||
}
|
||||
|
||||
String QualifyIds(ScopeInfo& nf, const String& k, const String& usings, bool all)
|
||||
{
|
||||
LTIMING("QualifyIds");
|
||||
String r;
|
||||
const char *s = k;
|
||||
Vector<String> empty;
|
||||
while(*s) {
|
||||
int c = *s;
|
||||
if(c == ':') {
|
||||
const char *b = s++;
|
||||
while(*s == ':' || iscid(*s)) s++;
|
||||
/* if(all) {
|
||||
if(iscid(*r.Last()))
|
||||
r << ' ';
|
||||
ScopeInfo nnf(nf.GetScope(), nf.base);
|
||||
Qualify(r, nnf, b, s, usings);
|
||||
}
|
||||
else*/
|
||||
r.Cat(b, s);
|
||||
}
|
||||
else
|
||||
if(iscid(c)) {
|
||||
if(iscid(*r.Last()))
|
||||
r << ' ';
|
||||
if(s[0] == 'c' && s[1] == 'o' && s[2] == 'n' && s[3] == 's' && s[4] == 't' && !iscid(s[5])) {
|
||||
r << s_const;
|
||||
s += 5;
|
||||
}
|
||||
else
|
||||
if(s[0] == 'm' && s[1] == 'u' && s[2] == 't' && s[3] == 'a' && s[4] == 'b' && s[5] == 'l' && s[6] == 'e' && !iscid(s[7])) {
|
||||
r << "mutable";
|
||||
s += 7;
|
||||
}
|
||||
else
|
||||
if(s[0] == 'v' && s[1] == 'o' && s[2] == 'l' && s[3] == 'a' && s[4] == 't' && s[5] == 'i' && s[6] == 'l' && s[7] == 'e' && !iscid(s[8])) {
|
||||
r << "volatile";
|
||||
s += 8;
|
||||
}
|
||||
else {
|
||||
const char *b = s++;
|
||||
while(*s == ':' || iscid(*s)) s++;
|
||||
if(all)
|
||||
Qualify(r, nf, b, s, usings);
|
||||
else
|
||||
r.Cat(b, s);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(c == '(')
|
||||
all = true;
|
||||
if(c != ' ')
|
||||
r.Cat(c);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
String Qualify(const CppBase& base, const String& scope, const String& type, const String& usings)
|
||||
{
|
||||
if(type.StartsWith("::"))
|
||||
return type.Mid(2);
|
||||
ScopeInfo nf(base, scope);
|
||||
return QualifyIds(nf, type, usings, true);
|
||||
}
|
||||
|
||||
String QualifyKey(const CppBase& base, const String& scope, const String& type, const String& usings)
|
||||
{
|
||||
ScopeInfo nf(base, scope);
|
||||
return QualifyIds(nf, type, usings, false);
|
||||
}
|
||||
|
||||
void QualifyTypes(CppBase& base, const String& scope, CppItem& m)
|
||||
{
|
||||
ScopeInfo nf(base, scope);
|
||||
m.qtype = QualifyIds(nf, m.type, m.using_namespaces, true);
|
||||
m.qptype = QualifyIds(nf, m.ptype, m.using_namespaces, true);
|
||||
}
|
||||
|
||||
void QualifyPass0(CppBase& base)
|
||||
{ // Move scopes - solve: namespace X { struct C { void Foo(); }; using namespace X; void C::Foo() {}
|
||||
Vector<int> remove_scope;
|
||||
for(int ni = 0; ni < base.GetCount(); ni++) {
|
||||
Array<CppItem>& n = base[ni];
|
||||
ScopeInfo nf(base);
|
||||
String scope = base.GetKey(ni);
|
||||
String usings;
|
||||
int toscopei = -1;
|
||||
Vector<int> remove_item;
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
CppItem& m = n[i];
|
||||
if(m.qualify && m.impl) {
|
||||
if(usings != m.using_namespaces) {
|
||||
usings = m.using_namespaces;
|
||||
toscopei = -1;
|
||||
Vector<String> h = Split(m.using_namespaces, ';');
|
||||
for(int i = 0; i < h.GetCount(); i++) {
|
||||
String ns = h[i] + "::" + scope;
|
||||
toscopei = base.Find(ns);
|
||||
if(toscopei >= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(toscopei >= 0 && toscopei != ni) {
|
||||
base[toscopei].Add(m);
|
||||
remove_item.Add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
n.Remove(remove_item);
|
||||
if(scope.GetCount() && n.GetCount() == 0)
|
||||
remove_scope.Add(ni);
|
||||
}
|
||||
base.Remove(remove_scope);
|
||||
}
|
||||
|
||||
void QualifyPass1(CppBase& base)
|
||||
{ // Qualify types
|
||||
LTIMING("QualifyPass1");
|
||||
for(int ni = 0; ni < base.GetCount(); ni++) {
|
||||
Array<CppItem>& n = base[ni];
|
||||
ScopeInfo nf(base, ni);
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
CppItem& m = n[i];
|
||||
if(m.kind == NAMESPACE)
|
||||
base.namespaces.FindAdd(base.GetKey(ni));
|
||||
if(m.IsType() && m.qualify) {
|
||||
m.qualify = false;
|
||||
m.qtype = QualifyIds(nf, m.type, m.using_namespaces, true); // type of item, now qualified (probaly already was)
|
||||
m.qptype = QualifyIds(nf, m.ptype, m.using_namespaces, true); // base classes
|
||||
m.qitem = m.item; // name of type (struct) item is already qualified
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QualifyPass2(CppBase& base)
|
||||
{ // Qualify function parameters
|
||||
LTIMING("QualifyPass2");
|
||||
for(int ni = 0; ni < base.GetCount(); ni++) {
|
||||
Array<CppItem>& n = base[ni];
|
||||
ScopeInfo nf(base, ni);
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
CppItem& m = n[i];
|
||||
if(m.uname.GetCount() == 0 && m.name.GetCount())
|
||||
m.uname = ToUpper(m.name);
|
||||
if(!m.IsType() && m.qualify) {
|
||||
m.qualify = false;
|
||||
m.qtype = QualifyIds(nf, m.type, m.using_namespaces, true);
|
||||
m.qptype = QualifyIds(nf, m.ptype, m.using_namespaces, true);
|
||||
m.qitem = m.IsCode() ? QualifyIds(nf, m.item, m.using_namespaces, false)
|
||||
: m.item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Qualify(CppBase& base)
|
||||
{
|
||||
Md5Stream md5;
|
||||
Vector<int> no = GetSortOrder(base.GetKeys());
|
||||
for(int q = 0; q < base.GetCount(); q++) {
|
||||
int ni = no[q];
|
||||
md5 << base.GetKey(ni);
|
||||
const Array<CppItem>& n = base[ni];
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
const CppItem& m = n[i];
|
||||
if(m.IsType())
|
||||
md5 << ';' << m.ptype;
|
||||
}
|
||||
md5 << '\n';
|
||||
}
|
||||
String c5 = md5.FinishString();
|
||||
if(c5 != base.types_md5) { // set of types changed, requalify everything
|
||||
base.types_md5 = c5;
|
||||
for(int ni = 0; ni < base.GetCount(); ni++) {
|
||||
Array<CppItem>& n = base[ni];
|
||||
for(int i = 0; i < n.GetCount(); i++)
|
||||
n[i].qualify = true;
|
||||
}
|
||||
}
|
||||
base.namespaces.Clear();
|
||||
QualifyPass0(base);
|
||||
QualifyPass1(base);
|
||||
QualifyPass2(base);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
#define LLOG(x)
|
||||
#define LTIMING(x) // DTIMING(x)
|
||||
|
||||
ScopeInfo::ScopeInfo(const CppBase& base, int scopei)
|
||||
: scopei(scopei), base(base)
|
||||
{
|
||||
LTIMING("ScopeInfo(const CppBase& base, int scopei)");
|
||||
Init();
|
||||
}
|
||||
|
||||
ScopeInfo::ScopeInfo(int scopei, const CppBase& base)
|
||||
: scopei(scopei), base(base)
|
||||
{
|
||||
LTIMING("ScopeInfo(int scopei, const CppBase& base)");
|
||||
Init();
|
||||
}
|
||||
|
||||
ScopeInfo::ScopeInfo(const CppBase& base, const String& scope)
|
||||
: scopei(base.Find(scope)), base(base)
|
||||
{
|
||||
LTIMING("ScopeInfo(const CppBase& base, const String& scope)");
|
||||
Init();
|
||||
}
|
||||
|
||||
ScopeInfo::ScopeInfo(const ScopeInfo& f)
|
||||
: base(f.base)
|
||||
{
|
||||
LTIMING("ScopeInfo copy contructor");
|
||||
scopes <<= f.scopes;
|
||||
bvalid = nvalid = false;
|
||||
scopei = f.scopei;
|
||||
}
|
||||
|
||||
void ScopeInfo::Init()
|
||||
{
|
||||
bvalid = nvalid = false;
|
||||
}
|
||||
|
||||
void ScopeInfo::Bases(int i, Vector<int>& g)
|
||||
{ // recursively retrieve all base classes
|
||||
if(base.IsType(i)) {
|
||||
const Array<CppItem>& n = base[i];
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
const CppItem& im = n[i];
|
||||
if(im.IsType()) {
|
||||
const char *q = im.qptype;
|
||||
const char *b = q;
|
||||
for(;;) {
|
||||
if(*q == ';' || *q == '\0') {
|
||||
if(b < q) {
|
||||
String h = String(b, q);
|
||||
int q = h.Find('<');
|
||||
if(q >= 0)
|
||||
h.Trim(q);
|
||||
h = TrimBoth(h);
|
||||
int nq = base.Find(h);
|
||||
if(nq >= 0)
|
||||
g.Add(nq);
|
||||
}
|
||||
if(*q == '\0')
|
||||
break;
|
||||
q++;
|
||||
b = q;
|
||||
}
|
||||
else
|
||||
q++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Vector<String>& ScopeInfo::GetBases()
|
||||
{
|
||||
LTIMING("GetBases");
|
||||
if(!bvalid) {
|
||||
bvalid = true;
|
||||
baselist.Clear();
|
||||
if(scopei < 0)
|
||||
return baselist;
|
||||
Vector<int> b;
|
||||
Index<int> bi;
|
||||
Bases(scopei, b);
|
||||
while(b.GetCount()) {
|
||||
Vector<int> bb;
|
||||
for(int i = 0; i < b.GetCount(); i++) {
|
||||
int q = b[i];
|
||||
if(bi.Find(q) < 0) {
|
||||
bi.Add(q);
|
||||
Bases(b[i], bb);
|
||||
}
|
||||
}
|
||||
b = pick(bb);
|
||||
}
|
||||
for(int i = 0; i < bi.GetCount(); i++)
|
||||
baselist.Add(base.GetKey(bi[i]) + "::");
|
||||
}
|
||||
return baselist;
|
||||
}
|
||||
|
||||
const Vector<String>& ScopeInfo::GetScopes(const String& usings_)
|
||||
{
|
||||
LTIMING("GetScopes");
|
||||
if(!nvalid || usings != usings_) {
|
||||
usings = usings_;
|
||||
nvalid = true;
|
||||
scopes.Clear();
|
||||
if(scopei >= 0) {
|
||||
String nn = base.GetKey(scopei);
|
||||
while(nn.GetCount()) {
|
||||
if(nn[0] == ':' && nn.GetCount() == 2) {
|
||||
scopes.Add(nn);
|
||||
return scopes;
|
||||
}
|
||||
scopes.Add(nn + "::");
|
||||
int q = nn.ReverseFind(':');
|
||||
nn.Trim(max(0, q - 1));
|
||||
}
|
||||
}
|
||||
scopes.Add("");
|
||||
Vector<String> h = Split(usings, ';');
|
||||
for(int i = 0; i < h.GetCount(); i++)
|
||||
scopes.Add(h[i] + "::");
|
||||
}
|
||||
return scopes;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,391 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
#define LTIMING(x) // DTIMING(x)
|
||||
#define LLOG(x) // DLOG(x)
|
||||
|
||||
void Cpp::ParamAdd(Vector<String>& param, const char *s, const char *e)
|
||||
{
|
||||
while(s < e && (byte)*s <= ' ') s++;
|
||||
while(e > s && (byte)*(e - 1) <= ' ') e--;
|
||||
String h;
|
||||
while(s < e) {
|
||||
if((byte)*s <= ' ') {
|
||||
h.Cat(' ');
|
||||
s++;
|
||||
while(s < e && (byte)*s <= ' ')
|
||||
s++;
|
||||
}
|
||||
else
|
||||
if(*s == '\"' || *s == '\'') {
|
||||
const char *q = SkipString(s);
|
||||
h.Cat(String(s, q));
|
||||
s = q;
|
||||
}
|
||||
else
|
||||
h.Cat(*s++);
|
||||
}
|
||||
param.Add(h);
|
||||
}
|
||||
|
||||
String Cpp::Expand(const char *s)
|
||||
{
|
||||
StringBuffer r;
|
||||
const char *l0 = s;
|
||||
while(*s) {
|
||||
if(incomment) {
|
||||
if(s[0] == '*' && s[1] == '/') {
|
||||
incomment = false;
|
||||
s += 2;
|
||||
r.Cat("*/");
|
||||
}
|
||||
else
|
||||
r.Cat(*s++);
|
||||
}
|
||||
else
|
||||
if(iscib(*s)) {
|
||||
LTIMING("Expand ID");
|
||||
const char *bid = s;
|
||||
s++;
|
||||
while(iscid(*s))
|
||||
s++;
|
||||
String id(bid, s);
|
||||
LTIMING("Expand ID2");
|
||||
if(notmacro.Find(id) < 0) {
|
||||
const PPMacro *pp = macro.FindLastPtr(id);
|
||||
int segmenti = pp ? segment_id.Find(pp->segment_id) : -1;
|
||||
const CppMacro *m = FindMacro(id, segment_id, segmenti);
|
||||
if(!m && pp)
|
||||
m = &pp->macro;
|
||||
if(m && m->IsUndef())
|
||||
m = NULL;
|
||||
if(m) {
|
||||
LTIMING("Expand macro");
|
||||
Vector<String> param;
|
||||
bool function_like = false;
|
||||
const char *s0 = s;
|
||||
if(m->param.GetCount()) {
|
||||
while(*s && (byte)*s <= ' ')
|
||||
s++;
|
||||
if(*s == '(') {
|
||||
function_like = true;
|
||||
s++;
|
||||
const char *b = s;
|
||||
int level = 0;
|
||||
for(;;)
|
||||
if(*s == ',' && level == 0) {
|
||||
ParamAdd(param, b, s);
|
||||
s++;
|
||||
b = s;
|
||||
}
|
||||
else
|
||||
if(*s == ')') {
|
||||
s++;
|
||||
if(level == 0) {
|
||||
ParamAdd(param, b, s - 1);
|
||||
break;
|
||||
}
|
||||
level--;
|
||||
}
|
||||
else
|
||||
if(*s == '(') {
|
||||
s++;
|
||||
level++;
|
||||
}
|
||||
else
|
||||
if(*s == '\0') { // macro use spread into more lines
|
||||
if(bid == l0) // begin of line
|
||||
prefix_macro = bid;
|
||||
else
|
||||
prefix_macro = String(' ', 1) + bid; // do not want to emit grounding in body
|
||||
return String(r);
|
||||
}
|
||||
else
|
||||
if(*s == '\"' || *s == '\'')
|
||||
s = SkipString(s);
|
||||
else
|
||||
s++;
|
||||
}
|
||||
}
|
||||
if(!!m->param.GetCount() == function_like) {
|
||||
int ti = notmacro.GetCount();
|
||||
Vector<String> eparam;
|
||||
eparam.SetCount(param.GetCount());
|
||||
for(int i = 0; i < param.GetCount(); i++)
|
||||
eparam[i] = Expand(param[i]);
|
||||
notmacro.Add(id);
|
||||
id = '\x1f' + Expand(m->Expand(param, eparam)); // \x1f is info for Pre that there was a macro expansion
|
||||
notmacro.Trim(ti);
|
||||
}
|
||||
else
|
||||
s = s0;
|
||||
}
|
||||
else
|
||||
notmacro.Add(id);
|
||||
}
|
||||
r.Cat(id);
|
||||
}
|
||||
else
|
||||
if(*s == '\"') {
|
||||
const char *e = SkipString(s);
|
||||
r.Cat(s, e);
|
||||
s = e;
|
||||
}
|
||||
else
|
||||
if(s[0] == '/' && s[1] == '*') {
|
||||
incomment = true;
|
||||
s += 2;
|
||||
r.Cat("/*");
|
||||
}
|
||||
else
|
||||
if(s[0] == '/' && s[1] == '/') {
|
||||
r.Cat(s);
|
||||
break;
|
||||
}
|
||||
else
|
||||
r.Cat(*s++);
|
||||
}
|
||||
return String(r);
|
||||
}
|
||||
|
||||
void Cpp::DoFlatInclude(const String& header_path)
|
||||
{
|
||||
LTIMING("DoFlatInclude");
|
||||
LLOG("Flat include " << header_path);
|
||||
if(header_path.GetCount()) {
|
||||
md5.Put(header_path);
|
||||
const FlatPP& pp = GetFlatPPFile(header_path);
|
||||
LLOG("DoFlatInclude " << header_path << ", " << pp.segment_id.GetCount() << " segments");
|
||||
for(int i = 0; i < pp.segment_id.GetCount(); i++)
|
||||
segment_id.FindAdd(pp.segment_id[i]);
|
||||
for(int i = 0; i < pp.usings.GetCount(); i++) {
|
||||
namespace_using.FindAdd(pp.usings[i]);
|
||||
LLOG(" Flat usings " << pp.usings[i]);
|
||||
md5.Put('$');
|
||||
md5.Put(pp.usings[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define IGNORE_ELSE
|
||||
|
||||
void Cpp::Do(const String& sourcefile, Stream& in, const String& currentfile, bool get_macros)
|
||||
{
|
||||
LLOG("Cpp::Do " << sourcefile << ", current: " << currentfile);
|
||||
if(visited.Find(currentfile) >= 0 || visited.GetCount() > 20000)
|
||||
return;
|
||||
visited.Add(currentfile);
|
||||
String current_folder = GetFileFolder(currentfile);
|
||||
bool notthefile = sourcefile != currentfile;
|
||||
if(notthefile || get_macros) {
|
||||
LTIMING("DO2");
|
||||
const PPFile& pp = GetPPFile(currentfile);
|
||||
for(int i = 0; i < pp.item.GetCount() && !done; i++) {
|
||||
const PPItem& m = pp.item[i];
|
||||
if(m.type == PP_DEFINES) {
|
||||
LTIMING("PP_DEFINES");
|
||||
if(notthefile) // if getting macros, we are interested in included macros only
|
||||
segment_id.FindAdd(m.segment_id);
|
||||
}
|
||||
else
|
||||
if(m.type == PP_INCLUDE) {
|
||||
String s = GetIncludePath(m.text, current_folder);
|
||||
if(s.GetCount()) {
|
||||
if(notthefile && (s == sourcefile || IncludesFile(s, sourcefile))) {
|
||||
LLOG("Include IN " << s);
|
||||
md5.Put(s);
|
||||
Do(sourcefile, in, s, get_macros);
|
||||
}
|
||||
else {
|
||||
LLOG("Include FLAT " << s);
|
||||
DoFlatInclude(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if(m.type == PP_NAMESPACE) {
|
||||
namespace_stack.Add(m.text);
|
||||
LLOG("pp namespace " << m.text << " " << namespace_stack);
|
||||
}
|
||||
else
|
||||
if(m.type == PP_NAMESPACE_END && namespace_stack.GetCount()) {
|
||||
namespace_stack.Drop();
|
||||
LLOG("pp end namespace " << namespace_stack);
|
||||
}
|
||||
else
|
||||
if(m.type == PP_USING) {
|
||||
namespace_using.FindAdd(m.text);
|
||||
md5.Put('$');
|
||||
md5.Put(m.text);
|
||||
}
|
||||
}
|
||||
if(sourcefile != currentfile)
|
||||
return;
|
||||
}
|
||||
|
||||
md5.Put('@');
|
||||
md5.Put(Join(namespace_stack, ";"));
|
||||
|
||||
done = true;
|
||||
|
||||
if(get_macros)
|
||||
return;
|
||||
|
||||
if(in.Peek() == 0xef) { // Skip UTF-8 BOM
|
||||
int64 pos = in.GetPos();
|
||||
in.Get();
|
||||
if(in.Get() != 0xbb || in.Get() != 0xbf)
|
||||
in.Seek(pos); // Was not UTF-8 BOM after all
|
||||
}
|
||||
|
||||
LTIMING("Expand");
|
||||
incomment = false;
|
||||
prefix_macro.Clear();
|
||||
StringBuffer result;
|
||||
result.Clear();
|
||||
result.Reserve(16384);
|
||||
int lineno = 0;
|
||||
bool incomment = false;
|
||||
bool do_pp = true;
|
||||
int segment_serial = 0;
|
||||
segment_id.Add(--segment_serial);
|
||||
#ifdef IGNORE_ELSE
|
||||
int ignore_else = 0;
|
||||
#endif
|
||||
while(!in.IsEof()) {
|
||||
String l = prefix_macro + in.GetLine();
|
||||
String ll = TrimLeft(l);
|
||||
if(ll.StartsWith("//$")) { // Do not remove assist++ parser directives
|
||||
result.Cat(l + "\n");
|
||||
do_pp = decode(ll[3], '+', true, '-', false, do_pp);
|
||||
continue;
|
||||
}
|
||||
prefix_macro.Clear();
|
||||
lineno++;
|
||||
int el = 0;
|
||||
while(*l.Last() == '\\' && !in.IsEof()) {
|
||||
el++;
|
||||
l.Trim(l.GetLength() - 1);
|
||||
l.Cat(in.GetLine());
|
||||
}
|
||||
RemoveComments(l, incomment);
|
||||
CParser p(l);
|
||||
if(p.Char('#')) {
|
||||
if(do_pp) {
|
||||
if(p.Id("define")) {
|
||||
result.Cat(l + "\n");
|
||||
CppMacro m;
|
||||
String id = m.Define(p.GetPtr());
|
||||
if(id.GetCount()) {
|
||||
PPMacro& pp = macro.Add(id);
|
||||
pp.macro = m;
|
||||
pp.segment_id = segment_serial;
|
||||
notmacro.Trim(kw.GetCount());
|
||||
}
|
||||
}
|
||||
else
|
||||
if(p.Id("undef")) {
|
||||
result.Cat(l + "\n");
|
||||
if(p.IsId()) {
|
||||
segment_id.Add(--segment_serial);
|
||||
PPMacro& m = macro.Add(p.ReadId());
|
||||
m.segment_id = segment_serial;
|
||||
m.macro.SetUndef();
|
||||
notmacro.Trim(kw.GetCount());
|
||||
segment_id.Add(--segment_serial);
|
||||
}
|
||||
}
|
||||
else
|
||||
if(p.Id("if") || p.Id("ifdef") || p.Id("ifndef")) // FLAGTEST support
|
||||
result.Cat(l + "\n");
|
||||
else {
|
||||
result.Cat('\n');
|
||||
#ifdef IGNORE_ELSE
|
||||
if(ignore_else) {
|
||||
if(p.Id("if") || p.Id("ifdef") || p.Id("ifndef"))
|
||||
ignore_else++;
|
||||
else
|
||||
if(p.Id("endif"))
|
||||
ignore_else--;
|
||||
}
|
||||
else {
|
||||
if(p.Id("else") || p.Id("elif"))
|
||||
ignore_else = 1;
|
||||
}
|
||||
#endif
|
||||
if(p.Id("include")) {
|
||||
LTIMING("Expand include");
|
||||
String s = GetIncludePath(p.GetPtr(), current_folder);
|
||||
DoFlatInclude(s);
|
||||
segment_id.Add(--segment_serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
result.Cat('\n');
|
||||
}
|
||||
else {
|
||||
LTIMING("Expand expand");
|
||||
#ifdef IGNORE_ELSE
|
||||
if(ignore_else)
|
||||
result.Cat('\n');
|
||||
else
|
||||
#endif
|
||||
result.Cat(Expand(l) + "\n");
|
||||
}
|
||||
while(el--)
|
||||
result.Cat("\n");
|
||||
}
|
||||
output = result;
|
||||
}
|
||||
|
||||
Index<String> Cpp::kw;
|
||||
|
||||
bool Cpp::Preprocess(const String& sourcefile, Stream& in, const String& currentfile,
|
||||
bool get_macros)
|
||||
{
|
||||
LLOG("===== Preprocess " << sourcefile << " <- " << currentfile);
|
||||
LTIMING("Cpp::Preprocess");
|
||||
macro.Clear();
|
||||
macro.Reserve(1000);
|
||||
segment_id.Clear();
|
||||
segment_id.Add(0);
|
||||
segment_id.Reserve(100);
|
||||
|
||||
ONCELOCK {
|
||||
const char **h = CppKeyword();
|
||||
while(*h) {
|
||||
kw.Add(*h);
|
||||
h++;
|
||||
}
|
||||
}
|
||||
notmacro = clone(kw);
|
||||
|
||||
done = false;
|
||||
incomment = false;
|
||||
output.Clear();
|
||||
visited.Clear();
|
||||
Do(NormalizePath(sourcefile), in, NormalizePath(currentfile), get_macros);
|
||||
if(!done)
|
||||
output.Clear();
|
||||
return done;
|
||||
}
|
||||
|
||||
void GetAllMacros(Md5Stream& md5, const String& id, Index<int>& segment_id);
|
||||
|
||||
String Cpp::GetDependeciesMd5(const Vector<String>& m)
|
||||
{
|
||||
String r;
|
||||
Md5Stream md5;
|
||||
md5.Put(Join(namespace_stack, ";"));
|
||||
md5.Put('@');
|
||||
md5.Put(Join(namespace_using.GetKeys(), ";"));
|
||||
md5.Put('@');
|
||||
for(int i = 0; i < m.GetCount(); i++)
|
||||
GetAllMacros(md5, m[i], segment_id);
|
||||
return md5.FinishString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,499 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
// #define LOGNEXT _DBG_
|
||||
|
||||
namespace Upp {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma inline_depth(255)
|
||||
#pragma optimize("t", on)
|
||||
#endif
|
||||
|
||||
#define case_id \
|
||||
case '_':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'g':case 'h': \
|
||||
case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':case 'o':case 'p':case 'q': \
|
||||
case 'r':case 's':case 't':case 'u':case 'v':case 'w':case 'x':case 'y':case 'z': \
|
||||
case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':case 'G':case 'H':case 'I': \
|
||||
case 'J':case 'K':case 'L':case 'M':case 'N':case 'O':case 'P':case 'Q':case 'R': \
|
||||
case 'S':case 'T':case 'U':case 'V':case 'W':case 'X':case 'Y':case 'Z':case '$'
|
||||
|
||||
#define case_nonzero_digit \
|
||||
case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9'
|
||||
|
||||
|
||||
const char *_CppKeyword[] = {
|
||||
#define CPPID(x) #x,
|
||||
#include "keyword.i"
|
||||
#undef CPPID
|
||||
NULL
|
||||
};
|
||||
|
||||
const char **CppKeyword() { return _CppKeyword; }
|
||||
|
||||
|
||||
LexSymbolStat::LexSymbolStat() :
|
||||
minSymbol(0)
|
||||
{
|
||||
}
|
||||
|
||||
void LexSymbolStat::Reset(int minSymbol, int maxSymbol)
|
||||
{
|
||||
ASSERT(minSymbol <= maxSymbol);
|
||||
v.Clear();
|
||||
this->minSymbol = minSymbol;
|
||||
v.SetCount(maxSymbol - minSymbol + 1, 0);
|
||||
}
|
||||
|
||||
void LexSymbolStat::IncStat(int symbol)
|
||||
{
|
||||
int symbolIndex = symbol - minSymbol;
|
||||
if(symbolIndex >= 0 && symbolIndex < v.GetCount())
|
||||
v[symbolIndex]++;
|
||||
}
|
||||
|
||||
int LexSymbolStat::GetStat(int symbol) const
|
||||
{
|
||||
int symbolIndex = symbol - minSymbol;
|
||||
return (symbolIndex >= 0 && symbolIndex < v.GetCount()) ?
|
||||
v[symbolIndex] :
|
||||
0;
|
||||
}
|
||||
|
||||
int LexSymbolStat::SumStat(const Vector<int> & symbols) const
|
||||
{
|
||||
int sum = 0;
|
||||
for(int i = 0; i < symbols.GetCount(); i++)
|
||||
sum += GetStat(symbols[i]);
|
||||
return sum;
|
||||
}
|
||||
|
||||
void LexSymbolStat::Merge(const LexSymbolStat & other)
|
||||
{
|
||||
if(v.GetCount() == 0) {
|
||||
minSymbol = other.minSymbol;
|
||||
v <<= other.v;
|
||||
return;
|
||||
}
|
||||
ASSERT(other.minSymbol == minSymbol && other.v.GetCount() == v.GetCount());
|
||||
for(int i = 0; i < v.GetCount(); i++)
|
||||
v[i] += other.v[i];
|
||||
}
|
||||
|
||||
|
||||
Lex::Lex()
|
||||
: statsCollected(false)
|
||||
{
|
||||
const char **cppk = CppKeyword();
|
||||
for(int i = 0; cppk[i]; i++)
|
||||
id.Add(cppk[i]);
|
||||
endkey = id.GetCount();
|
||||
braceslevel = body = 0;
|
||||
}
|
||||
|
||||
void Lex::Init(const char *s)
|
||||
{
|
||||
ptr = s;
|
||||
}
|
||||
|
||||
void Lex::StartStatCollection()
|
||||
{
|
||||
symbolStat.Reset(-200, endkey+256);
|
||||
statsCollected = true;
|
||||
}
|
||||
|
||||
const LexSymbolStat& Lex::FinishStatCollection()
|
||||
{
|
||||
statsCollected = false;
|
||||
return symbolStat;
|
||||
}
|
||||
|
||||
int Lex::GetCharacter()
|
||||
{
|
||||
if(*ptr == '\0') return t_eof;
|
||||
int c = *ptr++;
|
||||
if(c == '\\') {
|
||||
c = *ptr++;
|
||||
switch(c) {
|
||||
case 'a': return '\a';
|
||||
case 'b': return '\b';
|
||||
case 't': return '\t';
|
||||
case 'v': return '\v';
|
||||
case 'n': return '\n';
|
||||
case 'r': return '\r';
|
||||
case 'f': return '\f';
|
||||
case 'x':
|
||||
c = 0;
|
||||
if(isxdigit(*ptr)) {
|
||||
c = (*ptr >= 'A' ? ToUpper(*ptr) - 'A' + 10 : *ptr - '0');
|
||||
ptr++;
|
||||
if(isxdigit(*ptr)) {
|
||||
c = 16 * c + (*ptr >= 'A' ? ToUpper(*ptr) - 'A' + 10 : *ptr - '0');
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(c >= '0' && c <= '7') {
|
||||
c -= '0';
|
||||
if(*ptr >= '0' && *ptr <= '7')
|
||||
c = 8 * c + *ptr++ - '0';
|
||||
if(*ptr >= '0' && *ptr <= '7')
|
||||
c = 8 * c + *ptr++ - '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
return (byte)c;
|
||||
}
|
||||
|
||||
void Lex::Next()
|
||||
{
|
||||
grounding = false;
|
||||
while((byte)*ptr <= ' ') {
|
||||
if(*ptr == '\2')
|
||||
grounding = true;
|
||||
if(*ptr == '\0') return;
|
||||
ptr++;
|
||||
}
|
||||
pos = ptr;
|
||||
int c = (byte)*ptr++;
|
||||
if(c == '\0') return;
|
||||
switch(c) {
|
||||
case_id: {
|
||||
const char *b = ptr - 1;
|
||||
while(iscid(*ptr))
|
||||
ptr++;
|
||||
String x(b, ptr);
|
||||
int q = id.FindAdd(x);
|
||||
if(q == tk_rval_ - 256) { // simple hack for old rval macro
|
||||
AddCode('&');
|
||||
AddCode('&');
|
||||
}
|
||||
else
|
||||
AddCode(q + 256);
|
||||
break;
|
||||
}
|
||||
case ':': AddCode(Char(':') ? t_dblcolon : ':'); break;
|
||||
case '*': AssOp('*', t_mulass); break;
|
||||
case '/': AssOp('/', t_divass); break;
|
||||
case '%': AssOp('%', t_modass); break;
|
||||
case '^': AssOp('^', t_xorass); break;
|
||||
case '!': AssOp('!', t_neq); break;
|
||||
case '.':
|
||||
if(Char('*')) AddCode(t_dot_asteriks);
|
||||
else
|
||||
if(*ptr == '.' && ptr[1] == '.') {
|
||||
AddCode(t_elipsis);
|
||||
ptr += 2;
|
||||
}
|
||||
else
|
||||
AddCode('.');
|
||||
break;
|
||||
case '+':
|
||||
if(Char('+')) AddCode(t_inc);
|
||||
else
|
||||
AssOp('+', t_addass);
|
||||
return;
|
||||
case '-':
|
||||
if(Char('-')) AddCode(t_dec);
|
||||
else
|
||||
if(Char('>'))
|
||||
AddCode(Char('*') ? t_arrow_asteriks : t_arrow);
|
||||
else
|
||||
AssOp('-', t_subass);
|
||||
break;
|
||||
case '&':
|
||||
if(Char('&'))
|
||||
AddCode(t_and);
|
||||
else
|
||||
AssOp('&', t_andass);
|
||||
break;
|
||||
case '|':
|
||||
if(Char('|'))
|
||||
AddCode(t_or);
|
||||
else
|
||||
AssOp('|', t_orass);
|
||||
break;
|
||||
case '=':
|
||||
AssOp('=', t_eq);
|
||||
break;
|
||||
case '<':
|
||||
if(Char('<'))
|
||||
AssOp(t_shl, t_shlass);
|
||||
else
|
||||
AssOp('<', t_le);
|
||||
break;
|
||||
case '>':
|
||||
if(Char('>'))
|
||||
AssOp(t_shr, t_shrass);
|
||||
else
|
||||
AssOp('>', t_ge);
|
||||
break;
|
||||
case '0': {
|
||||
dword w = 0;
|
||||
if(Char('x') || Char('X')) {
|
||||
for(;;) {
|
||||
int d;
|
||||
if(*ptr >= '0' && *ptr <= '9')
|
||||
d = *ptr - '0';
|
||||
else
|
||||
if(*ptr >= 'A' && *ptr <= 'F')
|
||||
d = *ptr - 'A' + 10;
|
||||
else
|
||||
if(*ptr >= 'a' && *ptr <= 'f')
|
||||
d = *ptr - 'a' + 10;
|
||||
else
|
||||
break;
|
||||
if(w >= 0x8000000u - d) {
|
||||
AddCode(te_integeroverflow);
|
||||
return;
|
||||
}
|
||||
w = w * 16 + d - '0';
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
while(*ptr >= '0' && *ptr <= '7') {
|
||||
int d = *ptr++ - '0';
|
||||
if(w >= 0x1000000u - d) {
|
||||
AddCode(te_integeroverflow);
|
||||
return;
|
||||
}
|
||||
w = w * 8 + d - '0';
|
||||
}
|
||||
Term& tm = term.AddTail();
|
||||
tm.code = t_integer;
|
||||
tm.ptr = pos;
|
||||
tm.number = w;
|
||||
}
|
||||
break;
|
||||
case_nonzero_digit: {
|
||||
double w = c - '0';
|
||||
bool fp = false;
|
||||
while(*ptr >= '0' && *ptr <= '9')
|
||||
w = w * 10 + *ptr++ - '0';
|
||||
if(*ptr == '.') { //TODO TO BE Completed !!!
|
||||
fp = true;
|
||||
ptr++;
|
||||
double x = 0.1;
|
||||
while(*ptr >= '0' && *ptr <= '9') {
|
||||
w += x * (*ptr++ - '0');
|
||||
x /= 10;
|
||||
}
|
||||
}
|
||||
Term& tm = term.AddTail();
|
||||
if(fp || w < INT_MIN || w > INT_MAX)
|
||||
tm.code = t_double;
|
||||
else
|
||||
tm.code = t_integer;
|
||||
tm.ptr = pos;
|
||||
tm.number = w;
|
||||
}
|
||||
break;
|
||||
case '\'': {
|
||||
Term& tm = term.AddTail();
|
||||
tm.code = t_character;
|
||||
tm.ptr = pos;
|
||||
tm.text = String(GetCharacter(), 1);
|
||||
if(*ptr == '\'')
|
||||
ptr++;
|
||||
else
|
||||
tm.code = te_badcharacter;
|
||||
}
|
||||
break;
|
||||
case '\"': {
|
||||
Term& tm = term.AddTail();
|
||||
tm.code = t_string;
|
||||
tm.ptr = pos;
|
||||
for(;;) {
|
||||
while(*ptr != '\"') {
|
||||
if((byte)*ptr < ' ' && *ptr != 9) {
|
||||
tm.code = te_badstring;
|
||||
return;
|
||||
}
|
||||
tm.text.Cat(GetCharacter());
|
||||
}
|
||||
ptr++;
|
||||
while(*ptr && (byte)*ptr <= ' ') ptr++;
|
||||
if(*ptr != '\"') break;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
AddCode(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool Lex::Prepare(int pos) {
|
||||
while(term.GetCount() <= pos) {
|
||||
if(*ptr == '\0') return false;
|
||||
Next();
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
pp = term[0].ptr;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int Lex::Code(int pos)
|
||||
{
|
||||
if(!Prepare(pos)) return t_eof;
|
||||
return term[pos].code;
|
||||
}
|
||||
|
||||
bool Lex::IsId(int pos)
|
||||
{
|
||||
return Code(pos) >= endkey + 256;
|
||||
}
|
||||
|
||||
void Lex::ThrowError(const char *e)
|
||||
{
|
||||
WhenError(e);
|
||||
throw Parser::Error();
|
||||
}
|
||||
|
||||
String Lex::Id(int pos)
|
||||
{
|
||||
if(!IsId(pos))
|
||||
ThrowError("expected id");
|
||||
return id[Code(pos) - 256];
|
||||
}
|
||||
|
||||
void Lex::Get(int n)
|
||||
{
|
||||
while(n--) {
|
||||
if(term.GetCount()) {
|
||||
if(body && term.Head().grounding)
|
||||
throw Grounding();
|
||||
int chr = term.Head().code;
|
||||
if(statsCollected)
|
||||
symbolStat.IncStat(chr);
|
||||
if(chr == '{')
|
||||
braceslevel++;
|
||||
else
|
||||
if(chr == '}')
|
||||
braceslevel--;
|
||||
term.DropHead();
|
||||
}
|
||||
if(term.GetCount() == 0)
|
||||
Next();
|
||||
if(term.GetCount() == 0)
|
||||
break;
|
||||
}
|
||||
#ifdef LOGNEXT
|
||||
Dump(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Lex::Dump(int pos)
|
||||
{
|
||||
#ifdef LOGNEXT
|
||||
int code = Code(pos);
|
||||
switch(code) {
|
||||
case t_string: LOG(AsCString(Text(pos))); break;
|
||||
case t_double: LOG(Double(pos)); break;
|
||||
case t_integer: LOG(Int(pos)); break;
|
||||
case t_character: LOG("char " << AsCString(String(Chr(pos), 1))); break;
|
||||
default:
|
||||
if(code < 0)
|
||||
LOG(decode(Code(),
|
||||
t_dblcolon, "::",
|
||||
t_mulass, "*=",
|
||||
t_divass, "/=",
|
||||
t_modass, "%=",
|
||||
t_xorass, "^=",
|
||||
t_neq, "!=",
|
||||
t_dot_asteriks, ".*",
|
||||
t_elipsis, "...",
|
||||
t_inc, "++",
|
||||
t_addass, "+=",
|
||||
t_dec, "--",
|
||||
t_arrow_asteriks, "->*",
|
||||
t_arrow, "->",
|
||||
t_subass, "-=",
|
||||
t_and, "&&",
|
||||
t_andass, "&=",
|
||||
t_or, "||",
|
||||
t_orass, "|=",
|
||||
t_eq, "==",
|
||||
t_shl, "<<",
|
||||
t_shlass, "<<=",
|
||||
t_le, "<=",
|
||||
t_shr, ">>",
|
||||
t_shrass, ">>=",
|
||||
t_ge, ">=",
|
||||
te_integeroverflow, "<integer overflow>",
|
||||
te_badcharacter, "<bad char>",
|
||||
te_badstring, "<bad string>",
|
||||
"???"));
|
||||
else
|
||||
if(code < 256)
|
||||
LOG((char)code);
|
||||
else
|
||||
LOG(id[code - 256]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Lex::SkipToGrounding()
|
||||
{
|
||||
for(;;) {
|
||||
if(term.GetCount() == 0)
|
||||
Next();
|
||||
if(term.GetCount() == 0)
|
||||
break;
|
||||
int chr = term.Head().code;
|
||||
if(chr == t_eof)
|
||||
return;
|
||||
if(term.Head().grounding)
|
||||
return;
|
||||
if(chr == '{')
|
||||
braceslevel++;
|
||||
else
|
||||
if(chr == '}')
|
||||
braceslevel--;
|
||||
term.DropHead();
|
||||
}
|
||||
}
|
||||
|
||||
int Lex::Int(int pos)
|
||||
{
|
||||
Prepare(pos);
|
||||
if(term[pos].code != t_integer)
|
||||
ThrowError("expected integer literal");
|
||||
return (int)term[pos].number;
|
||||
}
|
||||
|
||||
double Lex::Double(int pos)
|
||||
{
|
||||
Prepare(pos);
|
||||
if(term[pos].code != t_double)
|
||||
ThrowError("expected floating point literal");
|
||||
return term[pos].number;
|
||||
}
|
||||
|
||||
String Lex::Text(int pos)
|
||||
{
|
||||
Prepare(pos);
|
||||
if(term[pos].code != t_string)
|
||||
ThrowError("expected string literal");
|
||||
return term[pos].text;
|
||||
}
|
||||
|
||||
int Lex::Chr(int pos)
|
||||
{
|
||||
Prepare(pos);
|
||||
if(term[pos].code != t_character)
|
||||
ThrowError("expected character literal");
|
||||
return (byte)*term[pos].text;
|
||||
}
|
||||
|
||||
const char *Lex::Pos(int pos)
|
||||
{
|
||||
Prepare(pos);
|
||||
return pos < term.GetCount() ? term[pos].ptr : ptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
//#BLITZ_APPROVE
|
||||
|
||||
CPPID(__asm)
|
||||
CPPID(else)
|
||||
CPPID(struct)
|
||||
CPPID(enum)
|
||||
CPPID(auto)
|
||||
CPPID(__except)
|
||||
CPPID(template)
|
||||
CPPID(explicit)
|
||||
CPPID(this)
|
||||
CPPID(bool)
|
||||
CPPID(extern)
|
||||
CPPID(mutable)
|
||||
CPPID(thread)
|
||||
CPPID(break)
|
||||
CPPID(false)
|
||||
CPPID(throw)
|
||||
CPPID(case)
|
||||
//CPPID(__fastcall)
|
||||
CPPID(namespace)
|
||||
CPPID(true)
|
||||
//CPPID(__finally)
|
||||
CPPID(new)
|
||||
//CPPID(__cdecl)
|
||||
CPPID(float)
|
||||
CPPID(__try)
|
||||
CPPID(char)
|
||||
CPPID(operator)
|
||||
CPPID(typedef)
|
||||
CPPID(class)
|
||||
CPPID(friend)
|
||||
CPPID(private)
|
||||
CPPID(typeid)
|
||||
CPPID(const)
|
||||
CPPID(goto)
|
||||
CPPID(protected)
|
||||
CPPID(typename)
|
||||
CPPID(const_cast)
|
||||
CPPID(public)
|
||||
CPPID(union)
|
||||
CPPID(continue)
|
||||
CPPID(inline)
|
||||
CPPID(register)
|
||||
CPPID(unsigned)
|
||||
//CPPID(__declspec)
|
||||
//CPPID(__inline)
|
||||
CPPID(reinterpret_cast)
|
||||
CPPID(using)
|
||||
CPPID(default)
|
||||
CPPID(int)
|
||||
CPPID(return)
|
||||
CPPID(delete)
|
||||
CPPID(__int8)
|
||||
CPPID(short)
|
||||
CPPID(__uuidof)
|
||||
CPPID(dllexport)
|
||||
CPPID(__int16)
|
||||
CPPID(signed)
|
||||
CPPID(virtual)
|
||||
CPPID(dllimport)
|
||||
CPPID(__int32)
|
||||
CPPID(sizeof)
|
||||
CPPID(void)
|
||||
CPPID(__int64)
|
||||
CPPID(static)
|
||||
CPPID(volatile)
|
||||
CPPID(double)
|
||||
CPPID(__leave)
|
||||
CPPID(static_cast)
|
||||
CPPID(dynamic_cast)
|
||||
CPPID(long)
|
||||
//CPPID(__stdcall)
|
||||
CPPID(__inline)
|
||||
|
||||
CPPID(if)
|
||||
CPPID(while)
|
||||
CPPID(switch)
|
||||
CPPID(for)
|
||||
CPPID(try)
|
||||
CPPID(catch)
|
||||
CPPID(do)
|
||||
|
||||
CPPID(SKYLARK)
|
||||
|
||||
CPPID(RPC_METHOD)
|
||||
CPPID(RPC_GMETHOD)
|
||||
CPPID(force_inline)
|
||||
CPPID(never_inline)
|
||||
|
||||
CPPID(rval_)
|
||||
|
||||
CPPID(constexpr)
|
||||
CPPID(noexcept)
|
||||
CPPID(alignas)
|
||||
CPPID(thread_local)
|
||||
CPPID(char16_t)
|
||||
CPPID(char32_t)
|
||||
CPPID(static_assert)
|
||||
CPPID(decltype)
|
||||
CPPID(__int128)
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
inline bool IsSpc(byte c)
|
||||
{
|
||||
return c > 0 && c <= 32;
|
||||
}
|
||||
|
||||
String CppMacro::Define(const char *s)
|
||||
{
|
||||
CParser p(s);
|
||||
String id;
|
||||
try {
|
||||
if(!p.IsId())
|
||||
return Null;
|
||||
p.NoSkipSpaces().NoSkipComments(); // '#define TEST(x)' is different form '#define TEST (x)' - later is parameterless
|
||||
id = p.ReadId();
|
||||
param.Clear();
|
||||
if(p.Char('(')) {
|
||||
p.SkipSpaces();
|
||||
p.Spaces();
|
||||
while(p.IsId()) {
|
||||
if(param.GetCount())
|
||||
param << ",";
|
||||
param << p.ReadId();
|
||||
p.Char(',');
|
||||
}
|
||||
if(p.Char3('.', '.', '.'))
|
||||
param << '.';
|
||||
p.Char(')');
|
||||
if(param.GetCount() == 0) // #define foo() bar - need to 'eat' parenthesis, cheap way
|
||||
param = ".";
|
||||
}
|
||||
const char *b = p.GetPtr();
|
||||
while(!p.IsEof() && !p.IsChar2('/', '/'))
|
||||
p.SkipTerm();
|
||||
body = String(b, p.GetPtr());
|
||||
Md5Stream m;
|
||||
m.Put(param);
|
||||
m.Put(body);
|
||||
m.Finish(md5);
|
||||
}
|
||||
catch(CParser::Error) {
|
||||
return Null;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
String CppMacro::ToString() const
|
||||
{
|
||||
String r;
|
||||
if(param.GetCount()) {
|
||||
String h = param;
|
||||
h.Replace(".", "...");
|
||||
r << "(" << h << ")";
|
||||
}
|
||||
if(IsUndef())
|
||||
r << " #undef";
|
||||
else
|
||||
r << ' ' << body;
|
||||
return r;
|
||||
}
|
||||
|
||||
void CppMacro::Serialize(Stream& s)
|
||||
{
|
||||
s % param % body;
|
||||
s.SerializeRaw(md5, 16);
|
||||
}
|
||||
|
||||
String CppMacro::Expand(const Vector<String>& p, const Vector<String>& ep) const
|
||||
{
|
||||
String r;
|
||||
const char *s = body;
|
||||
String pp = param;
|
||||
if(*pp.Last() == '.')
|
||||
pp.Trim(pp.GetCount() - 1);
|
||||
Index<String> param(Split(pp, ','));
|
||||
static String VA_ARGS("__VA_ARGS__"); // static - Speed optimization
|
||||
while(*s) {
|
||||
if(IsAlpha(*s) || *s == '_') {
|
||||
const char *b = s;
|
||||
s++;
|
||||
while(IsAlNum(*s) || *s == '_')
|
||||
s++;
|
||||
String id(b, s);
|
||||
const char *ss = b;
|
||||
bool cat = false;
|
||||
while(ss > ~body && ss[-1] == ' ')
|
||||
ss--;
|
||||
if(ss >= ~body + 2 && ss[-1] == '#' && ss[-2] == '#')
|
||||
cat = true;
|
||||
ss = s;
|
||||
while(*ss && *ss == ' ')
|
||||
ss++;
|
||||
if(ss[0] == '#' && ss[1] == '#')
|
||||
cat = true;
|
||||
if(id == VA_ARGS) {
|
||||
bool next = false;
|
||||
for(int i = param.GetCount(); i < ep.GetCount(); i++) {
|
||||
if(next)
|
||||
r.Cat(", ");
|
||||
r.Cat((cat ? p : ep)[i]);
|
||||
next = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int q = param.Find(id);
|
||||
if(q >= 0) {
|
||||
if(q < ep.GetCount())
|
||||
r.Cat((cat ? p : ep)[q]);
|
||||
}
|
||||
else
|
||||
r.Cat(id);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(s[0] == '#' && s[1] == '#') {
|
||||
int q = r.GetLength();
|
||||
while(q > 0 && IsSpc(r[q - 1]))
|
||||
q--;
|
||||
r.Trim(q);
|
||||
s += 2;
|
||||
while((byte)*s <= ' ')
|
||||
s++;
|
||||
continue;
|
||||
}
|
||||
if(*s == '#') {
|
||||
const char *ss = s + 1;
|
||||
while(IsSpc(*ss))
|
||||
ss++;
|
||||
if(IsAlpha(*ss) || *ss == '_') {
|
||||
const char *b = ss;
|
||||
ss++;
|
||||
while(IsAlNum(*ss) || *ss == '_')
|
||||
ss++;
|
||||
String id(b, ss);
|
||||
int q = param.Find(id);
|
||||
if(q >= 0) {
|
||||
if(q <= p.GetCount()) {
|
||||
if(q < p.GetCount())
|
||||
r.Cat(AsCString(p[q]));
|
||||
s = ss;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
r.Cat(String(s, ss));
|
||||
s = ss;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
r.Cat(*s++);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
String GetStdDefs()
|
||||
{
|
||||
static const char ns[] = "_STD_BEGIN:std;_C_STD_BEGIN:std;_STDEXT_BEGIN:stdext;NAMESPACE_UPP:Upp";
|
||||
static const char endns[] = "_STD_END;_STDEXT_END;_C_STD_END;END_UPP_NAMESPACE";
|
||||
static const char ignore[] = "__declspec(...);__cdecl;__attribute__(...);__stdcall;__forceinline;"
|
||||
"__out;__in;__inout;__deref_in;__deref_inout;__deref_out;"
|
||||
"__pragma(...);__pascal;_far;_pascal;_cdecl;"
|
||||
"__AuToQuOtE;__xin;__xout;__export;"
|
||||
"__clrcall;__alignof(...);"
|
||||
|
||||
"__asm__(...);__asm(...);__restrict;__inline;__typeof;"
|
||||
"_GLIBCXX_VISIBILITY(...);_GLIBCXX_BEGIN_NAMESPACE_VERSION;"
|
||||
"_GLIBCXX_END_NAMESPACE_VERSION;_GLIBCXX_CONSTEXPR;"
|
||||
"_GLIBCXX_HAS_NESTED_TYPE(...);"
|
||||
"__inline__;"
|
||||
"_GLIBCXX_CONST;"
|
||||
"_GLIBCXX_ABI_TAG_CXX11;"
|
||||
"__attribute(...);"
|
||||
"__glibcxx_class_requires(...);"
|
||||
"__glibcxx_class_requires2(...);"
|
||||
"__glibcxx_class_requires3(...);"
|
||||
"__glibcxx_class_requires4(...);"
|
||||
"__glibcxx_class_requires5(...);"
|
||||
;
|
||||
|
||||
String defs;
|
||||
Vector<String> h = Split(ns, ';');
|
||||
for(int i = 0; i < h.GetCount(); i++) {
|
||||
String id, n;
|
||||
SplitTo(h[i], ':', id, n);
|
||||
ValueMap m;
|
||||
m.Add(id, n);
|
||||
defs << "#define " << id << " namespace " << n << " {\n";
|
||||
}
|
||||
h = Split(endns, ';');
|
||||
for(int i = 0; i < h.GetCount(); i++)
|
||||
defs << "#define " << h[i] << " };\r\n";
|
||||
h = Split(ignore, ';');
|
||||
for(int i = 0; i < h.GetCount(); i++)
|
||||
defs << "#define " << h[i] << "\n";
|
||||
defs << "#define NULL NULL\n";
|
||||
defs << "#define DrawText DrawText\n"; // DrawTextA/DrawTextW fiasco...
|
||||
defs << "#define __typeof__ decltype\n";
|
||||
return defs;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -1,693 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
#define LTIMING(x) // DTIMING(x)
|
||||
#define LLOG(x) // DLOG(x)
|
||||
|
||||
static std::atomic<int> s_PPserial;
|
||||
static VectorMap<String, PPMacro> sAllMacros; // Only MakePP can write to this
|
||||
static ArrayMap<String, PPFile> sPPfile; // Only MakePP can write to this
|
||||
|
||||
static VectorMap<String, Time> s_PathFileTime;
|
||||
static StaticMutex s_PathFileTimeMutex;
|
||||
|
||||
static VectorMap<String, String> s_IncludePath;
|
||||
static String s_Include_Path;
|
||||
static StaticMutex s_IncludePathMutex;
|
||||
|
||||
static StaticMutex s_FlatPPMutex;
|
||||
static ArrayMap<String, FlatPP> s_FlatPP; // ArrayMap to allow read access
|
||||
|
||||
int NextPPSerial()
|
||||
{
|
||||
return ++s_PPserial;
|
||||
}
|
||||
|
||||
void SweepPPFiles(const Index<String>& keep)
|
||||
{
|
||||
Index<int> pp_segment_id;
|
||||
int unlinked_count = 0;
|
||||
for(int i = 0; i < sPPfile.GetCount(); i++)
|
||||
if(sPPfile.IsUnlinked(i))
|
||||
unlinked_count++;
|
||||
else
|
||||
if(keep.Find(sPPfile.GetKey(i)) < 0) {
|
||||
unlinked_count++;
|
||||
sPPfile.Unlink(i);
|
||||
}
|
||||
else {
|
||||
const PPFile& p = sPPfile[i];
|
||||
for(int j = 0; j < p.item.GetCount(); j++)
|
||||
pp_segment_id.FindAdd(p.item[j].segment_id);
|
||||
}
|
||||
if(unlinked_count > sPPfile.GetCount() / 2) {
|
||||
CleanPP();
|
||||
return;
|
||||
}
|
||||
unlinked_count = 0;
|
||||
for(int i = 0; i < sAllMacros.GetCount(); i++) {
|
||||
if(sAllMacros.IsUnlinked(i))
|
||||
unlinked_count++;
|
||||
else
|
||||
if(sAllMacros[i].segment_id && pp_segment_id.Find(sAllMacros[i].segment_id) < 0) {
|
||||
sAllMacros.Unlink(i);
|
||||
unlinked_count++;
|
||||
}
|
||||
if(unlinked_count > sAllMacros.GetCount() / 2) {
|
||||
CleanPP();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String GetSegmentFile(int segment_id)
|
||||
{
|
||||
for(int i = 0; i < sPPfile.GetCount(); i++) {
|
||||
const Array<PPItem>& m = sPPfile[i].item;
|
||||
for(int j = 0; j < m.GetCount(); j++)
|
||||
if(m[j].type == PP_DEFINES && m[j].segment_id == segment_id)
|
||||
return sPPfile.GetKey(i);
|
||||
}
|
||||
return "<not found>";
|
||||
}
|
||||
|
||||
PPMacro *FindPPMacro(const String& id, Index<int>& segment_id, int& segmenti)
|
||||
{
|
||||
Index<int> undef;
|
||||
PPMacro *r;
|
||||
int best;
|
||||
for(int pass = 0; pass < 2; pass++) {
|
||||
r = NULL;
|
||||
best = segmenti;
|
||||
int line = -1;
|
||||
int q = sAllMacros.Find(id);
|
||||
while(q >= 0) {
|
||||
PPMacro& m = sAllMacros[q];
|
||||
if(m.macro.IsUndef()) {
|
||||
if(pass == 0 && segment_id.Find(m.segment_id) >= 0)
|
||||
undef.FindAdd(m.segment_id); // cancel out undefined macro...
|
||||
}
|
||||
else
|
||||
if(pass == 0 || m.segment_id == 0 || undef.Find(m.undef_segment_id) < 0) {
|
||||
int si = m.segment_id == 0 ? INT_MAX : segment_id.Find(m.segment_id); // defs macros always override
|
||||
if(si > best || si >= 0 && si == best && m.line > line) {
|
||||
best = si;
|
||||
line = m.line;
|
||||
r = &m;
|
||||
}
|
||||
}
|
||||
q = sAllMacros.FindNext(q);
|
||||
}
|
||||
if(undef.GetCount() == 0)
|
||||
break;
|
||||
}
|
||||
segmenti = best;
|
||||
return r;
|
||||
}
|
||||
|
||||
const CppMacro *FindMacro(const String& id, Index<int>& segment_id, int& segmenti)
|
||||
{
|
||||
PPMacro *m = FindPPMacro(id, segment_id, segmenti);
|
||||
return m ? &m->macro : NULL;
|
||||
}
|
||||
|
||||
void PPFile::CheckEndNamespace(Vector<int>& namespace_block, int level, Md5Stream& md5)
|
||||
{
|
||||
if(namespace_block.GetCount() && namespace_block.Top() == level) {
|
||||
namespace_block.Drop();
|
||||
item.Add().type = PP_NAMESPACE_END;
|
||||
md5.Put('.');
|
||||
}
|
||||
}
|
||||
|
||||
void PPFile::Parse(Stream& in)
|
||||
{
|
||||
LTIMING("PPFile::Parse");
|
||||
for(int i = 0; i < ppmacro.GetCount(); i++)
|
||||
sAllMacros.Unlink(ppmacro[i]);
|
||||
ppmacro.Clear();
|
||||
item.Clear();
|
||||
includes.Clear();
|
||||
bool was_using = false;
|
||||
bool was_namespace = false;
|
||||
int level = 0;
|
||||
bool incomment = false;
|
||||
bool do_pp = true;
|
||||
Vector<int> namespace_block;
|
||||
bool next_segment = true;
|
||||
Index<int> local_segments;
|
||||
keywords.Clear();
|
||||
int linei = 0;
|
||||
Md5Stream md5;
|
||||
int current_serial = 0;
|
||||
|
||||
VectorMap<String, PPMacro> local_macro; // gather all macros first to reduce locking
|
||||
|
||||
while(!in.IsEof()) {
|
||||
String l = in.GetLine();
|
||||
const char *ll = l;
|
||||
while(*ll == ' ' || *ll == '\t')
|
||||
ll++;
|
||||
if(ll[0] == '/' && ll[1] == '/' && ll[2] == '$')
|
||||
do_pp = decode(ll[3], '+', true, '-', false, do_pp);
|
||||
while(*l.Last() == '\\' && !in.IsEof()) {
|
||||
l.Trim(l.GetLength() - 1);
|
||||
l.Cat(in.GetLine());
|
||||
}
|
||||
RemoveComments(l, incomment);
|
||||
try {
|
||||
CParser p(l);
|
||||
if(p.Char('#')) {
|
||||
if(do_pp) {
|
||||
if(p.Id("define")) {
|
||||
if(next_segment) {
|
||||
PPItem& m = item.Add();
|
||||
m.type = PP_DEFINES;
|
||||
m.segment_id = current_serial = NextPPSerial();
|
||||
next_segment = false;
|
||||
local_segments.Add(current_serial);
|
||||
}
|
||||
CppMacro def;
|
||||
String id = def.Define(p.GetPtr());
|
||||
if(id.GetCount()) {
|
||||
PPMacro& l = local_macro.Add(id);
|
||||
l.segment_id = current_serial;
|
||||
l.line = linei;
|
||||
l.macro = def;
|
||||
/*
|
||||
PPMacro m;
|
||||
m.segment_id = current_serial;
|
||||
m.line = linei;
|
||||
m.macro = def;
|
||||
ppmacro.Add(sAllMacros.Put(id, m));
|
||||
*/
|
||||
md5.Put("#", 1);
|
||||
md5.Put(id);
|
||||
md5.Put(0);
|
||||
md5.Put(l.macro.md5, 16);
|
||||
}
|
||||
}
|
||||
else
|
||||
if(p.Id("undef")) {
|
||||
if(p.IsId()) {
|
||||
String id = p.ReadId();
|
||||
if(id.GetCount()) {
|
||||
md5.Put("#", 1);
|
||||
md5.Put(id);
|
||||
md5.Put(1);
|
||||
int q = local_macro.FindLast(id); // heuristic: only local undefs are allowed
|
||||
while(q >= 0) {
|
||||
PPMacro& um = local_macro[q];
|
||||
if(!um.macro.IsUndef()) { // found corresponding macro to undef
|
||||
PPItem& m = item.Add();
|
||||
m.type = PP_DEFINES;
|
||||
m.segment_id = current_serial = NextPPSerial();
|
||||
um.undef_segment_id = m.segment_id;
|
||||
next_segment = true;
|
||||
local_segments.Add(current_serial);
|
||||
PPMacro& l = local_macro.Add(id);
|
||||
l.segment_id = current_serial;
|
||||
l.line = linei;
|
||||
l.macro.SetUndef();
|
||||
}
|
||||
q = local_macro.FindPrev(q);
|
||||
}
|
||||
}
|
||||
/*
|
||||
int segmenti = -1;
|
||||
PPMacro *um = FindPPMacro(id, local_segments, segmenti);
|
||||
if(um && segmenti) {
|
||||
PPItem& m = item.Add();
|
||||
m.type = PP_DEFINES;
|
||||
m.segment_id = current_serial = NextPPSerial();
|
||||
um->undef_segment_id = m.segment_id;
|
||||
next_segment = true;
|
||||
local_segments.Add(current_serial);
|
||||
if(id.GetCount()) {
|
||||
PPMacro m;
|
||||
m.segment_id = current_serial;
|
||||
m.line = linei;
|
||||
m.macro.SetUndef();
|
||||
ppmacro.Add(sAllMacros.Put(id, m));
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
if(p.Id("include")) {
|
||||
PPItem& m = item.Add();
|
||||
next_segment = true;
|
||||
m.type = PP_INCLUDE;
|
||||
m.text = TrimBoth(p.GetPtr());
|
||||
if(IsNull(m.text))
|
||||
item.Drop();
|
||||
else
|
||||
includes.FindAdd(m.text);
|
||||
md5.Put('@');
|
||||
md5.Put(m.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
while(!p.IsEof()) {
|
||||
if(was_namespace) {
|
||||
int type = was_using ? PP_USING : PP_NAMESPACE;
|
||||
String id;
|
||||
while(p.Char2(':', ':'))
|
||||
id = "::";
|
||||
if(p.IsId()) {
|
||||
id << p.ReadId();
|
||||
while(p.Char2(':', ':') && p.IsId())
|
||||
id << "::" << p.ReadId();
|
||||
if(!was_using)
|
||||
namespace_block.Add(level);
|
||||
if(!was_using || level == 0) {
|
||||
PPItem& m = item.Add();
|
||||
next_segment = true;
|
||||
m.type = type;
|
||||
m.text = id;
|
||||
}
|
||||
md5.Put('$');
|
||||
md5.Put(type);
|
||||
md5.Put(id);
|
||||
}
|
||||
was_namespace = was_using = false;
|
||||
}
|
||||
else
|
||||
if(p.Id("using"))
|
||||
was_using = true;
|
||||
else
|
||||
if(p.Id("namespace"))
|
||||
was_namespace = true;
|
||||
else {
|
||||
was_using = was_namespace = false;
|
||||
if(p.IsId()) {
|
||||
static const VectorMap<String, String>& namespace_macro = GetNamespaceMacros();
|
||||
static const Index<String>& namespace_end_macro = GetNamespaceEndMacros();
|
||||
|
||||
String id = p.ReadId();
|
||||
int q = namespace_macro.Find(id);
|
||||
if(q > 0) {
|
||||
PPItem& m = item.Add();
|
||||
next_segment = true;
|
||||
m.type = PP_NAMESPACE;
|
||||
m.text = namespace_macro[q];
|
||||
namespace_block.Add(level);
|
||||
level++;
|
||||
md5.Put('%');
|
||||
md5.Put(id);
|
||||
}
|
||||
else {
|
||||
q = namespace_end_macro.Find(id);
|
||||
if(q >= 0) {
|
||||
level--;
|
||||
CheckEndNamespace(namespace_block, level, md5);
|
||||
}
|
||||
}
|
||||
keywords.Add(id);
|
||||
}
|
||||
else
|
||||
if(p.Char('}')) {
|
||||
if(level > 0) {
|
||||
level--;
|
||||
CheckEndNamespace(namespace_block, level, md5);
|
||||
}
|
||||
}
|
||||
else
|
||||
if(p.Char('{'))
|
||||
level++;
|
||||
else
|
||||
p.SkipTerm();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...) {}
|
||||
linei++;
|
||||
}
|
||||
md5sum = md5.FinishString();
|
||||
Sort(keywords);
|
||||
Vector<int> remove;
|
||||
int i = 0;
|
||||
while(i < keywords.GetCount()) { // Remove identical items
|
||||
int ii = i;
|
||||
i++;
|
||||
while(i < keywords.GetCount() && keywords[ii] == keywords[i])
|
||||
remove.Add(i++);
|
||||
}
|
||||
keywords.Remove(remove);
|
||||
INTERLOCKED { // this is the only place that is allowed to write to sAllMacros
|
||||
for(int i = 0; i < local_macro.GetCount(); i++)
|
||||
ppmacro.Add(sAllMacros.Put(local_macro.GetKey(i), local_macro[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void PPFile::Dump() const
|
||||
{
|
||||
for(int i = 0; i < item.GetCount(); i++) {
|
||||
const PPItem& m = item[i];
|
||||
String ll;
|
||||
ll << decode(m.type, PP_DEFINES, "#defines ", PP_INCLUDE, "#include ",
|
||||
PP_USING, "using namespace ", PP_NAMESPACE, "namespace ",
|
||||
PP_NAMESPACE_END, "}", "");
|
||||
if(m.type == PP_DEFINES)
|
||||
ll << m.segment_id;
|
||||
else
|
||||
ll << m.text;
|
||||
if(m.type == PP_NAMESPACE)
|
||||
ll << " {";
|
||||
LOG(ll);
|
||||
}
|
||||
LOG("----- includes:");
|
||||
DUMPC(includes);
|
||||
}
|
||||
|
||||
void InvalidatePPCache()
|
||||
{
|
||||
{
|
||||
Mutex::Lock __(s_IncludePathMutex);
|
||||
s_IncludePath.Clear();
|
||||
}
|
||||
{
|
||||
Mutex::Lock __(s_FlatPPMutex);
|
||||
s_FlatPP.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void PPSync(const String& include_path)
|
||||
{
|
||||
LLOG("* PPSync");
|
||||
bool update = false;
|
||||
{
|
||||
Mutex::Lock __(s_IncludePathMutex);
|
||||
if(s_Include_Path != include_path) {
|
||||
s_IncludePath.Clear();
|
||||
s_Include_Path = include_path;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
if(update) {
|
||||
Mutex::Lock __(s_FlatPPMutex);
|
||||
s_FlatPP.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void InvalidateFileTimeCache()
|
||||
{
|
||||
Mutex::Lock __(s_PathFileTimeMutex);
|
||||
s_PathFileTime.Clear();
|
||||
}
|
||||
|
||||
void InvalidateFileTimeCache(const String& path)
|
||||
{
|
||||
LLOG("InvalidateFileTimeCache " << path);
|
||||
Mutex::Lock __(s_PathFileTimeMutex);
|
||||
s_PathFileTime.UnlinkKey(path);
|
||||
}
|
||||
|
||||
Time GetFileTimeCached(const String& p)
|
||||
{
|
||||
LTIMING("GetFileTimeCached");
|
||||
{
|
||||
Mutex::Lock __(s_PathFileTimeMutex);
|
||||
int q = s_PathFileTime.Find(p);
|
||||
if(q >= 0)
|
||||
return s_PathFileTime[q];
|
||||
}
|
||||
Time m = FileGetTime(p);
|
||||
{
|
||||
Mutex::Lock __(s_PathFileTimeMutex);
|
||||
s_PathFileTime.Put(p, m);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
String GetIncludePath()
|
||||
{
|
||||
Mutex::Lock __(s_IncludePathMutex);
|
||||
return s_Include_Path;
|
||||
}
|
||||
|
||||
String GetIncludePath0(const char *s, const char *filedir)
|
||||
{
|
||||
LTIMING("GetIncludePath0");
|
||||
while(IsSpace(*s))
|
||||
s++;
|
||||
int type = *s;
|
||||
if(type == '<' || type == '\"' || type == '?') {
|
||||
s++;
|
||||
String name;
|
||||
if(type == '<') type = '>';
|
||||
while(*s != '\r' && *s != '\n' && *s) {
|
||||
if(*s == type) {
|
||||
if(type == '\"') {
|
||||
String fn = NormalizeSourcePath(name, filedir);
|
||||
if(FileExists(fn))
|
||||
return fn;
|
||||
}
|
||||
String p = GetFileOnPath(name, GetIncludePath(), false);
|
||||
if(p.GetCount())
|
||||
return NormalizeSourcePath(p);
|
||||
return Null;
|
||||
}
|
||||
name.Cat(*s++);
|
||||
}
|
||||
}
|
||||
return Null;
|
||||
}
|
||||
|
||||
String GetIncludePath(const String& s, const String& filedir)
|
||||
{
|
||||
LTIMING("GetIncludePath");
|
||||
Mutex::Lock __(s_IncludePathMutex);
|
||||
String key;
|
||||
key << s << "#" << filedir;
|
||||
int q = s_IncludePath.Find(key);
|
||||
if(q >= 0)
|
||||
return s_IncludePath[q];
|
||||
LTIMING("GetIncludePath 2");
|
||||
String p = GetIncludePath0(s, filedir);
|
||||
s_IncludePath.Add(key, p);
|
||||
LLOG("GetIncludePath " << s << " " << filedir << ": " << p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void MakePP(const Index<String>& paths)
|
||||
{
|
||||
LLOG("MakePP " << paths);
|
||||
Vector<String> todo;
|
||||
Vector<PPFile *> pp;
|
||||
for(int i = 0; i < paths.GetCount(); i++) {
|
||||
String path = paths[i];
|
||||
PPFile& f = sPPfile.GetPut(path);
|
||||
Time tm = GetFileTimeCached(path);
|
||||
if(f.filetime != tm) {
|
||||
f.filetime = tm;
|
||||
pp.Add(&f);
|
||||
todo.Add(path);
|
||||
}
|
||||
}
|
||||
CoFor(todo.GetCount(), [&](int i) {
|
||||
FileIn in(todo[i]);
|
||||
pp[i]->Parse(in);
|
||||
});
|
||||
}
|
||||
|
||||
const PPFile& GetPPFile(const char *path)
|
||||
{
|
||||
LTIMING("GetPPFile");
|
||||
LLOG("GetPPFile " << path);
|
||||
static PPFile zero;
|
||||
return sPPfile.Get(path, zero);
|
||||
}
|
||||
|
||||
bool IsSameFile(const String& f1, const String& f2)
|
||||
{
|
||||
return NormalizePath(f1) == NormalizePath(f2);
|
||||
}
|
||||
|
||||
const FlatPP& GetFlatPPFile(const char *path, Index<String>& visited)
|
||||
{
|
||||
LTIMING("GetFlatPPFile");
|
||||
LLOG("GetFlatPPFile " << path);
|
||||
Mutex::Lock __(s_FlatPPMutex);
|
||||
int q = s_FlatPP.Find(path);
|
||||
if(q >= 0) {
|
||||
LLOG("From cache");
|
||||
return s_FlatPP[q];
|
||||
}
|
||||
FlatPP& fp = s_FlatPP.Add(path);
|
||||
const PPFile& pp = GetPPFile(path);
|
||||
int n = visited.GetCount();
|
||||
visited.FindAdd(path);
|
||||
for(int i = 0; i < pp.item.GetCount(); i++) {
|
||||
const PPItem& m = pp.item[i];
|
||||
if(m.type == PP_INCLUDE) {
|
||||
String s = GetIncludePath(m.text, GetFileFolder(path));
|
||||
LLOG("#include " << m.text << " -> " << s);
|
||||
if(s.GetCount() && visited.Find(s) < 0) {
|
||||
visited.Add(s);
|
||||
const FlatPP& pp = GetFlatPPFile(s, visited);
|
||||
for(int i = 0; i < pp.segment_id.GetCount(); i++)
|
||||
fp.segment_id.FindAdd(pp.segment_id[i]);
|
||||
for(int i = 0; i < pp.usings.GetCount(); i++)
|
||||
fp.usings.FindAdd(pp.usings[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
if(m.type == PP_DEFINES)
|
||||
fp.segment_id.FindAdd(m.segment_id);
|
||||
else
|
||||
if(m.type == PP_USING)
|
||||
fp.usings.FindAdd(m.text);
|
||||
}
|
||||
visited.Trim(n);
|
||||
return fp;
|
||||
}
|
||||
|
||||
const FlatPP& GetFlatPPFile(const char *path)
|
||||
{
|
||||
Index<String> visited;
|
||||
visited.Add(path);
|
||||
return GetFlatPPFile(path, visited);
|
||||
}
|
||||
|
||||
void GetAllMacros(Md5Stream& md5, const String& id, Index<int>& segment_id)
|
||||
{
|
||||
Vector< Tuple2<int, int> > pos;
|
||||
Vector<const CppMacro *> def;
|
||||
String r;
|
||||
int q = sAllMacros.Find(id);
|
||||
while(q >= 0) {
|
||||
const PPMacro& m = sAllMacros[q];
|
||||
int si = segment_id.Find(m.segment_id);
|
||||
if(si >= 0) {
|
||||
pos.Add(MakeTuple(si, m.line));
|
||||
def.Add(&m.macro);
|
||||
}
|
||||
q = sAllMacros.FindNext(q);
|
||||
}
|
||||
IndexSort(pos, def);
|
||||
int n = def.GetCount();
|
||||
if(n) {
|
||||
md5.Put(&n, sizeof(int));
|
||||
md5.Put(id);
|
||||
for(int i = 0; i < n; i++)
|
||||
md5.Put(def[i]->md5, 16);
|
||||
}
|
||||
}
|
||||
|
||||
static VectorMap<String, String> s_namespace_macro;
|
||||
static Index<String> s_namespace_end_macro;
|
||||
|
||||
static String sDefs;
|
||||
|
||||
void LoadPPConfig()
|
||||
{
|
||||
for(int i = 0; i < sAllMacros.GetCount(); i++)
|
||||
if(sAllMacros[i].segment_id == 0 && !sAllMacros.IsUnlinked(i))
|
||||
sAllMacros.Unlink(i);
|
||||
|
||||
s_namespace_macro.Clear();
|
||||
s_namespace_end_macro.Clear();
|
||||
|
||||
StringStream ss(sDefs);
|
||||
int linei = 0;
|
||||
while(!ss.IsEof()) {
|
||||
String l = ss.GetLine();
|
||||
try {
|
||||
CParser p(l);
|
||||
if(p.Char('#')) {
|
||||
if(p.Id("define")) {
|
||||
CppMacro def;
|
||||
String id = def.Define(p.GetPtr());
|
||||
if(id.GetCount()) {
|
||||
PPMacro m;
|
||||
m.segment_id = 0;
|
||||
m.line = linei;
|
||||
m.macro = def;
|
||||
sAllMacros.Put(id, m);
|
||||
if(findarg(TrimBoth(def.body), "}", "};") >= 0)
|
||||
s_namespace_end_macro.Add(id);
|
||||
try {
|
||||
CParser p(def.body);
|
||||
if(p.Id("namespace") && p.IsId()) {
|
||||
String n = p.ReadId();
|
||||
if(p.Char('{') && p.IsEof())
|
||||
s_namespace_macro.Add(id, n);
|
||||
}
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
linei++;
|
||||
}
|
||||
}
|
||||
|
||||
const VectorMap<String, String>& GetNamespaceMacros()
|
||||
{
|
||||
return s_namespace_macro;
|
||||
}
|
||||
|
||||
const Index<String>& GetNamespaceEndMacros()
|
||||
{
|
||||
return s_namespace_end_macro;
|
||||
}
|
||||
|
||||
void SetPPDefs(const String& defs)
|
||||
{
|
||||
sDefs = defs;
|
||||
LoadPPConfig();
|
||||
}
|
||||
|
||||
void CleanPP()
|
||||
{
|
||||
sAllMacros.Clear();
|
||||
sPPfile.Clear();
|
||||
s_PPserial = 0;
|
||||
LoadPPConfig();
|
||||
}
|
||||
|
||||
void SerializePPFiles(Stream& s)
|
||||
{
|
||||
int sPPserial = s_PPserial;
|
||||
s % sAllMacros % sPPfile % sPPserial;
|
||||
s_PPserial = sPPserial;
|
||||
if(s.IsLoading())
|
||||
LoadPPConfig();
|
||||
|
||||
#if 0
|
||||
if(s.IsLoading()) { _DBG_
|
||||
DDUMP(sPPfile.GetCount());
|
||||
DDUMP(sAllMacros.GetCount());
|
||||
DDUMP(sPPserial);
|
||||
|
||||
Index<int> psegment;
|
||||
for(int i = 0; i < sPPfile.GetCount(); i++) {
|
||||
const PPFile& p = sPPfile[i];
|
||||
for(int j = 0; j < p.item.GetCount(); j++)
|
||||
psegment.FindAdd(p.item[j].segment_id);
|
||||
}
|
||||
DDUMP(psegment.GetCount());
|
||||
|
||||
int n = 0; _DBG_
|
||||
Index<int> msegment;
|
||||
for(int i = 0; i < sAllMacros.GetCount(); i++) { _DBG_
|
||||
if(sAllMacros.IsUnlinked(i))
|
||||
n++;
|
||||
else
|
||||
msegment.FindAdd(sAllMacros[i].segment_id);
|
||||
}
|
||||
DLOG("UNLINKED " << n);
|
||||
DLOG("Segments " << msegment.GetCount());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
#define LTIMING(x) // DTIMING(x)
|
||||
#define LLOG(x) // DLOG(x)
|
||||
|
||||
static VectorMap<String, String> sSrcFile;
|
||||
static Index<uint64> sIncludes;
|
||||
|
||||
String NormalizeSourcePath(const String& path, const String& currdir)
|
||||
{
|
||||
LTIMING("NormalizeSourcePath");
|
||||
#ifdef PLATFORM_WIN32
|
||||
return ToLower(NormalizePath(path, currdir));
|
||||
#else
|
||||
return NormalizePath(path, currdir);
|
||||
#endif
|
||||
}
|
||||
|
||||
String NormalizeSourcePath(const String& path)
|
||||
{
|
||||
return NormalizeSourcePath(path, GetCurrentDirectory());
|
||||
}
|
||||
|
||||
void ClearSources()
|
||||
{
|
||||
sSrcFile.Clear();
|
||||
sIncludes.Clear();
|
||||
}
|
||||
|
||||
const Index<String>& GetAllSources()
|
||||
{
|
||||
return sSrcFile.GetIndex();
|
||||
}
|
||||
|
||||
const VectorMap<String, String>& GetAllSourceMasters()
|
||||
{
|
||||
return sSrcFile;
|
||||
}
|
||||
|
||||
void GatherSources(const String& master_path, const String& path_, Vector<int>& parents)
|
||||
{
|
||||
String path = NormalizeSourcePath(path_);
|
||||
LLOG("--- GatherSources " << master_path << " " << path);
|
||||
if(sSrcFile.Find(path) >= 0)
|
||||
return;
|
||||
int ii = sSrcFile.GetCount();
|
||||
for(int i = 0; i < parents.GetCount(); i++)
|
||||
sIncludes.Add(MAKEQWORD(parents[i], ii));
|
||||
sSrcFile.Add(path, master_path);
|
||||
parents.Add(ii);
|
||||
const PPFile& f = GetPPFile(path);
|
||||
Index<String> todo;
|
||||
for(String inc : f.includes) {
|
||||
String p = GetIncludePath(inc, GetFileFolder(path));
|
||||
if(p.GetCount())
|
||||
todo.FindAdd(p);
|
||||
}
|
||||
MakePP(todo); // parse PP files in parallel to accelerate things...
|
||||
for(String p : todo)
|
||||
GatherSources(master_path, p, parents);
|
||||
parents.Drop();
|
||||
}
|
||||
|
||||
void GatherSources(const String& path)
|
||||
{
|
||||
LTIMING("GatherSources");
|
||||
Vector<int> parents;
|
||||
LLOG("=== GatherSources " << path);
|
||||
MakePP({ NormalizeSourcePath(path) });
|
||||
GatherSources(NormalizeSourcePath(path), path, parents);
|
||||
}
|
||||
|
||||
String GetMasterFile(const String& file)
|
||||
{
|
||||
return sSrcFile.Get(file, Null);
|
||||
}
|
||||
|
||||
bool IncludesFile(const String& parent_path, const String& header_path)
|
||||
{
|
||||
LTIMING("IncludesFile");
|
||||
int pi = sSrcFile.Find(parent_path);
|
||||
int i = sSrcFile.Find(header_path);
|
||||
return pi >= 0 && i >= 0 && sIncludes.Find(MAKEQWORD(pi, i)) >= 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
#include "CppBase.h"
|
||||
#include "Internal.h"
|
||||
|
||||
namespace Upp {
|
||||
|
||||
bool IsCPPFile(const String& path)
|
||||
{
|
||||
return findarg(ToLower(GetFileExt(path)) , ".c", ".cpp", ".cc" , ".cxx", ".icpp") >= 0;
|
||||
}
|
||||
|
||||
bool IsHFile(const String& path)
|
||||
{
|
||||
return findarg(ToLower(GetFileExt(path)) , ".h", ".hpp", ".hxx" , ".hh") >= 0;
|
||||
}
|
||||
|
||||
void SetSpaces(String& l, int pos, int count)
|
||||
{
|
||||
StringBuffer s(l);
|
||||
memset(~s + pos, ' ', count);
|
||||
l = s;
|
||||
}
|
||||
|
||||
const char *SkipString(const char *s)
|
||||
{
|
||||
CParser p(s);
|
||||
try {
|
||||
p.ReadOneString(*s);
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
s = p.GetPtr();
|
||||
while((byte)*(s - 1) <= ' ')
|
||||
s--;
|
||||
return s;
|
||||
}
|
||||
|
||||
void RemoveComments(String& l, bool& incomment)
|
||||
{
|
||||
int q = -1;
|
||||
int w = -1;
|
||||
if(incomment)
|
||||
q = w = 0;
|
||||
else {
|
||||
const char *s = l;
|
||||
while(*s) {
|
||||
if(*s == '\"')
|
||||
s = SkipString(s);
|
||||
else
|
||||
if(s[0] == '/' && s[1] == '/') {
|
||||
q = int(s - ~l);
|
||||
SetSpaces(l, q, l.GetCount() - q);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(s[0] == '/' && s[1] == '*') {
|
||||
q = int(s - ~l);
|
||||
break;
|
||||
}
|
||||
else
|
||||
s++;
|
||||
}
|
||||
if(q >= 0)
|
||||
w = q + 2;
|
||||
}
|
||||
while(q >= 0) {
|
||||
int eq = l.Find("*/", w);
|
||||
if(eq < 0) {
|
||||
incomment = true;
|
||||
SetSpaces(l, q, l.GetCount() - q);
|
||||
return;
|
||||
}
|
||||
SetSpaces(l, q, eq + 2 - q);
|
||||
incomment = false;
|
||||
q = l.Find("/*");
|
||||
w = q + 2;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
//$ class Upp::Ctrl {
|
||||
private:
|
||||
friend struct MMCtrl;
|
||||
friend struct MMImp;
|
||||
|
|
@ -31,4 +30,3 @@ public:
|
|||
void RegisterCocoaDropFormats();
|
||||
|
||||
static Rect GetScreenArea(Point pt);
|
||||
//$ };
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
//$ class Upp::TopWindow {
|
||||
protected:
|
||||
friend struct MMImp;
|
||||
|
||||
|
|
@ -22,4 +21,3 @@ public:
|
|||
Event<Bar&> WhenDockMenu;
|
||||
|
||||
void SetMainMenu(Event<Bar&> menu);
|
||||
//$ };
|
||||
|
|
@ -110,8 +110,10 @@ void Ctrl::ShutdownThreads()
|
|||
{
|
||||
Thread::BeginShutdownThreads();
|
||||
while(Thread::GetCount()) {
|
||||
Thread::TryShutdownThreads();
|
||||
ProcessEvents();
|
||||
Sleep(0);
|
||||
GuiUnlock __;
|
||||
Sleep(100);
|
||||
}
|
||||
Thread::EndShutdownThreads();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,7 +179,6 @@ Vector<int> GetPropertyInts(GdkWindow *w, const char *property);
|
|||
|
||||
#define GUIPLATFORM_KEYCODES_INCLUDE <CtrlCore/GtkKeys.h>
|
||||
|
||||
//$ struct Ctrl::Top {
|
||||
#define GUIPLATFORM_CTRL_TOP_DECLS \
|
||||
GtkWidget *window; \
|
||||
GtkIMContext *im_context; \
|
||||
|
|
@ -187,7 +186,6 @@ Vector<int> GetPropertyInts(GdkWindow *w, const char *property);
|
|||
GtkIMContext *im_context_multi; \
|
||||
int64 cursor_id; \
|
||||
int id; \
|
||||
//$ }
|
||||
|
||||
#define GUIPLATFORM_CTRL_DECLS_INCLUDE <CtrlCore/GtkCtrl.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#ifdef GUI_GTK
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#define CATCH_ERRORS 1
|
||||
|
||||
namespace Upp {
|
||||
|
|
@ -55,6 +57,8 @@ int Ctrl::scale;
|
|||
void InitGtkApp(int argc, char **argv, const char **envptr)
|
||||
{
|
||||
LLOG(rmsecs() << " InitGtkApp");
|
||||
|
||||
XInitThreads(); // otherwise there are errors despide GuiLock
|
||||
|
||||
#if GTK_CHECK_VERSION(3, 10, 0)
|
||||
gdk_set_allowed_backends("x11"); // this fixes wayland issues
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
//$ namespace Upp {
|
||||
//$ class Ctrl {
|
||||
void Create(Ctrl *owner, bool popup);
|
||||
|
||||
static gboolean GtkProc(GtkWidget *widget, GdkEvent *event, gpointer user_data);
|
||||
|
|
@ -101,7 +99,7 @@ _DBG_
|
|||
static Ptr<Ctrl> activeCtrl;
|
||||
static bool invalids; // there are active invalid areas
|
||||
|
||||
static int FindId(int id);
|
||||
static int FindGtkId(int id);
|
||||
static int FindCtrl(Ctrl *ctrl);
|
||||
static int FindGtkWindow(GtkWidget *gtk);
|
||||
static int FindGdkWindow(GdkWindow *gdk);
|
||||
|
|
@ -213,5 +211,3 @@ public:
|
|||
GtkWindow *gtk() const;
|
||||
|
||||
static GdkFilterReturn RootKeyFilter(GdkXEvent *xevent, GdkEvent *event, gpointer data);
|
||||
|
||||
//$ }};
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ Tuple2<int, const char *> xEvent[] = {
|
|||
|
||||
Ctrl *Ctrl::GetTopCtrlFromId(int id)
|
||||
{
|
||||
int q = FindId(id);
|
||||
int q = FindGtkId(id);
|
||||
if(q >= 0) {
|
||||
Ctrl *p = wins[q].ctrl;
|
||||
if(p && p->top)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
//$ class Upp::TopWindow : Ctrl {
|
||||
ImageGdk gdk_icon;
|
||||
ImageGdk gdk_largeicon;
|
||||
bool topmost;
|
||||
|
|
@ -12,4 +11,3 @@
|
|||
static gboolean StateEvent(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data);
|
||||
|
||||
friend class Ctrl;
|
||||
//$ };
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ Ptr<Ctrl> Ctrl::activeCtrl;
|
|||
|
||||
bool Ctrl::invalids;
|
||||
|
||||
int Ctrl::FindId(int id)
|
||||
int Ctrl::FindGtkId(int id)
|
||||
{
|
||||
for(int i = 0; i < wins.GetCount(); i++)
|
||||
if(wins[i].id == id)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
//$ namespace Upp {
|
||||
//$ class Ctrl {
|
||||
private:
|
||||
bool activex:1;
|
||||
bool isdhctrl:1;
|
||||
|
|
@ -74,5 +72,3 @@ public:
|
|||
static void InitWin32(HINSTANCE hinst);
|
||||
static void ExitWin32();
|
||||
static void GuiFlush() { ::GdiFlush(); }
|
||||
//$ };
|
||||
//$ };
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
//$ class Upp::TopWindow {
|
||||
public:
|
||||
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
|
|
@ -16,4 +15,3 @@ public:
|
|||
dword GetStyle() const { return style; }
|
||||
TopWindow& ExStyle(dword _exstyle);
|
||||
dword GetExStyle() const { return exstyle; }
|
||||
//$ };
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
//$ namespace Upp {
|
||||
//$ class Ctrl {
|
||||
bool ignoretakefocus:1;
|
||||
protected:
|
||||
struct XWindow {
|
||||
|
|
@ -110,4 +108,3 @@ public:
|
|||
static void InitX11(const char *display);
|
||||
static void ExitX11();
|
||||
static void GuiFlush() { XFlush(Xdisplay); }
|
||||
//$ }};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
//$ class Upp::TopWindow {
|
||||
protected:
|
||||
virtual void EventProc(XWindow& w, XEvent *event);
|
||||
private:
|
||||
|
|
@ -20,4 +19,4 @@ private:
|
|||
WString title2;
|
||||
|
||||
static Rect windowFrameMargin;
|
||||
//$ };
|
||||
|
||||
|
|
|
|||
|
|
@ -2742,7 +2742,8 @@ should terminate.&]
|
|||
s]()&]
|
||||
[s2; Similiar to Thread`::ShutdownThreads, but as part of waiting
|
||||
for threads to finish calls ProcessEvents so that any Call methods
|
||||
can finish.&]
|
||||
can finish and also periodically unlocks GuiLock so that threads
|
||||
waiting on it can finish.&]
|
||||
[s3;%- &]
|
||||
[s4;%- &]
|
||||
[s5;:Ctrl`:`:GetEventId`(`):%- [@(0.0.255) static] [_^int64^ int64]_[* GetEventId]()&]
|
||||
|
|
|
|||
|
|
@ -2165,7 +2165,6 @@ void ArrayCtrl::AddHeading(const Value& v)
|
|||
DisableLine(ii);
|
||||
}
|
||||
|
||||
//$-
|
||||
#define E__Addv(I) Set0(q, I - 1, p##I)
|
||||
#define E__AddF(I) \
|
||||
void ArrayCtrl::Add(__List##I(E__Value)) { \
|
||||
|
|
@ -2174,7 +2173,6 @@ void ArrayCtrl::Add(__List##I(E__Value)) { \
|
|||
AfterSet(q); \
|
||||
}
|
||||
__Expand(E__AddF)
|
||||
//$+
|
||||
|
||||
void ArrayCtrl::Insert(int i, int count) {
|
||||
if(i < array.GetCount()) {
|
||||
|
|
|
|||
|
|
@ -490,10 +490,8 @@ public:
|
|||
void Add(Vector<Value>&& v) { Set(array.GetCount(), pick(v)); }
|
||||
void Add(const Nuller& null) { Add((Value)Null); }
|
||||
void Add(const VectorMap<String, Value>& m);
|
||||
//$-void Add(const Value& [, const Value& ]...);
|
||||
template <typename... Args>
|
||||
void Add(const Args& ...args) { Add(gather<Vector<Value>>(args...)); }
|
||||
//$+
|
||||
|
||||
void SetMap(int i, const ValueMap& m);
|
||||
void AddMap(const ValueMap& m);
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ protected:
|
|||
ATTR_NULLTEXT,
|
||||
ATTR_NULLINK,
|
||||
ATTR_NULLFONT,
|
||||
ATTR_BACKGROUND,
|
||||
ATTR_LAST,
|
||||
};
|
||||
|
||||
|
|
@ -238,6 +239,7 @@ public:
|
|||
EditField& SetCharset(byte cs) { charset = cs; return *this; }
|
||||
EditField& SetFont(Font _font);
|
||||
EditField& SetColor(Color c);
|
||||
EditField& SetBackground(Color c);
|
||||
EditField& ClickSelect(bool b = true) { clickselect = b; return *this; }
|
||||
bool IsClickSelect() const { return clickselect; }
|
||||
EditField& InitCaps(bool b = true) { initcaps = b; return *this; }
|
||||
|
|
|
|||
|
|
@ -295,8 +295,11 @@ void EditField::State(int)
|
|||
Color EditField::GetPaper()
|
||||
{
|
||||
bool enabled = IsShowEnabled();
|
||||
Color paper = enabled && !IsReadOnly() ? (HasFocus() ? style->focus : style->paper)
|
||||
: style->disabled;
|
||||
Color paper = GetColorAttr(ATTR_BACKGROUND);
|
||||
if(IsNull(paper))
|
||||
paper = enabled && !IsReadOnly() ? (HasFocus() ? style->focus
|
||||
: style->paper)
|
||||
: style->disabled;
|
||||
if(nobg)
|
||||
paper = Null;
|
||||
if(enabled && (convert && convert->Scan(text).IsError() || errorbg))
|
||||
|
|
@ -1068,8 +1071,19 @@ EditField& EditField::SetFont(Font _font)
|
|||
|
||||
EditField& EditField::SetColor(Color c)
|
||||
{
|
||||
SetColorAttr(ATTR_TEXTCOLOR, c);
|
||||
Refresh();
|
||||
if(GetColorAttr(ATTR_TEXTCOLOR) != c) {
|
||||
SetColorAttr(ATTR_TEXTCOLOR, c);
|
||||
Refresh();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
EditField& EditField::SetBackground(Color c)
|
||||
{
|
||||
if(GetColorAttr(ATTR_BACKGROUND) != c) {
|
||||
SetColorAttr(ATTR_BACKGROUND, c);
|
||||
Refresh();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,12 @@ bool HelpWindow::GoTo0(const String& link)
|
|||
FinishText(txt);
|
||||
view.Pick(pick(txt), zoom);
|
||||
current_link = link;
|
||||
return view.GotoLabel(label, true);;
|
||||
if(WhenMatchLabel) {
|
||||
WString lw = label.ToWString();
|
||||
return view.GotoLabel([=](const WString& data) { return WhenMatchLabel(data, lw); }, true);
|
||||
}
|
||||
else
|
||||
return view.GotoLabel(label, true);;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ public:
|
|||
Zoom GetZoom() const;
|
||||
Rect GetPage() const;
|
||||
|
||||
bool GotoLabel(Gate<const WString&> match, bool dohighlight = false);
|
||||
bool GotoLabel(const String& lbl, bool highlight = false);
|
||||
void ClearHighlight() { highlight = Null; Refresh(); }
|
||||
|
||||
|
|
@ -318,6 +319,8 @@ public:
|
|||
virtual Topic AcquireTopic(const String& topic);
|
||||
virtual void FinishText(RichText& text);
|
||||
virtual void BarEx(Bar& bar);
|
||||
|
||||
Gate<const WString&, const WString&> WhenMatchLabel;
|
||||
|
||||
bool GoTo(const String& link);
|
||||
|
||||
|
|
|
|||
|
|
@ -317,13 +317,12 @@ void RichTextView::Scroll()
|
|||
scroller.Scroll(*this, Rect(GetSize()).Deflated(margin), sb * GetZoom());
|
||||
}
|
||||
|
||||
bool RichTextView::GotoLabel(const String& lbl, bool dohighlight)
|
||||
bool RichTextView::GotoLabel(Gate<const WString&> match, bool dohighlight)
|
||||
{
|
||||
Vector<RichValPos> f = text.GetValPos(GetPage(), RichText::LABELS);
|
||||
highlight = Null;
|
||||
WString lw = lbl.ToWString();
|
||||
for(int i = 0; i < f.GetCount(); i++) {
|
||||
if(f[i].data == lw) {
|
||||
if(match(f[i].data)) {
|
||||
sb = f[i].py.y;
|
||||
if(dohighlight)
|
||||
highlight = f[i].pos;
|
||||
|
|
@ -334,6 +333,12 @@ bool RichTextView::GotoLabel(const String& lbl, bool dohighlight)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool RichTextView::GotoLabel(const String& lbl, bool dohighlight)
|
||||
{
|
||||
WString lw = lbl.ToWString();
|
||||
return GotoLabel([&](const WString& data) { return data == lw; }, dohighlight);
|
||||
}
|
||||
|
||||
void RichTextView::Clear()
|
||||
{
|
||||
sb = 0;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
topic "EditField";
|
||||
[2 $$0,0#00000000000000000000000000000000:Default]
|
||||
[i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class]
|
||||
[l288;2 $$2,0#27521748481378242620020725143825:desc]
|
||||
[0 $$3,0#96390100711032703541132217272105:end]
|
||||
|
|
@ -9,6 +8,7 @@ topic "EditField";
|
|||
[l288;i1121;b17;O9;~~~.1408;2 $$7,0#10431211400427159095818037425705:param]
|
||||
[i448;b42;O9;2 $$8,8#61672508125594000341940100500538:tparam]
|
||||
[b42;2 $$9,9#13035079074754324216151401829390:normal]
|
||||
[2 $$0,0#00000000000000000000000000000000:Default]
|
||||
[{_}
|
||||
[ {{10000@3 [s0;%% [*@(229)4 EditField]]}}&]
|
||||
[s3; &]
|
||||
|
|
@ -279,6 +279,11 @@ olor]_[*@3 c])&]
|
|||
[s2;%% [%- Sets the color] of displayed text. Returns `*this.&]
|
||||
[s3;%% &]
|
||||
[s4; &]
|
||||
[s5;:Upp`:`:EditField`:`:SetBackground`(Upp`:`:Color`): EditField[@(0.0.255) `&]
|
||||
[* SetBackground](Color [*@3 c])&]
|
||||
[s2;%% Sets the background color. Returns `*this.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:EditField`:`:ClickSelect`(bool`): [_^EditField^ EditField][@(0.0.255) `&]_[* ClickSele
|
||||
ct]([@(0.0.255) bool]_[*@3 b]_`=_[@(0.0.255) true])&]
|
||||
[s2; In ClickSelect mode, all the text of EditField is select when
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//#BLITZ_APPROVE
|
||||
|
||||
//$-
|
||||
|
||||
#define IMAGE_META(k, v)
|
||||
#define IMAGE_SCAN(s)
|
||||
#define IMAGE_PACKED(n, d)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
//#BLITZ_APPROVE
|
||||
|
||||
//$
|
||||
|
||||
#define IMAGE_META(k, v)
|
||||
|
||||
#define PREMULTIPLIED
|
||||
|
|
|
|||
|
|
@ -52,4 +52,5 @@ KEY(EMPTY_RECTANGLES, "Empty rectangles", K_T)
|
|||
KEY(HOTSPOTS, "Hotspots", K_H)
|
||||
KEY(RESIZE_SINGLE, "Resize", 0)
|
||||
KEY(TEXT, "Text", 0)
|
||||
KEY(REFERENCES, "Find references..", K_ALT_U)
|
||||
KEY(SLICE, "Slice..", 0)
|
||||
|
|
@ -443,17 +443,22 @@ void RichEdit::GotoEntry()
|
|||
GotoType(RichText::INDEXENTRIES, indexentry);
|
||||
}
|
||||
|
||||
bool RichEdit::GotoLabel(const String& lbl)
|
||||
bool RichEdit::GotoLabel(Gate<const WString&> match)
|
||||
{
|
||||
Vector<RichValPos> f = text.GetValPos(pagesz, RichText::LABELS);
|
||||
for(int i = 0; i < f.GetCount(); i++)
|
||||
if(f[i].data == WString(lbl)) {
|
||||
if(match(f[i].data)) {
|
||||
Move(f[i].pos);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RichEdit::GotoLabel(const String& lbl)
|
||||
{
|
||||
return GotoLabel([=](const WString& data) { return data == WString(lbl); });
|
||||
}
|
||||
|
||||
void RichEdit::BeginPara()
|
||||
{
|
||||
RichPos pos = text.GetRichPos(anchor);
|
||||
|
|
|
|||
|
|
@ -785,6 +785,7 @@ public:
|
|||
Value GetVar(const String& id) const { return vars.Get(id, Value()); }
|
||||
void EvaluateFields();
|
||||
|
||||
bool GotoLabel(Gate<const WString&> match);
|
||||
bool GotoLabel(const String& lbl);
|
||||
void BeginPara();
|
||||
void NextPara();
|
||||
|
|
|
|||
|
|
@ -74,11 +74,18 @@ Size SplashCtrl::MakeLogo(Ctrl& parent, Array<Ctrl>& ctrl)
|
|||
Label& v1 = ctrl.Create<Label>();
|
||||
l.SetImage(logo);
|
||||
Size sz = Size(isz.cx, isz.cy/* + 80*/);
|
||||
CodeBaseLock __;
|
||||
const CppBase& cpp = CodeBase();
|
||||
int total = 0;
|
||||
for(int i = 0; i < cpp.GetCount(); i++)
|
||||
total += cpp[i].GetCount();
|
||||
|
||||
Index<String> classes;
|
||||
Index<String> items;
|
||||
|
||||
for(const auto& f : ~CodeIndex())
|
||||
for(const AnnotationItem& m : f.value.items) {
|
||||
if(IsStruct(m.kind))
|
||||
classes.FindAdd(m.id);
|
||||
items.FindAdd(m.id);
|
||||
}
|
||||
|
||||
String h;
|
||||
h << GenerateVersionInfo() << "\n";
|
||||
h << "Using: " << MemoryUsedKb()
|
||||
|
|
@ -87,8 +94,8 @@ Size SplashCtrl::MakeLogo(Ctrl& parent, Array<Ctrl>& ctrl)
|
|||
#else
|
||||
<< " KB\n";
|
||||
#endif
|
||||
if(cpp.GetCount())
|
||||
h << "CodeBase: " << cpp.GetCount() << " classes, " << total << " items\n";
|
||||
if(items.GetCount())
|
||||
h << "CodeBase: " << classes.GetCount() << " classes, " << items.GetCount() << " items\n";
|
||||
if(IsUHDMode())
|
||||
h << "UHD mode\n";
|
||||
v1 = h;
|
||||
|
|
|
|||
|
|
@ -1,29 +1,5 @@
|
|||
#include "ide.h"
|
||||
|
||||
void AssistEditor::Annotate(const String& filename)
|
||||
{
|
||||
CodeBaseLock __;
|
||||
int fi = GetSourceFileIndex(filename);
|
||||
CppBase& base = CodeBase();
|
||||
ClearAnnotations();
|
||||
for(int j = 0; j < base.GetCount(); j++) {
|
||||
String nest = base.GetKey(j);
|
||||
if(*nest != '@') { // Annotations of anonymous structures not suported
|
||||
const Array<CppItem>& n = base[j];
|
||||
for(int k = 0; k < n.GetCount(); k++) {
|
||||
const CppItem& m = n[k];
|
||||
if(m.file == fi) {
|
||||
String coderef = MakeCodeRef(nest, m.qitem);
|
||||
SetAnnotation(m.line - 1,
|
||||
GetRefLinks(coderef).GetCount() ? IdeImg::tpp_doc()
|
||||
: IdeImg::tpp_pen(),
|
||||
coderef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsCodeItem(const RichTxt& txt, int i)
|
||||
{
|
||||
static Uuid codeitem = CodeItemUuid();
|
||||
|
|
@ -61,6 +37,14 @@ bool AssistEditor::GetAnnotationRefs(Vector<String>& tl, String& coderef, int q)
|
|||
return true;
|
||||
}
|
||||
|
||||
int GetMatchLen(const char *s, const char *t)
|
||||
{
|
||||
int i = 0;
|
||||
while(s[i] == t[i] && s[i])
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
bool AssistEditor::GetAnnotationRef(String& t, String& coderef, int q)
|
||||
{
|
||||
Vector<String> tl;
|
||||
|
|
@ -95,8 +79,10 @@ void AssistEditor::SyncAnnotationPopup()
|
|||
if(path != last_path)
|
||||
topic_text = ParseQTF(ReadTopic(LoadFile(path)).text);
|
||||
RichText result;
|
||||
String cr = coderef;
|
||||
for(int pass = 0; pass < 2; pass++) {
|
||||
#ifdef _DEBUG
|
||||
result = ParseQTF("[A1 [@b* " + DeQtf(coderef) + "]&");
|
||||
#endif
|
||||
for(String cr : AnnotationCandidates(coderef)) {
|
||||
for(int i = 0; i < topic_text.GetPartCount(); i++)
|
||||
if(topic_text.IsTable(i)) {
|
||||
const RichTable& t = topic_text.GetTable(i);
|
||||
|
|
@ -105,7 +91,7 @@ void AssistEditor::SyncAnnotationPopup()
|
|||
for(int x = 0; x < sz.cx; x++) {
|
||||
const RichTxt& txt = t.Get(y, x);
|
||||
for(int i = 0; i < txt.GetPartCount(); i++) {
|
||||
if(txt.IsPara(i) && txt.Get(i, topic_text.GetStyles()).format.label == cr) {
|
||||
if(txt.IsPara(i) && CleanupTppId(txt.Get(i, topic_text.GetStyles()).format.label) == cr) {
|
||||
RichTable r(t, 1);
|
||||
result.CatPick(pick(r));
|
||||
goto done;
|
||||
|
|
@ -114,7 +100,7 @@ void AssistEditor::SyncAnnotationPopup()
|
|||
}
|
||||
}
|
||||
else
|
||||
if(IsCodeItem(topic_text, i) && topic_text.Get(i).format.label == cr) {
|
||||
if(IsCodeItem(topic_text, i) && CleanupTppId(topic_text.Get(i).format.label) == cr) {
|
||||
while(i > 0 && IsCodeItem(topic_text, i)) i--;
|
||||
if(!IsCodeItem(topic_text, i)) i++;
|
||||
while(IsCodeItem(topic_text, i))
|
||||
|
|
@ -128,11 +114,8 @@ void AssistEditor::SyncAnnotationPopup()
|
|||
result.CatPick(pick(table));
|
||||
}
|
||||
}
|
||||
pass = 2;
|
||||
break;
|
||||
goto done;
|
||||
}
|
||||
if(pass == 0 && !LegacyRef(cr))
|
||||
break;
|
||||
}
|
||||
done:
|
||||
result.SetStyles(topic_text.GetStyles());
|
||||
|
|
@ -159,6 +142,28 @@ void AssistEditor::OpenTopic(String topic, String create, bool before)
|
|||
theide->OpenTopic(topic, create, before);
|
||||
}
|
||||
|
||||
const AnnotationItem *AssistEditor::GetAnnotationPtr(const String& id)
|
||||
{
|
||||
for(const AnnotationItem& h : annotations)
|
||||
if(h.id == id)
|
||||
return &h;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SplitCodeRef(const String& s, String& scope, String& item)
|
||||
{
|
||||
int q = s.FindFirstOf("( ");
|
||||
q = q >= 0 ? s.ReverseFind(':', q) : s.ReverseFind(':');
|
||||
if(q < 0) {
|
||||
scope.Clear();
|
||||
item = s;
|
||||
}
|
||||
else {
|
||||
scope = s.Mid(0, max(q - 1, 0));
|
||||
item = s.Mid(q + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void AssistEditor::NewTopic(String group, String coderef)
|
||||
{
|
||||
if(!theide)
|
||||
|
|
@ -173,7 +178,7 @@ void AssistEditor::NewTopic(String group, String coderef)
|
|||
return;
|
||||
String scope, item;
|
||||
SplitCodeRef(coderef, scope, item);
|
||||
if(!te->NewTopicEx(IsNull(scope) ? n : Join(Split(scope, ':'), "_"), coderef))
|
||||
if(!te->NewTopicEx(IsNull(scope) ? n : Join(Split(scope, ':'), "_"), GetAnnotationPtr(coderef)))
|
||||
theide->EditFile(ef);
|
||||
}
|
||||
|
||||
|
|
@ -189,15 +194,19 @@ void AssistEditor::EditAnnotation(bool leftclick)
|
|||
if(leftclick) {
|
||||
auto GoToTopic = [&] (int i) {
|
||||
if(theide) {
|
||||
theide->doc.WhenMatchLabel = [](const WString& lbl, const WString& ref) {
|
||||
return CleanupTppId(lbl.ToString()) == ref.ToString();
|
||||
};
|
||||
theide->ShowTopics();
|
||||
if(!theide->doc.GoTo(tl[i] + '#' + coderef) && LegacyRef(coderef))
|
||||
theide->doc.GoTo(tl[i] + '#' + coderef);
|
||||
for(String cr : AnnotationCandidates(coderef))
|
||||
if(theide->doc.GoTo(tl[i] + '#' + cr))
|
||||
break;
|
||||
}
|
||||
};
|
||||
if(tl.GetCount() > 1) {
|
||||
MenuBar bar;
|
||||
for(int i = 0; i < tl.GetCount(); i++)
|
||||
bar.Add(tl[i], [&] { GoToTopic(i); });
|
||||
bar.Add(tl[i], [=] { GoToTopic(i); });
|
||||
bar.Execute();
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,41 +12,12 @@
|
|||
|
||||
#define LTIMING(x) // DTIMING(x)
|
||||
|
||||
class IndexSeparatorFrameCls : public CtrlFrame {
|
||||
virtual void FrameLayout(Rect& r) { r.right -= 1; }
|
||||
virtual void FramePaint(Draw& w, const Rect& r) {
|
||||
w.DrawRect(r.right - 1, r.top, 1, r.Height(), SColorShadow);
|
||||
}
|
||||
virtual void FrameAddSize(Size& sz) { sz.cx += 2; }
|
||||
};
|
||||
|
||||
Value AssistEditor::AssistItemConvert::Format(const Value& q) const
|
||||
{
|
||||
int ii = q;
|
||||
if(ii >= 0 && ii < editor->assist_item_ndx.GetCount()) {
|
||||
ii = editor->assist_item_ndx[ii];
|
||||
if(ii < editor->assist_item.GetCount())
|
||||
return RawToValue(editor->assist_item[ii]);
|
||||
}
|
||||
CppItemInfo empty;
|
||||
return RawToValue(empty);
|
||||
}
|
||||
|
||||
void AssistEditor::SyncNavigatorPlacement()
|
||||
{
|
||||
int sz = navigatorframe.GetSize();
|
||||
if(navigator_right)
|
||||
navigatorframe.Right(navigatorpane, sz);
|
||||
else
|
||||
navigatorframe.Left(navigatorpane, sz);
|
||||
}
|
||||
|
||||
AssistEditor::AssistEditor()
|
||||
{
|
||||
assist_convert.editor = this;
|
||||
assist_display.editor = this;
|
||||
assist.NoHeader();
|
||||
assist.NoGrid();
|
||||
assist.AddRowNumColumn().Margin(0).SetConvert(assist_convert).SetDisplay(Single<CppItemInfoDisplay>());
|
||||
assist.AddRowNumColumn().Margin(0).SetDisplay(assist_display);
|
||||
assist.NoWantFocus();
|
||||
assist.WhenLeftClick = THISBACK(AssistInsert);
|
||||
type.NoHeader();
|
||||
|
|
@ -56,7 +27,7 @@ AssistEditor::AssistEditor()
|
|||
type.NoWantFocus();
|
||||
popup.Horz(type, assist);
|
||||
popup.SetPos(2000);
|
||||
auto_assist = auto_check = true;
|
||||
auto_assist = true;
|
||||
commentdp = false;
|
||||
|
||||
SyncNavigatorPlacement();
|
||||
|
|
@ -66,10 +37,7 @@ AssistEditor::AssistEditor()
|
|||
int cy = search.GetMinSize().cy;
|
||||
navigatorpane.Add(search.TopPos(0, cy).HSizePos(0, cy + 4));
|
||||
navigatorpane.Add(sortitems.TopPos(0, cy).RightPos(0, cy));
|
||||
navigatorpane.Add(navigator_splitter.VSizePos(cy, 0).HSizePos());
|
||||
navigator_splitter.Vert() << scope << list << navlines;
|
||||
navigator_splitter.SetPos(1500, 0);
|
||||
navigator_splitter.SetPos(9500, 1);
|
||||
navigatorpane.Add(list.VSizePos(cy, 0).HSizePos());
|
||||
|
||||
navigator = true;
|
||||
|
||||
|
|
@ -81,12 +49,10 @@ AssistEditor::AssistEditor()
|
|||
annotation_popup.SetFrame(BlackFrame());
|
||||
annotation_popup.Margins(6);
|
||||
annotation_popup.NoSb();
|
||||
|
||||
thisback = false;
|
||||
|
||||
|
||||
cachedpos = INT_MAX;
|
||||
cachedln = -1;
|
||||
|
||||
|
||||
parami = 0;
|
||||
|
||||
param_info.Margins(2);
|
||||
|
|
@ -94,20 +60,45 @@ AssistEditor::AssistEditor()
|
|||
param_info.SetFrame(BlackFrame());
|
||||
param_info.BackPaint();
|
||||
param_info.NoSb();
|
||||
|
||||
|
||||
include_assist = false;
|
||||
|
||||
|
||||
NoFindReplace();
|
||||
|
||||
WhenUpdate << [=] {
|
||||
if(IsSourceFile(theide->editfile) || master_source.GetCount() || IsHeaderFile(theide->editfile)) {
|
||||
annotating = true;
|
||||
annotate_trigger.KillSet(500, [=] { SyncCurrentFile(); });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
int CppItemInfoOrder(const Value& va, const Value& vb) {
|
||||
const CppItemInfo& a = ValueTo<CppItemInfo>(va);
|
||||
const CppItemInfo& b = ValueTo<CppItemInfo>(vb);
|
||||
return CombineCompare(a.name, b.name)(a.natural, b.natural);
|
||||
class IndexSeparatorFrameCls : public CtrlFrame {
|
||||
virtual void FrameLayout(Rect& r) { r.right -= 1; }
|
||||
virtual void FramePaint(Draw& w, const Rect& r) {
|
||||
w.DrawRect(r.right - 1, r.top, 1, r.Height(), SColorShadow);
|
||||
}
|
||||
virtual void FrameAddSize(Size& sz) { sz.cx += 2; }
|
||||
};
|
||||
|
||||
void AssistEditor::SyncNavigatorPlacement()
|
||||
{
|
||||
int sz = navigatorframe.GetSize();
|
||||
if(navigator_right)
|
||||
navigatorframe.Right(navigatorpane, sz);
|
||||
else
|
||||
navigatorframe.Left(navigatorpane, sz);
|
||||
}
|
||||
|
||||
AssistEditor::~AssistEditor()
|
||||
{
|
||||
CancelAutoComplete();
|
||||
CancelCurrentFile();
|
||||
}
|
||||
|
||||
void AssistEditor::CloseAssist()
|
||||
{
|
||||
CancelAutoComplete();
|
||||
if(popup.IsOpen())
|
||||
popup.Close();
|
||||
if(annotation_popup.IsOpen())
|
||||
|
|
@ -116,6 +107,24 @@ void AssistEditor::CloseAssist()
|
|||
CloseTip();
|
||||
}
|
||||
|
||||
void AssistEditor::PostInsert(int pos, const WString& s)
|
||||
{
|
||||
if(pos < assist_cursor) {
|
||||
CancelAutoComplete();
|
||||
assist_cursor = -1;
|
||||
}
|
||||
CodeEditor::PostInsert(pos, s);
|
||||
}
|
||||
|
||||
void AssistEditor::PostRemove(int pos, int size)
|
||||
{
|
||||
if(pos < assist_cursor) {
|
||||
CancelAutoComplete();
|
||||
assist_cursor = -1;
|
||||
}
|
||||
CodeEditor::PostRemove(pos, size);
|
||||
}
|
||||
|
||||
bool isincludefnchar(int c)
|
||||
{
|
||||
return c && c != '<' && c != '>' && c != '?' &&
|
||||
|
|
@ -134,18 +143,9 @@ String AssistEditor::ReadIdBackPos(int& pos, bool include)
|
|||
return id;
|
||||
}
|
||||
|
||||
String AssistEditor::ReadIdBack(int q, bool include, bool *destructor)
|
||||
String AssistEditor::ReadIdBack(int q, bool include)
|
||||
{
|
||||
String id = ReadIdBackPos(q, include);
|
||||
if(destructor) {
|
||||
int n = 0;
|
||||
while(q > 0 && isspace(GetChar(q - 1)) && n < 100) {
|
||||
q--;
|
||||
n++;
|
||||
}
|
||||
*destructor = q > 0 && GetChar(q - 1) == '~';
|
||||
}
|
||||
return id;
|
||||
return ReadIdBackPos(q, include);
|
||||
}
|
||||
|
||||
void AssistEditor::DirtyFrom(int line)
|
||||
|
|
@ -252,105 +252,22 @@ String AssistEditor::CompleteIdBack(int& q, const Index<String>& locals)
|
|||
return id;
|
||||
}
|
||||
|
||||
Vector<String> AssistEditor::ReadBack(int q, const Index<String>& locals)
|
||||
{
|
||||
Vector<String> r;
|
||||
type.Clear();
|
||||
bool wasid = true;
|
||||
for(;;) {
|
||||
if(r.GetCount() > 200) {
|
||||
r.Clear();
|
||||
type.Clear();
|
||||
break;
|
||||
}
|
||||
SkipSpcBack(q);
|
||||
int c = Ch(q - 1);
|
||||
if(c == '>' && !wasid) {
|
||||
q--;
|
||||
r.Add() = CompleteIdBack(q, locals) + ">";
|
||||
wasid = true;
|
||||
continue;
|
||||
}
|
||||
if(iscid(c)) {
|
||||
if(wasid)
|
||||
break;
|
||||
String id;
|
||||
for(;;) {
|
||||
id = IdBack(q) + id;
|
||||
SkipSpcBack(q);
|
||||
if(!(Ch(q - 1) == ':' && Ch(q - 2) == ':'))
|
||||
break;
|
||||
q -= 2;
|
||||
id = "::" + id;
|
||||
SkipSpcBack(q);
|
||||
}
|
||||
r.Add() = id;
|
||||
wasid = true;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// if(findarg(c, '(', '[', '{') >= 0)
|
||||
// break;
|
||||
if(c == ']') {
|
||||
if(wasid)
|
||||
break;
|
||||
r.Add("[]");
|
||||
q = ParsBack(q - 1);
|
||||
wasid = false;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if(c == ')') {
|
||||
if(wasid)
|
||||
break;
|
||||
r.Add("()");
|
||||
q = ParsBack(q - 1);
|
||||
wasid = false;
|
||||
continue;
|
||||
}
|
||||
wasid = false;
|
||||
c = Ch(q - 1);
|
||||
if(c == '>' && Ch(q - 2) == '-') {
|
||||
r.Add("->");
|
||||
q -= 2;
|
||||
continue;
|
||||
}
|
||||
if(c == '.') {
|
||||
r.Add(".");
|
||||
q--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
Reverse(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
void AssistEditor::SyncAssist()
|
||||
{
|
||||
LTIMING("SyncAssist");
|
||||
bool destructor;
|
||||
String name = ReadIdBack(GetCursor32(), include_assist, &destructor);
|
||||
String name = ReadIdBack(GetCursor32(), include_assist);
|
||||
String uname = ToUpper(name);
|
||||
assist_item_ndx.Clear();
|
||||
int typei = type.GetCursor() - 1;
|
||||
Buffer<bool> found(assist_item.GetCount(), false);
|
||||
for(int pass = 0; pass < 2; pass++) {
|
||||
VectorMap<String, int> over;
|
||||
for(int i = 0; i < assist_item.GetCount(); i++) {
|
||||
const CppItemInfo& m = assist_item[i];
|
||||
const AssistItem& m = assist_item[i];
|
||||
if(!found[i] &&
|
||||
(typei < 0 || m.typei == typei) &&
|
||||
(pass ? m.uname.StartsWith(uname) : m.name.StartsWith(name)) &&
|
||||
(!destructor || m.kind == DESTRUCTOR && m.scope == current_type + "::")) {
|
||||
int q = include_assist ? -1 : over.Find(m.qitem);
|
||||
if(q < 0 || over[q] == m.typei && m.scope.GetCount()) {
|
||||
found[i] = true;
|
||||
assist_item_ndx.Add(i);
|
||||
if(q < 0)
|
||||
over.Add(m.qitem, m.typei);
|
||||
}
|
||||
((pass ? m.uname.StartsWith(uname) : m.name.StartsWith(name)) || m.kind == KIND_ERROR)) {
|
||||
found[i] = true;
|
||||
assist_item_ndx.Add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -426,22 +343,23 @@ bool AssistEditor::IncludeAssist()
|
|||
String fn = folder[i];
|
||||
if(fnset.Find(fn) < 0) {
|
||||
fnset.Add(fn);
|
||||
CppItemInfo& f = assist_item.Add();
|
||||
f.name = f.natural = fn;
|
||||
f.access = 0;
|
||||
AssistItem& f = assist_item.Add();
|
||||
f.name = f.pretty = fn;
|
||||
f.uname = ToUpper(f.name);
|
||||
f.kind = KIND_INCLUDEFOLDER;
|
||||
}
|
||||
}
|
||||
IndexSort(upper_file, file);
|
||||
for(int i = 0; i < file.GetCount(); i++) {
|
||||
String fn = file[i];
|
||||
CppItemInfo& f = assist_item.Add();
|
||||
f.name = f.natural = fn;
|
||||
f.access = 0;
|
||||
AssistItem& f = assist_item.Add();
|
||||
f.name = f.pretty = fn;
|
||||
f.uname = ToUpper(f.name);
|
||||
static Index<String> hdr(Split(".h;.hpp;.hh;.hxx", ';'));
|
||||
String fext = GetFileExt(fn);
|
||||
f.kind = hdr.Find(ToLower(GetFileExt(fn))) >= 0 || fext.GetCount() == 0 ? KIND_INCLUDEFILE
|
||||
: KIND_INCLUDEFILE_ANY;
|
||||
f.priority = 0;
|
||||
}
|
||||
include_assist = true;
|
||||
if(include_path.GetCount())
|
||||
|
|
@ -450,81 +368,124 @@ bool AssistEditor::IncludeAssist()
|
|||
return true;
|
||||
}
|
||||
|
||||
void AssistEditor::Assist()
|
||||
CurrentFileContext AssistEditor::CurrentContext(int pos)
|
||||
{
|
||||
CurrentFileContext cfx;
|
||||
cfx.filename = cfx.real_filename = NormalizePath(theide->editfile);
|
||||
cfx.includes = theide->GetCurrentIncludePath();
|
||||
cfx.defines = theide->GetCurrentDefines();
|
||||
if(!IsView() && GetLength() < 4000000) {
|
||||
cfx.content = Get(0, min(GetLength(), pos));
|
||||
if(!IsSourceFile(cfx.filename)) {
|
||||
if(master_source.GetCount()) {
|
||||
MakeIncludeTrick(cfx);
|
||||
cfx.filename = master_source;
|
||||
}
|
||||
else
|
||||
if(!IsHeaderFile(cfx.filename)) {
|
||||
cfx.content.Clear();
|
||||
cfx.is_source_file = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
if(cfx.content.GetCount())
|
||||
SaveFile(ConfigFile("CurrentContext.cpp"), cfx.content);
|
||||
#endif
|
||||
return cfx;
|
||||
}
|
||||
|
||||
void AssistEditor::SetAnnotations(const CppFileInfo& f)
|
||||
{
|
||||
ClearAnnotations();
|
||||
annotations.Clear();
|
||||
references.Clear();
|
||||
for(const AnnotationItem& m : f.items) {
|
||||
annotations.Add(m);
|
||||
SetAnnotation(m.pos.y,
|
||||
GetRefLinks(m.id).GetCount() ? IdeImg::tpp_doc()
|
||||
: IdeImg::tpp_pen(),
|
||||
m.id);
|
||||
}
|
||||
references = clone(f.refs);
|
||||
locals = clone(f.locals);
|
||||
annotating = false;
|
||||
if(!navigator_global)
|
||||
Search();
|
||||
SyncCursor();
|
||||
}
|
||||
|
||||
void AssistEditor::SyncCurrentFile(const CurrentFileContext& cfx)
|
||||
{
|
||||
if(cfx.content.GetCount())
|
||||
SetCurrentFile(cfx, [=](const CppFileInfo& f) { SetAnnotations(f); });
|
||||
}
|
||||
|
||||
void AssistEditor::SyncCurrentFile()
|
||||
{
|
||||
if(is_source_file) {
|
||||
int line_delta;
|
||||
CurrentFileContext cfx = CurrentContext();
|
||||
SyncCurrentFile(cfx);
|
||||
}
|
||||
}
|
||||
|
||||
void AssistEditor::NewFile(bool reloading)
|
||||
{
|
||||
annotations.Clear();
|
||||
references.Clear();
|
||||
Search();
|
||||
SyncMaster();
|
||||
CurrentFileContext cfx = CurrentContext();
|
||||
|
||||
if(!reloading)
|
||||
is_source_file = cfx.is_source_file;
|
||||
|
||||
if(is_source_file) {
|
||||
// DLOG("=============");
|
||||
// DDUMP(cfx.real_filename);
|
||||
annotating = true;
|
||||
int q = CodeIndex().Find(cfx.real_filename);
|
||||
// DDUMP(q);
|
||||
if(q >= 0) {
|
||||
const FileAnnotation& f = CodeIndex()[q];
|
||||
SetAnnotations(f);
|
||||
// DDUMP(f.time);
|
||||
if(f.defines == cfx.defines && f.includes == cfx.includes && f.time >= GetFileTime(cfx.real_filename)) {
|
||||
annotating = false;
|
||||
PutVerbose(cfx.real_filename + " annotations loaded from index");
|
||||
}
|
||||
}
|
||||
SyncCurrentFile(cfx);
|
||||
}
|
||||
}
|
||||
|
||||
void AssistEditor::Assist(bool macros)
|
||||
{
|
||||
LTIMING("Assist");
|
||||
if(!assist_active)
|
||||
return;
|
||||
CloseAssist();
|
||||
int q = GetCursor32();
|
||||
assist_cursor = q;
|
||||
assist_type.Clear();
|
||||
assist_item.Clear();
|
||||
include_assist = false;
|
||||
if(IncludeAssist())
|
||||
return;
|
||||
ParserContext parser;
|
||||
Context(parser, GetCursor32());
|
||||
Index<String> in_types;
|
||||
while(iscid(Ch(q - 1)) || Ch(q - 1) == '~')
|
||||
q--;
|
||||
SkipSpcBack(q);
|
||||
thisback = false;
|
||||
current_type.Clear();
|
||||
LTIMING("Assist2");
|
||||
if(Ch(q - 1) == '(') {
|
||||
int qq = q - 1;
|
||||
String id = IdBack(qq);
|
||||
int tn = findarg(id, "THISBACK", "THISBACK1", "THISBACK2", "THISBACK3", "THISBACK4");
|
||||
if(tn >= 0) {
|
||||
thisback = true;
|
||||
thisbackn = tn > 0;
|
||||
GatherItems(parser.current_scope, false, in_types, false);
|
||||
RemoveDuplicates();
|
||||
|
||||
int pos = GetCursor();
|
||||
ReadIdBackPos(pos, false); // libclang does not work well if file is not truncated for autocomplete (?)
|
||||
assist_cursor = pos;
|
||||
CurrentFileContext cfx = CurrentContext(pos);
|
||||
int line = GetLinePos(pos);
|
||||
if(cfx.content.GetCount())
|
||||
StartAutoComplete(cfx, line + cfx.line_delta + 1, pos + 1, macros, [=](const Vector<AutoCompleteItem>& items) {
|
||||
for(const AutoCompleteItem& m : items) {
|
||||
AssistItem& f = assist_item.Add();
|
||||
(AutoCompleteItem&)f = m;
|
||||
f.uname = ToUpper(f.name);
|
||||
f.typei = assist_type.FindAdd(f.parent);
|
||||
}
|
||||
PopUpAssist();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(Ch(q - 1) == ':' && Ch(q - 2) == ':') {
|
||||
q -= 2;
|
||||
Vector<String> tparam;
|
||||
String scope = ParseTemplatedType(Qualify(parser.current_scope,
|
||||
CompleteIdBack(q, parser.local.GetIndex()),
|
||||
parser.context.namespace_using),
|
||||
tparam);
|
||||
GatherItems(scope, false, in_types, true);
|
||||
current_type = scope;
|
||||
}
|
||||
else {
|
||||
String tp;
|
||||
Vector<String> xp = ReadBack(q, parser.local.GetIndex());
|
||||
bool isok = false;
|
||||
if(xp.GetCount() && xp[0].StartsWith("::")) // ::Foo().
|
||||
xp[0] = xp[0].Mid(2);
|
||||
for(int i = 0; i < xp.GetCount(); i++)
|
||||
if(iscib(*xp[i])) {
|
||||
isok = true;
|
||||
break;
|
||||
}
|
||||
if(xp.GetCount()) {
|
||||
if(isok) { // Do nothing on pressing '.' when there is no identifier before
|
||||
Index<String> typeset = EvaluateExpressionType(parser, xp);
|
||||
for(int i = 0; i < typeset.GetCount(); i++)
|
||||
if(typeset[i].GetCount())
|
||||
GatherItems(typeset[i], xp[0] != "this", in_types, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
GatherItems(parser.current_scope, false, in_types, true);
|
||||
Vector<String> ns = parser.GetNamespaces();
|
||||
for(int i = 0; i < ns.GetCount(); i++)
|
||||
if(parser.current_scope != ns[i]) // Do not scan namespace already scanned
|
||||
GatherItems(ns[i], false, in_types, true);
|
||||
}
|
||||
}
|
||||
LTIMING("Assist3");
|
||||
RemoveDuplicates();
|
||||
PopUpAssist();
|
||||
});
|
||||
}
|
||||
|
||||
Ptr<Ctrl> AssistEditor::assist_ptr;
|
||||
|
|
@ -541,8 +502,19 @@ bool AssistEditor::WheelHook(Ctrl *, bool inframe, int event, Point p, int zdelt
|
|||
void AssistEditor::PopUpAssist(bool auto_insert)
|
||||
{
|
||||
LTIMING("PopUpAssist");
|
||||
if(assist_item.GetCount() == 0)
|
||||
int pos = GetCursor();
|
||||
ReadIdBackPos(pos, false);
|
||||
if(pos != assist_cursor)
|
||||
return;
|
||||
|
||||
if(assist_item.GetCount() == 0) {
|
||||
AssistItem& m = assist_item.Add();
|
||||
m.kind = KIND_ERROR;
|
||||
m.pretty = "No relevant autocomplete info found";
|
||||
}
|
||||
Upp::Sort(assist_item, [=](const AssistItem& a, const AssistItem& b) {
|
||||
return CombineCompare(a.priority, b.priority)(a.uname, b.uname) < 0;
|
||||
});
|
||||
int lcy = max(16, BrowserFont().Info().GetHeight());
|
||||
type.Clear();
|
||||
type.Add(AttrText("<all>").Ink(SColorHighlight()));
|
||||
|
|
@ -562,8 +534,6 @@ void AssistEditor::PopUpAssist(bool auto_insert)
|
|||
popup.NoZoom();
|
||||
}
|
||||
type.SetCursor(0);
|
||||
if(!assist.GetCount())
|
||||
return;
|
||||
LTIMING("PopUpAssist2");
|
||||
int cy = VertLayoutZoom(304);
|
||||
cy += HeaderCtrl::GetStdHeight();
|
||||
|
|
@ -595,6 +565,9 @@ bool sILess(const String& a, const String& b)
|
|||
|
||||
void AssistEditor::Complete()
|
||||
{
|
||||
if(!is_source_file)
|
||||
return;
|
||||
|
||||
CloseAssist();
|
||||
|
||||
int c = GetCursor32();
|
||||
|
|
@ -620,7 +593,7 @@ void AssistEditor::Complete()
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector<String> id = ids.PickKeys();
|
||||
Upp::Sort(id, sILess);
|
||||
|
||||
|
|
@ -645,10 +618,9 @@ void AssistEditor::Complete()
|
|||
Paste(h.Mid(q.GetCount()).ToWString());
|
||||
}
|
||||
for(int i = 0; i < id.GetCount(); i++) {
|
||||
CppItemInfo& f = assist_item.Add();
|
||||
f.name = f.natural = f.qitem = id[i];
|
||||
f.access = 0;
|
||||
f.kind = 100;
|
||||
AssistItem& f = assist_item.Add();
|
||||
f.name = f.pretty = id[i];
|
||||
f.kind = KIND_COMPLETE;
|
||||
}
|
||||
assist_type.Clear();
|
||||
PopUpAssist(true);
|
||||
|
|
@ -706,7 +678,7 @@ void AssistEditor::AssistInsert()
|
|||
IgnoreMouseUp();
|
||||
return;
|
||||
}
|
||||
const CppItemInfo& f = assist_item[ii];
|
||||
const AssistItem& f = assist_item[ii];
|
||||
if(include_assist) {
|
||||
int ln = GetLine(GetCursor32());
|
||||
int pos = GetPos32(ln);
|
||||
|
|
@ -722,7 +694,7 @@ void AssistEditor::AssistInsert()
|
|||
<< (f.kind == KIND_INCLUDEFOLDER ? "/" : include_local ? "\"" : ">")
|
||||
, CHARSET_WIN1250));
|
||||
if(f.kind == KIND_INCLUDEFOLDER) {
|
||||
Assist();
|
||||
Assist(false);
|
||||
IgnoreMouseUp();
|
||||
return;
|
||||
}
|
||||
|
|
@ -741,10 +713,12 @@ void AssistEditor::AssistInsert()
|
|||
}
|
||||
else {
|
||||
String txt = f.name;
|
||||
int l = txt.GetCount();
|
||||
int pl = txt.GetCount();
|
||||
if(!thisback && f.kind >= FUNCTION && f.kind <= INLINEFRIEND)
|
||||
int param_count;
|
||||
ParsePretty(f.name, f.pretty, ¶m_count);
|
||||
if(param_count >= 0)
|
||||
txt << "()";
|
||||
if(f.pretty.EndsWith("::"))
|
||||
txt << "::";
|
||||
int cl = GetCursor32();
|
||||
int ch = cl;
|
||||
while(iscid(Ch(cl - 1)))
|
||||
|
|
@ -753,40 +727,11 @@ void AssistEditor::AssistInsert()
|
|||
ch++;
|
||||
Remove(cl, ch - cl);
|
||||
SetCursor(cl);
|
||||
if(thisback)
|
||||
for(;;) {
|
||||
int c = Ch(cl++);
|
||||
if(!c || Ch(cl) == ',' || Ch(cl) == ')')
|
||||
break;
|
||||
if(c != ' ') {
|
||||
if(thisbackn)
|
||||
txt << ", ";
|
||||
txt << ')';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(findarg(f.kind, CONSTRUCTOR, DESTRUCTOR) >= 0)
|
||||
txt << "()";
|
||||
int n = Paste(ToUnicode(txt, CHARSET_WIN1250));
|
||||
if(!thisback && f.kind >= FUNCTION && f.kind <= INLINEFRIEND) {
|
||||
if(param_count > 0) {
|
||||
SetCursor(GetCursor32() - 1);
|
||||
StartParamInfo(f, cl);
|
||||
if(f.natural.EndsWith("()"))
|
||||
SetCursor(GetCursor32() + 1);
|
||||
}
|
||||
else
|
||||
if(thisback) {
|
||||
if(thisbackn)
|
||||
SetCursor(GetCursor32() - 1);
|
||||
}
|
||||
else
|
||||
if(!inbody)
|
||||
SetCursor(cl + n - thisbackn);
|
||||
else
|
||||
if(pl > l)
|
||||
SetSelection(cl + l, cl + pl);
|
||||
else
|
||||
SetCursor(cl + l);
|
||||
}
|
||||
}
|
||||
CloseAssist();
|
||||
|
|
@ -855,7 +800,7 @@ bool AssistEditor::Key(dword key, int count)
|
|||
if(b) {
|
||||
CloseAssist();
|
||||
if(include_assist ? (key == '/' || key == '\\') : key == '.')
|
||||
Assist();
|
||||
Assist(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -866,17 +811,10 @@ bool AssistEditor::Key(dword key, int count)
|
|||
if(InCode()) {
|
||||
if(key == '.' || key == '>' && Ch(GetCursor32() - 2) == '-' ||
|
||||
key == ':' && Ch(GetCursor32() - 2) == ':')
|
||||
Assist();
|
||||
else
|
||||
if(key == '(') {
|
||||
int q = GetCursor32() - 1;
|
||||
String id = IdBack(q);
|
||||
if(id == "THISBACK" || id == "THISBACK1" || id == "THISBACK2" || id == "THISBACK3" || id == "THISBACK4")
|
||||
Assist();
|
||||
}
|
||||
Assist(false);
|
||||
}
|
||||
if((key == '\"' || key == '<' || key == '/' || key == '\\') && GetUtf8Line(GetCursorLine()).StartsWith("#include"))
|
||||
Assist();
|
||||
Assist(false);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
|
@ -903,115 +841,6 @@ void AssistEditor::LostFocus()
|
|||
CloseAssist();
|
||||
}
|
||||
|
||||
String AssistEditor::RemoveDefPar(const char *s)
|
||||
{
|
||||
String r;
|
||||
int lvl = 0;
|
||||
bool dp = true;
|
||||
while(*s) {
|
||||
byte c = *s++;
|
||||
if(c == '(')
|
||||
lvl++;
|
||||
if(lvl == 0) {
|
||||
if(c == '=') {
|
||||
dp = false;
|
||||
if(commentdp)
|
||||
r.Cat("/* ");
|
||||
else
|
||||
while(r.GetCount() && *r.Last() == ' ')
|
||||
r.Trim(r.GetCount() - 1);
|
||||
}
|
||||
if(c == ')') {
|
||||
if(!dp && commentdp)
|
||||
r.Cat("*/");
|
||||
r.Cat(')');
|
||||
try {
|
||||
if(CParser(s).Char('='))
|
||||
break;
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
r.Cat(s);
|
||||
break;
|
||||
}
|
||||
if(c == ',') {
|
||||
if(!dp && commentdp)
|
||||
r.Cat("*/");
|
||||
dp = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
if(c == ')')
|
||||
lvl--;
|
||||
if(dp || commentdp)
|
||||
r.Cat(c);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
String AssistEditor::MakeDefinition(const String& cls, const String& _n)
|
||||
{
|
||||
String n = TrimLeft(_n);
|
||||
auto RemoveId = [&](const char *s) {
|
||||
int len = strlen(s);
|
||||
int q = n.Find(s);
|
||||
if(q >= 0 && (q == 0 || !iscid(n[q - 1])) && (q + len >= n.GetCount() || !iscid(n[q + len])))
|
||||
n.Remove(q, len);
|
||||
};
|
||||
RemoveId("override");
|
||||
RemoveId("final");
|
||||
CParser p(n);
|
||||
try {
|
||||
bool dest = false;
|
||||
const char *beg = n;
|
||||
while(!p.IsEof()) {
|
||||
const char *b = p.GetPtr();
|
||||
if(p.Id("operator"))
|
||||
return cls.GetCount() ? NormalizeSpaces(String(beg, b) + ' ' + cls + "::" + b)
|
||||
: NormalizeSpaces(String(beg, b) + ' ' + b);
|
||||
if(p.Char('~')) {
|
||||
beg = p.GetPtr();
|
||||
dest = true;
|
||||
}
|
||||
else
|
||||
if(p.IsId()) {
|
||||
String id = p.ReadId();
|
||||
if(p.Char('(')) {
|
||||
String rp = RemoveDefPar(p.GetPtr());
|
||||
auto merge = [](String a, String b) {
|
||||
return IsAlNum(*a.Last()) && IsAlNum(*b) ? a + ' ' + b : a + b;
|
||||
};
|
||||
if(cls.GetCount() == 0)
|
||||
return NormalizeSpaces(merge(String(beg, b), id) + '(' + rp);
|
||||
if(dest)
|
||||
return NormalizeSpaces(String(beg, b) + cls + "::~" + id + '(' + rp);
|
||||
else
|
||||
return NormalizeSpaces(merge(String(beg, b), cls) + "::" + id + '(' + rp);
|
||||
}
|
||||
}
|
||||
else
|
||||
p.SkipTerm();
|
||||
}
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
return n;
|
||||
}
|
||||
|
||||
void Ide::IdeGotoCodeRef(String coderef)
|
||||
{
|
||||
LLOG("IdeGotoLink " << coderef);
|
||||
CodeBaseLock __;
|
||||
if(IsNull(coderef)) return;
|
||||
String scope, item;
|
||||
SplitCodeRef(coderef, scope, item);
|
||||
int q = CodeBase().Find(scope);
|
||||
if(q < 0)
|
||||
return;
|
||||
const Array<CppItem>& n = CodeBase()[q];
|
||||
q = FindItem(n, item);
|
||||
if(q >= 0)
|
||||
JumpToDefinition(n, q, scope);
|
||||
}
|
||||
|
||||
bool AssistEditor::Esc()
|
||||
{
|
||||
bool r = false;
|
||||
|
|
@ -1019,9 +848,9 @@ bool AssistEditor::Esc()
|
|||
CloseAssist();
|
||||
r = true;
|
||||
}
|
||||
for(int i = 0; i < PARAMN; i++)
|
||||
param[i].line = -1;
|
||||
if(param_info.IsOpen()) {
|
||||
for(int i = 0; i < PARAMN; i++)
|
||||
param[i].line = -1;
|
||||
param_info.Close();
|
||||
r = true;
|
||||
}
|
||||
|
|
@ -1064,7 +893,7 @@ void AssistEditor::SelectionChanged()
|
|||
|
||||
void AssistEditor::SerializeNavigator(Stream& s)
|
||||
{
|
||||
int version = 5;
|
||||
int version = 6;
|
||||
s / version;
|
||||
s % navigatorframe;
|
||||
s % navigator;
|
||||
|
|
@ -1072,12 +901,14 @@ void AssistEditor::SerializeNavigator(Stream& s)
|
|||
Splitter dummy;
|
||||
s % dummy;
|
||||
}
|
||||
if(version >= 4)
|
||||
s % navigator_splitter;
|
||||
if(version >= 4 && version < 6) {
|
||||
Splitter dummy;
|
||||
s % dummy;
|
||||
}
|
||||
if(version >= 5)
|
||||
s % navigator_right;
|
||||
Navigator(navigator);
|
||||
|
||||
|
||||
if(s.IsLoading())
|
||||
SyncNavigatorPlacement();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,106 +5,53 @@ struct Navigator {
|
|||
bool impl:1;
|
||||
int file:31;
|
||||
int line;
|
||||
|
||||
|
||||
bool operator<(const NavLine& b) const;
|
||||
};
|
||||
|
||||
struct NavItem {
|
||||
String nest;
|
||||
String qitem;
|
||||
String name;
|
||||
String uname;
|
||||
String natural;
|
||||
String type;
|
||||
String pname;
|
||||
String ptype;
|
||||
String tname;
|
||||
String ctname;
|
||||
byte access;
|
||||
byte kind;
|
||||
int16 at;
|
||||
int line;
|
||||
int file;
|
||||
int decl_line; // header position
|
||||
int decl_file;
|
||||
bool impl;
|
||||
bool decl;
|
||||
int8 pass;
|
||||
Vector<NavLine> linefo;
|
||||
|
||||
void Set(const CppItem& m);
|
||||
};
|
||||
|
||||
enum KindEnum { KIND_LINE = 123, KIND_NEST, KIND_FILE, KIND_SRCFILE };
|
||||
|
||||
struct ScopeDisplay : Display {
|
||||
Navigator *navigator;
|
||||
|
||||
int DoPaint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const;
|
||||
virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const;
|
||||
virtual Size GetStdSize(const Value& q) const;
|
||||
};
|
||||
|
||||
struct LineDisplay : Display {
|
||||
int DoPaint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style, int x) const;
|
||||
virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const;
|
||||
virtual Size GetStdSize(const Value& q) const;
|
||||
enum KindEnum { KIND_LINE = -4000, KIND_NEST, KIND_FILE, KIND_SRCFILE };
|
||||
|
||||
struct NavItem : AnnotationItem {
|
||||
String path;
|
||||
};
|
||||
|
||||
struct NavigatorDisplay : Display {
|
||||
const Vector<NavItem *>& item;
|
||||
|
||||
const Vector<const NavItem *>& item;
|
||||
|
||||
int DoPaint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const;
|
||||
virtual void PaintBackground(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const;
|
||||
virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const;
|
||||
virtual Size GetStdSize(const Value& q) const;
|
||||
|
||||
NavigatorDisplay(const Vector<NavItem *>& item) : item(item) {}
|
||||
|
||||
NavigatorDisplay(const Vector<const NavItem *>& item) : item(item) {}
|
||||
};
|
||||
|
||||
Ide *theide;
|
||||
|
||||
Array<NavItem> nitem;
|
||||
VectorMap<String, Vector<NavItem *> > gitem;
|
||||
Vector<NavItem *> litem;
|
||||
Array<NavItem> nest_item;
|
||||
VectorMap<int, SortedVectorMap<int, int> > linefo;
|
||||
Vector<const NavItem *> litem;
|
||||
Array<NavItem> nest_item; // list separators with nest (scope) or file
|
||||
NavigatorDisplay navidisplay;
|
||||
bool navigating;
|
||||
bool navigating; // click on item
|
||||
TimeCallback search_trigger;
|
||||
TimeCallback annotate_trigger;
|
||||
bool navigator_global;
|
||||
ToolButton sortitems;
|
||||
bool sorting;
|
||||
bool dlgmode;
|
||||
|
||||
ArrayCtrl scope;
|
||||
ArrayCtrl list;
|
||||
ArrayCtrl navlines;
|
||||
EditString search;
|
||||
|
||||
ScopeDisplay scope_display;
|
||||
|
||||
|
||||
void TriggerSearch();
|
||||
void NavGroup(bool local);
|
||||
void Search();
|
||||
void Scope();
|
||||
void ListLineEnabled(int i, bool& b);
|
||||
void NaviSort();
|
||||
|
||||
Vector<NavLine> GetNavLines(const NavItem& m);
|
||||
|
||||
void Navigate();
|
||||
void ScopeDblClk();
|
||||
void NavigatorClick();
|
||||
void NavigatorEnter();
|
||||
void SyncLines();
|
||||
void SyncNavLines();
|
||||
void GoToNavLine();
|
||||
void SyncCursor();
|
||||
|
||||
static bool SortByLines(const NavItem *a, const NavItem *b);
|
||||
static bool SortByNames(const NavItem *a, const NavItem *b);
|
||||
|
||||
typedef Navigator CLASSNAME;
|
||||
|
||||
Navigator();
|
||||
|
|
@ -118,6 +65,8 @@ struct AssistEditor : CodeEditor, Navigator {
|
|||
virtual void SelectionChanged();
|
||||
virtual void DirtyFrom(int line);
|
||||
virtual void State(int reason);
|
||||
virtual void PostInsert(int pos, const WString& s);
|
||||
virtual void PostRemove(int pos, int size);
|
||||
|
||||
virtual int GetCurrentLine();
|
||||
|
||||
|
|
@ -129,138 +78,134 @@ struct AssistEditor : CodeEditor, Navigator {
|
|||
bool navigator;
|
||||
SplitterFrame navigatorframe;
|
||||
StaticRect navigatorpane;
|
||||
Splitter navigator_splitter;
|
||||
|
||||
struct AssistItemConvert : Convert {
|
||||
AssistEditor *editor;
|
||||
|
||||
virtual Value Format(const Value& q) const;
|
||||
}
|
||||
assist_convert;
|
||||
|
||||
Splitter popup;
|
||||
ArrayCtrl assist;
|
||||
ArrayCtrl type;
|
||||
Index<String> assist_type;
|
||||
Array<CppItemInfo> assist_item;
|
||||
Vector<int> assist_item_ndx;
|
||||
RichTextCtrl annotation_popup;
|
||||
|
||||
|
||||
struct AssistItem : AutoCompleteItem {
|
||||
int typei = -1;
|
||||
String uname;
|
||||
};
|
||||
|
||||
Index<String> assist_type;
|
||||
Array<AssistItem> assist_item;
|
||||
Vector<int> assist_item_ndx;
|
||||
|
||||
struct AssistDisplay : Display {
|
||||
AssistEditor *editor;
|
||||
|
||||
void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const override;
|
||||
} assist_display;
|
||||
|
||||
RichTextCtrl annotation_popup;
|
||||
bool is_source_file = false;
|
||||
bool annotating = false;
|
||||
Vector<AnnotationItem> annotations;
|
||||
Vector<ReferenceItem> references;
|
||||
Vector<AnnotationItem> locals;
|
||||
|
||||
int assist_cursor;
|
||||
bool auto_assist;
|
||||
bool auto_check;
|
||||
bool assist_active;
|
||||
bool commentdp;
|
||||
bool inbody;
|
||||
bool thisback, thisbackn;
|
||||
bool include_assist;
|
||||
WString cachedline;
|
||||
int cachedpos;
|
||||
int cachedln;
|
||||
|
||||
WString cachedline; // for Ch method
|
||||
int cachedpos; // for Ch method
|
||||
int cachedln; // for Ch method
|
||||
|
||||
bool include_local;
|
||||
int include_back;
|
||||
String include_path;
|
||||
int scan_counter;
|
||||
|
||||
|
||||
RichTextCtrl param_info;
|
||||
String param_qtf;
|
||||
struct ParamInfo {
|
||||
int line;
|
||||
int pos;
|
||||
WString test;
|
||||
CppItem item;
|
||||
AssistItem item;
|
||||
String editfile;
|
||||
|
||||
|
||||
ParamInfo() { line = -1; }
|
||||
};
|
||||
enum { PARAMN = 16 };
|
||||
ParamInfo param[PARAMN];
|
||||
int parami;
|
||||
|
||||
String current_type;
|
||||
|
||||
static Ptr<Ctrl> assist_ptr;
|
||||
|
||||
bool navigator_right = true;
|
||||
|
||||
bool navigator_right = true;
|
||||
|
||||
PPInfo ppi;
|
||||
String master_source;
|
||||
|
||||
CurrentFileContext CurrentContext(int pos = INT_MAX);
|
||||
void SetAnnotations(const CppFileInfo& f);
|
||||
void SyncCurrentFile(const CurrentFileContext& ctx);
|
||||
void SyncCurrentFile();
|
||||
void SyncMaster();
|
||||
void NewFile(bool reloading);
|
||||
bool DoIncludeTrick(Index<String>& visited, int level, StringBuffer& out, String path, const String& target_path, int& line_delta);
|
||||
void MakeIncludeTrick(CurrentFileContext& cfx);
|
||||
|
||||
void PopUpAssist(bool auto_insert = false);
|
||||
void CloseAssist();
|
||||
static bool WheelHook(Ctrl *, bool inframe, int event, Point p, int zdelta, dword keyflags);
|
||||
void Assist();
|
||||
void Assist(bool macros);
|
||||
bool IncludeAssist();
|
||||
String ReadIdBackPos(int& pos, bool include);
|
||||
String ReadIdBack(int q, bool include = false, bool *destructor = NULL);
|
||||
String ReadIdBack(int q, bool include = false);
|
||||
void SyncAssist();
|
||||
void AssistInsert();
|
||||
bool InCode();
|
||||
|
||||
|
||||
void SyncParamInfo();
|
||||
void StartParamInfo(const CppItem& m, int pos);
|
||||
void StartParamInfo(const AssistItem& m, int pos);
|
||||
|
||||
void Complete();
|
||||
void Abbr();
|
||||
|
||||
void Context(ParserContext& parser, int pos);
|
||||
void ExpressionType(const String& type,
|
||||
const String& context_type,
|
||||
const String& usings,
|
||||
const Vector<String>& xp, int ii,
|
||||
Index<String>& typeset, bool variable,
|
||||
bool can_shortcut_operator, Index<String>& visited_bases,
|
||||
int lvl);
|
||||
void ExpressionType(const String& type,
|
||||
const String& context_type,
|
||||
const String& usings,
|
||||
const Vector<String>& xp, int ii,
|
||||
Index<String>& typeset, bool variable, int lvl);
|
||||
// void ExpressionType(const String& type, const Vector<String>& xp, int ii,
|
||||
// Index<String>& typeset);
|
||||
Index<String> ExpressionType(const ParserContext& parser, const Vector<String>& xp);
|
||||
Point GetCurrentPos() const;
|
||||
AnnotationItem FindCurrentAnnotation();
|
||||
|
||||
Index<String> EvaluateExpressionType(const ParserContext& parser, const Vector<String>& xp);
|
||||
|
||||
String RemoveDefPar(const char *s);
|
||||
String MakeDefinition(const String& cls, const String& _n);
|
||||
void DCopy();
|
||||
String FindCurrentNest();
|
||||
void Virtuals();
|
||||
void Thisbacks();
|
||||
void AssistItemAdd(const String& scope, const CppItem& m, int typei);
|
||||
void GatherItems(const String& type, bool only_public, Index<String>& in_types,
|
||||
bool types);
|
||||
void RemoveDuplicates();
|
||||
void Events();
|
||||
|
||||
void SelParam();
|
||||
int Ch(int q);
|
||||
int ParsBack(int q);
|
||||
Vector<String> ReadBack(int q, const Index<String>& locals);
|
||||
void SkipSpcBack(int& q);
|
||||
String IdBack(int& qq);
|
||||
String CompleteIdBack(int& q, const Index<String>& locals);
|
||||
|
||||
void SwapSContext(ParserContext& p);
|
||||
|
||||
bool WaitCurrentFile();
|
||||
|
||||
const AnnotationItem *GetAnnotationPtr(const String& id);
|
||||
|
||||
bool GetAnnotationRefs(Vector<String>& tl, String& coderef, int q = -1);
|
||||
bool GetAnnotationRef(String& t, String& coderef, int q = -1);
|
||||
void SyncAnnotationPopup();
|
||||
void EditAnnotation(bool fastedit);
|
||||
void Annotate(const String& filename);
|
||||
void OpenTopic(String topic, String create, bool before);
|
||||
void NewTopic(String group, String coderef);
|
||||
|
||||
|
||||
bool Esc();
|
||||
|
||||
|
||||
bool IsNavigator() const { return navigator; }
|
||||
void Navigator(bool navigator);
|
||||
void SyncNavigatorShow();
|
||||
void SyncNavigator();
|
||||
void SerializeNavigator(Stream& s);
|
||||
void SyncNavigatorPlacement();
|
||||
|
||||
|
||||
Event<int> WhenFontScroll;
|
||||
Event<> WhenSelectionChanged;
|
||||
|
||||
typedef AssistEditor CLASSNAME;
|
||||
|
||||
AssistEditor();
|
||||
};
|
||||
~AssistEditor();
|
||||
};
|
||||
123
uppsrc/ide/AssistDisplay.cpp
Normal file
123
uppsrc/ide/AssistDisplay.cpp
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
#include "ide.h"
|
||||
|
||||
// TODO: Move to (renamed) ide/Browser
|
||||
|
||||
Image CxxIcon(int kind)
|
||||
{
|
||||
switch(kind) {
|
||||
case CXCursor_CXXMethod: return BrowserImg::instance_function();
|
||||
case CXCursor_Destructor: return BrowserImg::destructor();
|
||||
case CXCursor_EnumConstantDecl: return BrowserImg::type_enum();
|
||||
case CXCursor_ClassDecl: return BrowserImg::type_struct();
|
||||
case CXCursor_StructDecl: return BrowserImg::type_struct();
|
||||
case CXCursor_ClassTemplate: return BrowserImg::template_struct();
|
||||
case CXCursor_FunctionTemplate: return BrowserImg::template_function();
|
||||
case CXCursor_ConversionFunction: return BrowserImg::function();
|
||||
case CXCursor_FieldDecl: return BrowserImg::instance_data();
|
||||
case CXCursor_VarDecl: return BrowserImg::data();
|
||||
case CXCursor_TypedefDecl: return BrowserImg::type_def();
|
||||
case CXCursor_FunctionDecl: return BrowserImg::function();
|
||||
case CXCursor_Constructor: return BrowserImg::constructor();
|
||||
case CXCursor_EnumDecl: return BrowserImg::type_enum();
|
||||
case CXCursor_UnionDecl: return BrowserImg::type_struct();
|
||||
case CXCursor_TypeAliasDecl: return BrowserImg::type_def();
|
||||
case CXCursor_TypeAliasTemplateDecl: return BrowserImg::type_def();
|
||||
case CXCursor_MacroDefinition: return BrowserImg::macro();
|
||||
case KIND_INCLUDEFILE: return IdeCommonImg::Header();
|
||||
case KIND_INCLUDEFILE_ANY: return CtrlImg::File();
|
||||
case KIND_INCLUDEFOLDER: return CtrlImg::Dir();
|
||||
case KIND_ERROR: return IdeImg::errors();
|
||||
}
|
||||
return BrowserImg::unknown();
|
||||
}
|
||||
|
||||
void PaintText(Draw& w, int& x, int y, const char *text, const Vector<ItemTextPart>& n,
|
||||
int starti, int count, bool focuscursor, Color _ink, bool italic)
|
||||
{
|
||||
static int maxascent = MaxAscent(BrowserFont());
|
||||
for(int i = 0; i < count; i++) {
|
||||
const ItemTextPart& p = n[starti + i];
|
||||
Font f = BrowserFont();
|
||||
Color ink = SColorText;
|
||||
switch(p.type) {
|
||||
case ITEM_PNAME:
|
||||
f.Bold();
|
||||
case ITEM_NUMBER:
|
||||
ink = SRed();
|
||||
break;
|
||||
case ITEM_TNAME:
|
||||
ink = SGreen();
|
||||
case ITEM_NAME:
|
||||
f.Bold();
|
||||
break;
|
||||
case ITEM_UPP:
|
||||
ink = SCyan();
|
||||
break;
|
||||
case ITEM_CPP_TYPE:
|
||||
case ITEM_CPP:
|
||||
case ITEM_OPERATOR:
|
||||
case ITEM_SIGN:
|
||||
ink = SLtBlue();
|
||||
break;
|
||||
}
|
||||
if(italic)
|
||||
f.Italic();
|
||||
Size fsz = GetTextSize(text + p.pos, f, p.len);
|
||||
w.DrawText(x, y + maxascent - f.GetAscent(), text + p.pos,
|
||||
f, focuscursor ? _ink : ink, p.len);
|
||||
x += fsz.cx;
|
||||
}
|
||||
}
|
||||
|
||||
int PaintCpp(Draw& w, const Rect& r, int kind, const String& name, const String& pretty, Color ink, bool focuscursor, bool retval_last)
|
||||
{
|
||||
int x = r.left;
|
||||
|
||||
Image img = CxxIcon(kind);
|
||||
Size isz = img.GetSize();
|
||||
w.DrawImage(x + (DPI(16) - isz.cx) / 2, r.top + (r.GetHeight() - isz.cy) / 2, img);
|
||||
|
||||
x += DPI(16);
|
||||
int y = r.top + (r.GetHeight() - Draw::GetStdFontCy()) / 2;
|
||||
|
||||
#ifdef _DEBUG
|
||||
String ks = " [" + AsString(kind) + "] ";
|
||||
w.DrawText(x, y, ks);
|
||||
x += GetTextSize(ks, StdFont()).cx;
|
||||
#endif
|
||||
|
||||
Vector<ItemTextPart> n = ParsePretty(name, pretty);
|
||||
int count = n.GetCount();
|
||||
if(retval_last)
|
||||
for(int i = 0; i < n.GetCount(); i++)
|
||||
if(findarg(n[i].type, ITEM_NAME, ITEM_OPERATOR) >= 0 || pretty[n[i].pos] == '(') {
|
||||
PaintText(w, x, y, pretty, n, i, count - i, focuscursor, ink, false);
|
||||
count = i;
|
||||
while(count) { // remove trailing spaces
|
||||
const ItemTextPart& p = n[count - 1];
|
||||
if(p.len == 1 && pretty[p.pos] == ' ')
|
||||
count--;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if(count) {
|
||||
w.DrawText(x, y, " → ", StdFont(), SGray());
|
||||
x += GetTextSize(" → ", StdFont()).cx;
|
||||
}
|
||||
break;
|
||||
}
|
||||
PaintText(w, x, y, pretty, n, 0, count, focuscursor, ink, false);
|
||||
return x;
|
||||
}
|
||||
|
||||
void AssistEditor::AssistDisplay::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const
|
||||
{
|
||||
int ii = q;
|
||||
if(ii >= 0 && ii < editor->assist_item_ndx.GetCount()) {
|
||||
AutoCompleteItem& m = editor->assist_item[editor->assist_item_ndx[ii]];
|
||||
|
||||
w.DrawRect(r, paper);
|
||||
|
||||
PaintCpp(w, r, m.kind, m.name, m.pretty, ink, (style & (FOCUS|CURSOR)) == (FOCUS|CURSOR) || (style & SELECT), true);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,565 +0,0 @@
|
|||
#include "Browser.h"
|
||||
|
||||
#include <plugin/lz4/lz4.h>
|
||||
|
||||
#define LTIMING(x) // DTIMING(x)
|
||||
#define LLOG(x) // DLOG(x)
|
||||
#define LTIMESTOP(x) // RTIMESTOP(x)
|
||||
|
||||
#define LDUMP(x) // DDUMP(x)
|
||||
|
||||
// #define HAS_CLOG
|
||||
|
||||
#ifdef HAS_CLOG
|
||||
#define CLOG(x) // RLOG(x)
|
||||
#else
|
||||
#define CLOG(x)
|
||||
#endif
|
||||
|
||||
#define MLOG(x)
|
||||
|
||||
#define CPP_CODEBASE_VERSION 3141592
|
||||
|
||||
static StaticMutex sGLock;
|
||||
static thread_local int sGLockLevel = 0;
|
||||
|
||||
bool DeadLockCheck()
|
||||
{
|
||||
if(sGLockLevel) {
|
||||
PostCallback([] {
|
||||
Exclamation("Internal error (deadlock on sGLock)");
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LockCodeBase()
|
||||
{
|
||||
if(sGLockLevel++ == 0)
|
||||
sGLock.Enter();
|
||||
}
|
||||
|
||||
bool TryLockCodeBase()
|
||||
{
|
||||
if(sGLockLevel == 0 && sGLock.TryEnter()) {
|
||||
sGLockLevel++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UnlockCodeBase()
|
||||
{
|
||||
if(sGLockLevel > 0 && --sGLockLevel == 0)
|
||||
sGLock.Leave();
|
||||
}
|
||||
|
||||
void UnlockCodeBaseAll()
|
||||
{
|
||||
if(sGLockLevel > 0)
|
||||
sGLock.Leave();
|
||||
sGLockLevel = 0; // just in case
|
||||
}
|
||||
|
||||
INITIALIZER(CodeBase)
|
||||
{
|
||||
void InitializeTopicModule();
|
||||
InitializeTopicModule();
|
||||
}
|
||||
|
||||
CppBase& CodeBase()
|
||||
{
|
||||
static CppBase b;
|
||||
return b;
|
||||
}
|
||||
|
||||
static Mutex CppBaseMutex; // this is to enforce "one thread rule" for CppBase functions
|
||||
|
||||
ArrayMap<String, SourceFileInfo> source_file;
|
||||
|
||||
void SourceFileInfo::Serialize(Stream& s)
|
||||
{
|
||||
s % time % dependencies_md5sum % md5sum;
|
||||
if(s.IsLoading()) {
|
||||
depends.Clear();
|
||||
depends_time = Null;
|
||||
}
|
||||
}
|
||||
|
||||
String CodeBaseCacheDir()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
return ConfigFile("cfg/debug_codebase");
|
||||
#else
|
||||
return ConfigFile("cfg/codebase");
|
||||
#endif
|
||||
}
|
||||
|
||||
struct RCB_FileInfo {
|
||||
String path;
|
||||
Time time;
|
||||
int64 length;
|
||||
|
||||
bool operator<(const RCB_FileInfo& a) const { return time > a.time; }
|
||||
};
|
||||
|
||||
void ReduceCacheFolder(const char *path, int max_total)
|
||||
{
|
||||
Array<RCB_FileInfo> file;
|
||||
FindFile ff(AppendFileName(path, "*.*"));
|
||||
int64 total = 0;
|
||||
while(ff) {
|
||||
if(ff.IsFile()) {
|
||||
RCB_FileInfo& m = file.Add();
|
||||
m.path = ff.GetPath();
|
||||
m.time = ff.GetLastAccessTime();
|
||||
m.length = ff.GetLength();
|
||||
total += m.length;
|
||||
}
|
||||
ff.Next();
|
||||
}
|
||||
Sort(file);
|
||||
while(total > max_total && file.GetCount()) {
|
||||
DeleteFile(file.Top().path);
|
||||
total -= file.Top().length;
|
||||
file.Drop();
|
||||
}
|
||||
}
|
||||
|
||||
void ReduceCodeBaseCache()
|
||||
{
|
||||
ReduceCacheFolder(CodeBaseCacheDir(), 256000000);
|
||||
}
|
||||
|
||||
String CodeBaseCacheFile()
|
||||
{
|
||||
return AppendFileName(CodeBaseCacheDir(), GetAssemblyId() + '.' + IdeGetCurrentMainPackage() + '.' + IdeGetCurrentBuildMethod() + ".codebase");
|
||||
}
|
||||
|
||||
static bool s_console;
|
||||
|
||||
void BrowserScanError(int line, const String& text, int file)
|
||||
{
|
||||
if(s_console)
|
||||
PostCallback([=] { IdePutErrorLine(String().Cat() << source_file.GetKey(file) << " (" << line << "): " << text); });
|
||||
}
|
||||
|
||||
void SerializeCodeBase(Stream& s)
|
||||
{
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
MLOG(s.IsLoading());
|
||||
source_file.Serialize(s);
|
||||
MLOG("source_file " << MemoryUsedKb());
|
||||
SerializePPFiles(s);
|
||||
MLOG("PP files " << MemoryUsedKb());
|
||||
CodeBase().Serialize(s);
|
||||
MLOG("codebase " << MemoryUsedKb());
|
||||
}
|
||||
|
||||
void SaveCodeBase()
|
||||
{
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
LTIMING("SaveCodeBase");
|
||||
LLOG("Save code base " << CodeBase().GetCount());
|
||||
RealizeDirectory(CodeBaseCacheDir());
|
||||
StringStream ss;
|
||||
Store(callback(SerializeCodeBase), ss, CPP_CODEBASE_VERSION);
|
||||
String data = ss.GetResult();
|
||||
String path = CodeBaseCacheFile();
|
||||
SaveFile(path, LZ4Compress(data));
|
||||
}
|
||||
|
||||
bool TryLoadCodeBase(const char *pattern)
|
||||
{
|
||||
if(DeadLockCheck()) return false;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
LLOG("+++ Trying to load " << pattern);
|
||||
FindFile ff(pattern);
|
||||
String path;
|
||||
int64 len = -1;
|
||||
while(ff) { // Load biggest file, as it has the most chances to have the data we need
|
||||
if(ff.IsFile() && ff.GetLength() > len) {
|
||||
path = ff.GetPath();
|
||||
len = ff.GetLength();
|
||||
}
|
||||
ff.Next();
|
||||
}
|
||||
if(path.GetCount()) {
|
||||
LTIMING("Load code base");
|
||||
StringStream ss(LZ4Decompress(LoadFile(path)));
|
||||
MLOG("Decompressed " << MemoryUsedKb());
|
||||
if(Load(callback(SerializeCodeBase), ss, CPP_CODEBASE_VERSION)) {
|
||||
CLOG("*** Loaded " << ff.GetPath() << ' ' << GetSysTime() << ", file count: " << source_file.GetCount() << ", codebase: " << CodeBase().GetCount());
|
||||
MLOG("TryLoadCodeBase loaded: " << MemoryUsedKb());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LoadCodeBase()
|
||||
{
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
MLOG("LoadCodeBase start: " << MemoryUsedKb());
|
||||
TryLoadCodeBase(CodeBaseCacheFile()) ||
|
||||
TryLoadCodeBase(AppendFileName(CodeBaseCacheDir(), GetAssemblyId() + ".*." + IdeGetCurrentBuildMethod() + ".codebase")) ||
|
||||
TryLoadCodeBase(AppendFileName(CodeBaseCacheDir(), GetAssemblyId() + ".*.codebase")) ||
|
||||
TryLoadCodeBase(AppendFileName(CodeBaseCacheDir(), "*.codebase"));
|
||||
|
||||
LLOG("LoadCodeBase: " << CodeBase().GetCount());
|
||||
}
|
||||
|
||||
void FinishCodeBase()
|
||||
{
|
||||
LTIMING("FinishBase");
|
||||
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
Qualify(CodeBase());
|
||||
}
|
||||
|
||||
void LoadDefs()
|
||||
{
|
||||
LTIMING("LoadDefs");
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
Vector<String> defs;
|
||||
defs.Add(ConfigFile("global.defs"));
|
||||
const Workspace& wspc = GetIdeWorkspace();
|
||||
for(int i = 0; i < wspc.GetCount(); i++) {
|
||||
const Package& pk = wspc.GetPackage(i);
|
||||
String n = wspc[i];
|
||||
for(int i = 0; i < pk.file.GetCount(); i++) {
|
||||
String path = SourcePath(n, pk.file[i]);
|
||||
if(GetFileExt(path) == ".defs")
|
||||
defs.Add(path);
|
||||
}
|
||||
}
|
||||
|
||||
String fp;
|
||||
for(int i = 0; i < defs.GetCount(); i++)
|
||||
fp << defs[i] << "\n" << GetFileTimeCached(defs[i]) << "\n";
|
||||
|
||||
static String defs_fp;
|
||||
if(fp != defs_fp) {
|
||||
defs_fp = fp;
|
||||
String h;
|
||||
for(int i = 0; i < defs.GetCount(); i++)
|
||||
h << LoadFile(defs[i]) << "\n";
|
||||
SetPPDefs(h);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseInfoSync(Progress& pi)
|
||||
{ // clears temporary caches (file times etc..)
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
PPSync(TheIde()->IdeGetIncludePath());
|
||||
|
||||
LTIMESTOP("Gathering files");
|
||||
ClearSources();
|
||||
LoadDefs();
|
||||
const Workspace& wspc = GetIdeWorkspace();
|
||||
LTIMING("Gathering files");
|
||||
pi.SetText("Gathering files");
|
||||
pi.SetTotal(wspc.GetCount());
|
||||
|
||||
for(int pass = 0; pass < 2; pass++) // Ignore headers in the first pass to get correct master files
|
||||
for(int i = 0; i < wspc.GetCount(); i++) {
|
||||
pi.Step();
|
||||
const Package& pk = wspc.GetPackage(i);
|
||||
String n = wspc[i];
|
||||
for(int i = 0; i < pk.file.GetCount(); i++) {
|
||||
String path = SourcePath(n, pk.file[i]);
|
||||
if(pass ? IsHFile(path)
|
||||
: IsCPPFile(path) || findarg(ToLower(GetFileExt(path)), ".lay", ".sch", ".iml") >= 0)
|
||||
GatherSources(path);
|
||||
}
|
||||
}
|
||||
|
||||
SweepPPFiles(GetAllSources());
|
||||
}
|
||||
|
||||
int GetSourceFileIndex(const String& path)
|
||||
{
|
||||
CodeBaseLock __;
|
||||
return source_file.FindPut(NormalizeSourcePath(path));
|
||||
}
|
||||
|
||||
String GetSourceFilePath(int file)
|
||||
{
|
||||
CodeBaseLock __;
|
||||
if(file < 0 || file >= source_file.GetCount())
|
||||
return Null;
|
||||
return source_file.GetKey(file);
|
||||
}
|
||||
|
||||
bool CheckFile0(SourceFileInfo& f, const String& path)
|
||||
{
|
||||
static Mutex sTimePathMutex;
|
||||
static Index<String> sTimePath; // map of f.depends indices to real filenames
|
||||
auto GetDependsTime = [&](const Vector<int>& file) {
|
||||
LTIMING("CreateTimePrint");
|
||||
Time tm = Time::Low();
|
||||
for(int i = 0; i < file.GetCount(); i++)
|
||||
if(file[i] < sTimePath.GetCount())
|
||||
tm = max(tm, GetFileTimeCached(sTimePath[file[i]]));
|
||||
return tm;
|
||||
};
|
||||
|
||||
Time ftm = GetFileTimeCached(path);
|
||||
bool tmok = f.time == ftm;
|
||||
f.time = ftm;
|
||||
if(findarg(ToLower(GetFileExt(path)), ".lay", ".iml", ".sch") >= 0)
|
||||
return tmok;
|
||||
{
|
||||
Mutex::Lock __(sTimePathMutex);
|
||||
if(!IsNull(f.depends_time) && tmok && f.depends_time == GetDependsTime(f.depends) && f.dependencies_md5sum.GetCount())
|
||||
return true;
|
||||
}
|
||||
Index<String> visited;
|
||||
String md5 = GetDependeciesMD5(path, visited);
|
||||
bool r = f.dependencies_md5sum == md5 && tmok;
|
||||
#ifdef HAS_CLOG
|
||||
if(!r) CLOG(path << " " << f.dependencies_md5sum << " " << md5);
|
||||
#endif
|
||||
f.depends.Clear();
|
||||
f.dependencies_md5sum = md5;
|
||||
Mutex::Lock __(sTimePathMutex);
|
||||
for(int i = 0; i < visited.GetCount(); i++)
|
||||
f.depends.Add(sTimePath.FindAdd(visited[i]));
|
||||
f.depends_time = GetDependsTime(f.depends);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool CheckFile(SourceFileInfo& f, const String& path)
|
||||
{
|
||||
LTIMING("CheckFile");
|
||||
if(DeadLockCheck()) return false;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
return CheckFile0(f, path);
|
||||
}
|
||||
|
||||
void UpdateCodeBase2(Progress& pi)
|
||||
{
|
||||
CLOG("============= UpdateCodeBase2 " << GetSysTime());
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
Index<int> parse_file;
|
||||
{
|
||||
pi.SetText("Checking source files");
|
||||
VectorMap<int, bool> filecheck;
|
||||
{
|
||||
CodeBaseLock __;
|
||||
for(const String& path : GetAllSources())
|
||||
filecheck.GetAdd(GetSourceFileIndex(path));
|
||||
}
|
||||
|
||||
pi.SetPos(0);
|
||||
pi.SetTotal(filecheck.GetCount());
|
||||
CoFor(filecheck.GetCount(), [&](int i) {
|
||||
int q = filecheck.GetKey(i);
|
||||
filecheck[i] = CheckFile0(source_file[q], source_file.GetKey(q));
|
||||
});
|
||||
|
||||
CodeBaseLock __;
|
||||
|
||||
Index<int> keep_file;
|
||||
|
||||
for(String path : GetAllSources()) {
|
||||
int q = GetSourceFileIndex(path);
|
||||
if(filecheck.Get(q, false))
|
||||
keep_file.Add(q);
|
||||
else
|
||||
parse_file.Add(q);
|
||||
}
|
||||
|
||||
CodeBase().Sweep(keep_file);
|
||||
|
||||
for(int i = 0; i < source_file.GetCount(); i++)
|
||||
if(keep_file.Find(i) < 0 && parse_file.Find(i) < 0 && !source_file.IsUnlinked(i))
|
||||
source_file.Unlink(i);
|
||||
}
|
||||
|
||||
#ifdef HAS_CLOG
|
||||
for(int i = 0; i < source_file.GetCount(); i++)
|
||||
if(!source_file.IsUnlinked(i))
|
||||
CLOG(i << " " << source_file.GetKey(i) << " " << source_file[i].dependencies_md5sum << " " << source_file[i].time);
|
||||
#endif
|
||||
|
||||
pi.SetTotal(parse_file.GetCount());
|
||||
pi.SetPos(0);
|
||||
pi.AlignText(ALIGN_LEFT);
|
||||
LLOG("=========================");
|
||||
CoFor(parse_file.GetCount(), [&](int i) {
|
||||
String path = source_file.GetKey(parse_file[i]);
|
||||
pi.SetText(GetFileName(GetFileFolder(path)) + "/" + GetFileName(path));
|
||||
pi.Step();
|
||||
FileIn fi(path);
|
||||
LDUMP(path);
|
||||
LDUMP(parse_file[i]);
|
||||
ParseSrc(fi, parse_file[i], callback1(BrowserScanError, i));
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateCodeBase(Progress& pi)
|
||||
{
|
||||
BaseInfoSync(pi);
|
||||
|
||||
UpdateCodeBase2(pi);
|
||||
}
|
||||
|
||||
void ParseSrc(Stream& in, int file, Event<int, const String&> error)
|
||||
{
|
||||
String path = source_file.GetKey(file);
|
||||
CLOG("====== Parse " << file << ": " << path);
|
||||
CppBase base;
|
||||
Vector<String> pp;
|
||||
String ext = ToLower(GetFileExt(path));
|
||||
if(ext == ".lay")
|
||||
pp.Add(PreprocessLayFile(path));
|
||||
else
|
||||
if(ext == ".iml")
|
||||
pp.Add(PreprocessImlFile(path));
|
||||
else
|
||||
if(ext == ".sch")
|
||||
pp.Append(PreprocessSchFile(path));
|
||||
else
|
||||
PreprocessParse(base, in, file, path, error);
|
||||
|
||||
for(int i = 0; i < pp.GetCount(); i++)
|
||||
Parse(base, pp[i], file, FILE_OTHER, path, error, Vector<String>(), Index<String>());
|
||||
|
||||
CodeBaseLock __;
|
||||
CodeBase().Append(pick(base));
|
||||
}
|
||||
|
||||
void CodeBaseScanFile0(Stream& in, const String& fn)
|
||||
{
|
||||
LLOG("===== CodeBaseScanFile " << fn);
|
||||
|
||||
InvalidateFileTimeCache(NormalizeSourcePath(fn));
|
||||
PPSync(TheIde()->IdeGetIncludePath());
|
||||
|
||||
LTIMING("CodeBaseScanFile0");
|
||||
|
||||
int file;
|
||||
{
|
||||
CodeBaseLock __;
|
||||
file = GetSourceFileIndex(fn);
|
||||
CppBase& base = CodeBase();
|
||||
base.RemoveFile(file);
|
||||
}
|
||||
ParseSrc(in, file, CNULL);
|
||||
}
|
||||
|
||||
void CodeBaseScanFile(Stream& in, const String& fn)
|
||||
{
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
CodeBaseScanFile0(in, fn);
|
||||
FinishCodeBase();
|
||||
}
|
||||
|
||||
bool TryCodeBaseScanFile(Stream& in, const String& fn)
|
||||
{
|
||||
if(DeadLockCheck() || !CppBaseMutex.TryEnter())
|
||||
return false;
|
||||
CodeBaseScanFile0(in, fn);
|
||||
FinishCodeBase();
|
||||
CppBaseMutex.Leave();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CodeBaseScanFile(const String& fn, bool auto_check)
|
||||
{
|
||||
LLOG("CodeBaseScanFile " << fn);
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
String md5sum = GetPPMD5(fn);
|
||||
FileIn in(fn);
|
||||
CodeBaseScanFile0(in, fn);
|
||||
int file = GetSourceFileIndex(fn);
|
||||
SourceFileInfo& f = source_file[file];
|
||||
CLOG("CodeBaseScanFile " << fn << ", " << md5sum << " " << f.md5sum);
|
||||
if(md5sum != f.md5sum) {
|
||||
if(auto_check)
|
||||
SyncCodeBase();
|
||||
f.md5sum = md5sum;
|
||||
}
|
||||
else
|
||||
FinishCodeBase();
|
||||
}
|
||||
|
||||
void ClearCodeBase()
|
||||
{
|
||||
// TODO: Create combined defs
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
CleanPP();
|
||||
CodeBase().Clear();
|
||||
source_file.Clear();
|
||||
}
|
||||
|
||||
void SyncCodeBase()
|
||||
{
|
||||
LTIMING("SyncCodeBase");
|
||||
LTIMESTOP("SyncCodeBase");
|
||||
CLOG("============= Sync code base");
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
if(IsNull(IdeGetCurrentMainPackage())) {
|
||||
ClearCodeBase();
|
||||
return;
|
||||
}
|
||||
Progress pi;
|
||||
pi.Title("Parsing source files");
|
||||
UpdateCodeBase(pi);
|
||||
FinishCodeBase();
|
||||
}
|
||||
|
||||
void NewCodeBase()
|
||||
{
|
||||
if(DeadLockCheck()) return;
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
InvalidatePPCache();
|
||||
ReduceCodeBaseCache();
|
||||
if(IsNull(IdeGetCurrentMainPackage())) {
|
||||
ClearCodeBase();
|
||||
return;
|
||||
}
|
||||
static int start;
|
||||
if(start) return;
|
||||
start++;
|
||||
LoadCodeBase();
|
||||
LLOG("NewCodeBase loaded " << CodeBase().GetCount());
|
||||
SyncCodeBase();
|
||||
LLOG("NewCodeBase synced " << CodeBase().GetCount());
|
||||
SaveCodeBase();
|
||||
LLOG("NewCodeBase saved " << CodeBase().GetCount());
|
||||
start--;
|
||||
}
|
||||
|
||||
void RescanCodeBase()
|
||||
{
|
||||
if(DeadLockCheck()) return;
|
||||
InvalidatePPCache();
|
||||
Mutex::Lock __(CppBaseMutex);
|
||||
ClearCodeBase();
|
||||
s_console = true;
|
||||
Progress pi;
|
||||
pi.Title("Parsing source files");
|
||||
UpdateCodeBase(pi);
|
||||
FinishCodeBase();
|
||||
s_console = false;
|
||||
}
|
||||
|
||||
bool ExistsBrowserItem(const String& item)
|
||||
{
|
||||
CodeBaseLock __;
|
||||
return GetCodeRefItem(item);
|
||||
}
|
||||
|
|
@ -2,193 +2,24 @@
|
|||
#define _Browser_Browser_h
|
||||
|
||||
#include <CtrlLib/CtrlLib.h>
|
||||
#include <CppBase/CppBase.h>
|
||||
#include <ide/Common/Common.h>
|
||||
#include <ide/clang/clang.h>
|
||||
#include <RichEdit/RichEdit.h>
|
||||
#include <PdfDraw/PdfDraw.h>
|
||||
|
||||
#define LAYOUTFILE <ide/Browser/Browser.lay>
|
||||
#include <CtrlCore/lay.h>
|
||||
|
||||
#define IMAGECLASS BrowserImg
|
||||
#define IMAGEFILE <ide/Browser/Browser.iml>
|
||||
#include <Draw/iml_header.h>
|
||||
|
||||
INITIALIZE(CodeBase)
|
||||
|
||||
class Browser;
|
||||
|
||||
void ReduceCacheFolder(const char *path, int max_total);
|
||||
|
||||
void LockCodeBase();
|
||||
bool TryLockCodeBase();
|
||||
void UnlockCodeBase();
|
||||
void UnlockCodeBaseAll();
|
||||
|
||||
struct CodeBaseLock { // Use when accessing CodeBase
|
||||
CodeBaseLock() { LockCodeBase(); }
|
||||
~CodeBaseLock() { UnlockCodeBase(); }
|
||||
};
|
||||
|
||||
CppBase& CodeBase();
|
||||
|
||||
struct SourceFileInfo {
|
||||
Time time;
|
||||
String dependencies_md5sum; // dependencies from other files - usings, initial namespace, macros
|
||||
String md5sum; // preprocessing 'fingerprint' to detect changes
|
||||
Vector<int> depends; // indicies of file this files depends on, for time-check
|
||||
Time depends_time;
|
||||
|
||||
void Serialize(Stream& s);
|
||||
|
||||
SourceFileInfo() { time = Null; depends_time = Null; }
|
||||
};
|
||||
|
||||
void NewCodeBase();
|
||||
void ParseSrc(Stream& in, int file, Event<int, const String&> error);
|
||||
void CodeBaseScanFile(Stream& in, const String& fn);
|
||||
void CodeBaseScanFile(const String& fn, bool auto_check);
|
||||
bool TryCodeBaseScanFile(Stream& in, const String& fn);
|
||||
void ClearCodeBase();
|
||||
// void CheckCodeBase();
|
||||
void RescanCodeBase();
|
||||
void SyncCodeBase();
|
||||
void SaveCodeBase();
|
||||
bool ExistsBrowserItem(const String& item);
|
||||
void FinishCodeBase();
|
||||
|
||||
String PreprocessLayFile(const char *fn);
|
||||
Vector<String> PreprocessSchFile(const char *fn);
|
||||
String PreprocessImlFile(const char *fn);
|
||||
|
||||
int GetSourceFileIndex(const String& path);
|
||||
String GetSourceFilePath(int file);
|
||||
|
||||
String MakeCodeRef(const String& scope, const String& item);
|
||||
void SplitCodeRef(const String& ref, String& scope, String& item);
|
||||
|
||||
const CppItem *GetCodeRefItem(const String& ref, const String& rfile);
|
||||
const CppItem *GetCodeRefItem(const String& ref);
|
||||
|
||||
int GetMatchLen(const char *s, const char *t);
|
||||
|
||||
|
||||
enum WithBodyEnum { WITHBODY = 33 };
|
||||
|
||||
inline Font BrowserFont() { return StdFont(); }
|
||||
|
||||
struct CppItemInfo : CppItem {
|
||||
String scope;
|
||||
bool over;
|
||||
bool overed;
|
||||
int inherited;
|
||||
int typei;
|
||||
|
||||
CppItemInfo() { over = overed = virt = false; inherited = line = 0; }
|
||||
};
|
||||
|
||||
enum {
|
||||
ITEM_TEXT,
|
||||
ITEM_NAME,
|
||||
ITEM_CPP_TYPE,
|
||||
ITEM_CPP,
|
||||
ITEM_PNAME,
|
||||
ITEM_TNAME,
|
||||
ITEM_NUMBER,
|
||||
ITEM_SIGN,
|
||||
ITEM_UPP,
|
||||
ITEM_TYPE,
|
||||
|
||||
ITEM_PTYPE = ITEM_TYPE + 10000,
|
||||
};
|
||||
|
||||
struct ItemTextPart : Moveable<ItemTextPart> {
|
||||
int pos;
|
||||
int len;
|
||||
int type;
|
||||
int ii;
|
||||
int pari;
|
||||
};
|
||||
|
||||
Vector<ItemTextPart> ParseItemNatural(const String& name, const String& natural, const String& ptype,
|
||||
const String& pname, const String& type, const String& tname,
|
||||
const String& ctname, const char *s);
|
||||
Vector<ItemTextPart> ParseItemNatural(const String& name, const CppItem& m, const char *natural);
|
||||
Vector<ItemTextPart> ParseItemNatural(const CppItemInfo& m);
|
||||
Vector<ItemTextPart> ParseItemNatural(const CppItemInfo& m);
|
||||
|
||||
int GetItemHeight(const CppItem& m, int cx);
|
||||
|
||||
enum AdditionalKinds {
|
||||
KIND_INCLUDEFILE = 100,
|
||||
KIND_INCLUDEFILE_ANY,
|
||||
KIND_INCLUDEFOLDER,
|
||||
};
|
||||
|
||||
void PaintText(Draw& w, int& x, int y, const char *text,
|
||||
const Vector<ItemTextPart>& n, int starti, int count, bool focuscursor,
|
||||
Color _ink, bool italic);
|
||||
void PaintCppItemImage(Draw& w, int& x, int ry, int access, int kind, bool focuscursor);
|
||||
|
||||
struct CppItemInfoDisplay : public Display
|
||||
{
|
||||
bool namestart;
|
||||
bool showtopic;
|
||||
|
||||
int DoPaint(Draw& w, const Rect& r, const Value& q,
|
||||
Color _ink, Color paper, dword style) const;
|
||||
virtual void Paint(Draw& w, const Rect& r, const Value& q,
|
||||
Color _ink, Color paper, dword style) const;
|
||||
virtual Size GetStdSize(const Value& q) const;
|
||||
|
||||
CppItemInfoDisplay() { namestart = false; showtopic = false; }
|
||||
};
|
||||
|
||||
int SearchItemFilter(int c);
|
||||
|
||||
struct CodeBrowser {
|
||||
typedef CodeBrowser CLASSNAME;
|
||||
|
||||
CppItemInfoDisplay display;
|
||||
ArrayCtrl scope;
|
||||
ArrayCtrl item;
|
||||
EditString search_scope;
|
||||
EditString search;
|
||||
// FrameRight<Button> clear;
|
||||
int range;
|
||||
ButtonOption rangebutton[3];
|
||||
ButtonOption sort;
|
||||
Event<> WhenKeyItem;
|
||||
Event<> WhenClear;
|
||||
|
||||
String GetPm();
|
||||
void Load();
|
||||
void LoadScope();
|
||||
void Goto(const String& coderef, const String& rfile);
|
||||
void Search();
|
||||
void NameStart() { display.namestart = true; }
|
||||
String GetCodeRef(int i) const;
|
||||
String GetCodeRef() const;
|
||||
CppItemInfo GetItemInfo(int i) const;
|
||||
CppItemInfo GetItemInfo() const;
|
||||
bool Key(dword key, int count);
|
||||
bool IsSearch() const;
|
||||
void ClearSearch();
|
||||
void SetRange(int r);
|
||||
void Sort();
|
||||
|
||||
CodeBrowser();
|
||||
};
|
||||
|
||||
struct TopicInfo : Moveable<TopicInfo> {
|
||||
Time time;
|
||||
String path;
|
||||
String title;
|
||||
Vector<int> words;
|
||||
|
||||
TopicInfo() {}
|
||||
|
||||
rval_default(TopicInfo);
|
||||
};
|
||||
|
||||
String GetTopicPath(const TopicLink& link);
|
||||
|
|
@ -204,8 +35,8 @@ void SyncTopicFile(const String& link);
|
|||
String GetTopicTitle(const String& link);
|
||||
void InvalidateTopicInfoPath(const String& path);
|
||||
|
||||
bool LegacyRef(String& ref);
|
||||
|
||||
String CleanupTppId(const String& ref);
|
||||
Vector<String> AnnotationCandidates(const String& ref);
|
||||
Vector<String> GetRefLinks(const String& ref);
|
||||
|
||||
int TopicWordIndex(const String& w);
|
||||
|
|
@ -215,25 +46,11 @@ bool MatchTopicLink(const String& link, const Vector<String>& query);
|
|||
#define LAYOUTFILE <ide/Browser/Topic.lay>
|
||||
#include <CtrlCore/lay.h>
|
||||
|
||||
struct ReferenceDlg : WithReferenceDlgLayout<TopWindow>, CodeBrowser {
|
||||
void EnterItem();
|
||||
void EnterItemOk();
|
||||
void Set(const String& s);
|
||||
String Get() const { return ~reference; }
|
||||
|
||||
void Serialize(Stream& s) { SerializePlacement(s); }
|
||||
|
||||
typedef ReferenceDlg CLASSNAME;
|
||||
|
||||
ReferenceDlg();
|
||||
};
|
||||
|
||||
#define IMAGEFILE <ide/Browser/Topic.iml>
|
||||
#define IMAGECLASS TopicImg
|
||||
#include <Draw/iml_header.h>
|
||||
|
||||
String DecoratedItem(const String& name, const CppItem& m, const char *natural, int pari = INT_MIN);
|
||||
|
||||
int CharFilterID(int c);
|
||||
|
||||
bool ParseTopicFileName(const String& fn, String& topic, int& lang);
|
||||
|
|
@ -330,13 +147,14 @@ protected:
|
|||
|
||||
String GetCurrentTopicPath();
|
||||
|
||||
void InsertNew(const String& coderef);
|
||||
void InsertNew(const String& id, const String& pretty);
|
||||
void InsertNew(const AnnotationItem& m);
|
||||
void NewTopic();
|
||||
void MoveTopic();
|
||||
void RemoveTopic();
|
||||
|
||||
bool autosave;
|
||||
ReferenceDlg ref;
|
||||
// ReferenceDlg ref; // TODO
|
||||
|
||||
void ShowTopic(bool b = true);
|
||||
void HideTopic() { ShowTopic(false); }
|
||||
|
|
@ -362,7 +180,6 @@ protected:
|
|||
|
||||
void Tools(Bar& bar);
|
||||
void Label(String&);
|
||||
void InsertItem();
|
||||
|
||||
void FindBrokenRef();
|
||||
void JumpToDefinition();
|
||||
|
|
@ -392,10 +209,10 @@ public:
|
|||
typedef TopicEditor CLASSNAME;
|
||||
|
||||
void ShowEditor(bool b) { editor.Show(b); }
|
||||
bool NewTopicEx(const String& name, const String& create);
|
||||
bool NewTopicEx(const String& name, const AnnotationItem *create);
|
||||
void Open(const String& grouppath);
|
||||
void OpenFile(const String& path);
|
||||
void GoTo(const String& topic, const String& link, const String& create, bool before);
|
||||
void GoTo(const String& _topic, const String& link, const AnnotationItem *create, bool before);
|
||||
void PersistentFindReplace(bool b) { editor.PersistentFindReplace(b); }
|
||||
|
||||
static int GetSerial();
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
LAYOUT(QueryLayout, 612, 416)
|
||||
ITEM(Upp::Label, dv___0, SetLabel(t_("Name")).LeftPosZ(8, 72).TopPosZ(4, 19))
|
||||
ITEM(Upp::WithDropChoice<Upp::EditString>, name, LeftPosZ(8, 168).TopPosZ(24, 19))
|
||||
ITEM(Upp::LabelBox, dv___2, SetLabel(t_("Access")).LeftPosZ(8, 164).TopPosZ(52, 72))
|
||||
ITEM(Upp::Option, a_private, SetLabel(t_("private")).LeftPosZ(20, 56).TopPosZ(68, 16))
|
||||
ITEM(Upp::Option, a_protected, SetLabel(t_("protected")).LeftPosZ(20, 64).TopPosZ(84, 16))
|
||||
ITEM(Upp::Option, a_public, SetLabel(t_("public")).LeftPosZ(20, 56).TopPosZ(100, 16))
|
||||
ITEM(Upp::LabelBox, dv___6, SetLabel(t_("Kind")).LeftPosZ(8, 164).TopPosZ(148, 88))
|
||||
ITEM(Upp::Option, type, SetLabel(t_("Type")).LeftPosZ(20, 44).TopPosZ(164, 16))
|
||||
ITEM(Upp::Option, code, SetLabel(t_("Code")).LeftPosZ(20, 44).TopPosZ(180, 16))
|
||||
ITEM(Upp::Option, data, SetLabel(t_("Data")).LeftPosZ(20, 44).TopPosZ(196, 16))
|
||||
ITEM(Upp::Option, macro, SetLabel(t_("Macro")).LeftPosZ(20, 52).TopPosZ(212, 16))
|
||||
ITEM(Upp::LabelBox, dv___11, SetLabel(t_("Documentation")).LeftPosZ(8, 164).TopPosZ(260, 60))
|
||||
ITEM(Upp::Option, documented, SetLabel(t_("Documented")).LeftPosZ(20, 100).TopPosZ(280, 15))
|
||||
ITEM(Upp::Option, notdocumented, SetLabel(t_("Not documented")).LeftPosZ(20, 100).TopPosZ(296, 15))
|
||||
ITEM(FileList, package, LeftPosZ(184, 208).VSizePosZ(8, 44))
|
||||
ITEM(FileList, file, HSizePosZ(400, 8).VSizePosZ(8, 44))
|
||||
ITEM(Upp::Button, clear, SetLabel(t_("Clear")).LeftPosZ(12, 64).BottomPosZ(8, 24))
|
||||
ITEM(Upp::Button, ok, SetLabel(t_("OK")).RightPosZ(8, 64).BottomPosZ(8, 24))
|
||||
ITEM(Upp::Button, cancel, SetLabel(t_("Cancel")).RightPosZ(80, 64).BottomPosZ(8, 24))
|
||||
END_LAYOUT
|
||||
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
description "TheIDE - code browser and Topic++\377B";
|
||||
|
||||
uses
|
||||
CppBase,
|
||||
PdfDraw,
|
||||
RichEdit,
|
||||
plugin/lz4,
|
||||
|
|
@ -10,19 +9,10 @@ uses
|
|||
file
|
||||
Browser.h options(BUILDER_OPTION) PCH,
|
||||
CodeBase readonly separator,
|
||||
Lay.cpp,
|
||||
Iml.cpp,
|
||||
Sch.cpp,
|
||||
Util.cpp,
|
||||
Base.cpp,
|
||||
Item.cpp,
|
||||
ItemDisplay.cpp,
|
||||
CodeBrowser.cpp,
|
||||
Browser.lay,
|
||||
Browser.iml,
|
||||
Topic readonly separator,
|
||||
TopicBase.cpp,
|
||||
Reference.cpp,
|
||||
File.cpp,
|
||||
Topic.cpp,
|
||||
Template.cpp,
|
||||
|
|
|
|||
|
|
@ -1,378 +0,0 @@
|
|||
#include "Browser.h"
|
||||
|
||||
bool MatchCib(const String& s, const String& match)
|
||||
{
|
||||
if(IsNull(match)) return true;
|
||||
int q = ToUpper(s).Find(match);
|
||||
return q > 0 && !iscid(s[q - 1]) || q == 0;
|
||||
}
|
||||
|
||||
bool MatchPm(const String& fn, const String& pm)
|
||||
{
|
||||
if(IsNull(pm))
|
||||
return true;
|
||||
return fn.StartsWith(pm);
|
||||
}
|
||||
|
||||
bool MatchPm(int file, const String& pm)
|
||||
{
|
||||
if(IsNull(pm))
|
||||
return true;
|
||||
return GetSourceFilePath(file).StartsWith(pm);
|
||||
}
|
||||
|
||||
bool MatchPm(const Array<CppItem>& n, const String& pm)
|
||||
{
|
||||
if(IsNull(pm))
|
||||
return true;
|
||||
for(int i = 0; i < n.GetCount(); i++)
|
||||
if(MatchPm(n[i].file, pm))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasItem(const Array<CppItem>& n, const String& m)
|
||||
{
|
||||
if(IsNull(m))
|
||||
return true;
|
||||
for(int i = 0; i < n.GetCount(); i++)
|
||||
if(n[i].uname.StartsWith(m))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ScopeLess {
|
||||
bool operator()(const String& a, const String& b) const {
|
||||
if((*a == '<') != (*b == '<'))
|
||||
return *a > *b;
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
String CodeBrowser::GetPm()
|
||||
{
|
||||
String pm;
|
||||
if(TheIde() && range) {
|
||||
if(range == 1)
|
||||
pm = TheIde()->IdeGetNestFolder();
|
||||
else {
|
||||
pm = TheIde()->IdeGetFileName();
|
||||
if(range == 2)
|
||||
pm = GetFileFolder(pm);
|
||||
}
|
||||
}
|
||||
return pm;
|
||||
}
|
||||
|
||||
String GetFileText(const String& s)
|
||||
{
|
||||
return '<' + GetFileName(GetFileFolder(s)) + '/' + GetFileName(s) + '>';
|
||||
}
|
||||
|
||||
void CodeBrowser::Load()
|
||||
{
|
||||
String match = ToUpper((String)~search_scope);
|
||||
String pm = GetPm();
|
||||
Vector<String> txt;
|
||||
Vector<Value> ndx;
|
||||
Index<int> fi;
|
||||
Index<String> fs;
|
||||
{
|
||||
CodeBaseLock __;
|
||||
for(int i = 0; i < CodeBase().GetCount(); i++) {
|
||||
String s = CodeBase().GetKey(i);
|
||||
const Array<CppItem>& n = CodeBase()[i];
|
||||
if(s.GetCount())
|
||||
if(MatchCib(s, match) && MatchPm(n, pm)) {
|
||||
txt.Add(s);
|
||||
ndx.Add(s);
|
||||
}
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
int f = n[i].file;
|
||||
if(fi.Find(f) < 0) {
|
||||
String s = GetFileText(GetSourceFilePath(f));
|
||||
if(s.StartsWith(pm) && MatchCib(s, match)) {
|
||||
txt.Add(s);
|
||||
ndx.Add(f);
|
||||
fs.Add(s);
|
||||
fi.Add(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const Workspace& wspc = GetIdeWorkspace();
|
||||
for(int i = 0; i < wspc.GetCount(); i++) {
|
||||
String pn = wspc[i];
|
||||
const Package& p = wspc.GetPackage(i);
|
||||
String pp = PackageDirectory(pn);
|
||||
for(int j = 0; j < p.GetCount(); j++)
|
||||
if(!p[j].separator) {
|
||||
String fn = AppendFileName(pp, p[j]);
|
||||
String s = GetFileText(AppendFileName(pn, p[j]));
|
||||
if(fs.Find(s) < 0 && MatchCib(s, match) && MatchPm(fn, pm)) {
|
||||
int f = GetSourceFileIndex(SourcePath(pn, p[j]));
|
||||
txt.Add(s);
|
||||
ndx.Add(f);
|
||||
fs.Add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IndexSort(txt, ndx, ScopeLess());
|
||||
Value key = scope.GetKey();
|
||||
int sc = scope.GetCursorSc();
|
||||
scope.Clear();
|
||||
for(int i = 0; i < txt.GetCount(); i++)
|
||||
scope.Add(IsString(ndx[i]) ? ndx[i] : Null, txt[i], ndx[i]);
|
||||
if(scope.FindSetCursor(key))
|
||||
scope.ScCursor(sc);
|
||||
// clear.Enable(IsSearch());
|
||||
}
|
||||
|
||||
int ItemCompare(const Value& v1, const Value& v2)
|
||||
{
|
||||
const CppItemInfo& a = ValueTo<CppItemInfo>(v1);
|
||||
const CppItemInfo& b = ValueTo<CppItemInfo>(v2);
|
||||
int q = a.inherited - b.inherited;
|
||||
if(q) return q;
|
||||
q = SgnCompare(GetSourceFilePath(a.file), GetSourceFilePath(b.file));
|
||||
return q ? q : a.line - b.line;
|
||||
}
|
||||
|
||||
int ItemCompareLexical(const Value& v1, const Value& v2)
|
||||
{
|
||||
const CppItemInfo& a = ValueTo<CppItemInfo>(v1);
|
||||
const CppItemInfo& b = ValueTo<CppItemInfo>(v2);
|
||||
int q = (int)b.IsType() - (int)a.IsType();
|
||||
if(q) return q;
|
||||
q = SgnCompare(a.name, b.name);
|
||||
if(q) return q;
|
||||
return SgnCompare(a.qitem, b.qitem);
|
||||
}
|
||||
|
||||
void GatherMethods(const String& type, VectorMap<String, bool>& inherited, bool g, Index<String>& done)
|
||||
{
|
||||
CodeBaseLock __;
|
||||
if(done.Find(type) >= 0) return;
|
||||
done.Add(type);
|
||||
int q = CodeBase().Find(type);
|
||||
if(q < 0) return;
|
||||
const Array<CppItem>& n = CodeBase()[q];
|
||||
Index<String> set;
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
const CppItem& m = n[i];
|
||||
if(set.Find(m.qitem) < 0) {
|
||||
set.Add(m.qitem);
|
||||
if(m.IsType()) {
|
||||
Vector<String> base = Split(m.qptype, ';');
|
||||
for(int i = 0; i < base.GetCount(); i++)
|
||||
GatherMethods(base[i], inherited, true, done);
|
||||
}
|
||||
if(m.IsCode() && g) {
|
||||
bool& virt = inherited.GetAdd(m.qitem);
|
||||
virt = virt || m.virt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GatherMethods(const String& type, VectorMap<String, bool>& inherited, bool g)
|
||||
{
|
||||
Index<String> done;
|
||||
GatherMethods(type, inherited, g, done);
|
||||
}
|
||||
|
||||
void CodeBrowser::LoadScope()
|
||||
{
|
||||
Value key = item.GetKey();
|
||||
int sc = item.GetCursorSc();
|
||||
{
|
||||
CodeBaseLock __;
|
||||
String find = ToUpper((String)~search);
|
||||
item.Clear();
|
||||
if(!scope.IsCursor())
|
||||
return;
|
||||
Value x = scope.Get(2);
|
||||
int file = IsNumber(x) ? (int)x : -1;
|
||||
String scope = file < 0 ? String(x) : String();
|
||||
auto Do = [&](int q) {
|
||||
const Array<CppItem>& n = CodeBase()[q];
|
||||
VectorMap<String, bool> inherited;
|
||||
if(file < 0)
|
||||
GatherMethods(scope, inherited, false);
|
||||
Index<String> set;
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
CppItemInfo m;
|
||||
(CppItem&) m = n[i];
|
||||
if((file < 0 || m.file == file) && m.uname.StartsWith(find) && set.Find(m.qitem) < 0) {
|
||||
set.Add(m.qitem);
|
||||
int q = inherited.Find(m.qitem);
|
||||
if(q >= 0) {
|
||||
m.over = true;
|
||||
m.virt = m.virt || inherited[q];
|
||||
}
|
||||
item.Add(m.qitem, RawToValue(m));
|
||||
}
|
||||
}
|
||||
};
|
||||
if(file >= 0)
|
||||
for(int q = 0; q < CodeBase().GetCount(); q++)
|
||||
Do(q);
|
||||
else {
|
||||
int q = CodeBase().Find(scope);
|
||||
if(q >= 0)
|
||||
Do(q);
|
||||
}
|
||||
}
|
||||
item.Sort(1, sort ? ItemCompareLexical : ItemCompare);
|
||||
if(item.FindSetCursor(key))
|
||||
item.ScCursor(sc);
|
||||
// clear.Enable(IsSearch());
|
||||
}
|
||||
|
||||
String CodeBrowser::GetCodeRef(int i) const
|
||||
{
|
||||
if(scope.IsCursor())
|
||||
return MakeCodeRef(scope.GetKey(), item.Get(i, 0));
|
||||
return Null;
|
||||
}
|
||||
|
||||
String CodeBrowser::GetCodeRef() const
|
||||
{
|
||||
return item.IsCursor() ? GetCodeRef(item.GetCursor()) : String();
|
||||
}
|
||||
|
||||
CppItemInfo CodeBrowser::GetItemInfo(int i) const
|
||||
{
|
||||
return ValueTo<CppItemInfo>(item.Get(i, 1));
|
||||
}
|
||||
|
||||
CppItemInfo CodeBrowser::GetItemInfo() const
|
||||
{
|
||||
return GetItemInfo(item.GetCursor());
|
||||
}
|
||||
|
||||
int SearchItemFilter(int c)
|
||||
{
|
||||
c = ToUpper(c);
|
||||
return IsAlNum(c) || c == '/' || c == '.' || c == '<' || c == '>' || c == '_' ? c : 0;
|
||||
}
|
||||
|
||||
void CodeBrowser::Goto(const String& coderef, const String& rfile)
|
||||
{
|
||||
if(IsNull(coderef)) {
|
||||
item.KillCursor();
|
||||
scope.FindSetCursor(GetFileText(rfile), 1);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(coderef != GetCodeRef()) {
|
||||
if(!IsNull(search_scope)) {
|
||||
Load();
|
||||
LoadScope();
|
||||
}
|
||||
String sc, im;
|
||||
SplitCodeRef(coderef, sc, im);
|
||||
if(IsNull(sc)) {
|
||||
const CppItem *m = GetCodeRefItem(coderef, rfile);
|
||||
if(m)
|
||||
scope.FindSetCursor(m->file, 2);
|
||||
}
|
||||
else
|
||||
scope.FindSetCursor(sc);
|
||||
item.FindSetCursor(im);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeBrowser::Search()
|
||||
{
|
||||
LoadScope();
|
||||
if(!scope.IsCursor())
|
||||
scope.SetCursor(0);
|
||||
if(!item.IsCursor())
|
||||
item.SetCursor(0);
|
||||
}
|
||||
|
||||
bool CodeBrowser::Key(dword key, int count)
|
||||
{
|
||||
// clear.Enable(IsSearch());
|
||||
if(key == K_UP || key == K_DOWN) {
|
||||
if(search.HasFocus()) {
|
||||
int l, h;
|
||||
search.GetSelection(l, h);
|
||||
Value v = ~search;
|
||||
if(item.IsCursor())
|
||||
item.Key(key, count);
|
||||
else
|
||||
if(key == K_UP)
|
||||
item.GoEnd();
|
||||
else
|
||||
item.GoBegin();
|
||||
WhenKeyItem();
|
||||
search <<= v;
|
||||
search.SetFocus();
|
||||
search.SetSelection(l, h);
|
||||
return true;
|
||||
}
|
||||
if(search_scope.HasFocus()) {
|
||||
scope.Key(key, count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CodeBrowser::IsSearch() const
|
||||
{
|
||||
return !IsNull(search) || !IsNull(search_scope);
|
||||
}
|
||||
|
||||
void CodeBrowser::ClearSearch()
|
||||
{
|
||||
if(!IsSearch())
|
||||
return;
|
||||
search_scope <<= search <<= Null;
|
||||
Load();
|
||||
WhenClear();
|
||||
}
|
||||
|
||||
void CodeBrowser::SetRange(int r)
|
||||
{
|
||||
if(range == r)
|
||||
r = 0;
|
||||
range = r;
|
||||
for(int i = 0; i < 3; i++)
|
||||
rangebutton[i] <<= range == i + 1;
|
||||
Load();
|
||||
}
|
||||
|
||||
CodeBrowser::CodeBrowser()
|
||||
{
|
||||
scope.AddKey();
|
||||
scope.AddColumn("Scope");
|
||||
scope.WhenSel = THISBACK(LoadScope);
|
||||
scope.NoHeader().NoGrid();
|
||||
search_scope <<= THISBACK(Load);
|
||||
search_scope.SetFilter(SearchItemFilter);
|
||||
search_scope.NullText("Search type or header ");
|
||||
item.AddKey();
|
||||
item.AddColumn("Item").SetDisplay(display).Margin(2);
|
||||
item.NoHeader();
|
||||
item.SetLineCy(BrowserFont().Info().GetHeight() + 3);
|
||||
search.NullText("Find ");
|
||||
search.SetFilter(SearchItemFilter);
|
||||
search <<= THISBACK(Search);
|
||||
// search.AddFrame(clear);
|
||||
// clear.SetImage(BrowserImg::Clear());
|
||||
// clear.NoWantFocus();
|
||||
// clear <<= THISBACK(ClearSearch);
|
||||
range = 0;
|
||||
static const char *tip[] = { "Nest", "Package", "File" };
|
||||
for(int i = 0; i < 3; i++)
|
||||
rangebutton[i].SetImage(BrowserImg::Get(BrowserImg::I_range_nest + i)).Tip(tip[i]).NoWantFocus()
|
||||
<<= THISBACK1(SetRange, i + 1);
|
||||
SetRange(0);
|
||||
sort.Tip("Order by names");
|
||||
sort.SetImage(BrowserImg::Sort()).NoWantFocus();
|
||||
sort <<= THISBACK(LoadScope);
|
||||
}
|
||||
|
|
@ -17,12 +17,14 @@ static const char styles[] =
|
|||
|
||||
void TopicEditor::JumpToDefinition()
|
||||
{
|
||||
PostCallback(callback1(IdeGotoCodeRef, editor.GetFormatInfo().label));
|
||||
//TODO
|
||||
// PostCallback(callback1(IdeGotoCodeRef, editor.GetFormatInfo().label));
|
||||
}
|
||||
|
||||
void TopicEditor::Label(String& label)
|
||||
{
|
||||
Save();
|
||||
/* TODO ReferenceDlg
|
||||
if(ref.item.IsMultiSelect())
|
||||
ref.item.ClearSelection();
|
||||
ref.item.MultiSelect(false);
|
||||
|
|
@ -32,6 +34,7 @@ void TopicEditor::Label(String& label)
|
|||
if(ref.Execute() != IDOK)
|
||||
return;
|
||||
label = ref.Get();
|
||||
*/
|
||||
}
|
||||
|
||||
Uuid CodeItemUuid()
|
||||
|
|
@ -72,10 +75,19 @@ void TopicEditor::FindBrokenRef()
|
|||
RichPara para = txt.Get(i);
|
||||
if(para.format.label == "noref")
|
||||
continue;
|
||||
if(!IsNull(para.format.label) && GetCodeRefItem(para.format.label))
|
||||
continue;
|
||||
editor.Move(txt.GetPartPos(i));
|
||||
return;
|
||||
bool found = false;
|
||||
String lbl_id = CleanupTppId(para.format.label);
|
||||
if(!IsNull(para.format.label))
|
||||
for(const auto& f : ~CodeIndex())
|
||||
for(const AnnotationItem& m : f.value.items)
|
||||
if(FindIndex(AnnotationCandidates(m.id), lbl_id) >= 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if(!found) {
|
||||
editor.Move(txt.GetPartPos(i));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -94,12 +106,10 @@ void TopicEditor::FindBrokenRef()
|
|||
|
||||
void TopicEditor::Tools(Bar& bar)
|
||||
{
|
||||
bar.Add("Insert code item..", IdeCommonImg::InsertItem(), THISBACK(InsertItem))
|
||||
.Key(K_CTRL_INSERT);
|
||||
String l = editor.GetFormatInfo().label;
|
||||
bool b = l.GetCount() > 2 && l != "noref";
|
||||
bar.Add(b, "See referenced code", IdeCommonImg::Source(), THISBACK(JumpToDefinition))
|
||||
.Key(K_ALT_J).Key(K_ALT_I);
|
||||
bar.Add(b, "See referenced code", IdeCommonImg::Cpp(), THISBACK(JumpToDefinition))
|
||||
.Key(K_ALT_U).Key(K_ALT_I);
|
||||
bar.Add("Find broken references..", IdeCommonImg::FindBrokenRef(), THISBACK(FindBrokenRef))
|
||||
.Key(K_CTRL_F3);
|
||||
#ifdef REPAIR
|
||||
|
|
@ -165,31 +175,34 @@ static int sSplitT(int c) {
|
|||
return c == ';' || c == '<' || c == '>' || c == ',';
|
||||
}
|
||||
|
||||
bool IsCodeRefType(const String& type)
|
||||
String TopicEditor::GetLang() const
|
||||
{
|
||||
if(type.GetCount() == 0)
|
||||
return false;
|
||||
CodeBaseLock __;
|
||||
return CodeBase().Find(type) >= 0;
|
||||
int q = topicpath.ReverseFind('@');
|
||||
if(q >= 0) {
|
||||
int lang = LNGFromText(~topicpath + q + 1);
|
||||
if(lang)
|
||||
return LNGAsText(lang);
|
||||
}
|
||||
return "%";
|
||||
}
|
||||
|
||||
String DecoratedItem(const String& name, const CppItem& m, const char *natural, int pari)
|
||||
String DecoratedItem(const String& name, const String& pretty)
|
||||
{
|
||||
String qtf = "[%00-00K ";
|
||||
Vector<ItemTextPart> n = ParseItemNatural(name, m, natural);
|
||||
Vector<ItemTextPart> n = ParsePretty(name, pretty);
|
||||
/* TODO
|
||||
if(pari < 0) {
|
||||
if(m.virt)
|
||||
qtf << "[@B virtual] ";
|
||||
if(m.kind == CLASSFUNCTION || m.kind == CLASSFUNCTIONTEMPLATE)
|
||||
qtf << "[@B static] ";
|
||||
}
|
||||
Vector<String> qt = Split(m.qptype, sSplitT, false);
|
||||
Vector<String> tt = Split(m.qtype, sSplitT, false);
|
||||
*/
|
||||
// Vector<String> qt = Split(m.qptype, sSplitT, false);
|
||||
// Vector<String> tt = Split(m.qtype, sSplitT, false);
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
ItemTextPart& p = n[i];
|
||||
qtf << "[";
|
||||
if(p.pari == pari)
|
||||
qtf << "$C";
|
||||
switch(p.type) {
|
||||
case ITEM_PNAME:
|
||||
qtf << "*";
|
||||
|
|
@ -209,37 +222,29 @@ String DecoratedItem(const String& name, const CppItem& m, const char *natural,
|
|||
case ITEM_CPP:
|
||||
qtf << "@B";
|
||||
break;
|
||||
default:
|
||||
int q = p.type - ITEM_PTYPE;
|
||||
if(q >= 0 && q < qt.GetCount() && IsCodeRefType(qt[q]) && pari < 0)
|
||||
qtf << "_^" << qt[q] << '^';
|
||||
q = p.type - ITEM_TYPE;
|
||||
if(q >= 0 && q < tt.GetCount() && IsCodeRefType(tt[q]) && pari < 0)
|
||||
qtf << "_^" << tt[q] << '^';
|
||||
break;
|
||||
}
|
||||
qtf << ' ';
|
||||
qtf << NaturalDeQtf(String(~m.natural + p.pos, p.len));
|
||||
qtf << ']';
|
||||
qtf << " \1";
|
||||
qtf << String(~pretty + p.pos, p.len);
|
||||
qtf << "\1]";
|
||||
}
|
||||
return qtf + "]";
|
||||
}
|
||||
|
||||
String CreateQtf(const String& item, const String& name, const CppItem& m, const String& lang, bool onlyhdr = false)
|
||||
String CreateQtf(const AnnotationItem& m, const String& lang, bool onlyhdr = false)
|
||||
{
|
||||
String qtf;
|
||||
bool str = m.kind == STRUCT || m.kind == STRUCTTEMPLATE;
|
||||
bool str = IsStruct(m.kind);
|
||||
if(!str)
|
||||
qtf << "[s4 &]";
|
||||
String st = str ? "[s2;" : "[s1;";
|
||||
String k = st + ':' + DeQtf(item) + ": ";
|
||||
if(m.IsTemplate() && str) {
|
||||
String k = st + ":" + DeQtf(m.id) + ": ";
|
||||
if(IsTemplate(m.kind) && str) {
|
||||
int q = 0;
|
||||
int w = 0;
|
||||
while(q < m.natural.GetLength()) {
|
||||
if(m.natural[q] == '<')
|
||||
while(q < m.pretty.GetLength()) {
|
||||
if(m.pretty[q] == '<')
|
||||
w++;
|
||||
if(m.natural[q] == '>') {
|
||||
if(m.pretty[q] == '>') {
|
||||
w--;
|
||||
if(w == 0) {
|
||||
q++;
|
||||
|
|
@ -248,121 +253,58 @@ String CreateQtf(const String& item, const String& name, const CppItem& m, const
|
|||
}
|
||||
q++;
|
||||
}
|
||||
qtf << "[s2:noref: " << DecoratedItem(name, m, m.natural.Mid(0, q)) << "&][s2 " << k;
|
||||
if(q < m.natural.GetLength()) {
|
||||
while((byte)m.natural[q] <= 32)
|
||||
qtf << "[s2:noref: " << DecoratedItem(m.name, m.pretty.Mid(0, q)) << "&][s2 " << k;
|
||||
if(q < m.pretty.GetLength()) {
|
||||
while((byte)m.pretty[q] <= 32)
|
||||
q++;
|
||||
qtf << DecoratedItem(name, m, m.natural.Mid(q));
|
||||
qtf << DecoratedItem(m.name, m.pretty.Mid(q));
|
||||
}
|
||||
}
|
||||
else
|
||||
qtf << k << DecoratedItem(name, m, m.natural);
|
||||
qtf << k << DecoratedItem(m.name, m.pretty);
|
||||
|
||||
qtf << "&]";
|
||||
if(onlyhdr)
|
||||
return qtf;
|
||||
|
||||
qtf << "[s3%" << lang << " ";
|
||||
String d;
|
||||
Vector<String> t = Split(m.tname, ';');
|
||||
for(int i = 0; i < t.GetCount(); i++) {
|
||||
if(i)
|
||||
d << ' ';
|
||||
d << "[%-*@g " << DeQtf(t[i]) << "]";
|
||||
|
||||
if(!str) {
|
||||
Vector<ItemTextPart> n = ParsePretty(m.name, m.pretty);
|
||||
if(!str) {
|
||||
bool was;
|
||||
for(const auto& h : n)
|
||||
if(h.type == ITEM_PNAME) {
|
||||
qtf << " [%-*@r \1" << m.pretty.Mid(h.pos, h.len) << "\1]";
|
||||
was = true;
|
||||
}
|
||||
if(was)
|
||||
qtf << " .";
|
||||
}
|
||||
}
|
||||
d.Clear();
|
||||
d << "[%" << lang << " ";
|
||||
Vector<String> p = Split(m.pname, ';');
|
||||
if(!str)
|
||||
for(int i = 0; i < p.GetCount(); i++)
|
||||
d << " [%-*@r " << DeQtf(p[i]) << "]";
|
||||
if(!str && p.GetCount())
|
||||
qtf << d << " .";
|
||||
qtf << "&]";
|
||||
qtf << "[s7 &]";
|
||||
return qtf;
|
||||
}
|
||||
|
||||
String TopicEditor::GetLang() const
|
||||
void TopicEditor::InsertNew(const AnnotationItem& m)
|
||||
{
|
||||
int q = topicpath.ReverseFind('@');
|
||||
if(q >= 0) {
|
||||
int lang = LNGFromText(~topicpath + q + 1);
|
||||
if(lang)
|
||||
return LNGAsText(lang);
|
||||
}
|
||||
return "%";
|
||||
}
|
||||
|
||||
void TopicEditor::InsertItem()
|
||||
{
|
||||
if(IsNull(topicpath))
|
||||
return;
|
||||
Save();
|
||||
ref.Title("Insert");
|
||||
if(ref.item.IsCursor())
|
||||
ref.item.SetFocus();
|
||||
ref.item.MultiSelect();
|
||||
ref.classlist.Show();
|
||||
int c = ref.Execute();
|
||||
if(c == IDCANCEL)
|
||||
return;
|
||||
if(c == IDYES) {
|
||||
String qtf = "&{{1 ";
|
||||
bool next = false;
|
||||
for(int i = 0; i < ref.scope.GetCount(); i++) {
|
||||
String s = ref.scope.Get(i, 1);
|
||||
if(*s != '<') {
|
||||
if(next)
|
||||
qtf << ":: ";
|
||||
qtf << DeQtf(s);
|
||||
next = true;
|
||||
}
|
||||
}
|
||||
qtf << "}}&";
|
||||
editor.PasteText(ParseQTF(qtf));
|
||||
return;
|
||||
}
|
||||
String qtf;
|
||||
if(ref.item.IsSelection()) {
|
||||
for(int i = 0; i < ref.item.GetCount(); i++)
|
||||
if(ref.item.IsSelected(i)) {
|
||||
CppItemInfo m = ref.GetItemInfo(i);
|
||||
qtf << CreateQtf(ref.GetCodeRef(i), m.name, m, GetLang());
|
||||
}
|
||||
}
|
||||
else
|
||||
if(ref.item.IsCursor()) {
|
||||
CppItemInfo m = ref.GetItemInfo();
|
||||
qtf << CreateQtf(ref.GetCodeRef(), m.name, m, GetLang());
|
||||
}
|
||||
else
|
||||
return;
|
||||
editor.BeginOp();
|
||||
editor.PasteText(ParseQTF(styles + qtf));
|
||||
editor.PasteText(ParseQTF(styles + CreateQtf(m, GetLang())));
|
||||
editor.PrevPara();
|
||||
editor.PrevPara();
|
||||
}
|
||||
|
||||
void TopicEditor::InsertNew(const String& coderef)
|
||||
{
|
||||
const CppItem *m = GetCodeRefItem(coderef);
|
||||
if(!m)
|
||||
return;
|
||||
editor.BeginOp();
|
||||
editor.PasteText(ParseQTF(styles + CreateQtf(coderef, m->name, *m, GetLang())));
|
||||
editor.PrevPara();
|
||||
editor.PrevPara();
|
||||
}
|
||||
/* TODO: remove
|
||||
void GoTo(const String& topic, const String& link, const String& create, bool before);
|
||||
|
||||
void TopicEditor::GoTo(const String& _topic, const String& link, const String& create, bool before)
|
||||
{
|
||||
if(topics_list.FindSetCursor(_topic) && !IsNull(link)) {
|
||||
editor.Select(editor.GetLength(), 0);
|
||||
if(!editor.GotoLabel(link)) {
|
||||
String l = link;
|
||||
LegacyRef(l);
|
||||
editor.GotoLabel(l);
|
||||
}
|
||||
for(String cr : AnnotationCandidates(link))
|
||||
if(editor.GotoLabel([&](const WString& id) { return cr == CleanupTppId(id.ToString()); }))
|
||||
break;
|
||||
if(!IsNull(create)) {
|
||||
if(!before)
|
||||
for(int pass = 0; pass < 2; pass++)
|
||||
|
|
@ -379,9 +321,36 @@ void TopicEditor::GoTo(const String& _topic, const String& link, const String& c
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void TopicEditor::GoTo(const String& _topic, const String& link, const AnnotationItem *create, bool before)
|
||||
{
|
||||
if(topics_list.FindSetCursor(_topic) && !IsNull(link)) {
|
||||
editor.Select(editor.GetLength(), 0);
|
||||
for(String cr : AnnotationCandidates(link))
|
||||
if(editor.GotoLabel([&](const WString& id) { return cr == CleanupTppId(id.ToString()); }))
|
||||
break;
|
||||
if(create) {
|
||||
if(!before)
|
||||
for(int pass = 0; pass < 2; pass++)
|
||||
for(;;) {
|
||||
int c = editor.GetCursor();
|
||||
RichText::FormatInfo f = editor.GetFormatInfo();
|
||||
if(f.styleid == BeginUuid() || (IsNull(f.label) || f.label == "noref") && pass)
|
||||
break;
|
||||
editor.NextPara();
|
||||
if(editor.GetCursor() == c)
|
||||
break;
|
||||
}
|
||||
InsertNew(*create);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TopicEditor::FixTopic()
|
||||
{
|
||||
// TODO
|
||||
#if 0
|
||||
String nest;
|
||||
if(!EditText(nest, "Fix topic", "Nest"))
|
||||
return;
|
||||
|
|
@ -460,6 +429,7 @@ void TopicEditor::FixTopic()
|
|||
editor.BeginOp();
|
||||
editor.SetSelection(0, txt.GetLength());
|
||||
editor.PasteText(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
String TopicEditor::GetFileName() const
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
#include "Browser.h"
|
||||
|
||||
#define LDUMP(x) // DDUMP(x)
|
||||
|
||||
String PreprocessImlFile(const char *fn)
|
||||
{
|
||||
String s = LoadFile(fn);
|
||||
|
||||
CParser p(s);
|
||||
String iml, i_ml;
|
||||
try {
|
||||
p.PassId("PREMULTIPLIED");
|
||||
for(;;) {
|
||||
if(p.Id("IMAGE_ID")) {
|
||||
p.Char('(');
|
||||
String id = p.ReadId();
|
||||
i_ml << "\tI_" << id << ",\n";
|
||||
iml << "\tstatic Image " << id << "();\n";
|
||||
p.Char(')');
|
||||
}
|
||||
else
|
||||
if(p.Id("IMAGE_META")) {
|
||||
p.Char('(');
|
||||
p.ReadString();
|
||||
p.Char(',');
|
||||
p.ReadString();
|
||||
p.Char(')');
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
|
||||
String r;
|
||||
#ifdef PLATFORM_WIN32
|
||||
FindFile ff(fn);
|
||||
r << "struct " << GetFileTitle(ff.GetPath()) << "Img {\n";
|
||||
#else
|
||||
r << "struct " << GetFileTitle(fn) << "Img {\n";
|
||||
#endif
|
||||
if(iml.GetCount())
|
||||
r << "\tenum {" << i_ml << "\t};\n" << iml;
|
||||
r <<
|
||||
"\n\tstatic Iml& Iml();"
|
||||
"static int Find(const Upp::String& s);"
|
||||
"static int Find(const char *s);"
|
||||
"static int GetCount();"
|
||||
"static String GetId(int i);"
|
||||
"static Image Get(int i);"
|
||||
"static Image Get(const char *s);"
|
||||
"static Image Get(const Upp::String& s);"
|
||||
"static void Set(int i, const Upp::Image& m);"
|
||||
"static void Set(const char *s, const Upp::Image& m);"
|
||||
"static void Reset();"
|
||||
"};\n";
|
||||
LDUMP(r);
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
#include "Browser.h"
|
||||
|
||||
#define IMAGECLASS BrowserImg
|
||||
#define IMAGEFILE <ide/Browser/Browser.iml>
|
||||
#include <Draw/iml_source.h>
|
||||
|
||||
#define LLOG(x) // DLOG(x)
|
||||
|
||||
bool IsCppKeyword(const String& id)
|
||||
{
|
||||
static Index<String> kw;
|
||||
ONCELOCK {
|
||||
const char **cppk = CppKeyword();
|
||||
for(int i = 0; cppk[i]; i++)
|
||||
kw.Add(cppk[i]);
|
||||
}
|
||||
return kw.Find(id) >= 0;
|
||||
}
|
||||
|
||||
bool IsCppType(const String& id)
|
||||
{
|
||||
static const char *t[] = {
|
||||
"int", "long", "short", "void", "float", "double", "char", "signed", "unsigned", "bool",
|
||||
"const", "mutable", "struct", "class", "union"
|
||||
};
|
||||
static Index<String> kt;
|
||||
ONCELOCK {
|
||||
for(int i = 0; i < __countof(t); i++)
|
||||
kt.Add(t[i]);
|
||||
}
|
||||
return kt.Find(id) >= 0;
|
||||
}
|
||||
|
||||
int InScListIndext(const char *s, const char *list)
|
||||
{
|
||||
int ii = 0;
|
||||
for(;;) {
|
||||
const char *q = s;
|
||||
while(*list == ' ') list++;
|
||||
for(;;) {
|
||||
if(*q == '\0' && *list == '\0') return ii;
|
||||
if(*q != *list) {
|
||||
if(*q == '\0' && (*list == '<' || *list == ';' || *list == ',' || *list == '>'))
|
||||
return ii;
|
||||
if(*list == '\0') return -1;
|
||||
break;
|
||||
}
|
||||
q++;
|
||||
list++;
|
||||
}
|
||||
while(*list && *list != ';' && *list != '<' && *list != '>' && *list != ',') list++;
|
||||
if(*list == '\0') return -1;
|
||||
list++;
|
||||
ii++;
|
||||
}
|
||||
}
|
||||
|
||||
static String s_pick_("pick_");
|
||||
|
||||
static bool sOperatorTab[256];
|
||||
|
||||
INITBLOCK {
|
||||
for(const char *s = "!+-*^/%~&|=[]:?."; *s; s++)
|
||||
sOperatorTab[(int)*s] = true;
|
||||
}
|
||||
|
||||
inline bool sOperator(byte c)
|
||||
{
|
||||
return sOperatorTab[c];
|
||||
}
|
||||
|
||||
Vector<ItemTextPart> ParseItemNatural(const String& name,
|
||||
const String& natural,
|
||||
const String& ptype, const String& pname,
|
||||
const String& type, const String& tname,
|
||||
const String& ctname,
|
||||
const char *s)
|
||||
{
|
||||
Vector<ItemTextPart> part;
|
||||
int len = name.GetLength();
|
||||
if(len == 0) {
|
||||
ItemTextPart& p = part.Add();
|
||||
p.pos = 0;
|
||||
p.len = natural.GetLength();
|
||||
p.type = ITEM_TEXT;
|
||||
p.pari = -1;
|
||||
return part;
|
||||
}
|
||||
bool param = false;
|
||||
int pari = -1;
|
||||
int par = 0;
|
||||
while(*s) {
|
||||
ItemTextPart& p = part.Add();
|
||||
p.pos = (int)(s - ~natural);
|
||||
p.type = ITEM_TEXT;
|
||||
p.pari = pari;
|
||||
int n = 1;
|
||||
if(*s >= '0' && *s <= '9') {
|
||||
while(s[n] >= '0' && s[n] <= '9' || (s[n] == 'x' || s[n] == 'X'))
|
||||
n++;
|
||||
p.type = ITEM_NUMBER;
|
||||
}
|
||||
else
|
||||
if(iscid(*s) || *s == ':') {
|
||||
if(strncmp(s, name, len) == 0 && !iscid(s[len])) {
|
||||
p.type = ITEM_NAME;
|
||||
n = len;
|
||||
param = true;
|
||||
}
|
||||
else {
|
||||
String id;
|
||||
n = 0;
|
||||
while(iscid(s[n]) || s[n] == ':')
|
||||
id.Cat(s[n++]);
|
||||
if(IsCppType(id))
|
||||
p.type = ITEM_CPP_TYPE;
|
||||
else
|
||||
if(IsCppKeyword(id))
|
||||
p.type = ITEM_CPP;
|
||||
else
|
||||
if(InScList(id, pname))
|
||||
p.type = ITEM_PNAME;
|
||||
else
|
||||
if(id == s_pick_) {
|
||||
p.type = ITEM_UPP;
|
||||
}
|
||||
else
|
||||
if(InScList(id, tname) || InScList(id, ctname))
|
||||
p.type = ITEM_TNAME;
|
||||
else
|
||||
if(param) {
|
||||
int ii = InScListIndext(id, ptype);
|
||||
if(ii >= 0)
|
||||
p.type = ITEM_PTYPE + ii;
|
||||
}
|
||||
else {
|
||||
int ii = InScListIndext(id, type);
|
||||
if(ii >= 0)
|
||||
p.type = ITEM_TYPE + ii;
|
||||
}
|
||||
LLOG("id: " << id << ", type: " << p.type);
|
||||
}
|
||||
}
|
||||
else
|
||||
if(sOperator(*s)) {
|
||||
while(sOperator(s[n]))
|
||||
n++;
|
||||
p.type = ITEM_CPP;
|
||||
}
|
||||
else {
|
||||
p.type = ITEM_SIGN;
|
||||
if(pari >= 0) {
|
||||
if(*s == '(' || *s == '<')
|
||||
par++;
|
||||
if(*s == ')' || *s == '>') {
|
||||
par--;
|
||||
if(par < 0) {
|
||||
p.pari = -1;
|
||||
pari = -1;
|
||||
param = false;
|
||||
}
|
||||
}
|
||||
if(*s == ',' && par == 0) {
|
||||
p.pari = -1;
|
||||
pari++;
|
||||
}
|
||||
}
|
||||
else
|
||||
if(*s == '(' && param) {
|
||||
pari = 0;
|
||||
par = 0;
|
||||
}
|
||||
while(s[n] && !iscid(s[n])) { // Anonymous structure name
|
||||
if(s[n] == '@') {
|
||||
p.len = n;
|
||||
return part;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
}
|
||||
p.len = n;
|
||||
s += n;
|
||||
}
|
||||
return part;
|
||||
}
|
||||
|
||||
Vector<ItemTextPart> ParseItemNatural(const String& name, const CppItem& m, const char *s)
|
||||
{
|
||||
return ParseItemNatural(name, m.natural, m.ptype, m.pname, m.type, m.tname, m.ctname, s);
|
||||
}
|
||||
|
||||
Vector<ItemTextPart> ParseItemNatural(const CppItemInfo& m, const char *s)
|
||||
{
|
||||
return ParseItemNatural(m.name, m, s);
|
||||
}
|
||||
|
||||
Vector<ItemTextPart> ParseItemNatural(const CppItemInfo& m)
|
||||
{
|
||||
return ParseItemNatural(m, ~m.natural + m.at);
|
||||
}
|
||||
|
|
@ -1,212 +0,0 @@
|
|||
#include "Browser.h"
|
||||
|
||||
void PaintText(Draw& w, int& x, int y, const char *text, const Vector<ItemTextPart>& n,
|
||||
int starti, int count, bool focuscursor, Color _ink, bool italic)
|
||||
{
|
||||
static int maxascent = MaxAscent(BrowserFont());
|
||||
for(int i = starti; i < count; i++) {
|
||||
const ItemTextPart& p = n[i];
|
||||
Font f = BrowserFont();
|
||||
Color ink = SColorText;
|
||||
switch(p.type) {
|
||||
case ITEM_PNAME:
|
||||
f.Bold();
|
||||
case ITEM_NUMBER:
|
||||
ink = SRed();
|
||||
break;
|
||||
case ITEM_TNAME:
|
||||
ink = SGreen();
|
||||
case ITEM_NAME:
|
||||
f.Bold();
|
||||
break;
|
||||
case ITEM_UPP:
|
||||
ink = SCyan();
|
||||
break;
|
||||
case ITEM_CPP_TYPE:
|
||||
case ITEM_CPP:
|
||||
case ITEM_SIGN:
|
||||
ink = SLtBlue();
|
||||
break;
|
||||
}
|
||||
if(italic)
|
||||
f.Italic();
|
||||
Size fsz = GetTextSize(text + p.pos, f, p.len);
|
||||
w.DrawText(x, y + maxascent - f.GetAscent(), text + p.pos,
|
||||
f, focuscursor ? _ink : ink, p.len);
|
||||
x += fsz.cx;
|
||||
}
|
||||
}
|
||||
|
||||
void PaintText(Draw& w, int& x, int y, const CppItemInfo& m, const Vector<ItemTextPart>& n,
|
||||
int starti, int count, bool focuscursor, Color _ink)
|
||||
{
|
||||
PaintText(w, x, y, ~m.natural, n, starti, count, focuscursor, _ink, m.overed);
|
||||
}
|
||||
|
||||
void PaintCppItemImage(Draw& w, int& x, int ry, int access, int kind, bool focuscursor)
|
||||
{
|
||||
Image img = decode(access, PROTECTED, BrowserImg::mprotected(),
|
||||
PRIVATE, BrowserImg::mprivate(),
|
||||
WITHBODY, BrowserImg::impl(),
|
||||
Image());
|
||||
if(!IsNull(img))
|
||||
w.DrawImage(x, ry - img.GetHeight() / 2, DPI(img));
|
||||
x += Zx(3);
|
||||
img = BrowserImg::unknown();
|
||||
Image bk;
|
||||
switch(kind) {
|
||||
case FUNCTIONTEMPLATE:
|
||||
bk = BrowserImg::template_function();
|
||||
case FUNCTION:
|
||||
img = BrowserImg::function();
|
||||
break;
|
||||
case INSTANCEFUNCTIONTEMPLATE:
|
||||
bk = BrowserImg::template_function();
|
||||
case INSTANCEFUNCTION:
|
||||
img = BrowserImg::instance_function();
|
||||
break;
|
||||
case CLASSFUNCTIONTEMPLATE:
|
||||
bk = BrowserImg::template_function();
|
||||
case CLASSFUNCTION:
|
||||
img = BrowserImg::class_function();
|
||||
break;
|
||||
case STRUCTTEMPLATE:
|
||||
bk = BrowserImg::template_struct();
|
||||
case STRUCT:
|
||||
img = BrowserImg::type_struct();
|
||||
break;
|
||||
case INSTANCEVARIABLE:
|
||||
img = BrowserImg::instance_data();
|
||||
break;
|
||||
case CLASSVARIABLE:
|
||||
img = BrowserImg::class_data();
|
||||
break;
|
||||
case VARIABLE:
|
||||
img = BrowserImg::data();
|
||||
break;
|
||||
case ENUM:
|
||||
img = BrowserImg::type_enum();
|
||||
break;
|
||||
case INLINEFRIEND:
|
||||
img = BrowserImg::inline_friend();
|
||||
break;
|
||||
case TYPEDEF:
|
||||
img = BrowserImg::type_def();
|
||||
break;
|
||||
case CONSTRUCTOR:
|
||||
img = BrowserImg::constructor();
|
||||
break;
|
||||
case DESTRUCTOR:
|
||||
img = BrowserImg::destructor();
|
||||
break;
|
||||
case MACRO:
|
||||
img = BrowserImg::macro();
|
||||
break;
|
||||
case FLAGTEST:
|
||||
img = BrowserImg::flagtest();
|
||||
break;
|
||||
case FRIENDCLASS:
|
||||
img = BrowserImg::friend_class();
|
||||
break;
|
||||
case KIND_INCLUDEFILE:
|
||||
img = IdeCommonImg::Header();
|
||||
break;
|
||||
case KIND_INCLUDEFILE_ANY:
|
||||
img = CtrlImg::File();
|
||||
break;
|
||||
case KIND_INCLUDEFOLDER:
|
||||
img = CtrlImg::Dir();
|
||||
break;
|
||||
}
|
||||
|
||||
img = DPI(img);
|
||||
bk = DPI(bk);
|
||||
|
||||
int by = ry - bk.GetSize().cy / 2;
|
||||
int iy = ry - img.GetSize().cy / 2;
|
||||
|
||||
if(focuscursor) {
|
||||
DrawHighlightImage(w, x, by, bk);
|
||||
w.DrawImage(x, iy, img);
|
||||
}
|
||||
else {
|
||||
w.DrawImage(x, by, bk);
|
||||
w.DrawImage(x, iy, img);
|
||||
}
|
||||
}
|
||||
|
||||
int CppItemInfoDisplay::DoPaint(Draw& w, const Rect& r, const Value& q,
|
||||
Color _ink, Color paper, dword style) const
|
||||
{
|
||||
const CppItemInfo& m = ValueTo<CppItemInfo>(q);
|
||||
w.DrawRect(r, paper);
|
||||
bool focuscursor = (style & (FOCUS|CURSOR)) == (FOCUS|CURSOR) || (style & SELECT);
|
||||
if(IsNull(q)) return 0;
|
||||
int x = r.left;
|
||||
int ry = r.top + r.GetHeight() / 2;
|
||||
PaintCppItemImage(w, x, ry, m.access, m.kind, focuscursor);
|
||||
|
||||
if(m.inherited) {
|
||||
w.DrawImage(x + Zx(10), r.top, BrowserImg::inherited());
|
||||
for(int i = 1; i < min(m.inherited, 5); i++)
|
||||
w.DrawRect(x + Zx(10), r.top + Zy(7) + 2 * i, Zx(7), Zy(1), SColorText);
|
||||
}
|
||||
x += Zx(16);
|
||||
int y = ry - Draw::GetStdFontCy() / 2;
|
||||
int x0 = x;
|
||||
Vector<ItemTextPart> n = ParseItemNatural(m);
|
||||
int starti = 0;
|
||||
if(namestart)
|
||||
for(int i = 0; i < n.GetCount(); i++)
|
||||
if(n[i].type == ITEM_NAME) {
|
||||
starti = i;
|
||||
break;
|
||||
}
|
||||
PaintText(w, x, y, m, n, starti, n.GetCount(), focuscursor, _ink);
|
||||
if(starti) {
|
||||
const char *h = " : ";
|
||||
w.DrawText(x, y, h, BrowserFont(), SColorText);
|
||||
x += GetTextSize(h, BrowserFont()).cx;
|
||||
}
|
||||
PaintText(w, x, y, m, n, 0, starti, focuscursor, _ink);
|
||||
if(m.virt || m.over)
|
||||
w.DrawRect(x0, r.bottom - 2, x - x0, 1, m.over ? m.virt ? SLtRed() : SLtBlue() : SColorText());
|
||||
if(m.inherited && m.IsType())
|
||||
w.DrawRect(r.left, r.top, r.Width(), 1, SColorDisabled);
|
||||
|
||||
if(showtopic) {
|
||||
String k = MakeCodeRef(m.scope, m.qitem);
|
||||
int cnt = GetRefLinks(k).GetCount();
|
||||
if(cnt) {
|
||||
Size sz = BrowserImg::Ref().GetSize();
|
||||
int xx = r.right - sz.cx - 1;
|
||||
int yy = r.top + (r.Height() - sz.cy) / 2;
|
||||
DrawHighlightImage(w, xx, yy, BrowserImg::Ref());
|
||||
if(cnt > 1) {
|
||||
String txt = AsString(cnt);
|
||||
Font fnt = Arial(Ctrl::VertLayoutZoom(10)).Bold();
|
||||
Size tsz = GetTextSize(txt, fnt);
|
||||
Point p(xx + (sz.cx - tsz.cx) / 2, yy + (sz.cy - tsz.cy) / 2);
|
||||
for(int ax = -1; ax <= 1; ax++)
|
||||
for(int ay = -1; ay <= 1; ay++)
|
||||
w.DrawText(p.x + ax, p.y + ay, txt, fnt, SWhite());
|
||||
w.DrawText(p.x, p.y, txt, fnt, SBlue());
|
||||
}
|
||||
x += sz.cx + Zx(3);
|
||||
}
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void CppItemInfoDisplay::Paint(Draw& w, const Rect& r, const Value& q,
|
||||
Color _ink, Color paper, dword style) const {
|
||||
DoPaint(w, r, q, _ink, paper, style);
|
||||
}
|
||||
|
||||
Size CppItemInfoDisplay::GetStdSize(const Value& q) const
|
||||
{
|
||||
NilDraw w;
|
||||
return Size(DoPaint(w, Rect(0, 0, INT_MAX, INT_MAX), q, Null, Null, 0),
|
||||
max(Zy(16), BrowserFont().Info().GetHeight()));
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
#include "Browser.h"
|
||||
|
||||
#define LTIMING(x) // RTIMING(x)
|
||||
#define LDUMP(x) // DUMP(x)
|
||||
|
||||
void LaySkipRest(CParser& p)
|
||||
{
|
||||
int lvl = 1;
|
||||
while(!p.IsEof()) {
|
||||
if(p.Char('('))
|
||||
lvl++;
|
||||
else
|
||||
if(p.Char(')')) {
|
||||
if(--lvl == 0)
|
||||
break;
|
||||
}
|
||||
else
|
||||
p.SkipTerm();
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteLines(String& r, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
r << '\n';
|
||||
}
|
||||
|
||||
String PreprocessLayFile(const char *fn)
|
||||
{
|
||||
LTIMING("Lay file");
|
||||
String s = LoadFile(fn);
|
||||
CParser p(s);
|
||||
|
||||
String r = "using namespace Upp;";
|
||||
try {
|
||||
int line = p.GetLine();
|
||||
if(p.Char('#') && p.Id("ifdef")) {
|
||||
if(!p.Id("LAYOUTFILE"))
|
||||
p.Id("LAYOUT");
|
||||
WriteLines(r, p.GetLine() - line);
|
||||
}
|
||||
while(!p.IsEof()) {
|
||||
line = p.GetLine();
|
||||
p.PassId("LAYOUT");
|
||||
p.PassChar('(');
|
||||
String id = p.ReadId();
|
||||
r << "void SetLayout_" + id + "(); template <class T> struct With" << id << " : public T {"
|
||||
<< "\tstatic Size GetLayoutSize();";
|
||||
LaySkipRest(p);
|
||||
WriteLines(r, p.GetLine() - line);
|
||||
for(;;) {
|
||||
line = p.GetLine();
|
||||
if(p.Id("ITEM")) {
|
||||
p.PassChar('(');
|
||||
if(p.IsId()) {
|
||||
String type = p.ReadIdt();
|
||||
int q = type.ReverseFind(':');
|
||||
if(q >= 0)
|
||||
type = type.Mid(q + 1);
|
||||
p.PassChar(',');
|
||||
String name = p.ReadId();
|
||||
if(!name.StartsWith("dv___")) {
|
||||
r << '\t' << type;
|
||||
r << ' ' << name << ";";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if(p.Id("UNTYPED"))
|
||||
p.Char('(');
|
||||
else
|
||||
break;
|
||||
LaySkipRest(p);
|
||||
WriteLines(r, p.GetLine() - line);
|
||||
}
|
||||
line = p.GetLine();
|
||||
p.PassId("END_LAYOUT");
|
||||
if(p.Char('#'))
|
||||
p.Id("endif");
|
||||
r << "};";
|
||||
WriteLines(r, p.GetLine() - line);
|
||||
}
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
LDUMP(r);
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "Browser.h"
|
||||
#include <ide/ide.h>
|
||||
|
||||
struct MoveTopicDlg : public WithMoveTopicLayout<TopWindow> {
|
||||
typedef MoveTopicDlg CLASSNAME;
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
#include "Browser.h"
|
||||
|
||||
void ReferenceDlg::EnterItem()
|
||||
{
|
||||
reference <<= GetCodeRef();
|
||||
}
|
||||
|
||||
void ReferenceDlg::EnterItemOk()
|
||||
{
|
||||
if(item.IsCursor()) {
|
||||
EnterItem();
|
||||
Break(IDOK);
|
||||
}
|
||||
}
|
||||
|
||||
void ReferenceDlg::Set(const String& s)
|
||||
{
|
||||
Goto(s, Null);
|
||||
reference <<= s;
|
||||
}
|
||||
|
||||
ReferenceDlg::ReferenceDlg()
|
||||
{
|
||||
CtrlLayoutOKCancel(*this, "Reference");
|
||||
Breaker(classlist, IDYES);
|
||||
item.WhenEnterRow = THISBACK(EnterItem);
|
||||
item.WhenLeftDouble = THISBACK(EnterItemOk);
|
||||
Sizeable().Zoomable();
|
||||
Icon(TopicImg::Topic());
|
||||
display.showtopic = true;
|
||||
Load();
|
||||
}
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
#include "Browser.h"
|
||||
|
||||
String SchId(CParser& p, String& rr)
|
||||
{
|
||||
p.Char('(');
|
||||
String id = p.ReadId();
|
||||
rr << "SqlId " << id << "(\"" << id << "\");";
|
||||
return id;
|
||||
}
|
||||
|
||||
String ReadId(CParser& p, String& rr)
|
||||
{
|
||||
String id = SchId(p, rr);
|
||||
p.Char(',');
|
||||
if(p.IsNumber())
|
||||
p.ReadNumber();
|
||||
p.Char(',');
|
||||
if(p.IsNumber())
|
||||
p.ReadNumber();
|
||||
p.Char(')');
|
||||
return id;
|
||||
}
|
||||
|
||||
Vector<String> PreprocessSchFile(const char *fn)
|
||||
{
|
||||
String s = LoadFile(fn);
|
||||
CParser p(s);
|
||||
String r = "using namespace Upp;";
|
||||
String rr = "using namespace Upp;";
|
||||
String S_name;
|
||||
int line;
|
||||
while(!p.IsEof())
|
||||
try {
|
||||
line = p.GetLine();
|
||||
if(p.Id("TABLE") || p.Id("TABLE_") || p.Id("TYPE") || p.Id("TYPE_")) {
|
||||
S_name = "S_" + SchId(p, rr);
|
||||
r << "struct " << S_name << " {";
|
||||
}
|
||||
else
|
||||
if(p.Id("TABLE_I") || p.Id("TABLE_I_") || p.Id("TYPE_I") || p.Id("TYPE_I_")) {
|
||||
S_name = "S_" + SchId(p, rr);
|
||||
p.Char(',');
|
||||
String S_base = "S_" + p.ReadId();
|
||||
r << "struct " << S_name << " : " << S_base << " {";
|
||||
}
|
||||
else
|
||||
if(p.Id("TABLE_II") || p.Id("TABLE_II_") || p.Id("TYPE_II") || p.Id("TYPE_II_")) {
|
||||
S_name = "S_" + SchId(p, rr);
|
||||
p.Char(',');
|
||||
String S_base = "S_" + p.ReadId();
|
||||
p.Char(',');
|
||||
String S_base2 = "S_" + p.ReadId();
|
||||
r << "struct " << S_name << " : " << S_base << ", " << S_base2 << " {";
|
||||
}
|
||||
else
|
||||
if(p.Id("TABLE_III") || p.Id("TABLE_III_") || p.Id("TYPE_III") || p.Id("TYPE_III_")) {
|
||||
S_name = "S_" + SchId(p, rr);
|
||||
p.Char(',');
|
||||
String S_base = "S_" + p.ReadId();
|
||||
p.Char(',');
|
||||
String S_base2 = "S_" + p.ReadId();
|
||||
p.Char(',');
|
||||
String S_base3 = "S_" + p.ReadId();
|
||||
r << "struct " << S_name << " : " << S_base << ", " << S_base2 << ", " << S_base3 << " {";
|
||||
}
|
||||
else
|
||||
if(p.Id("END_TABLE") || p.Id("END_TYPE"))
|
||||
r << "\t"
|
||||
"static const char TableName[];"
|
||||
"static const SqlSet& ColumnSet();"
|
||||
"static SqlSet ColumnSet(const String& prefix);"
|
||||
"static SqlSet Of(SqlId table);"
|
||||
"static const Vector<SqlId>& GetColumnIds();"
|
||||
""
|
||||
"void Clear();"
|
||||
""
|
||||
"void FieldLayoutRaw(FieldOperator& f, const String& prefix = String());"
|
||||
"void FieldLayout(FieldOperator& f);"
|
||||
"operator Fields();"
|
||||
""
|
||||
"bool operator==(const " << S_name << "& x) const;"
|
||||
"bool operator!=(const " << S_name << "& x) const;"
|
||||
"String ToString() const;"
|
||||
""
|
||||
"int GetCount() const;"
|
||||
"SqlId GetId(int i) const;"
|
||||
"Ref GetRef(int i);"
|
||||
"Ref GetRef(const SqlId& id);"
|
||||
"Value Get(const SqlId& id) const;"
|
||||
"Value Get(int i) const;"
|
||||
"ValueMap Get() const;"
|
||||
"void Set(int i, const Value& v);"
|
||||
"void Set(const SqlId& id, const Value& v);"
|
||||
"void Set(const ValueMap& m);"
|
||||
<< S_name << "();"
|
||||
<< S_name << "(const ValueMap& m);"
|
||||
"};";
|
||||
else
|
||||
if(p.Id("LONGRAW") || p.Id("LONGRAW_") || p.Id("BLOB") || p.Id("BLOB_") ||
|
||||
p.Id("STRING_") || p.Id("STRING") || p.Id("CLOB") || p.Id("CLOB_"))
|
||||
r << "\tString " << ReadId(p, rr) << ";";
|
||||
else
|
||||
if(p.Id("INT") || p.Id("INT_") || p.Id("ISERIAL"))
|
||||
r << "\tint " << ReadId(p, rr) << ";";
|
||||
else
|
||||
if(p.Id("INT64") || p.Id("INT64_") || p.Id("SERIAL") || p.Id("BIGSERIAL"))
|
||||
r << "\tint64 " << ReadId(p, rr) << ";";
|
||||
else
|
||||
if(p.Id("DOUBLE") || p.Id("DOUBLE_"))
|
||||
r << "\tdouble " << ReadId(p, rr) << ";";
|
||||
else
|
||||
if(p.Id("TIME") || p.Id("TIME_"))
|
||||
r << "\tTime " << ReadId(p, rr) << ";";
|
||||
else
|
||||
if(p.Id("DATE") || p.Id("DATE_"))
|
||||
r << "\tDate " << ReadId(p, rr) << ";";
|
||||
else
|
||||
if(p.Id("BIT") || p.Id("BIT_") || p.Id("BOOL") || p.Id("BOOL_"))
|
||||
r << "\tbool " << ReadId(p, rr) << ";";
|
||||
else
|
||||
if(p.Id("INT_ARRAY") || p.Id("INT_ARRAY_"))
|
||||
r << "\tint " << ReadId(p, rr) << "[1];";
|
||||
else
|
||||
if(p.Id("DOUBLE_ARRAY") || p.Id("DOUBLE_ARRAY_"))
|
||||
r << "\tdouble " << ReadId(p, rr) << "[1];";
|
||||
else
|
||||
if(p.Id("TIME_ARRAY") || p.Id("TIME_ARRAY_"))
|
||||
r << "\tTime " << ReadId(p, rr) << "[1];";
|
||||
else
|
||||
if(p.Id("DATE_ARRAY") || p.Id("DATE_ARRAY_"))
|
||||
r << "\tDate " << ReadId(p, rr) << "[1];";
|
||||
else
|
||||
if(p.Id("BOOL_ARRAY") || p.Id("BOOL_ARRAY_") || p.Id("BIT_ARRAY") || p.Id("BIT_ARRAY_"))
|
||||
r << "\tbool " << ReadId(p, rr) << "[1];";
|
||||
else
|
||||
if(p.Id("STRING_ARRAY") || p.Id("STRING_ARRAY_"))
|
||||
r << "\tbool " << ReadId(p, rr) << "[1];";
|
||||
else
|
||||
if(p.Id("SEQUENCE") || p.Id("SEQUENCE_"))
|
||||
ReadId(p, rr);
|
||||
else
|
||||
p.SkipTerm();
|
||||
line = p.GetLine() - line;
|
||||
for(int i = 0; i < line; ++i) {
|
||||
r << '\n';
|
||||
rr << '\n';
|
||||
}
|
||||
}
|
||||
catch(CParser::Error)
|
||||
{}
|
||||
return pick(Vector<String>() << r << rr);
|
||||
}
|
||||
|
|
@ -43,8 +43,18 @@ VectorMap<String, TopicInfo>& topic_info()
|
|||
return x;
|
||||
}
|
||||
|
||||
void AddLinkRef(const String& link, const String& ref)
|
||||
String CleanupTppId(const String& ref_)
|
||||
{
|
||||
String ref = ref_;
|
||||
ref.TrimEnd("::struct"); // fix legacy format
|
||||
ref.TrimEnd("::class");
|
||||
ref.TrimEnd("::union");
|
||||
return CleanupId(ref);
|
||||
}
|
||||
|
||||
void AddLinkRef(const String& link, const String& ref_)
|
||||
{
|
||||
String ref = CleanupTppId(ref_);
|
||||
int q = ref_link().Put(link);
|
||||
if(q < ref_ref().GetCount())
|
||||
ref_ref().Set(q, ref);
|
||||
|
|
@ -98,9 +108,7 @@ int NoSlashDot(int c)
|
|||
|
||||
String TopicCacheName(const char *path)
|
||||
{
|
||||
String cfg = ConfigFile("cfg");
|
||||
RealizeDirectory(cfg);
|
||||
return AppendFileName(cfg, ForceExt(Filter(path, NoSlashDot), ".tdx"));
|
||||
return CacheFile(ForceExt(Filter(path, NoSlashDot), ".tdx"));
|
||||
}
|
||||
|
||||
const char *tdx_version = "tdx version 2.0";
|
||||
|
|
@ -229,6 +237,7 @@ void SyncRefs()
|
|||
SyncRefsShowProgress = true;
|
||||
return;
|
||||
}
|
||||
TIMESTOP("SyncRefs");
|
||||
Progress pi;
|
||||
pi.AlignText(ALIGN_LEFT);
|
||||
Vector<String> upp = GetUppDirs();
|
||||
|
|
@ -237,35 +246,50 @@ void SyncRefs()
|
|||
SyncRefsFinished = true;
|
||||
}
|
||||
|
||||
bool LegacyRef(String& ref)
|
||||
{
|
||||
if(ref.StartsWith("Upp::")) { // Fix links with legacy docs
|
||||
ref = ref.Mid(5);
|
||||
ref.Replace(" Upp::", " ");
|
||||
ref.Replace("(Upp::", "(");
|
||||
ref.Replace(",Upp::", ",");
|
||||
ref.Replace("<Upp::", "<");
|
||||
ref.Replace("const Upp::", "const ");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
String LegacyRef(String ref)
|
||||
{ // Fix links with legacy docs
|
||||
ref.TrimStart("Upp::");
|
||||
ref.Replace(" Upp::", " ");
|
||||
ref.Replace("(Upp::", "(");
|
||||
ref.Replace(",Upp::", ",");
|
||||
ref.Replace("<Upp::", "<");
|
||||
ref.Replace("const Upp::", "const ");
|
||||
return ref;
|
||||
}
|
||||
|
||||
Vector<String> GetRefLinks(const String& ref_)
|
||||
Vector<String> AnnotationCandidates(const String& ref)
|
||||
{ // Make older refs compatible
|
||||
Index<String> l;
|
||||
l.FindAdd(ref);
|
||||
String lr = LegacyRef(ref);
|
||||
l.FindAdd(lr);
|
||||
int lvl = 0;
|
||||
StringBuffer h;
|
||||
for(const char *s = lr; *s; s++) { // remove template arguments - Vector<T> -> Vector
|
||||
if(*s == '<')
|
||||
lvl++;
|
||||
else
|
||||
if(*s == '>')
|
||||
lvl--;
|
||||
else
|
||||
if(lvl == 0)
|
||||
h.Cat(*s);
|
||||
}
|
||||
l.FindAdd(h);
|
||||
return l.PickKeys();
|
||||
}
|
||||
|
||||
Vector<String> GetRefLinks(const String& ref)
|
||||
{
|
||||
String ref = ref_;
|
||||
Vector<String> l;
|
||||
for(int pass = 0; pass < 2; pass++) {
|
||||
int q = ref_ref().Find(ref);
|
||||
Index<String> l;
|
||||
for(String cr : AnnotationCandidates(ref)) {
|
||||
int q = ref_ref().Find(cr);
|
||||
while(q >= 0) {
|
||||
l.Add(ref_link()[q]);
|
||||
l.FindAdd(ref_link()[q]);
|
||||
q = ref_ref().FindNext(q);
|
||||
}
|
||||
|
||||
if(pass == 0 && !LegacyRef(ref))
|
||||
break;
|
||||
}
|
||||
return l;
|
||||
};
|
||||
return l.PickKeys();
|
||||
}
|
||||
|
||||
String GetTopicTitle(const String& link)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include "Browser.h"
|
||||
#include <ide/ide.h>
|
||||
|
||||
bool IsTopicFile(const char *path)
|
||||
{
|
||||
|
|
@ -39,4 +39,10 @@ struct TopicModule : public IdeModule {
|
|||
void InitializeTopicModule()
|
||||
{
|
||||
RegisterIdeModule(Single<TopicModule>());
|
||||
}
|
||||
}
|
||||
|
||||
INITIALIZER(CodeBase)
|
||||
{
|
||||
void InitializeTopicModule();
|
||||
InitializeTopicModule();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ void CreateTopic(const char *fn, int lang, const String& ss)
|
|||
SaveFile(fn, WriteTopic("", ParseQTF(ss + "[{_}%" + LNGAsText(lang) + " ")));
|
||||
}
|
||||
|
||||
bool TopicEditor::NewTopicEx(const String& iname, const String& create)
|
||||
bool TopicEditor::NewTopicEx(const String& iname, const AnnotationItem *create)
|
||||
{
|
||||
TopicDlg<WithNewTopicLayout<TopWindow> > d("New topic");
|
||||
d.lang <<= lastlang;
|
||||
|
|
@ -326,14 +326,14 @@ bool TopicEditor::NewTopicEx(const String& iname, const String& create)
|
|||
topics_list.FindSetCursor(GetFileTitle(fn));
|
||||
editor.SetFocus();
|
||||
serial++;
|
||||
if(create.GetCount())
|
||||
InsertNew(create);
|
||||
if(create)
|
||||
InsertNew(*create);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TopicEditor::NewTopic()
|
||||
{
|
||||
NewTopicEx(Null, Null);
|
||||
NewTopicEx(Null, nullptr);
|
||||
}
|
||||
|
||||
void TopicEditor::RemoveTopic()
|
||||
|
|
|
|||
|
|
@ -1,63 +1,5 @@
|
|||
#include "Browser.h"
|
||||
|
||||
void SplitCodeRef(const String& s, String& scope, String& item)
|
||||
{
|
||||
int q = s.FindFirstOf("( ");
|
||||
q = q >= 0 ? s.ReverseFind(':', q) : s.ReverseFind(':');
|
||||
if(q < 0) {
|
||||
scope.Clear();
|
||||
item = s;
|
||||
}
|
||||
else {
|
||||
scope = s.Mid(0, max(q - 1, 0));
|
||||
item = s.Mid(q + 1);
|
||||
}
|
||||
}
|
||||
|
||||
String MakeCodeRef(const String& nest, const String& item)
|
||||
{
|
||||
if(nest.GetCount())
|
||||
return nest + "::" + item;
|
||||
return item;
|
||||
}
|
||||
|
||||
int GetMatchLen(const char *s, const char *t)
|
||||
{
|
||||
int i = 0;
|
||||
while(s[i] == t[i] && s[i])
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
const CppItem *GetCodeRefItem(const String& ref, const String& rfile)
|
||||
{
|
||||
CodeBaseLock __;
|
||||
String scope;
|
||||
String item;
|
||||
SplitCodeRef(ref, scope, item);
|
||||
int q = CodeBase().Find(scope);
|
||||
if(q < 0)
|
||||
return NULL;
|
||||
const Array<CppItem>& n = CodeBase()[q];
|
||||
q = FindItem(n, item);
|
||||
if(q < 0)
|
||||
return NULL;
|
||||
if(!IsNull(rfile)) {
|
||||
int i = q;
|
||||
int qml = 0;
|
||||
while(i < n.GetCount() && n[i].qitem == item) {
|
||||
int ml = GetMatchLen(GetSourceFilePath(n[i].file), rfile);
|
||||
if(ml > qml) {
|
||||
q = i;
|
||||
qml = ml;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return &n[q];
|
||||
}
|
||||
|
||||
const CppItem *GetCodeRefItem(const String& ref)
|
||||
{
|
||||
return GetCodeRefItem(ref, Null);
|
||||
}
|
||||
#define IMAGECLASS BrowserImg
|
||||
#define IMAGEFILE <ide/Browser/Browser.iml>
|
||||
#include <Draw/iml_source.h>
|
||||
|
|
|
|||
|
|
@ -21,11 +21,6 @@ void Ide::DoProcessEvents()
|
|||
ProcessEvents();
|
||||
}
|
||||
|
||||
void Ide::ReQualifyCodeBase()
|
||||
{
|
||||
FinishCodeBase();
|
||||
}
|
||||
|
||||
String Ide::GetMain()
|
||||
{
|
||||
return main;
|
||||
|
|
@ -154,22 +149,6 @@ void Ide::FileCompile()
|
|||
SetErrorEditor();
|
||||
}
|
||||
|
||||
void Ide::PreprocessInternal()
|
||||
{
|
||||
if(editor.GetLength64() >= 1000000) // Sanity...
|
||||
return;
|
||||
int l = editor.GetCurrentLine();
|
||||
PPSync(GetIncludePath());
|
||||
String pfn = ConfigFile(GetFileTitle(editfile) + ".i.tmp");
|
||||
Upp::SaveFile(pfn, PreprocessCpp(editor.Get(), editfile));
|
||||
HideBottom();
|
||||
EditFile(pfn);
|
||||
EditAsText();
|
||||
if(!editor.IsReadOnly())
|
||||
ToggleReadOnly();
|
||||
editor.SetCursor(editor.GetPos64(l));
|
||||
}
|
||||
|
||||
void Ide::Preprocess(bool asmout) {
|
||||
if(editfile.IsEmpty())
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -516,7 +516,6 @@ bool MakeBuild::Build(const Workspace& wspc, String mainparam, String outfile, b
|
|||
}
|
||||
}
|
||||
EndBuilding(ok);
|
||||
ReQualifyCodeBase();
|
||||
SetErrorEditor();
|
||||
return ok;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ public:
|
|||
virtual void EndBuilding(bool ok) = 0;
|
||||
virtual void ClearErrorEditor() = 0;
|
||||
virtual void DoProcessEvents() = 0;
|
||||
virtual void ReQualifyCodeBase() = 0;
|
||||
virtual void SetErrorEditor() = 0;
|
||||
virtual String GetMain() = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ void Sentinel(Stream& s, const char *txt)
|
|||
|
||||
void Ide::Serialize(Stream& s)
|
||||
{
|
||||
int version = 20;
|
||||
int version = 22;
|
||||
Sentinel(s, "before 12341234");
|
||||
s.Magic(0x12341234);
|
||||
Sentinel(s, "after magic");
|
||||
|
|
@ -270,9 +270,15 @@ void Ide::Serialize(Stream& s)
|
|||
s % splash_screen;
|
||||
s % editor.auto_assist;
|
||||
if(version >= 9)
|
||||
s % auto_rescan;
|
||||
if(version >= 10)
|
||||
s % auto_check;
|
||||
s % AutoIndexer;
|
||||
if(version >= 10) {
|
||||
bool dummy;
|
||||
s % dummy;
|
||||
}
|
||||
if(version >= 21) {
|
||||
bool dummy;
|
||||
s % dummy;
|
||||
}
|
||||
s % editor.commentdp;
|
||||
s % bordercolumn;
|
||||
s % bordercolor;
|
||||
|
|
@ -326,6 +332,10 @@ void Ide::Serialize(Stream& s)
|
|||
if(version >= 19) {
|
||||
s % gui_font % gui_font_override;
|
||||
}
|
||||
|
||||
if(version >= 22) {
|
||||
ClangConfigSerialize(s);
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
if(s.IsLoading() && HostConsole == "/usr/bin/xterm -e")
|
||||
|
|
|
|||
|
|
@ -10,48 +10,6 @@
|
|||
#define LLOG(x)
|
||||
#endif
|
||||
|
||||
bool GetIdScope(String& os, const String& scope, const String& id, Index<String>& done)
|
||||
{
|
||||
CodeBaseLock __;
|
||||
if(done.Find(scope) >= 0)
|
||||
return Null;
|
||||
done.Add(scope);
|
||||
Vector<String> tparam;
|
||||
String n = ParseTemplatedType(scope, tparam);
|
||||
String nn = n + "::" + id;
|
||||
if(CodeBase().Find(nn) >= 0) { // Console -> LineEdit::EditPos
|
||||
os = nn;
|
||||
return true;
|
||||
}
|
||||
int q = CodeBase().Find(n);
|
||||
if(q < 0)
|
||||
return Null;
|
||||
const Array<CppItem>& m = CodeBase()[q];
|
||||
Vector<String> r;
|
||||
if(FindName(m, id) >= 0) {
|
||||
os = n;
|
||||
return true;
|
||||
}
|
||||
for(int i = 0; i < m.GetCount(); i++) {
|
||||
const CppItem& im = m[i];
|
||||
if(im.IsType()) {
|
||||
Vector<String> b = Split(im.qptype, ';');
|
||||
ResolveTParam(b, tparam);
|
||||
for(int i = 0; i < b.GetCount(); i++) {
|
||||
if(GetIdScope(os, b[i], id, done))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetIdScope(String& os, const String& scope, const String& id)
|
||||
{
|
||||
Index<String> done;
|
||||
return GetIdScope(os, scope, id, done);
|
||||
}
|
||||
|
||||
bool IsPif(const String& l)
|
||||
{
|
||||
return l.Find("#if") >= 0;
|
||||
|
|
@ -67,36 +25,6 @@ bool IsPendif(const String& l)
|
|||
return l.Find("#endif") >= 0;
|
||||
}
|
||||
|
||||
void Ide::FindId(const String& id)
|
||||
{
|
||||
int pos = editor.GetCursor();
|
||||
int h = min(editor.GetLength(), pos + 4000);
|
||||
for(;;) {
|
||||
if(pos >= h || editor[pos] == ';')
|
||||
break;
|
||||
if(iscib(editor[pos])) {
|
||||
int p0 = pos;
|
||||
String tid;
|
||||
while(pos < h && iscid(editor[pos])) {
|
||||
tid.Cat(editor[pos]);
|
||||
pos++;
|
||||
}
|
||||
if(tid == id) {
|
||||
editor.SetCursor(p0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
String RemoveTemplateParams(const String& s)
|
||||
{
|
||||
Vector<String> dummy;
|
||||
return ParseTemplatedType(s, dummy);
|
||||
}
|
||||
|
||||
bool Ide::OpenLink(const String& s, int pos)
|
||||
{ // try to find link at cursor, either http, https or file
|
||||
auto IsLinkChar = [](int c) { return findarg(c, '\'', '\"', '\t', ' ', '\0') < 0; };
|
||||
|
|
@ -185,7 +113,7 @@ void Ide::ContextGoto0(int pos)
|
|||
try {
|
||||
CParser p(l);
|
||||
if(p.Char('#') && p.Id("include")) {
|
||||
String path = FindIncludeFile(p.GetPtr(), GetFileFolder(editfile), SplitDirs(GetIncludePath()));
|
||||
String path = Hdepend::FindIncludeFile(p.GetPtr(), GetFileFolder(editfile), SplitDirs(GetIncludePath()));
|
||||
if(!IsNull(path)) {
|
||||
AddHistory();
|
||||
EditFile(path);
|
||||
|
|
@ -196,228 +124,90 @@ void Ide::ContextGoto0(int pos)
|
|||
}
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
int q = pos;
|
||||
while(iscid(editor.Ch(q - 1)))
|
||||
q--;
|
||||
String tp;
|
||||
Vector<String> xp = editor.ReadBack(q, Index<String>()); // try to load expression like "x[i]." or "ptr->"
|
||||
Index<String> type;
|
||||
ParserContext parser;
|
||||
int ci = pos;
|
||||
for(;;) {
|
||||
int c = editor.Ch(ci);
|
||||
if(c == '{' && editor.Ch(ci + 1)) {
|
||||
ci++;
|
||||
break;
|
||||
}
|
||||
if(c == '}' || c == 0 || c == ';')
|
||||
break;
|
||||
ci++;
|
||||
}
|
||||
editor.Context(parser, ci);
|
||||
|
||||
CodeBaseLock __;
|
||||
|
||||
if(xp.GetCount()) {
|
||||
type = editor.EvaluateExpressionType(parser, xp);
|
||||
if(type.GetCount() == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
String id = editor.GetWord(pos);
|
||||
if(id.GetCount() == 0)
|
||||
if(!editor.WaitCurrentFile())
|
||||
return;
|
||||
|
||||
String qual; // Try to load type qualification like Foo::Bar, Vector<String>::Iterator
|
||||
while(editor.Ch(q - 1) == ' ')
|
||||
q--;
|
||||
if(editor.Ch(q - 1) == ':' && editor.Ch(q - 2) == ':') {
|
||||
q -= 3;
|
||||
while(q >= 0) {
|
||||
int c = editor.Ch(q);
|
||||
if(iscid(c) || findarg(c, '<', '>', ':', ',', ' ') >= 0) {
|
||||
if(c != ' ')
|
||||
qual = (char)c + qual;
|
||||
q--;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if(qual.GetCount() == 0)
|
||||
qual = ":";
|
||||
}
|
||||
|
||||
Vector<String> scope;
|
||||
Vector<bool> istype; // prefer type (e.g. struct Foo) over constructor (Foo::Foo())
|
||||
for(int i = 0; i < type.GetCount(); i++) { // 'x.attr'
|
||||
Index<String> done;
|
||||
String r;
|
||||
if(GetIdScope(r, type[i], id, done)) {
|
||||
Vector<String> todo;
|
||||
todo.Add(r);
|
||||
while(scope.GetCount() < 100 && todo.GetCount()) { // Add base classes
|
||||
String t = todo[0];
|
||||
todo.Remove(0);
|
||||
if(t.EndsWith("::"))
|
||||
t.Trim(t.GetCount() - 2);
|
||||
if(t.GetCount()) {
|
||||
scope.Add(t);
|
||||
istype.Add(false);
|
||||
ScopeInfo f(CodeBase(), t); // Try base classes too!
|
||||
todo.Append(f.GetBases());
|
||||
String ref_id;
|
||||
int ci = 0;
|
||||
String name = editor.ReadIdBack(pos);
|
||||
for(int pass = 0; pass < 2 && IsNull(ref_id); pass++)
|
||||
for(const ReferenceItem& m : editor.references) {
|
||||
if(m.pos.y == li && m.pos.x <= lp && m.pos.x >= ci &&
|
||||
(GetNameFromId(m.id) == name || pass == 1)) {
|
||||
ref_id = m.id;
|
||||
ci = m.pos.x;
|
||||
}
|
||||
}
|
||||
|
||||
PutAssist("ref_id: " + ref_id);
|
||||
|
||||
if(ref_id.GetCount()) {
|
||||
String found_path;
|
||||
Point found_pos(INT_MAX, INT_MAX);
|
||||
bool found_definition = false;
|
||||
String found_name;
|
||||
String found_nest;
|
||||
|
||||
AnnotationItem cm = editor.FindCurrentAnnotation(); // what function body are we in?
|
||||
PutAssist("Context: " + cm.id);
|
||||
if(IsFunction(cm.kind)) { // do local variables
|
||||
for(const AnnotationItem& m : editor.locals) {
|
||||
int ppy = -1;
|
||||
if(m.id == ref_id && m.pos.y >= cm.pos.y && m.pos.y <= li && m.pos.y > ppy) {
|
||||
ppy = m.pos.y;
|
||||
found_path = editfile;
|
||||
found_pos = m.pos;
|
||||
found_definition = m.definition;
|
||||
found_name = m.name;
|
||||
found_nest = m.nest;
|
||||
PutAssist("Found Local: " + AsString(m.pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> ns = parser.GetNamespaces();
|
||||
|
||||
if(qual.GetCount() > 2 && qual.StartsWith("::"))
|
||||
qual = qual.Mid(2);
|
||||
if(qual.GetCount()) { // Ctrl::MOUSELEFT, Vector<String>::Iterator
|
||||
Vector<String> todo;
|
||||
String qa = Qualify(CodeBase(), parser.current_scope, *qual == ':' ? id : qual + "::" + id,
|
||||
parser.context.namespace_using);
|
||||
qa = RemoveTemplateParams(qa);
|
||||
if(CodeBase().Find(qa) < 0) { // Upp::FileTabs::RenameFile
|
||||
int q = qa.ReverseFind("::");
|
||||
if(q > 0) {
|
||||
String h = qa.Mid(0, q);
|
||||
if(CodeBase().Find(h) >= 0) {
|
||||
scope.Add(h);
|
||||
istype.Add(false);
|
||||
|
||||
if(IsNull(found_path))
|
||||
for(const auto& f : ~CodeIndex())
|
||||
for(const AnnotationItem& m : f.value.items)
|
||||
if(m.id == ref_id &&
|
||||
(IsNull(found_path) ||
|
||||
CombineCompare(found_definition, m.definition)(f.key, found_path)
|
||||
(m.pos.y, found_pos.y)(m.pos.x, found_pos.x) < 0)) {
|
||||
found_path = f.key;
|
||||
found_pos = m.pos;
|
||||
found_definition = m.definition;
|
||||
found_name = m.name;
|
||||
found_nest = m.nest;
|
||||
PutAssist("Found Global: " + found_path);
|
||||
}
|
||||
|
||||
if(found_path.GetCount()) {
|
||||
AddHistory();
|
||||
EditFile(found_path);
|
||||
LayDesigner *l = dynamic_cast<LayDesigner *>(~designer);
|
||||
if(l) {
|
||||
String cls = found_nest;
|
||||
int q = cls.ReverseFind(':');
|
||||
if(q >= 0)
|
||||
cls = cls.Mid(q + 1);
|
||||
if(cls.TrimStart("With")) {
|
||||
l->FindLayout(cls, found_name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(found_name.TrimStart("SetLayout_")) {
|
||||
l->FindLayout(found_name, Null);
|
||||
return;
|
||||
}
|
||||
DoEditAsText(found_path);
|
||||
}
|
||||
else {
|
||||
scope.Add(Null); // Add global namespace
|
||||
istype.Add(false);
|
||||
}
|
||||
}
|
||||
todo.Add(qa);
|
||||
while(scope.GetCount() < 100 && todo.GetCount()) {
|
||||
String t = todo[0];
|
||||
if(t.EndsWith("::"))
|
||||
t.Trim(t.GetCount() - 2);
|
||||
todo.Remove(0);
|
||||
if(CodeBase().Find(t) >= 0) { // Ctrl::MOUSELEFT
|
||||
scope.Add(t);
|
||||
istype.Add(true);
|
||||
}
|
||||
String tt = t;
|
||||
tt << "::" << id;
|
||||
if(CodeBase().Find(tt) >= 0) { // Vector<String>::Iterator
|
||||
scope.Add(tt);
|
||||
istype.Add(true);
|
||||
}
|
||||
ScopeInfo f(CodeBase(), t); // Try base classes too!
|
||||
todo.Append(f.GetBases());
|
||||
}
|
||||
}
|
||||
else {
|
||||
Vector<String> todo;
|
||||
todo.Add(parser.current_scope);
|
||||
while(scope.GetCount() < 100 && todo.GetCount()) { // Add base classes
|
||||
String t = todo[0];
|
||||
todo.Remove(0);
|
||||
t.TrimEnd("::");
|
||||
if(t.GetCount()) {
|
||||
scope.Add(t);
|
||||
istype.Add(false);
|
||||
ScopeInfo f(CodeBase(), t); // Try base classes too!
|
||||
todo.Append(f.GetBases());
|
||||
}
|
||||
}
|
||||
if(xp.GetCount() == 0) {
|
||||
q = parser.local.Find(id);
|
||||
if(q >= 0) { // Try locals
|
||||
AddHistory();
|
||||
editor.SetCursor(editor.GetPos64(parser.local[q].line - 1));
|
||||
FindId(id);
|
||||
IdeIconDes *k = dynamic_cast<IdeIconDes *>(~designer);
|
||||
if(k) {
|
||||
k->FindId(found_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Can be unqualified type name like 'String'
|
||||
String t = RemoveTemplateParams(Qualify(CodeBase(), parser.current_scope, id, parser.context.namespace_using));
|
||||
for(int i = 0; i < ns.GetCount(); i++) {
|
||||
String tt = Merge("::", ns[i], t);
|
||||
if(CodeBase().Find(tt) >= 0) {
|
||||
scope.Add(tt);
|
||||
istype.Add(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> usings = Split(parser.context.namespace_using, ';');
|
||||
usings.Add(""); // Add global namespace too
|
||||
|
||||
Index<String> done;
|
||||
for(int i = 0; i < ns.GetCount(); i++) {
|
||||
String r;
|
||||
if(GetIdScope(r, ns[i], id, done)) {
|
||||
scope.Add(r);
|
||||
istype.Add(false);
|
||||
}
|
||||
}
|
||||
|
||||
for(int j = 0; j < scope.GetCount(); j++) {
|
||||
q = CodeBase().Find(scope[j]);
|
||||
if(q >= 0) {
|
||||
int ii = -1;
|
||||
const Array<CppItem>& n = CodeBase()[q];
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
const CppItem& m = n[i];
|
||||
if(m.name == id) {
|
||||
if(ii < 0)
|
||||
ii = i;
|
||||
else {
|
||||
const CppItem& mm = n[ii];
|
||||
if(CombineCompare(findarg(mm.kind, CONSTRUCTOR, DESTRUCTOR) < 0,
|
||||
findarg(m.kind, CONSTRUCTOR, DESTRUCTOR) < 0)
|
||||
(!istype[j] || mm.IsType(), !istype[j] || m.IsType())
|
||||
(mm.impl, m.impl)
|
||||
(findarg(mm.filetype, FILE_CPP, FILE_C) >= 0,
|
||||
findarg(m.filetype, FILE_CPP, FILE_C) >= 0)
|
||||
(mm.line, m.line) < 0)
|
||||
ii = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ii >= 0) {
|
||||
JumpToDefinition(n, ii, scope[j]);
|
||||
FindId(id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(id.StartsWith("AK_")) {
|
||||
String ak_id = id.Mid(3);
|
||||
const Workspace& wspc = GetIdeWorkspace();
|
||||
for(int i = 0; i < wspc.GetCount(); i++) {
|
||||
String pn = wspc[i];
|
||||
const Package& p = wspc.GetPackage(i);
|
||||
String pp = PackageDirectory(pn);
|
||||
for(int j = 0; j < p.GetCount(); j++)
|
||||
if(!p[j].separator) {
|
||||
String fn = AppendFileName(pp, p[j]);
|
||||
if(GetFileExt(fn) == ".key") {
|
||||
FileIn in(fn);
|
||||
int line = 0;
|
||||
while(!in.IsEof()) {
|
||||
String s = in.GetLine();
|
||||
try {
|
||||
CParser p(s);
|
||||
if(p.Id("KEY") && p.Char('(') && p.Id(ak_id)) {
|
||||
UnlockCodeBaseAll(); // so that scan in SaveFile does not fail with deadlock
|
||||
GotoPos(fn, line + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
line++;
|
||||
}
|
||||
}
|
||||
}
|
||||
GotoPos(found_pos);
|
||||
AddHistory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -433,98 +223,45 @@ void Ide::CtrlClick(int64 pos)
|
|||
ContextGoto0((int)pos);
|
||||
}
|
||||
|
||||
bool Ide::GotoDesignerFile(const String& path, const String& scope, const String& name, int line)
|
||||
void Ide::FindDesignerItemReferences(const String& id, const String& name)
|
||||
{
|
||||
if(ToLower(GetFileExt(path)) == ".lay") {
|
||||
AddHistory();
|
||||
EditFile(path);
|
||||
LayDesigner *l = dynamic_cast<LayDesigner *>(~designer);
|
||||
if(l) {
|
||||
if(scope.StartsWith("With"))
|
||||
l->FindLayout(scope.Mid(4), name);
|
||||
else
|
||||
if(name.StartsWith("SetLayout_"))
|
||||
l->FindLayout(name.Mid(10), Null);
|
||||
}
|
||||
else {
|
||||
editor.SetCursor(editor.GetPos64(line - 1));
|
||||
editor.TopCursor(4);
|
||||
editor.SetFocus();
|
||||
}
|
||||
AddHistory();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
if(ToLower(GetFileExt(path)) == ".iml") {
|
||||
AddHistory();
|
||||
EditFile(path);
|
||||
IdeIconDes *l = dynamic_cast<IdeIconDes *>(~designer);
|
||||
if(l)
|
||||
l->FindId(name);
|
||||
else
|
||||
editor.SetFocus();
|
||||
AddHistory();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Ide::JumpToDefinition(const Array<CppItem>& n, int q, const String& scope)
|
||||
{
|
||||
String qitem = n[q].qitem;
|
||||
int i = q;
|
||||
int qml = 0;
|
||||
int qcpp = -1;
|
||||
int qcppml = 0;
|
||||
int qimpl = -1;
|
||||
int qimplml = 0;
|
||||
String currentfile = editfile;
|
||||
while(i < n.GetCount() && n[i].qitem == qitem) {
|
||||
const CppItem& m = n[i];
|
||||
int ml = GetMatchLen(editfile, GetSourceFilePath(m.file));
|
||||
if(m.impl && ml > qimplml) {
|
||||
qimplml = ml;
|
||||
qimpl = i;
|
||||
}
|
||||
if((m.filetype == FILE_CPP || m.filetype == FILE_C) && ml > qcppml) {
|
||||
qcpp = i;
|
||||
qcppml = ml;
|
||||
}
|
||||
if(ml > qml) {
|
||||
q = i;
|
||||
qml = ml;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
CppItem pos = n[qimpl >= 0 ? qimpl : qcpp >= 0 ? qcpp : q];
|
||||
String path = GetSourceFilePath(pos.file);
|
||||
editastext.RemoveKey(path);
|
||||
editashex.RemoveKey(path);
|
||||
UnlockCodeBaseAll();
|
||||
if(!GotoDesignerFile(path, scope, pos.name, pos.line))
|
||||
GotoCpp(pos);
|
||||
}
|
||||
|
||||
void Ide::GotoFileAndId(const String& path, const String& id)
|
||||
{
|
||||
AddHistory();
|
||||
EditFile(path);
|
||||
WString wid = id.ToWString();
|
||||
if(editor.GetLength64() < 100000) {
|
||||
for(int i = 0; i < editor.GetLineCount(); i++) {
|
||||
WString ln = editor.GetWLine(i);
|
||||
int q = ln.Find(wid);
|
||||
while(q >= 0) {
|
||||
if(q == 0 || !iscid(ln[q - 1]) && !iscid(ln[q + wid.GetCount()])) {
|
||||
editor.SetCursor(editor.GetPos64(i, q));
|
||||
editor.CenterCursor();
|
||||
return;
|
||||
String path = NormalizePath(editfile);
|
||||
int q = CodeIndex().Find(path);
|
||||
if(q >= 0) {
|
||||
AnnotationItem cm;
|
||||
for(const AnnotationItem& m : CodeIndex()[q].items)
|
||||
if(m.id.EndsWith(id) &&
|
||||
(m.id.GetCount() <= id.GetCount() || !iscid(m.id[m.id.GetCount() - id.GetCount() - 1]))) {
|
||||
cm = m;
|
||||
break;
|
||||
}
|
||||
if(cm.id.GetCount()) {
|
||||
Vector<Tuple<String, Point>> set;
|
||||
for(const auto& f : ~CodeIndex()) {
|
||||
if(f.key != path) {
|
||||
for(const AnnotationItem& m : f.value.items)
|
||||
if(FindId(m.type, cm.id) >= 0 || FindId(m.bases, cm.id) >= 0 || FindId(m.pretty, cm.id) >= 0)
|
||||
set.Add({ f.key, m.pos });
|
||||
for(const ReferenceItem& m : f.value.refs)
|
||||
if(FindId(m.id, cm.id) >= 0)
|
||||
set.Add({ f.key, m.pos });
|
||||
}
|
||||
if(q + 1 >= ln.GetCount())
|
||||
break;
|
||||
q = ln.Find(wid, q + 1);
|
||||
}
|
||||
if(set.GetCount()) {
|
||||
if(set.GetCount() > 1) {
|
||||
SetFFound(ffoundi_next);
|
||||
FFound().Clear();
|
||||
Index<String> unique;
|
||||
for(auto& m : set)
|
||||
AddReferenceLine(m.a, m.b, name, unique);
|
||||
SortByKey(CodeIndex());
|
||||
FFoundFinish();
|
||||
}
|
||||
else
|
||||
GotoPos(set[0].a, set[0].b);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
AddHistory();
|
||||
Exclamation("No usage has been found.");
|
||||
}
|
||||
|
|
|
|||
56
uppsrc/ide/Core/Cache.cpp
Normal file
56
uppsrc/ide/Core/Cache.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#include "Core.h"
|
||||
|
||||
String CacheDir()
|
||||
{
|
||||
String dir;
|
||||
#ifdef PLATFORM_WIN32
|
||||
dir = ConfigFile("cache");
|
||||
#else
|
||||
dir = ConfigFile(".cache/upp.cache");
|
||||
#endif
|
||||
ONCELOCK {
|
||||
RealizeDirectory(dir);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
String CacheFile(const char *name)
|
||||
{
|
||||
return AppendFileName(CacheDir(), name);
|
||||
}
|
||||
|
||||
void ReduceCacheFolder(const char *path, int64 max_total)
|
||||
{
|
||||
struct RCB_FileInfo {
|
||||
String path;
|
||||
Time time;
|
||||
int64 length;
|
||||
|
||||
bool operator<(const RCB_FileInfo& a) const { return time > a.time; }
|
||||
};
|
||||
|
||||
Array<RCB_FileInfo> file;
|
||||
FindFile ff(AppendFileName(path, "*.*"));
|
||||
int64 total = 0;
|
||||
while(ff) {
|
||||
if(ff.IsFile()) {
|
||||
RCB_FileInfo& m = file.Add();
|
||||
m.path = ff.GetPath();
|
||||
m.time = ff.GetLastAccessTime();
|
||||
m.length = ff.GetLength();
|
||||
total += m.length;
|
||||
}
|
||||
ff.Next();
|
||||
}
|
||||
Sort(file);
|
||||
while(total > max_total && file.GetCount()) {
|
||||
if(DeleteFile(file.Top().path))
|
||||
total -= file.Top().length;
|
||||
file.Drop();
|
||||
}
|
||||
}
|
||||
|
||||
void ReduceCache()
|
||||
{ // TODO: Parametrize limits
|
||||
ReduceCacheFolder(CacheDir(), (int64)4096 * 1024 * 1024);
|
||||
}
|
||||
|
|
@ -37,6 +37,124 @@ class Ctrl;
|
|||
class Image;
|
||||
}
|
||||
|
||||
String CacheDir();
|
||||
String CacheFile(const char *name);
|
||||
void ReduceCache();
|
||||
void ReduceCache(int mb_limit);
|
||||
void ReduceCacheFolder(const char *path, int64 max_total);
|
||||
|
||||
class Hdepend { // to be replaced by PPInfo
|
||||
struct Info {
|
||||
Time time;
|
||||
Vector<int> depend;
|
||||
Vector<bool> bydefine;
|
||||
Index<String> macroinclude; // includes by macro, like #include LAYOUTFILE
|
||||
Vector<String> define;
|
||||
bool flag;
|
||||
bool macroflag; // prevent infinite recursion in GetMacroIndex
|
||||
bool timedirty;
|
||||
bool guarded; // has guards or BLITZ_APPROVED
|
||||
bool blitzprohibit; // has BLITZ_PROHIBIT
|
||||
|
||||
bool CanBlitz() { return guarded && !blitzprohibit; }
|
||||
|
||||
void Serialize(Stream& s);
|
||||
|
||||
Info() { time = Null; flag = false; timedirty = true; guarded = false; }
|
||||
};
|
||||
|
||||
ArrayMap<String, Info> map;
|
||||
Vector<String> incdir; // include directories
|
||||
VectorMap<String, Index<String> > depends; // externally forced dependecies
|
||||
bool console = true;
|
||||
|
||||
void Include(const char *trm, Info& info, const String& filedir, bool bydefine);
|
||||
void ScanFile(const String& path, int map_index);
|
||||
int File(const String& path);
|
||||
Time FileTime(int i);
|
||||
void ClearFlag();
|
||||
void ClearMacroFlag();
|
||||
void GetMacroIndex(Index<String>& dest, int ix);
|
||||
|
||||
public:
|
||||
void SetDirs(Vector<String>&& id);
|
||||
void SetDirs(const String& includes);
|
||||
void TimeDirty();
|
||||
|
||||
void ClearDependencies() { depends.Clear(); }
|
||||
void AddDependency(const String& file, const String& depends);
|
||||
|
||||
Time FileTime(const String& path);
|
||||
bool BlitzApproved(const String& path);
|
||||
|
||||
static String FindIncludeFile(const char *s, const String& filedir, const Vector<String>& incdirs);
|
||||
|
||||
String FindIncludeFile(const char *s, const String& filedir) { return FindIncludeFile(s, filedir, incdir); }
|
||||
const Vector<String>& GetDefines(const String& path);
|
||||
Vector<String> GetDependencies(const String& path, bool bydefine_too = true);
|
||||
const Vector<String>& GetAllFiles() { return map.GetKeys(); }
|
||||
void NoConsole() { console = false; }
|
||||
|
||||
void Serialize(Stream& s);
|
||||
};
|
||||
|
||||
class PPInfo {
|
||||
enum { AUTO, APPROVED, PROHIBITED };
|
||||
struct PPFile : Moveable<PPFile> {
|
||||
int scan_serial = 0;
|
||||
Vector<Tuple<String, int>> flags; // "#if... flagXXXX"
|
||||
VectorMap<String, String> defines; // #define ...
|
||||
Index<String> includes[2]; // 1 - speculative includes
|
||||
Index<String> define_includes[2]; // #define LAYOUTFILE
|
||||
bool guarded; // has include guards
|
||||
int blitz; // AUTO, APPROVED, PROHIBITED
|
||||
Time time = Null; // file time
|
||||
|
||||
bool dirty = true; // need to be rechecked
|
||||
|
||||
void Dirty() { dirty = true; time = Null; }
|
||||
void Parse(Stream& in);
|
||||
void Serialize(Stream& s);
|
||||
};
|
||||
|
||||
ArrayMap<String, PPFile> files;
|
||||
Vector<String> includes; // include dirs
|
||||
VectorMap<String, String> inc_cache; // cache for FindIncludeFile
|
||||
VectorMap<String, VectorMap<String, Time>> dir_cache; // cache for GetFileTime, FileExists
|
||||
static std::atomic<int> scan_serial;
|
||||
|
||||
|
||||
PPFile& File(const String& path);
|
||||
|
||||
public:
|
||||
static void RescanAll() { scan_serial++; }
|
||||
|
||||
Event<const String&, const String&> WhenBlitzBlock;
|
||||
Time GetFileTime(const String& path);
|
||||
bool FileExists(const String& path) { return !IsNull(GetFileTime(path)); }
|
||||
|
||||
void SetIncludes(const String& includes);
|
||||
|
||||
String FindIncludeFile(const char *s, const String& filedir, const Vector<String>& incdirs);
|
||||
String FindIncludeFile(const char *s, const String& filedir);
|
||||
|
||||
bool BlitzApproved(const String& path);
|
||||
|
||||
Time GatherDependencies(const String& path, VectorMap<String, Time>& result,
|
||||
ArrayMap<String, Index<String>>& define_includes,
|
||||
Vector<Tuple<String, String, int>>& flags, bool speculative = true);
|
||||
void GatherDependencies(const String& path, VectorMap<String, Time>& result,
|
||||
ArrayMap<String, Index<String>>& define_includes,
|
||||
bool speculative = true);
|
||||
|
||||
Time GetTime(const String& path);
|
||||
|
||||
const VectorMap<String, String>& GetFileDefines(const String& path) { return File(NormalizePath(path)).defines; }
|
||||
const Vector<Tuple<String, int>>& GetFileFlags(const String& path) { return File(NormalizePath(path)).flags; }
|
||||
|
||||
void Dirty();
|
||||
};
|
||||
|
||||
class IdeContext
|
||||
{
|
||||
public:
|
||||
|
|
@ -80,7 +198,6 @@ public:
|
|||
virtual bool IdeDebugUnLock() = 0;
|
||||
virtual bool IdeIsDebugLock() const = 0;
|
||||
virtual void IdeSetBar() = 0;
|
||||
virtual void IdeGotoCodeRef(String link) = 0;
|
||||
virtual void IdeOpenTopicFile(const String& file) = 0;
|
||||
virtual void IdeFlushFile() = 0;
|
||||
virtual String IdeGetFileName() = 0;
|
||||
|
|
@ -97,13 +214,12 @@ public:
|
|||
virtual String IdeGetCurrentBuildMethod() = 0;
|
||||
virtual String IdeGetCurrentMainPackage() = 0;
|
||||
virtual void IdePutErrorLine(const String&) = 0;
|
||||
virtual void IdeGotoFileAndId(const String& path, const String& id) = 0;
|
||||
|
||||
virtual ~IdeContext() {}
|
||||
};
|
||||
|
||||
IdeContext *TheIde();
|
||||
void TheIde(IdeContext *context);
|
||||
IdeContext *TheIdeContext();
|
||||
void SetTheIde(IdeContext *context);
|
||||
|
||||
bool IsVerbose();
|
||||
void PutConsole(const char *s);
|
||||
|
|
@ -126,7 +242,6 @@ void IdeConsoleEndGroup();
|
|||
bool IdeConsoleWait();
|
||||
bool IdeConsoleWait(int slot);
|
||||
void IdeConsoleOnFinish(Event<> cb);
|
||||
void IdeGotoCodeRef(String s);
|
||||
|
||||
String GetSourcePackage(const String& path);
|
||||
|
||||
|
|
@ -154,13 +269,10 @@ bool IdeIsDebugLock();
|
|||
|
||||
void IdeSetBar();
|
||||
|
||||
void IdeGotoFileAndId(const String& path, const String& id);
|
||||
|
||||
int IdeGetHydraThreads();
|
||||
String IdeGetCurrentBuildMethod();
|
||||
String IdeGetCurrentMainPackage();
|
||||
void IdePutErrorLine(const String& s);
|
||||
void IdeGotoFileAndId(const String& path, const String& id);
|
||||
|
||||
#include "Host.h"
|
||||
|
||||
|
|
@ -340,7 +452,6 @@ public:
|
|||
|
||||
File() { Init(); }
|
||||
File(const String& s) : String(s) { Init(); }
|
||||
rval_default(File);
|
||||
};
|
||||
struct Config {
|
||||
String name;
|
||||
|
|
@ -385,11 +496,13 @@ public:
|
|||
String IdeCharsetName(byte charset);
|
||||
|
||||
class Workspace {
|
||||
void AddUses(Package& p, bool match, const Vector<String>& flag);
|
||||
void AddLoad(const String& name, bool match, const Vector<String>& flag);
|
||||
void AddUses(Package& p, const Vector<String> *flag);
|
||||
void AddLoad(const String& name);
|
||||
void Scan(const char *prjname, const Vector<String> *flag);
|
||||
|
||||
public:
|
||||
ArrayMap<String, Package> package;
|
||||
Vector<int> use_order;
|
||||
|
||||
void Clear() { package.Clear(); }
|
||||
String operator[](int i) const { return package.GetKey(i); }
|
||||
|
|
@ -397,8 +510,8 @@ public:
|
|||
const Package& GetPackage(int i) const { return package[i]; }
|
||||
int GetCount() const { return package.GetCount(); }
|
||||
|
||||
void Scan(const char *prjname);
|
||||
void Scan(const char *prjname, const Vector<String>& flag);
|
||||
void Scan(const char *prjname) { Scan(prjname, nullptr); }
|
||||
void Scan(const char *prjname, const Vector<String>& flag) { Scan(prjname, &flag); }
|
||||
|
||||
Vector<String> GetAllAccepts(int pk) const;
|
||||
|
||||
|
|
@ -501,15 +614,12 @@ struct Builder {
|
|||
VectorMap<String, Builder *(*)()>& BuilderMap();
|
||||
void RegisterBuilder(const char *name, Builder *(*create)());
|
||||
|
||||
String FindIncludeFile(const char *s, const String& filedir, const Vector<String>& incdir);
|
||||
|
||||
void HdependSetDirs(Vector<String> pick_ id);
|
||||
void HdependTimeDirty();
|
||||
void HdependClearDependencies();
|
||||
void HdependAddDependency(const String& file, const String& depends);
|
||||
Time HdependFileTime(const String& path);
|
||||
Vector<String> HdependGetDependencies(const String& file, bool bydefine_too = true);
|
||||
String FindIncludeFile(const char *s, const String& filedir);
|
||||
bool HdependBlitzApproved(const String& path);
|
||||
const Vector<String>& HdependGetDefines(const String& path);
|
||||
const Vector<String>& HdependGetAllFiles();
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@ uses
|
|||
file
|
||||
Core.h options(BUILDER_OPTION) PCH,
|
||||
Ide.cpp,
|
||||
Cache.cpp,
|
||||
Core.cpp,
|
||||
Builder.cpp,
|
||||
Hdepend.cpp,
|
||||
Hdepend2.cpp,
|
||||
Assembly.cpp,
|
||||
Package.cpp,
|
||||
Workspace.cpp,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,25 @@
|
|||
#include "Core.h"
|
||||
#include "Core.h"
|
||||
|
||||
const char *SkipSpc(const char *term) {
|
||||
while(*term == '\t' || *term == ' ')
|
||||
term++;
|
||||
return term;
|
||||
void Hdepend::Info::Serialize(Stream& s)
|
||||
{
|
||||
s % time
|
||||
% depend
|
||||
% bydefine
|
||||
% macroinclude
|
||||
% define
|
||||
% flag
|
||||
% macroflag
|
||||
% timedirty
|
||||
% guarded
|
||||
% blitzprohibit
|
||||
;
|
||||
}
|
||||
|
||||
String FindIncludeFile(const char *s, const String& filedir, const Vector<String>& incdir)
|
||||
String Hdepend::FindIncludeFile(const char *s, const String& filedir, const Vector<String>& incdirs)
|
||||
{
|
||||
s = SkipSpc(s);
|
||||
while(*s == ' ' || *s == '\t')
|
||||
s++;
|
||||
int type = *s;
|
||||
if(type == '<' || type == '\"' || type == '?') {
|
||||
s++;
|
||||
|
|
@ -21,10 +32,10 @@ String FindIncludeFile(const char *s, const String& filedir, const Vector<String
|
|||
if(FileExists(fn))
|
||||
return fn;
|
||||
}
|
||||
for(int i = 0; i < incdir.GetCount(); i++) {
|
||||
String fn = CatAnyPath(incdir[i], name);
|
||||
for(int i = 0; i < incdirs.GetCount(); i++) {
|
||||
String fn = CatAnyPath(incdirs[i], name);
|
||||
if(FileExists(fn))
|
||||
return fn;
|
||||
return NormalizePath(fn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -34,71 +45,21 @@ String FindIncludeFile(const char *s, const String& filedir, const Vector<String
|
|||
return String();
|
||||
}
|
||||
|
||||
class Hdepend {
|
||||
struct Info {
|
||||
Time time;
|
||||
Vector<int> depend;
|
||||
Vector<bool> bydefine;
|
||||
Index<String> macroinclude;
|
||||
Vector<String> define;
|
||||
bool flag;
|
||||
bool macroflag;
|
||||
bool timedirty;
|
||||
bool guarded;
|
||||
bool blitzprohibit;
|
||||
|
||||
bool CanBlitz() { return guarded && !blitzprohibit; }
|
||||
|
||||
Info() { time = Null; flag = false; timedirty = true; guarded = false; }
|
||||
};
|
||||
|
||||
ArrayMap<String, Info> map;
|
||||
Vector<String> incdir;
|
||||
VectorMap<String, Index<String> > depends;
|
||||
|
||||
void Include(const char *trm, Info& info, const String& filedir, bool bydefine);
|
||||
void ScanFile(const String& path, int map_index);
|
||||
int File(const String& path);
|
||||
Time FileTime(int i);
|
||||
void ClearFlag();
|
||||
void ClearMacroFlag();
|
||||
void GetMacroIndex(Index<String>& dest, int ix);
|
||||
|
||||
public:
|
||||
void SetDirs(Vector<String> pick_ id) { incdir = pick(id); map.Clear(); }
|
||||
void TimeDirty();
|
||||
|
||||
void ClearDependencies() { depends.Clear(); }
|
||||
void AddDependency(const String& file, const String& depends);
|
||||
|
||||
Time FileTime(const String& path);
|
||||
bool BlitzApproved(const String& path);
|
||||
String FindIncludeFile(const char *s, const String& filedir) { return ::FindIncludeFile(s, filedir, incdir); }
|
||||
const Vector<String>& GetDefines(const String& path);
|
||||
Vector<String> GetDependencies(const String& path, bool bydefine_too = true);
|
||||
const Vector<String>& GetAllFiles() { return map.GetKeys(); }
|
||||
};
|
||||
|
||||
void Hdepend::AddDependency(const String& file, const String& dep)
|
||||
{
|
||||
depends.GetAdd(NormalizePath(file)).FindAdd(NormalizePath(dep));
|
||||
}
|
||||
|
||||
const char *RestOfLine(const char *term, String& val) {
|
||||
while(*term && *term != '\r' && *term != '\n')
|
||||
val.Cat(*term++);
|
||||
return term;
|
||||
}
|
||||
|
||||
void Hdepend::Include(const char *s, Hdepend::Info& info, const String& filedir, bool bydefine) {
|
||||
s = SkipSpc(s);
|
||||
if(IsAlpha(*s) || *s == '_') {
|
||||
while(*s == ' ' || *s == '\t')
|
||||
s++;
|
||||
if(iscib(*s)) { // #include MACRO
|
||||
const char *macid = s;
|
||||
while(IsAlNum(*++s) || *s == '_')
|
||||
;
|
||||
while(iscid(*s))
|
||||
s++;
|
||||
info.macroinclude.FindAdd(String(macid, s));
|
||||
}
|
||||
else {
|
||||
else { // normal include
|
||||
String fn = FindIncludeFile(s, filedir);
|
||||
if(!IsNull(fn)) {
|
||||
info.depend.Add(File(fn));
|
||||
|
|
@ -122,19 +83,47 @@ static const char *SkipComment(const char *s) {
|
|||
return s;
|
||||
}
|
||||
|
||||
void Hdepend::ScanFile(const String& path, int map_index) {
|
||||
void Hdepend::ScanFile(const String& path, int map_index)
|
||||
{
|
||||
Info& info = map[map_index];
|
||||
String src = LoadFile(path);
|
||||
const char *term = src;
|
||||
info.depend.Clear();
|
||||
info.bydefine.Clear();
|
||||
info.macroinclude.Clear();;
|
||||
info.define.Clear();;
|
||||
info.macroinclude.Clear();
|
||||
info.define.Clear();
|
||||
info.guarded = false;
|
||||
info.blitzprohibit = false;
|
||||
|
||||
String src;
|
||||
if(GetFileLength(path) < 10000000)
|
||||
src = LoadFile(path);
|
||||
const char *term = src;
|
||||
|
||||
auto Id = [&](const char *id) {
|
||||
int n = strlen(id);
|
||||
if(memcmp(term, id, n) == 0 && findarg(term[n], ' ', '\t') >= 0) {
|
||||
term += n + 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto SkipSpc = [&] {
|
||||
while(*term == '\t' || *term == ' ')
|
||||
term++;
|
||||
};
|
||||
|
||||
auto RestOfLine = [&] {
|
||||
SkipSpc();
|
||||
const char *b = term;
|
||||
while(*term && *term != '\r' && *term != '\n')
|
||||
term++;
|
||||
return TrimRight(String(b, term));
|
||||
};
|
||||
|
||||
String filedir = GetFileDirectory(path);
|
||||
bool testg = true;
|
||||
bool defines = IsCSourceFile(path);
|
||||
|
||||
goto begin;
|
||||
while(*term) {
|
||||
if(term[0] == '/' && term[1] == '*') {
|
||||
|
|
@ -172,46 +161,38 @@ void Hdepend::ScanFile(const String& path, int map_index) {
|
|||
if(*term == '#') {
|
||||
term++;
|
||||
while(*term == ' ' || *term == '\t') term++;
|
||||
if(term[0] == 'i' && term[1] == 'n' && term[2] == 'c' && term[3] == 'l' &&
|
||||
term[4] == 'u' && term[5] == 'd' && term[6] == 'e' &&
|
||||
(term[7] == ' ' || term[7] == '\t')) {
|
||||
term = SkipSpc(term + 7);
|
||||
String val;
|
||||
term = RestOfLine(term, val);
|
||||
val = TrimRight(val);
|
||||
Include(val, info, filedir, false);
|
||||
if(Id("include")) {
|
||||
SkipSpc();
|
||||
Include(RestOfLine(), info, filedir, false);
|
||||
}
|
||||
else
|
||||
if(testg && term[0] == 'i' && term[1] == 'f' && term[2] == 'n' &&
|
||||
term[3] == 'd' && term[4] == 'e' && term[5] == 'f' &&
|
||||
(term[6] == ' ' || term[6] == '\t')) {
|
||||
if(testg && Id("ifndef")) {
|
||||
testg = false;
|
||||
try {
|
||||
CParser p(term + 6);
|
||||
CParser p(term);
|
||||
if(p.IsId()) {
|
||||
String id = p.ReadId();
|
||||
if(p.Char('#') && p.Id("define") && p.IsId() && id == p.ReadId())
|
||||
info.guarded = true;
|
||||
}
|
||||
term = p.GetPtr();
|
||||
goto begin;
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
}
|
||||
else
|
||||
if(defines && term[0] == 'd' && term[1] == 'e' && term[2] == 'f' &&
|
||||
term[3] == 'i' && term[4] == 'n' && term[5] == 'e' &&
|
||||
(term[6] == ' ' || term[6] == '\t')) {
|
||||
try {
|
||||
CParser p(term + 6);
|
||||
if(p.IsId())
|
||||
info.define.Add(p.ReadId());
|
||||
term = p.GetPtr();
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
if(defines && Id("define")) {
|
||||
try {
|
||||
CParser p(term);
|
||||
if(p.IsId())
|
||||
info.define.Add(p.ReadId());
|
||||
term = p.GetPtr();
|
||||
goto begin;
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
}
|
||||
else
|
||||
if(term[0] == 'p' && term[1] == 'r' && term[2] == 'a' &&
|
||||
term[3] == 'g' && term[4] == 'm' && term[5] == 'a' &&
|
||||
(term[6] == ' ' || term[6] == '\t')) {
|
||||
if(Id("pragma")) {
|
||||
try {
|
||||
CParser p(term + 6);
|
||||
if(p.Id("BLITZ_APPROVE") || p.Id("once"))
|
||||
|
|
@ -220,11 +201,13 @@ void Hdepend::ScanFile(const String& path, int map_index) {
|
|||
if(p.Id("BLITZ_PROHIBIT"))
|
||||
info.blitzprohibit = true;
|
||||
term = p.GetPtr();
|
||||
goto begin;
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
}
|
||||
}
|
||||
else if(IsAlpha(*term) || *term == '_') {
|
||||
else
|
||||
if(IsAlpha(*term) || *term == '_') { // .brc file
|
||||
const char *id = term;
|
||||
while(IsAlNum(*++term) || *term == '_')
|
||||
;
|
||||
|
|
@ -273,27 +256,17 @@ void Hdepend::ScanFile(const String& path, int map_index) {
|
|||
term++;
|
||||
while(*term && *term != '\n' && (byte)*term <= ' ')
|
||||
term++;
|
||||
if(Peek32le(term) == 'd' + ('e' << 8) + ('f' << 16) + ('i' << 24)
|
||||
&& Peek16le(term + 4) == 'n' + ('e' << 8)) {
|
||||
term += 6;
|
||||
if(Id("define")) {
|
||||
SkipSpc();
|
||||
while(*term && *term != '\n' && (byte)*term <= ' ')
|
||||
term++;
|
||||
const char *id = term;
|
||||
if(IsAlpha(*term) || *term == '_')
|
||||
while(IsAlNum(*++term) || *term == '_')
|
||||
;
|
||||
String ident(id, term);
|
||||
if(minc.Find(ident) >= 0) {
|
||||
term = SkipSpc(term);
|
||||
String incfn;
|
||||
id = term;
|
||||
while(*term && *term != '\n')
|
||||
if(iscib(*term))
|
||||
while(iscid(*term))
|
||||
term++;
|
||||
const char *e = term;
|
||||
while(e > id && (byte)e[-1] <= ' ')
|
||||
e--;
|
||||
Include(String(id, e), info, filedir, true);
|
||||
}
|
||||
String ident(id, term);
|
||||
if(minc.Find(ident) >= 0)
|
||||
Include(RestOfLine(), info, filedir, true);
|
||||
}
|
||||
}
|
||||
while(*term && *term != '\n')
|
||||
|
|
@ -307,14 +280,15 @@ void Hdepend::ScanFile(const String& path, int map_index) {
|
|||
}
|
||||
}
|
||||
|
||||
int Hdepend::File(const String& f) {
|
||||
int Hdepend::File(const String& f)
|
||||
{
|
||||
String path = NormalizePath(f);
|
||||
int ii = map.FindAdd(path);
|
||||
Info& info = map[ii];
|
||||
if(info.flag) return ii;
|
||||
info.flag = true;
|
||||
FindFile ff(path);
|
||||
if(!ff || ff.GetLastWriteTime() == info.time) {
|
||||
Time file_time = FileGetTime(path);
|
||||
if(IsNull(file_time) || file_time == info.time) {
|
||||
if(info.timedirty) {
|
||||
for(int i = 0; i < info.depend.GetCount(); i++)
|
||||
File(map.GetKey(info.depend[i]));
|
||||
|
|
@ -322,15 +296,16 @@ int Hdepend::File(const String& f) {
|
|||
}
|
||||
}
|
||||
else {
|
||||
info.time = ff.GetLastWriteTime();
|
||||
if(info.time > GetSysTime() + 10)
|
||||
info.time = file_time;
|
||||
if(console && info.time > GetSysTime() + 10)
|
||||
PutConsole(String().Cat() << "WARNING: " << path << " has invalid (future) time " << info.time);
|
||||
ScanFile(path, ii);
|
||||
}
|
||||
return ii;
|
||||
}
|
||||
|
||||
void Hdepend::GetMacroIndex(Index<String>& dest, int ix) {
|
||||
void Hdepend::GetMacroIndex(Index<String>& dest, int ix)
|
||||
{ // gather all macro includes in dependent files
|
||||
Info& info = map[ix];
|
||||
if(!info.macroflag) {
|
||||
info.macroflag = true;
|
||||
|
|
@ -389,6 +364,19 @@ void Hdepend::ClearMacroFlag()
|
|||
map[i].macroflag = false;
|
||||
}
|
||||
|
||||
void Hdepend::SetDirs(Vector<String>&& id)
|
||||
{
|
||||
if(incdir != id) {
|
||||
incdir = pick(id);
|
||||
map.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Hdepend::SetDirs(const String& includes)
|
||||
{
|
||||
SetDirs(pick(Split(includes, ';')));
|
||||
}
|
||||
|
||||
void Hdepend::TimeDirty()
|
||||
{
|
||||
for(int i = 0; i < map.GetCount(); i++)
|
||||
|
|
@ -410,7 +398,7 @@ Time Hdepend::FileTime(const String& path)
|
|||
FindFile ff(dep[i]);
|
||||
if(ff) {
|
||||
Time tm = ff.GetLastWriteTime();
|
||||
if(tm > GetSysTime() + 10)
|
||||
if(console && tm > GetSysTime() + 10)
|
||||
PutConsole(String().Cat() << "WARNING: " << dep[i] << " has invalid (future) time " << tm);
|
||||
if(tm > h)
|
||||
h = tm;
|
||||
|
|
@ -432,8 +420,9 @@ bool Hdepend::BlitzApproved(const String& path)
|
|||
return true;
|
||||
for(int i = 0; i < info.depend.GetCount(); i++)
|
||||
if(!info.bydefine[i] && !map[info.depend[i]].CanBlitz()) {
|
||||
PutVerbose(String().Cat() << map.GetKey(info.depend[i])
|
||||
<< "(1) : blocks BLITZ of " << path);
|
||||
if(console)
|
||||
PutVerbose(String().Cat() << map.GetKey(info.depend[i])
|
||||
<< "(1) : blocks BLITZ of " << path);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
400
uppsrc/ide/Core/Hdepend2.cpp
Normal file
400
uppsrc/ide/Core/Hdepend2.cpp
Normal file
|
|
@ -0,0 +1,400 @@
|
|||
#include "Core.h"
|
||||
|
||||
#define LTIMING(x) // RTIMING(x)
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
void SetSpaces(String& l, int pos, int count)
|
||||
{
|
||||
StringBuffer s(l);
|
||||
memset(~s + pos, ' ', count);
|
||||
l = s;
|
||||
}
|
||||
|
||||
const char *SkipString(const char *s)
|
||||
{
|
||||
CParser p(s);
|
||||
try {
|
||||
p.ReadOneString(*s);
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
s = p.GetPtr();
|
||||
while((byte)*(s - 1) <= ' ')
|
||||
s--;
|
||||
return s;
|
||||
}
|
||||
|
||||
void RemoveComments(String& l, bool& incomment)
|
||||
{
|
||||
int q = -1;
|
||||
int w = -1;
|
||||
if(incomment)
|
||||
q = w = 0;
|
||||
else {
|
||||
const char *s = l;
|
||||
while(*s) {
|
||||
if(*s == '\"')
|
||||
s = SkipString(s);
|
||||
else
|
||||
if(s[0] == '/' && s[1] == '/') {
|
||||
q = int(s - ~l);
|
||||
SetSpaces(l, q, l.GetCount() - q);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(s[0] == '/' && s[1] == '*') {
|
||||
q = int(s - ~l);
|
||||
break;
|
||||
}
|
||||
else
|
||||
s++;
|
||||
}
|
||||
if(q >= 0)
|
||||
w = q + 2;
|
||||
}
|
||||
while(q >= 0) {
|
||||
int eq = l.Find("*/", w);
|
||||
if(eq < 0) {
|
||||
incomment = true;
|
||||
SetSpaces(l, q, l.GetCount() - q);
|
||||
return;
|
||||
}
|
||||
SetSpaces(l, q, eq + 2 - q);
|
||||
incomment = false;
|
||||
q = l.Find("/*");
|
||||
w = q + 2;
|
||||
}
|
||||
}
|
||||
|
||||
void PPInfo::PPFile::Parse(Stream& in)
|
||||
{
|
||||
LTIMING("PPInfo::Parse");
|
||||
|
||||
flags.Clear();
|
||||
defines.Clear();
|
||||
includes[0].Clear();
|
||||
includes[1].Clear();
|
||||
define_includes[0].Clear();
|
||||
define_includes[1].Clear();
|
||||
guarded = false;
|
||||
blitz = AUTO;
|
||||
|
||||
int linei = 0;
|
||||
bool incomment = false;
|
||||
|
||||
String guard_id;
|
||||
bool first = true;
|
||||
int speculative = 0;
|
||||
|
||||
auto Flag = [&](const String& id) {
|
||||
if(id.StartsWith("flag"))
|
||||
flags.Add({ id, linei });
|
||||
};
|
||||
|
||||
auto Blitz = [&](const char *s) {
|
||||
try {
|
||||
CParser p(s);
|
||||
if(p.Id("BLITZ_APPROVE"))
|
||||
blitz = APPROVED;
|
||||
else
|
||||
if(p.Id("BLITZ_PROHIBIT"))
|
||||
blitz = PROHIBITED;
|
||||
else
|
||||
if(p.Id("once"))
|
||||
guarded = true;
|
||||
}
|
||||
catch(CParser::Error) {}
|
||||
};
|
||||
|
||||
while(!in.IsEof()) {
|
||||
String l = in.GetLine();
|
||||
while(*l.Last() == '\\' && !in.IsEof()) {
|
||||
l.TrimLast();
|
||||
linei++;
|
||||
l.Cat(in.GetLine());
|
||||
}
|
||||
|
||||
if(!incomment && l[0] == '/' && l[1] == '/' && l[2] == '#')
|
||||
Blitz(~l + 3);
|
||||
RemoveComments(l, incomment);
|
||||
try {
|
||||
CParser p(l);
|
||||
if(p.Char('#')) {
|
||||
if(p.Id("define") && p.IsId()) {
|
||||
p.NoSkipSpaces().NoSkipComments(); // '#define TEST(x)' is different form '#define TEST (x)' - later is parameterless
|
||||
String id = p.ReadId();
|
||||
if(id == guard_id) {
|
||||
guarded = true;
|
||||
speculative = 0;
|
||||
}
|
||||
if(p.Char('(')) {
|
||||
id << "(";
|
||||
p.SkipSpaces();
|
||||
p.Spaces();
|
||||
bool was = false;
|
||||
while(p.IsId()) {
|
||||
if(was)
|
||||
id << ", ";
|
||||
id << p.ReadId();
|
||||
was = true;
|
||||
}
|
||||
if(p.Char3('.', '.', '.'))
|
||||
id << "...";
|
||||
p.Char(')');
|
||||
id << ")";
|
||||
}
|
||||
p.Spaces();
|
||||
defines.Add(id, p.GetPtr());
|
||||
}
|
||||
else
|
||||
if(p.Id("ifndef") && p.IsId()) {
|
||||
String id = p.ReadId();
|
||||
Flag(id);
|
||||
if(first)
|
||||
guard_id = id;
|
||||
speculative++;
|
||||
}
|
||||
else
|
||||
if(p.Id("ifdef") && p.IsId()) {
|
||||
Flag(p.ReadId());
|
||||
speculative++;
|
||||
}
|
||||
else
|
||||
if(p.Id("if")) {
|
||||
while(!p.IsEof()) {
|
||||
if(p.IsId())
|
||||
Flag(p.ReadId());
|
||||
else
|
||||
p.Skip();
|
||||
}
|
||||
speculative++;
|
||||
}
|
||||
else
|
||||
if(p.Id("endif"))
|
||||
speculative--;
|
||||
else
|
||||
if(p.Id("include")) {
|
||||
if(p.IsId())
|
||||
define_includes[!!speculative].Add(p.ReadId());
|
||||
else
|
||||
includes[!!speculative].FindAdd(TrimBoth(p.GetPtr()));
|
||||
}
|
||||
else
|
||||
if(p.Id("pragma"))
|
||||
Blitz(p.GetPtr());
|
||||
}
|
||||
}
|
||||
catch(...) {}
|
||||
if(first)
|
||||
for(char s : l)
|
||||
if(s != ' ' && s != '\t') {
|
||||
first = false;
|
||||
break;
|
||||
}
|
||||
|
||||
linei++;
|
||||
}
|
||||
}
|
||||
|
||||
void PPInfo::PPFile::Serialize(Stream& s)
|
||||
{
|
||||
s % time
|
||||
% flags
|
||||
% defines
|
||||
% includes[0]
|
||||
% includes[1]
|
||||
% define_includes[0]
|
||||
% define_includes[1]
|
||||
% guarded
|
||||
% blitz
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
void PPInfo::SetIncludes(const String& incs)
|
||||
{
|
||||
inc_cache.Clear();
|
||||
includes = Split(incs, ';');
|
||||
}
|
||||
|
||||
Time PPInfo::GetFileTime(const String& path)
|
||||
{
|
||||
String dir = GetFileFolder(path);
|
||||
String name = GetFileName(path);
|
||||
int q = dir_cache.Find(dir);
|
||||
if(q < 0) {
|
||||
q = dir_cache.GetCount();
|
||||
VectorMap<String, Time>& files = dir_cache.Add(dir);
|
||||
for(FindFile ff(dir + "/*.*"); ff; ff.Next())
|
||||
if(ff.IsFile())
|
||||
files.Add(ff.GetName(), ff.GetLastWriteTime());
|
||||
}
|
||||
return dir_cache[q].Get(name, Null);
|
||||
}
|
||||
|
||||
String PPInfo::FindIncludeFile(const char *s, const String& filedir, const Vector<String>& incdirs)
|
||||
{
|
||||
while(*s == ' ' || *s == '\t')
|
||||
s++;
|
||||
int type = *s;
|
||||
if(type == '<' || type == '\"' || type == '?') {
|
||||
s++;
|
||||
String name;
|
||||
if(type == '<') type = '>';
|
||||
while(*s != '\r' && *s != '\n') {
|
||||
if(*s == type) {
|
||||
if(type == '\"') {
|
||||
String fn = NormalizePath(name, filedir);
|
||||
if(FileExists(fn))
|
||||
return fn;
|
||||
}
|
||||
for(int i = 0; i < incdirs.GetCount(); i++) {
|
||||
String fn = NormalizePath(CatAnyPath(incdirs[i], name));
|
||||
if(FileExists(fn))
|
||||
return fn;
|
||||
}
|
||||
break;
|
||||
}
|
||||
name.Cat(*s++);
|
||||
}
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
String PPInfo::FindIncludeFile(const char *s, const String& filedir)
|
||||
{
|
||||
String key = filedir + "|" + s;
|
||||
int q = inc_cache.Find(key);
|
||||
if(q >= 0)
|
||||
return inc_cache[q];
|
||||
String r = FindIncludeFile(s, filedir, includes);
|
||||
inc_cache.Add(key, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
void PPInfo::Dirty()
|
||||
{
|
||||
for(PPFile& f : files)
|
||||
f.dirty = true;
|
||||
inc_cache.Clear();
|
||||
dir_cache.Clear();
|
||||
}
|
||||
|
||||
std::atomic<int> PPInfo::scan_serial;
|
||||
|
||||
PPInfo::PPFile& PPInfo::File(const String& path)
|
||||
{
|
||||
PPFile& f = files.GetAdd(path);
|
||||
if(f.dirty) {
|
||||
Time tm;
|
||||
|
||||
tm = GetFileTime(path);
|
||||
if(tm != f.time || scan_serial != f.scan_serial) {
|
||||
String cache_path = CacheFile(GetFileTitle(path) + "$" + SHA1String(path) + ".ppi");
|
||||
if(IsNull(f.time)) {
|
||||
LoadFromFile(f, cache_path);
|
||||
}
|
||||
if(tm != f.time || scan_serial) {
|
||||
FileIn in(path);
|
||||
f.Parse(in); // TODO: If open fails, try to reopen!
|
||||
f.time = tm;
|
||||
f.scan_serial = scan_serial;
|
||||
StoreToFile(f, cache_path);
|
||||
}
|
||||
}
|
||||
f.dirty = false;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
Time PPInfo::GatherDependencies(const String& path, VectorMap<String, Time>& result,
|
||||
ArrayMap<String, Index<String>>& define_includes,
|
||||
Vector<Tuple<String, String, int>>& flags, bool speculative)
|
||||
{
|
||||
PPFile& f = File(path);
|
||||
String dir = GetFileFolder(path);
|
||||
Index<String>& dics = define_includes.GetAdd(path);
|
||||
for(int i = 0; i <= (int)speculative; i++) {
|
||||
for(const String& i : f.define_includes[i])
|
||||
dics.FindAdd(i);
|
||||
}
|
||||
|
||||
Time ftm = GetFileTime(path);
|
||||
|
||||
for(const Tuple<String, int>& x : f.flags)
|
||||
flags.Add({ path, x.a, x.b });
|
||||
|
||||
auto DoInclude = [&](const String& inc) {
|
||||
String ipath = FindIncludeFile(inc, dir);
|
||||
if(ipath.GetCount()) {
|
||||
int q = result.Find(ipath);
|
||||
if(q < 0) {
|
||||
q = result.GetCount();
|
||||
result.Add(ipath); // prevent infinite recursion
|
||||
result[q] = GetFileTime(ipath); // temporary
|
||||
result[q] = GatherDependencies(ipath, result, define_includes, flags, speculative);
|
||||
}
|
||||
ftm = max(result[q], ftm);
|
||||
q = define_includes.Find(ipath);
|
||||
if(q >= 0)
|
||||
for(const String& i : define_includes[q])
|
||||
dics.FindAdd(i);
|
||||
}
|
||||
};
|
||||
|
||||
for(int i = 0; i <= (int)speculative; i++) {
|
||||
for(const String& inc : f.includes[i])
|
||||
DoInclude(inc);
|
||||
for(int i = 0; i < dics.GetCount(); i++) { // cannot use range for as dics can change
|
||||
String id = dics[i];
|
||||
for(int q = f.defines.Find(id); q >= 0; q = f.defines.FindNext(q))
|
||||
DoInclude(f.defines[q]);
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(path, ftm);
|
||||
|
||||
return ftm;
|
||||
}
|
||||
|
||||
void PPInfo::GatherDependencies(const String& path, VectorMap<String, Time>& result,
|
||||
ArrayMap<String, Index<String>>& define_includes,
|
||||
bool speculative)
|
||||
{
|
||||
Vector<Tuple<String, String, int>> flags;
|
||||
GatherDependencies(path, result, define_includes, flags, speculative);
|
||||
}
|
||||
|
||||
Time PPInfo::GetTime(const String& path)
|
||||
{
|
||||
VectorMap<String, Time> result;
|
||||
ArrayMap<String, Index<String>> define_includes;
|
||||
Vector<Tuple<String, String, int>> flags;
|
||||
return GatherDependencies(NormalizePath(path), result, define_includes, flags, true);
|
||||
}
|
||||
|
||||
bool PPInfo::BlitzApproved(const String& path)
|
||||
{
|
||||
PPFile& f = File(path);
|
||||
if(f.blitz == APPROVED)
|
||||
return true;
|
||||
if(f.blitz == PROHIBITED)
|
||||
return false;
|
||||
String dir = GetFileFolder(path);
|
||||
for(int speculative = 0; speculative < 2; speculative++)
|
||||
for(const String& inc : f.includes[speculative]) {
|
||||
String ipath = FindIncludeFile(inc, dir);
|
||||
if(ipath.GetCount()) {
|
||||
PPFile& f = File(ipath);
|
||||
if(f.blitz == APPROVED)
|
||||
return true;
|
||||
if(f.blitz == PROHIBITED)
|
||||
return false;
|
||||
if(!f.guarded) {
|
||||
WhenBlitzBlock(ipath, path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -307,11 +307,8 @@ void Host::Launch(const char *_cmdline, bool console)
|
|||
#endif
|
||||
}
|
||||
|
||||
void Host::AddFlags(Index<String>& cfg)
|
||||
void AddHostFlags(Index<String>& cfg)
|
||||
{
|
||||
if(HasPlatformFlag(cfg))
|
||||
return;
|
||||
|
||||
#if defined(PLATFORM_WIN32)
|
||||
cfg.Add("WIN32");
|
||||
#endif
|
||||
|
|
@ -361,6 +358,13 @@ void Host::AddFlags(Index<String>& cfg)
|
|||
#endif
|
||||
}
|
||||
|
||||
void Host::AddFlags(Index<String>& cfg)
|
||||
{
|
||||
if(HasPlatformFlag(cfg))
|
||||
return;
|
||||
AddHostFlags(cfg);
|
||||
}
|
||||
|
||||
const Vector<String>& Host::GetExecutablesDirs() const
|
||||
{
|
||||
return exedirs;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ enum { REMOTE_TIMEOUT = 2000 };
|
|||
|
||||
extern String HostConsole;
|
||||
|
||||
void AddHostFlags(Index<String>& cfg);
|
||||
|
||||
struct Host {
|
||||
struct FileInfo : Time, Moveable<FileInfo> {
|
||||
int length;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
static IdeContext *the_ide;
|
||||
|
||||
IdeContext *TheIde() { return the_ide; }
|
||||
void TheIde(IdeContext *context) { the_ide = context; }
|
||||
IdeContext *TheIdeContext() { return the_ide; }
|
||||
void SetTheIde(IdeContext *context) { the_ide = context; }
|
||||
|
||||
bool IsVerbose() { return the_ide ? the_ide->IsVerbose() : false; }
|
||||
void PutConsole(const char *s) { if(the_ide) the_ide->PutConsole(s); }
|
||||
|
|
@ -140,11 +140,6 @@ void IdeConsoleOnFinish(Event<> cb)
|
|||
if(the_ide) the_ide->IdeConsoleOnFinish(cb);
|
||||
}
|
||||
|
||||
void IdeGotoCodeRef(String s)
|
||||
{
|
||||
if(the_ide) the_ide->IdeGotoCodeRef(s);
|
||||
}
|
||||
|
||||
void IdeSetBottom(Ctrl& ctrl)
|
||||
{
|
||||
if(the_ide) the_ide->IdeSetBottom(ctrl);
|
||||
|
|
@ -242,10 +237,3 @@ void IdePutErrorLine(const String& s)
|
|||
if(the_ide)
|
||||
the_ide->IdePutErrorLine(s);
|
||||
}
|
||||
|
||||
void IdeGotoFileAndId(const String& path, const String& id)
|
||||
{
|
||||
if(the_ide)
|
||||
the_ide->IdeGotoFileAndId(path, id);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ bool IsCSourceFile(const char *path)
|
|||
bool IsCHeaderFile(const char *path)
|
||||
{
|
||||
String ext = ToLower(GetFileExt(path));
|
||||
return ext == ".h" || ext == ".hpp" || ext == ".hh" || ext == ".hxx";
|
||||
return ext == ".h" || ext == ".hpp" || ext == ".hh" || ext == ".hxx" || ext == ".i";
|
||||
}
|
||||
|
||||
bool IsFullDirectory(const String& d) {
|
||||
|
|
@ -215,33 +215,32 @@ bool GetFlag(const Vector<String>& conf, const char *flag) {
|
|||
return FindIndex(conf, flag) >= 0;
|
||||
}
|
||||
|
||||
void Workspace::AddLoad(const String& name, bool match, const Vector<String>& flag)
|
||||
void Workspace::AddLoad(const String& name)
|
||||
{
|
||||
package.Add(name).Load(PackagePath(name));
|
||||
}
|
||||
|
||||
void Workspace::AddUses(Package& p, bool match, const Vector<String>& flag)
|
||||
void Workspace::AddUses(Package& p, const Vector<String> *flag)
|
||||
{
|
||||
int q = package.GetCount();
|
||||
for(int i = 0; i < p.uses.GetCount(); i++) {
|
||||
String uses = UnixPath(p.uses[i].text);
|
||||
if((!match || MatchWhen(p.uses[i].when, flag)) && package.Find(uses) < 0)
|
||||
AddLoad(uses, match, flag);
|
||||
if((!flag || MatchWhen(p.uses[i].when, *flag)) && package.Find(uses) < 0)
|
||||
AddLoad(uses);
|
||||
}
|
||||
int n = package.GetCount();
|
||||
for(int i = q; i < package.GetCount(); i++)
|
||||
AddUses(package[i], match, flag);
|
||||
AddUses(package[i], flag);
|
||||
for(int i = q; i < n; i++)
|
||||
use_order.Add(i);
|
||||
}
|
||||
|
||||
void Workspace::Scan(const char *prjname) {
|
||||
void Workspace::Scan(const char *prjname, const Vector<String> *flag) {
|
||||
package.Clear();
|
||||
AddLoad(prjname, false, Vector<String>());
|
||||
AddUses(package[0], false, Vector<String>());
|
||||
}
|
||||
|
||||
void Workspace::Scan(const char *prjname, const Vector<String>& flag) {
|
||||
package.Clear();
|
||||
AddLoad(prjname, true, flag);
|
||||
AddUses(package[0], true, flag);
|
||||
use_order.Clear();
|
||||
AddLoad(prjname);
|
||||
AddUses(package[0], flag);
|
||||
use_order.Add(0);
|
||||
}
|
||||
|
||||
void Workspace::Dump() {
|
||||
|
|
|
|||
|
|
@ -1,173 +0,0 @@
|
|||
#include "ide.h"
|
||||
|
||||
#if 0
|
||||
#define LDUMP(x) DDUMP(x)
|
||||
#define LDUMPC(x) DDUMPC(x)
|
||||
#define LLOG(x) DLOG(x)
|
||||
#else
|
||||
#define LDUMP(x)
|
||||
#define LDUMPC(x)
|
||||
#define LLOG(x)
|
||||
#endif
|
||||
|
||||
#define LTIMING(x) // DTIMING(x)
|
||||
|
||||
String ResolveTParam(const String& type, const Vector<String>& tparam)
|
||||
{
|
||||
CodeBaseLock __;
|
||||
return ResolveTParam(CodeBase(), type, tparam);
|
||||
}
|
||||
|
||||
void ResolveTParam(Vector<String>& type, const Vector<String>& tparam)
|
||||
{
|
||||
CodeBaseLock __;
|
||||
return ResolveTParam(CodeBase(), type, tparam);
|
||||
}
|
||||
|
||||
String Qualify(const String& scope, const String& type, const String& usings)
|
||||
{
|
||||
CodeBaseLock __;
|
||||
return Qualify(CodeBase(), scope, type, usings);
|
||||
}
|
||||
|
||||
void AssistScanError(int line, const String& text)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
PutVerbose(String().Cat() << "(" << line << "): " << text);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AssistEditor::Context(ParserContext& parser, int pos)
|
||||
{
|
||||
LTIMING("Context");
|
||||
LLOG("---------- Context " << path);
|
||||
|
||||
theide->ScanFile(true);
|
||||
|
||||
parser = AssistParse(Get(0, pos), theide->editfile, AssistScanError,
|
||||
[&](String scope, String type, String usings) {
|
||||
CodeBaseLock __;
|
||||
String t = Qualify(CodeBase(), scope, type, usings);
|
||||
return CodeBase().Find(NoTemplatePars(t)) >= 0 ? t : Null;
|
||||
});
|
||||
inbody = parser.IsInBody();
|
||||
#ifdef _DEBUG
|
||||
PutVerbose("body: " + AsString(inbody));
|
||||
PutVerbose("scope: " + AsString(parser.current_scope));
|
||||
PutVerbose("using: " + AsString(parser.context.namespace_using));
|
||||
for(int i = 0; i < parser.local.GetCount(); i++)
|
||||
PutVerbose(parser.local.GetKey(i) + ": " + parser.local[i].type);
|
||||
#endif
|
||||
}
|
||||
|
||||
Index<String> AssistEditor::EvaluateExpressionType(const ParserContext& parser, const Vector<String>& xp)
|
||||
{
|
||||
CodeBaseLock __;
|
||||
return GetExpressionType(CodeBase(), parser, xp);
|
||||
}
|
||||
|
||||
void AssistEditor::AssistItemAdd(const String& scope, const CppItem& m, int typei)
|
||||
{
|
||||
if(!iscib(*m.name) || m.name.GetCount() == 0)
|
||||
return;
|
||||
CppItemInfo& f = assist_item.Add();
|
||||
f.typei = typei;
|
||||
f.scope = scope;
|
||||
(CppItem&)f = m;
|
||||
}
|
||||
|
||||
void AssistEditor::GatherItems(const String& type, bool only_public, Index<String>& in_types, bool types)
|
||||
{
|
||||
LTIMING("GatherItems");
|
||||
LLOG("---- GatherItems " << type);
|
||||
CodeBaseLock __;
|
||||
if(in_types.Find(type) >= 0) {
|
||||
LLOG("-> recursion, exiting");
|
||||
return;
|
||||
}
|
||||
in_types.Add(type);
|
||||
Vector<String> tparam;
|
||||
String ntp = ParseTemplatedType(ResolveTParam(type, tparam), tparam);
|
||||
int q = CodeBase().Find(ntp);
|
||||
if(q < 0) {
|
||||
ntp.Replace("*", ""); // * can be part of type as result of template substitution
|
||||
q = CodeBase().Find(ntp);
|
||||
}
|
||||
if(q >= 0) {
|
||||
if(types) {
|
||||
if(ntp.GetCount())
|
||||
ntp << "::";
|
||||
int typei = assist_type.FindAdd("<types>");
|
||||
for(int i = 0; i < CodeBase().GetCount(); i++) {
|
||||
String nest = CodeBase().GetKey(i);
|
||||
if(nest.GetLength() > ntp.GetLength() && // Subscope of scope
|
||||
memcmp(~ntp, ~nest, ntp.GetLength()) == 0 && // e.g. Upp:: -> Upp::String
|
||||
nest.Find("::", ntp.GetLength()) < 0) { // but not Upp::String::Buffer
|
||||
Array<CppItem>& n = CodeBase()[i];
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
const CppItem& m = n[i];
|
||||
if(m.IsType())
|
||||
AssistItemAdd(nest, m, typei);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const Array<CppItem>& n = CodeBase()[q];
|
||||
String base;
|
||||
int typei = assist_type.FindAdd(ntp);
|
||||
bool op = only_public;
|
||||
for(int i = 0; i < n.GetCount(); i++)
|
||||
if(n[i].kind == FRIENDCLASS)
|
||||
op = false;
|
||||
for(int i = 0; i < n.GetCount(); i++) {
|
||||
const CppItem& im = n[i];
|
||||
if(im.kind == STRUCT || im.kind == STRUCTTEMPLATE)
|
||||
base << im.qptype << ';';
|
||||
if((im.IsCode() || !thisback && (im.IsData() || im.IsMacro() && IsNull(type)))
|
||||
&& (!op || im.access == PUBLIC)) {
|
||||
AssistItemAdd(ntp, im, typei);
|
||||
}
|
||||
}
|
||||
if(!thisback) {
|
||||
Vector<String> b = Split(base, ';');
|
||||
Index<String> h;
|
||||
for(int i = 0; i < b.GetCount(); i++)
|
||||
h.FindAdd(b[i]);
|
||||
b = h.PickKeys();
|
||||
ResolveTParam(b, tparam);
|
||||
for(int i = 0; i < b.GetCount(); i++)
|
||||
if(b[i].GetCount())
|
||||
GatherItems(b[i], only_public, in_types, types);
|
||||
}
|
||||
}
|
||||
in_types.Drop();
|
||||
}
|
||||
|
||||
bool OrderAssistItems(const CppItemInfo& a, const CppItemInfo& b)
|
||||
{
|
||||
return CombineCompare(a.uname, b.uname)(a.typei, b.typei)(a.qitem, b.qitem)(a.impl, b.impl)(a.filetype, b.filetype)(a.line, b.line) < 0;
|
||||
}
|
||||
|
||||
void AssistEditor::RemoveDuplicates()
|
||||
{
|
||||
LTIMING("RemoveDuplicates");
|
||||
{ LTIMING("Sort");
|
||||
Upp::Sort(assist_item, OrderAssistItems);
|
||||
}
|
||||
Vector<int> remove;
|
||||
{
|
||||
LTIMING("Find duplicates");
|
||||
int i = 0;
|
||||
while(i < assist_item.GetCount()) { // Remove identical items
|
||||
int ii = i;
|
||||
i++;
|
||||
while(i < assist_item.GetCount()
|
||||
&& assist_item[ii].typei == assist_item[i].typei
|
||||
&& assist_item[ii].qitem == assist_item[i].qitem
|
||||
&& assist_item[ii].scope == assist_item[i].scope)
|
||||
remove.Add(i++);
|
||||
}
|
||||
}
|
||||
LTIMING("Final remove");
|
||||
assist_item.Remove(remove);
|
||||
}
|
||||
|
|
@ -10,8 +10,89 @@
|
|||
#define LLOG(x)
|
||||
#endif
|
||||
|
||||
void AssistEditor::DCopy()
|
||||
bool AssistEditor::WaitCurrentFile()
|
||||
{
|
||||
if(annotating) {
|
||||
if(!IsCurrentFileParsing())
|
||||
SyncCurrentFile();
|
||||
Progress pi("Parsing");
|
||||
while(annotating)
|
||||
if(pi.StepCanceled())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssistEditor::DCopy()
|
||||
{ // changes declaration <-> definition
|
||||
String r;
|
||||
int l, h;
|
||||
if(!GetSelection32(l, h))
|
||||
l = h = GetCursor();
|
||||
|
||||
int first_line = GetLine(l);
|
||||
int last_line = GetLine(h);
|
||||
|
||||
if(last_line - first_line > 10000) {
|
||||
Exclamation("Too many lines.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!WaitCurrentFile())
|
||||
return;
|
||||
|
||||
String result;
|
||||
|
||||
for(const AnnotationItem& m : annotations) {
|
||||
if(first_line <= m.pos.y && m.pos.y <= last_line) {
|
||||
String cls = GetClass(m);
|
||||
if(IsFunction(m.kind)) {
|
||||
if(m.definition) {
|
||||
if(cls.GetCount())
|
||||
result << '\t';
|
||||
result << m.pretty << ";\n";
|
||||
}
|
||||
else {
|
||||
result << MakeDefinition(m);
|
||||
}
|
||||
}
|
||||
if(m.kind == CXCursor_VarDecl) {
|
||||
if(cls.GetCount()) { // class variable
|
||||
if(m.definition) {
|
||||
int q = FindId(m.pretty, m.name);
|
||||
if(q >= 0) {
|
||||
int w = m.pretty.ReverseFind(' ', q);
|
||||
if(w >= 0)
|
||||
result << "\tstatic " << m.pretty.Mid(0, w + 1) << m.pretty.Mid(q) << ";\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
String h = m.pretty;
|
||||
h.TrimStart("static ");
|
||||
h = TrimLeft(h);
|
||||
int q = FindId(h, m.name);
|
||||
if(q >= 0)
|
||||
result << h.Mid(0, q) << cls << h.Mid(q) << ";\n";
|
||||
}
|
||||
}
|
||||
else { // just toggle extern
|
||||
String h = m.pretty;
|
||||
if(FindId(GetUtf8Line(m.pos.y), "extern") < 0)
|
||||
h = "extern " + h;
|
||||
result << h << ";\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(result.GetCount() == 0) {
|
||||
PromptOK("No relevant declarations found.");
|
||||
return;
|
||||
}
|
||||
|
||||
WriteClipboardText(result);
|
||||
|
||||
#if 0
|
||||
String r;
|
||||
int l, h;
|
||||
bool decla = false;
|
||||
|
|
@ -42,7 +123,7 @@ void AssistEditor::DCopy()
|
|||
}
|
||||
else
|
||||
decla = true;
|
||||
|
||||
|
||||
ParserContext ctx;
|
||||
Context(ctx, l);
|
||||
String txt = Get(l, h - l);
|
||||
|
|
@ -62,88 +143,74 @@ void AssistEditor::DCopy()
|
|||
CppBase cpp;
|
||||
SimpleParse(cpp, txt, cls);
|
||||
|
||||
if(cpp.GetCount() == 0) { // scan for THISBACKs
|
||||
Index<String> id;
|
||||
CParser p(txt);
|
||||
try {
|
||||
while(!p.IsEof()) {
|
||||
if(p.Id("THISBACK") && p.Char('('))
|
||||
id.FindAdd(p.ReadId());
|
||||
p.SkipTerm();
|
||||
}
|
||||
}
|
||||
catch(CParser::Error) {
|
||||
}
|
||||
for(int i = 0; i < id.GetCount(); i++)
|
||||
r << "\tvoid " << id[i] << "();\n";
|
||||
}
|
||||
else
|
||||
for(int i = 0; i < cpp.GetCount(); i++) {
|
||||
const Array<CppItem>& n = cpp[i];
|
||||
bool decl = decla;
|
||||
for(int j = 0; j < n.GetCount(); j++)
|
||||
if(n[j].impl)
|
||||
decl = false;
|
||||
for(int j = 0; j < n.GetCount(); j++) {
|
||||
const CppItem& m = n[j];
|
||||
if(m.IsCode()) {
|
||||
if(decl)
|
||||
r << MakeDefinition(cls, m.natural) << "\n{\n}\n\n";
|
||||
else {
|
||||
if(cpp.IsType(i))
|
||||
r << String('\t', Split(cpp.GetKey(i), ':').GetCount());
|
||||
r << m.natural << ";\n";
|
||||
}
|
||||
for(int i = 0; i < cpp.GetCount(); i++) {
|
||||
const Array<CppItem>& n = cpp[i];
|
||||
bool decl = decla;
|
||||
for(int j = 0; j < n.GetCount(); j++)
|
||||
if(n[j].impl)
|
||||
decl = false;
|
||||
for(int j = 0; j < n.GetCount(); j++) {
|
||||
const CppItem& m = n[j];
|
||||
if(m.IsCode()) {
|
||||
if(decl)
|
||||
r << MakeDefinition(cls, m.natural) << "\n{\n}\n\n";
|
||||
else {
|
||||
if(cpp.IsType(i))
|
||||
r << String('\t', Split(cpp.GetKey(i), ':').GetCount());
|
||||
r << m.natural << ";\n";
|
||||
}
|
||||
if(m.IsData()) {
|
||||
String nat = m.natural;
|
||||
if(cls.GetCount()) {
|
||||
nat.Replace("static", "");
|
||||
nat = TrimLeft(nat);
|
||||
const char *s = nat;
|
||||
while(*s) {
|
||||
if(iscib(*s)) {
|
||||
const char *b = s;
|
||||
while(iscid(*s)) s++;
|
||||
String id(b, s);
|
||||
if(m.name == id) {
|
||||
if(cls.GetCount())
|
||||
r << cls << "::" << m.name << s;
|
||||
else
|
||||
r << m.name << s;
|
||||
break;
|
||||
}
|
||||
r << id;
|
||||
}
|
||||
if(m.IsData()) {
|
||||
String nat = m.natural;
|
||||
if(cls.GetCount()) {
|
||||
nat.Replace("static", "");
|
||||
nat = TrimLeft(nat);
|
||||
const char *s = nat;
|
||||
while(*s) {
|
||||
if(iscib(*s)) {
|
||||
const char *b = s;
|
||||
while(iscid(*s)) s++;
|
||||
String id(b, s);
|
||||
if(m.name == id) {
|
||||
if(cls.GetCount())
|
||||
r << cls << "::" << m.name << s;
|
||||
else
|
||||
r << m.name << s;
|
||||
break;
|
||||
}
|
||||
else
|
||||
r << *s++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int q = nat.ReverseFind("::");
|
||||
if(q >= 0) { // Foo Class2 :: Class::variable; -> static Foo variable;
|
||||
int e = q + 2;
|
||||
for(;;) {
|
||||
while(q >= 0 && nat[q - 1] == ' ')
|
||||
q--;
|
||||
if(q == 0 || !iscid(nat[q - 1]))
|
||||
break;
|
||||
while(q >= 0 && iscid(nat[q - 1]))
|
||||
q--;
|
||||
int w = nat.ReverseFind("::", q);
|
||||
if(w < 0)
|
||||
break;
|
||||
q = w;
|
||||
}
|
||||
nat.Remove(q, e - q);
|
||||
r << "static " << nat;
|
||||
r << id;
|
||||
}
|
||||
else
|
||||
r << "extern " << nat;
|
||||
r << *s++;
|
||||
}
|
||||
r << ";\n";
|
||||
}
|
||||
else {
|
||||
int q = nat.ReverseFind("::");
|
||||
if(q >= 0) { // Foo Class2 :: Class::variable; -> static Foo variable;
|
||||
int e = q + 2;
|
||||
for(;;) {
|
||||
while(q >= 0 && nat[q - 1] == ' ')
|
||||
q--;
|
||||
if(q == 0 || !iscid(nat[q - 1]))
|
||||
break;
|
||||
while(q >= 0 && iscid(nat[q - 1]))
|
||||
q--;
|
||||
int w = nat.ReverseFind("::", q);
|
||||
if(w < 0)
|
||||
break;
|
||||
q = w;
|
||||
}
|
||||
nat.Remove(q, e - q);
|
||||
r << "static " << nat;
|
||||
}
|
||||
else
|
||||
r << "extern " << nat;
|
||||
}
|
||||
r << ";\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WriteClipboardText(r);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
174
uppsrc/ide/Events.cpp
Normal file
174
uppsrc/ide/Events.cpp
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
#include "ide.h"
|
||||
|
||||
struct EventsDlg : WithEventsLayout<TopWindow> {
|
||||
struct CbInfo {
|
||||
String scope;
|
||||
String type;
|
||||
String name;
|
||||
};
|
||||
|
||||
String cls;
|
||||
Index<String> existing_methods; // to avoid duplicite names
|
||||
Array<CbInfo> cb;
|
||||
|
||||
void GatherEvents(const String& var, Index<String>& done, const String& cls);
|
||||
void CbEdit(One<Ctrl>& ctrl);
|
||||
void Generate(String& ins, String& clip, const String& scope, bool in_line);
|
||||
|
||||
typedef EventsDlg CLASSNAME;
|
||||
|
||||
EventsDlg(const String& cls);
|
||||
};
|
||||
|
||||
int FilterId(int c)
|
||||
{
|
||||
return iscid(c) ? c : 0;
|
||||
}
|
||||
|
||||
void EventsDlg::CbEdit(One<Ctrl>& ctrl)
|
||||
{
|
||||
ctrl.Create<EditString>().SetFilter(FilterId);
|
||||
}
|
||||
|
||||
EventsDlg::EventsDlg(const String& cls)
|
||||
: cls(cls) {
|
||||
CtrlLayoutOKCancel(*this, "Events");
|
||||
list.AddColumn("Defined");
|
||||
list.AddColumn("Type");
|
||||
list.AddColumn("Event");
|
||||
list.AddColumn("New Method Name").Ctrls(THISBACK(CbEdit));
|
||||
list.ColumnWidths("121 178 254 124");
|
||||
list.SetLineCy(EditField::GetStdHeight());
|
||||
list.EvenRowColor();
|
||||
list.SetEditLineCy();
|
||||
list.MultiSelect();
|
||||
Sizeable().Zoomable();
|
||||
|
||||
for(const auto& f : ~CodeIndex())
|
||||
for(const AnnotationItem& m : f.value.items)
|
||||
if(m.nest == cls)
|
||||
existing_methods.FindAdd(m.name);
|
||||
|
||||
Index<String> visited;
|
||||
GatherEvents("", visited, cls);
|
||||
|
||||
Breaker(yes, IDYES);
|
||||
}
|
||||
|
||||
void EventsDlg::GatherEvents(const String& var, Index<String>& visited, const String& cls)
|
||||
{
|
||||
String h = cls + " " + var;
|
||||
if(IsNull(cls) || visited.Find(h) >= 0 || h.GetCount() > 200 || list.GetCount() > 500 || visited.GetCount() > 2000)
|
||||
return;
|
||||
visited.Add(h);
|
||||
for(const auto& f : ~CodeIndex())
|
||||
for(const AnnotationItem& m : f.value.items)
|
||||
if(m.nest == cls && IsVariable(m.kind) && (m.pretty.StartsWith("Event<") || m.pretty.StartsWith("Gate<"))) {
|
||||
String n = m.name;
|
||||
String event = Merge(".", var, n);
|
||||
if(n == "WhenAction")
|
||||
n = "Action";
|
||||
else {
|
||||
Vector<String> ss = Split(event, '.');
|
||||
for(int i = 0; i < ss.GetCount(); i++) {
|
||||
String& s = ss[i];
|
||||
if(s == "WhenAction")
|
||||
s.Clear();
|
||||
else {
|
||||
s.TrimStart("When");
|
||||
if(s.GetCount())
|
||||
s.Set(0, ToUpper(s[0]));
|
||||
}
|
||||
}
|
||||
n = Join(ss, "");
|
||||
while(existing_methods.Find(n) >= 0)
|
||||
n = "On" + n;
|
||||
}
|
||||
list.Add(cls, m.type, event, n);
|
||||
}
|
||||
|
||||
for(const auto& f : ~CodeIndex())
|
||||
for(const AnnotationItem& m : f.value.items)
|
||||
if(m.id == cls && IsStruct(m.kind)) {
|
||||
// we cheat with With..<TopWindow> by splitting it to With... and TopWindow
|
||||
for(String s : Split(m.bases, [](int c) { return iscid(c) || c == ':' ? 0 : 1; }))
|
||||
GatherEvents(var, visited, s);
|
||||
}
|
||||
|
||||
for(const auto& f : ~CodeIndex())
|
||||
for(const AnnotationItem& m : f.value.items) {
|
||||
if(m.nest == cls
|
||||
&& IsVariable(m.kind)
|
||||
&& !IsSourceFile(f.key)
|
||||
&& m.type.Find('&') < 0 && m.type.Find('*') < 0
|
||||
&& !m.name.StartsWith("dv___")
|
||||
&& m.pretty.Find("static") < 0) {
|
||||
GatherEvents(Merge(".", var, m.name), visited, m.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EventsDlg::Generate(String& ins, String& clip, const String& scope, bool in_line)
|
||||
{
|
||||
String n;
|
||||
Vector<String> nn = Split(cls, ':');
|
||||
if(nn.GetCount())
|
||||
n = nn.Top();
|
||||
String ac;
|
||||
for(int i = 0; i < list.GetCount(); i++) {
|
||||
if(list.IsSel(i)) {
|
||||
String type = list.Get(i, 1);
|
||||
String var = list.Get(i, 2);
|
||||
String method = list.Get(i, 3);
|
||||
|
||||
String param;
|
||||
int q = type.Find('<');
|
||||
if(q >= 0) {
|
||||
int qq = type.ReverseFind('>');
|
||||
if(q < qq) {
|
||||
param = String(~type + q + 1, ~type + qq);
|
||||
}
|
||||
}
|
||||
|
||||
q = var.ReverseFind('.');
|
||||
ins << '\t';
|
||||
if(q >= 0 && var.Mid(q + 1) == "WhenAction")
|
||||
ins << var.Mid(0, q) << " <<=";
|
||||
else
|
||||
ins << var << " =";
|
||||
if(in_line)
|
||||
ins << " [=](" << param << ") {\n\t}\n\t\n";
|
||||
else {
|
||||
ins << " THISFN(" << method << ");\n";
|
||||
String t = type.StartsWith("Gate") ? "bool " : "void ";
|
||||
clip << t << n << "::" << method << "(" << param << ")\n{\n}\n\n";
|
||||
ac << '\t' << t << method << "(" << param << ");\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
clip << ac;
|
||||
}
|
||||
|
||||
INITBLOCK
|
||||
{
|
||||
RegisterGlobalConfig("EventsDlg");
|
||||
}
|
||||
|
||||
void AssistEditor::Events()
|
||||
{
|
||||
SortByKey(CodeIndex());
|
||||
String nest = FindCurrentNest();
|
||||
if(IsNull(nest))
|
||||
return;
|
||||
EventsDlg dlg(nest);
|
||||
LoadFromGlobal(dlg, "EventsDlg");
|
||||
int c = dlg.Run();
|
||||
StoreToGlobal(dlg, "EventsDlg");
|
||||
if(c == IDOK)
|
||||
return;
|
||||
String a, b;
|
||||
dlg.Generate(a, b, nest, c == IDYES);
|
||||
Paste(a.ToWString());
|
||||
if(c != IDYES)
|
||||
WriteClipboardText(b);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue