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:
mirek-fidler 2022-09-16 10:31:14 +02:00 committed by GitHub
parent b1617ed3d3
commit e8035690b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
147 changed files with 8943 additions and 11172 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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 {

View file

@ -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();

View file

@ -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

View file

@ -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;
}

View file

@ -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)
{

View file

@ -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();
}

View file

@ -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

View file

@ -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;
}
//$-

View file

@ -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> >
{

View file

@ -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); }
};

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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];
}
}

View file

@ -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.

View file

@ -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

View file

@ -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;

View file

@ -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
}
}

View file

@ -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;
}
};

View file

@ -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>());
}
};

View file

@ -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

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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)

View file

@ -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;
}
}

View file

@ -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;
}
};

View file

@ -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
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
};

View file

@ -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);
//$ };

View file

@ -1,4 +1,3 @@
//$ class Upp::TopWindow {
protected:
friend struct MMImp;
@ -22,4 +21,3 @@ public:
Event<Bar&> WhenDockMenu;
void SetMainMenu(Event<Bar&> menu);
//$ };

View file

@ -110,8 +110,10 @@ void Ctrl::ShutdownThreads()
{
Thread::BeginShutdownThreads();
while(Thread::GetCount()) {
Thread::TryShutdownThreads();
ProcessEvents();
Sleep(0);
GuiUnlock __;
Sleep(100);
}
Thread::EndShutdownThreads();
}

View file

@ -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>

View file

@ -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

View file

@ -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);
//$ }};

View file

@ -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)

View file

@ -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;
//$ };

View file

@ -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)

View file

@ -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(); }
//$ };
//$ };

View file

@ -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; }
//$ };

View file

@ -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); }
//$ }};

View file

@ -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;
//$ };

View file

@ -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]()&]

View file

@ -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()) {

View file

@ -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);

View file

@ -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; }

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -1,7 +1,5 @@
//#BLITZ_APPROVE
//$-
#define IMAGE_META(k, v)
#define IMAGE_SCAN(s)
#define IMAGE_PACKED(n, d)

View file

@ -1,7 +1,5 @@
//#BLITZ_APPROVE
//$
#define IMAGE_META(k, v)
#define PREMULTIPLIED

View file

@ -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)

View file

@ -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);

View file

@ -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();

View file

@ -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;

View file

@ -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;
}

View file

@ -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, &param_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();
}
}

View file

@ -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();
};

View 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);
}
}

View file

@ -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);
}

View file

@ -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();

View file

@ -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

View file

@ -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,

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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()));
}

View file

@ -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;
}

View file

@ -1,4 +1,4 @@
#include "Browser.h"
#include <ide/ide.h>
struct MoveTopicDlg : public WithMoveTopicLayout<TopWindow> {
typedef MoveTopicDlg CLASSNAME;

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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)

View file

@ -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();
}

View file

@ -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()

View file

@ -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>

View file

@ -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;

View file

@ -516,7 +516,6 @@ bool MakeBuild::Build(const Workspace& wspc, String mainparam, String outfile, b
}
}
EndBuilding(ok);
ReQualifyCodeBase();
SetErrorEditor();
return ok;
}

View file

@ -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;

View file

@ -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")

View file

@ -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
View 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);
}

View file

@ -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();

View file

@ -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,

View file

@ -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;

View 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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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() {

View file

@ -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);
}

View file

@ -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
View 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