From 49d3de4a8abad43eaaafe2c0caa76d85ffc4cfe8 Mon Sep 17 00:00:00 2001 From: cxl Date: Mon, 11 May 2015 17:13:55 +0000 Subject: [PATCH] New Cpp preprocesing parser merged git-svn-id: svn://ultimatepp.org/upp/trunk@8427 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Core/Defs.h | 2 +- uppsrc/Core/Diag.h | 2 + uppsrc/Core/Format.cpp | 14 +- uppsrc/Core/Format.h | 2 +- uppsrc/Core/Map.h | 4 + uppsrc/Core/Map.hpp | 32 +- uppsrc/Core/Path.cpp | 1 + uppsrc/Core/ValueUtil.cpp | 10 +- uppsrc/Core/mathutil.cpp | 4 +- uppsrc/Core/parser.cpp | 2 +- uppsrc/Core/src.tpp/AMap$en-us.tpp | 40 +- uppsrc/CppBase/Base.cpp | 50 +- uppsrc/CppBase/CppBase.h | 241 +++++++-- uppsrc/CppBase/CppBase.upp | 6 +- uppsrc/CppBase/CppItem.cpp | 3 +- uppsrc/CppBase/Parser.cpp | 755 +++++++++++++++++----------- uppsrc/CppBase/Pre.cpp | 55 +- uppsrc/CppBase/Qualify.cpp | 135 ++--- uppsrc/CppBase/Scopefo.cpp | 128 ----- uppsrc/CppBase/cpplex.cpp | 23 +- uppsrc/TCore/util.cpp | 4 +- uppsrc/ide/Annotations.cpp | 58 ++- uppsrc/ide/Assist.cpp | 52 +- uppsrc/ide/Assist.h | 9 +- uppsrc/ide/Browser/Base.cpp | 645 +++++++++++++++--------- uppsrc/ide/Browser/Browser.h | 51 +- uppsrc/ide/Browser/Browser.upp | 6 +- uppsrc/ide/Browser/CodeBrowser.cpp | 34 +- uppsrc/ide/Browser/Iml.cpp | 6 +- uppsrc/ide/Browser/Item.cpp | 11 +- uppsrc/ide/Browser/ItemDisplay.cpp | 1 - uppsrc/ide/Browser/Lay.cpp | 6 +- uppsrc/ide/Browser/Sch.cpp | 7 +- uppsrc/ide/Browser/TopicBase.cpp | 2 + uppsrc/ide/Browser/Util.cpp | 2 +- uppsrc/ide/Browser/init | 1 + uppsrc/ide/Build.cpp | 22 +- uppsrc/ide/Builders/MscBuilder.icpp | 4 +- uppsrc/ide/Builders/init | 10 +- uppsrc/ide/Core/Core.h | 4 + uppsrc/ide/Core/Core.upp | 1 + uppsrc/ide/Cpp.cpp | 134 +++-- uppsrc/ide/Errors.cpp | 9 +- uppsrc/ide/FindInFiles.cpp | 3 + uppsrc/ide/Goto.cpp | 21 +- uppsrc/ide/Jump.cpp | 2 +- uppsrc/ide/Methods.cpp | 26 + uppsrc/ide/Navigator.cpp | 58 ++- uppsrc/ide/OutputMode.cpp | 1 + uppsrc/ide/Thisbacks.cpp | 4 +- uppsrc/ide/Virtuals.cpp | 4 +- uppsrc/ide/ide.cpp | 4 +- uppsrc/ide/ide.h | 11 +- uppsrc/ide/ide.key | 2 +- uppsrc/ide/ide.lay | 2 +- uppsrc/ide/idebar.cpp | 5 +- uppsrc/ide/idefile.cpp | 20 +- uppsrc/ide/idetool.cpp | 2 +- uppsrc/ide/idewin.cpp | 32 +- uppsrc/plugin/lz4/lz4upp.cpp | 2 +- 60 files changed, 1673 insertions(+), 1114 deletions(-) delete mode 100644 uppsrc/CppBase/Scopefo.cpp diff --git a/uppsrc/Core/Defs.h b/uppsrc/Core/Defs.h index d614ef643..7415fd2e1 100644 --- a/uppsrc/Core/Defs.h +++ b/uppsrc/Core/Defs.h @@ -732,7 +732,7 @@ void EndianSwap(uint64 *v, int count); class Fail__ {}; // Used as return value for function that are not to be called #define SVO_MEMCPY(tgt, src, len) \ -do { \ +do { \ const char *s__ = (const char *)(src); \ char *t__ = (char *)(tgt); \ switch(len) { \ diff --git a/uppsrc/Core/Diag.h b/uppsrc/Core/Diag.h index 73861336e..36bbedb41 100644 --- a/uppsrc/Core/Diag.h +++ b/uppsrc/Core/Diag.h @@ -124,6 +124,8 @@ inline void LOGF(const char *format, ...) {} #define ACTIVATE_TIMING() LOG_NOP #define DEACTIVATE_TIMING() LOG_NOP +#define TIMESTOP(x) LOG_NOP + #endif struct DebugLogBlock diff --git a/uppsrc/Core/Format.cpp b/uppsrc/Core/Format.cpp index f03a5d322..c88f04814 100644 --- a/uppsrc/Core/Format.cpp +++ b/uppsrc/Core/Format.cpp @@ -252,7 +252,7 @@ String FormatDoubleDigits(double d, int raw_digits, int flags, int& exponent) else p[-1]++; } - if(flags & FD_ZERO) + if(flags & FD_ZEROS) { char *e = p; while(e > ~buffer && e[-1] == '0') @@ -313,7 +313,7 @@ String FormatDoubleFix(double d, int digits, int flags) int pointchar = (flags & FD_COMMA) ? ',' : '.'; if(IsNull(exp) || exp < -digits) { out.Cat('0'); - if((flags & FD_ZERO) && digits) { + if((flags & FD_ZEROS) && digits) { out.Cat(pointchar); out.Cat('0', digits); } @@ -323,7 +323,7 @@ String FormatDoubleFix(double d, int digits, int flags) out.Cat(pointchar); out.Cat('0', -1 - exp); int fill = digits + exp + 1; - if(!(flags & FD_ZERO) || dig.GetLength() >= fill) + if(!(flags & FD_ZEROS) || dig.GetLength() >= fill) out.Cat(dig, min(fill, dig.GetLength())); else { out.Cat(dig); @@ -332,9 +332,9 @@ String FormatDoubleFix(double d, int digits, int flags) } else if(exp < dig.GetLength()) { out.Cat(dig, ++exp); - if(digits > 0 && ((flags & FD_ZERO) || dig.GetLength() > exp)) { + if(digits > 0 && ((flags & FD_ZEROS) || dig.GetLength() > exp)) { out.Cat(pointchar); - if(!(flags & FD_ZERO) || dig.GetLength() - exp >= digits) + if(!(flags & FD_ZEROS) || dig.GetLength() - exp >= digits) out.Cat(dig.Begin() + exp, min(dig.GetLength() - exp, digits)); else { out.Cat(dig.Begin() + exp, dig.GetLength() - exp); @@ -346,7 +346,7 @@ String FormatDoubleFix(double d, int digits, int flags) { out.Cat(dig); out.Cat('0', exp - dig.GetLength() + 1); - if(digits > 0 && (flags & FD_ZERO)) + if(digits > 0 && (flags & FD_ZEROS)) { out.Cat(pointchar); out.Cat('0', digits); @@ -620,7 +620,7 @@ String RealFormatter(const Formatting& f) } if(*s == '@') { s++; flags |= FD_NOTHSEPS; } if(*s == ',') { s++; flags |= FD_COMMA; } - if(*s == '!') { s++; flags |= FD_ZERO; } + if(*s == '!') { s++; flags |= FD_ZEROS; } if(*s == '^') { if(*++s == '+') { flags |= FD_SIGN_EXP; diff --git a/uppsrc/Core/Format.h b/uppsrc/Core/Format.h index d1b8ffd7b..c6cdd30fa 100644 --- a/uppsrc/Core/Format.h +++ b/uppsrc/Core/Format.h @@ -40,7 +40,7 @@ enum FD_REL = 0x02, // relative decimal places (valid digits) FD_SIGN_EXP = 0x04, // always prepend sign to exponent (1e+2) FD_CAP_E = 0x08, // capital E for exponent (1E10) - FD_ZERO = 0x10, // keep trailing zeros (1.25000) + FD_ZEROS = 0x10, // keep trailing zeros (1.25000) FD_FIX = 0x20, // always use fixed notation (FormatDouble) FD_EXP = 0x40, // always use exponential notation (FormatDouble) FD_COMMA = 0x80, // use ',' instead of '.' diff --git a/uppsrc/Core/Map.h b/uppsrc/Core/Map.h index 35f37d14a..abd988aa7 100644 --- a/uppsrc/Core/Map.h +++ b/uppsrc/Core/Map.h @@ -21,6 +21,7 @@ public: int FindAddPick(const K& k, T rval_ init); int Put(const K& k, const T& x); + int PutDefault(const K& k); int PutPick(const K& k, T rval_ x); T& Put(const K& k); @@ -47,6 +48,9 @@ public: T *FindPtr(const K& k) { int i = Find(k); return i >= 0 ? &value[i] : NULL; } const T *FindPtr(const K& k) const { int i = Find(k); return i >= 0 ? &value[i] : NULL; } + T *FindLastPtr(const K& k) { int i = FindLast(k); return i >= 0 ? &value[i] : NULL; } + const T *FindLastPtr(const K& k) const { int i = FindLast(k); return i >= 0 ? &value[i] : NULL; } + void Unlink(int i) { key.Unlink(i); } int UnlinkKey(const K& k, unsigned h) { return key.UnlinkKey(k, h); } int UnlinkKey(const K& k) { return key.UnlinkKey(k); } diff --git a/uppsrc/Core/Map.hpp b/uppsrc/Core/Map.hpp index 349b084e9..4288bbef3 100644 --- a/uppsrc/Core/Map.hpp +++ b/uppsrc/Core/Map.hpp @@ -421,6 +421,21 @@ int AMap::Put(const K& k, const T& x) return i; } +template +int AMap::PutDefault(const K& k) +{ + int i = key.Put(k); + if(i >= value.GetCount()) { + ASSERT(i == value.GetCount()); + value.Add(); + } + else { + DestroyArray(&value[i], &value[i] + 1); + ConstructArray(&value[i], &value[i] + 1); + } + return i; +} + template int AMap::PutPick(const K& k, T rval_ x) { @@ -438,8 +453,11 @@ template T& AMap::Put(const K& k) { int i = key.Put(k); - if(i < value.GetCount()) + if(i < value.GetCount()) { + DestroyArray(&value[i], &value[i] + 1); + ConstructArray(&value[i], &value[i] + 1); return value[i]; + } else { ASSERT(i == value.GetCount()); return value.Add(); @@ -451,11 +469,7 @@ int AMap::FindPut(const K& k) { unsigned hash = key.hashfn(k); int i = Find(k, hash); - if(i < 0) { - i = key.Put(k, hash); - value.At(i); - } - return i; + return i < 0 ? PutDefault(k) : i; } template @@ -520,17 +534,17 @@ T& AMap::GetAddPick(const K& k, T rval_ x) { template T& AMap::GetPut(const K& k) { - return value[FindAdd(k)]; + return value[FindPut(k)]; } template T& AMap::GetPut(const K& k, const T& x) { - return value[FindAdd(k, x)]; + return value[FindPut(k, x)]; } template T& AMap::GetPutPick(const K& k, T rval_ x) { - return value[FindAddPick(k, x)]; + return value[FindPutPick(k, x)]; } #ifdef UPP diff --git a/uppsrc/Core/Path.cpp b/uppsrc/Core/Path.cpp index c7f917723..1360e7ac7 100644 --- a/uppsrc/Core/Path.cpp +++ b/uppsrc/Core/Path.cpp @@ -868,6 +868,7 @@ int Compare_FileTime(const FileTime& fa, const FileTime& fb) Time FileGetTime(const char *filename) { + RTIMING("FileGetTime"); #if defined(PLATFORM_WIN32) HANDLE handle; if(IsWinNT()) diff --git a/uppsrc/Core/ValueUtil.cpp b/uppsrc/Core/ValueUtil.cpp index 7e9797b67..7f6ed8fe4 100644 --- a/uppsrc/Core/ValueUtil.cpp +++ b/uppsrc/Core/ValueUtil.cpp @@ -164,7 +164,10 @@ ValueArray::ValueArray(const Value& src) return; } else { - ASSERT(dynamic_cast(src.GetVoidPtr())); + if(src.GetType() != VALUEARRAY_V) + throw ValueTypeError(String().Cat() << "Invalid value conversion: " + << src.GetTypeName() << " -> ValueArray", + src, VALUEARRAY_V); data = (ValueArray::Data *)src.GetVoidPtr(); } } @@ -525,7 +528,10 @@ ValueMap::ValueMap(const Value& src) return; } else { - ASSERT(dynamic_cast(src.GetVoidPtr())); + if(src.GetType() != VALUEMAP_V) + throw ValueTypeError(String().Cat() << "Invalid value conversion: " + << src.GetTypeName() << " -> ValueMap", + src, VALUEMAP_V); data = (ValueMap::Data *)src.GetVoidPtr(); } } diff --git a/uppsrc/Core/mathutil.cpp b/uppsrc/Core/mathutil.cpp index ba767aa56..3dca60143 100644 --- a/uppsrc/Core/mathutil.cpp +++ b/uppsrc/Core/mathutil.cpp @@ -154,8 +154,8 @@ String AsString(double x, int digits) { if(IsNull(x)) return Null; if(fabs(x) >= 1e15) - return FormatDoubleExp(x, tabs(digits), digits < 0 ? FD_ZERO : 0); - return FormatDoubleFix(x, tabs(digits), digits < 0 ? FD_ZERO : 0); + return FormatDoubleExp(x, tabs(digits), digits < 0 ? FD_ZEROS : 0); + return FormatDoubleFix(x, tabs(digits), digits < 0 ? FD_ZEROS : 0); } // modulo: working version of math function `fmod'. diff --git a/uppsrc/Core/parser.cpp b/uppsrc/Core/parser.cpp index bddf83683..d64a9271c 100644 --- a/uppsrc/Core/parser.cpp +++ b/uppsrc/Core/parser.cpp @@ -416,7 +416,7 @@ void CParser::SkipTerm() { LTIMING("SkipTerm"); if(IsId()) - while(IsAlNum(*term) || *term == '_') + while(iscid(*term)) term++; else if(IsNumber()) diff --git a/uppsrc/Core/src.tpp/AMap$en-us.tpp b/uppsrc/Core/src.tpp/AMap$en-us.tpp index b614edbcd..50d45cdb0 100644 --- a/uppsrc/Core/src.tpp/AMap$en-us.tpp +++ b/uppsrc/Core/src.tpp/AMap$en-us.tpp @@ -132,6 +132,17 @@ number is returned. Unlinked elements are ignored.&] is not in AMap.&] [s3;%- &] [s4;%- &] +[s5;:AMap`:`:FindNext`(int`)const:%- [@(0.0.255) int]_[* FindNext]([@(0.0.255) int]_[*@3 i])_ +[@(0.0.255) const]&] +[s2; Retrieves the position of next element with the same key as +element at the specified position. If multi`-key ordering is +not broken and more than one element with that value exists in +AMap, the lowest position greater than specified one is retrieved +(so that positions got by subsequent calls to FindNext are in +ascending order). When there are no more elements with required +key, a negative number is returned. Unlinked elements are ignored.&] +[s3; &] +[s4;%- &] [s5;:AMap`:`:Find`(const K`&`,unsigned`)const:%- [@(0.0.255) int]_[* Find]([@(0.0.255) cons t]_[*@4 K][@(0.0.255) `&]_[*@3 k], [@(0.0.255) unsigned]_[*@3 h])_[@(0.0.255) const]&] [s2; Retrieves the position of next element with the same key as @@ -178,7 +189,7 @@ is not in AMap.&] as element at the specified position. If multi`-key ordering is not broken and more than one element with that value exists in AMap, the greatest position lower than specified one is retrieved -(so that positions got by subsequent calls to FindNext are in +(so that positions got by subsequent calls to FindPrev are in descending order). When there are no more elements with required key, a negative number is returned. Unlinked elements are ignored.&] [s7; [*C@3 i]-|Position of element.&] @@ -256,8 +267,18 @@ Value is transfered using deep copy constructor.&] [s7; [*C@3 x]-|Value.&] [s3;%- &] [s4;%- &] -[s5;:AMap`:`:PutPick`(const K`&`,pick`_ T`&`):%- [@(0.0.255) int]_[* PutPick]([@(0.0.255) c -onst]_[*@4 K][@(0.0.255) `&]_[*@3 k], [@(0.128.128) pick`_]_[*@4 T][@(0.0.255) `&]_[*@3 x])&] +[s5;:AMap`:`:PutDefault`(const K`&`):%- [@(0.0.255) int]_[* PutDefault]([@(0.0.255) const]_ +[*@4 K][@(0.0.255) `&]_[*@3 k])&] +[s2; Similar to Put, but value is default constructed.&] +[s6; T must have deep copy constructor.&] +[s6; Invalidates multi`-key ordering.&] +[s6; Invalidates iterators to AMap.&] +[s6; Invalidates references to keys.&] +[s6; Invalidates references to VectorMap values.&] +[s3; &] +[s4;%- &] +[s5;:AMap`:`:PutPick`(const K`&`,T rval`_`):%- [@(0.0.255) int]_[* PutPick]([@(0.0.255) con +st]_[*@4 K][@(0.0.255) `&]_[*@3 k], [*@4 T]_[@(0.0.255) rval`_]_[*@3 x])&] [s2; If there are any unlinked elements in AMap, one of them is replaced by the specified key/value pair. If there is no unlinked element, the key/value pair is added at the end of AIndex using [* Add]. @@ -492,7 +513,7 @@ is not in AMap.&] [s4;%- &] [s5;:AMap`:`:FindPtr`(const K`&`)const:%- [@(0.0.255) const]_[*@4 T]_`*[* FindPtr]([@(0.0.255) c onst]_[*@4 K][@(0.0.255) `&]_[*@3 k])_[@(0.0.255) const]&] -[s2; Retrieves a constant pointer to value of first element with +[s2; Retrieves a constant pointer to value of the first element with the specified key in AMap. If multi`-key ordering is not broken and more than one element with the same value exists in AMap, the lowest position is retrieved. If the element does not exist @@ -502,6 +523,17 @@ in AMap, NULL pointer is returned. Unlinked elements are ignored.&] is not in AMap.&] [s3;%- &] [s4;%- &] +[s5;:AMap`:`:FindLastPtr`(const K`&`):%- [*@4 T]_`*[* FindLastPtr]([@(0.0.255) const]_[*@4 K][@(0.0.255) `& +]_[*@3 k])&] +[s5;:AMap`:`:FindLastPtr`(const K`&`)const:%- [@(0.0.255) const]_[*@4 T]_`*[* FindLastPtr]( +[@(0.0.255) const]_[*@4 K][@(0.0.255) `&]_[*@3 k])_[@(0.0.255) const]&] +[s2; Retrieves a constant pointer to value of the last element with +the specified key in AMap. If multi`-key ordering is not broken +and more than one element with the same value exists in AMap, +the greatest position is retrieved. If the element does not exist +in AMap, NULL pointer is returned. Unlinked elements are ignored..&] +[s3; &] +[s4;%- &] [s5;:AMap`:`:UnlinkKey`(const K`&`,unsigned`):%- [@(0.0.255) int]_[* UnlinkKey]([@(0.0.255) c onst]_[*@4 K][@(0.0.255) `&]_[*@3 k], [@(0.0.255) unsigned]_[*@3 h])&] [s2; Unlinks all elements with the specified key using precomputed diff --git a/uppsrc/CppBase/Base.cpp b/uppsrc/CppBase/Base.cpp index a8c01fdfd..0e8152646 100644 --- a/uppsrc/CppBase/Base.cpp +++ b/uppsrc/CppBase/Base.cpp @@ -9,7 +9,7 @@ void CppItem::Serialize(Stream& s) { s % kind % access % item % name % natural % at % tparam % param % pname - % tname % ctname % type % ptype % virt % line % impl; + % tname % ctname % type % ptype % virt % filetype % file % line % impl; } struct CmpItem { @@ -21,9 +21,9 @@ struct CmpItem { int FindItem(const Array& x, const String& qitem) { - int q = FindLowerBound(x, qitem, CmpItem()); - if(q < x.GetCount() && x[q].qitem == qitem) - return q; + for(int i = 0; i < x.GetCount(); i++) + if(x[i].qitem == qitem) + return i; return -1; } @@ -67,20 +67,18 @@ void CppBase::Dump(Stream& s) } } -void Remove(CppBase& base, const Vector& pf) +void CppBase::Sweep(const Index& keep_file) { int ni = 0; - Index file; - for(int i = 0; i < pf.GetCount(); i++) - file.Add(GetCppFileIndex(pf[i])); - while(ni < base.GetCount()) { - Array& n = base[ni]; + while(ni < GetCount()) { + Array& n = (*this)[ni]; Vector nr; - for(int i = 0; i < n.GetCount(); i++) - if(file.Find(n[i].file) >= 0) + for(int i = 0; i < n.GetCount(); i++) { + if(keep_file.Find(n[i].file) < 0) nr.Add(i); + } if(nr.GetCount() == n.GetCount()) - base.Remove(ni); + Remove(ni); else { n.Remove(nr); ni++; @@ -88,4 +86,30 @@ void Remove(CppBase& base, const Vector& pf) } } +void CppBase::RemoveFiles(const Index& remove_file) +{ + int ni = 0; + while(ni < GetCount()) { + Array& n = (*this)[ni]; + Vector nr; + for(int i = 0; i < n.GetCount(); i++) + if(remove_file.Find(n[i].file) >= 0) + nr.Add(i); + if(nr.GetCount() == n.GetCount()) + Remove(ni); + else { + n.Remove(nr); + ni++; + } + } +} + +void CppBase::RemoveFile(int filei) +{ + Index h; + h.Add(filei); + RemoveFiles(h); +} + + END_UPP_NAMESPACE diff --git a/uppsrc/CppBase/CppBase.h b/uppsrc/CppBase/CppBase.h index d51e2fc67..aba90ddf8 100644 --- a/uppsrc/CppBase/CppBase.h +++ b/uppsrc/CppBase/CppBase.h @@ -5,18 +5,147 @@ NAMESPACE_UPP -int GetCppFileIndex(const String& path); -const String& GetCppFile(int i); -Vector GetCppFiles(); +bool IsCPPFile(const String& file); +bool IsHFile(const String& path); -enum { +void RemoveComments(String& l, bool& incomment); + +void LoadPPConfig(const String& json); + +String GetStdConfig(); + +const VectorMap& GetNamespaceMacros(); +const Index& GetNamespaceEndMacros(); +const Vector& GetIgnoreList(); + +struct CppMacro : Moveable { + + String param; + String body; + + String Define(const char *s); + void SetUndef() { body = "\x7f"; } + bool IsUndef() const { return body[0] == '\x7f' && body[1] == '\0'; } + + String Expand(const Vector& p, const Vector& ep) const; + + void Serialize(Stream& s) { s % param % body; } + + 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 { + 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() { undef_segment_id = 0; } +}; + +struct PPFile { // contains "macro extract" of file, only info about macros defined and namespaces + Time filetime; + Array item; + Index includes; + + void Parse(Stream& in); + void Serialize(Stream& s) { s % filetime % item % includes; } + void Dump() const; + +private: + Vector ppmacro; // indicies of macros in sAllMacros + + void CheckEndNamespace(Vector& namespace_block, int level); +}; + +PPMacro *FindPPMacro(const String& id, Index& segment_id, int& segmenti); +const CppMacro *FindMacro(const String& id, Index& segment_id, int& segmenti); + +String GetAllMacros(const String& id, Index& segment_id); + +void PPSync(const String& include_path); +String GetIncludePath(); + +void CleanPP(); +void SerializePPFiles(Stream& s); +void SweepPPFiles(const Index& keep); + +String GetSegmentFile(int segment_id); + +const PPFile& GetPPFile(const char *path); + +String GetIncludePath(const String& s, const String& filedir); +bool IncludesFile(const String& parent_path, const String& header_path); +const PPFile& GetFlatPPFile(const char *path); // with #includes resolved + +struct Cpp { + static Index kw; + + bool incomment; + bool done; + + Index segment_id; // segments of included macros + VectorMap macro; // macros defined + int std_macros; // standard macros (keywords and trick - fixed) + Index notmacro; // accelerator / expanding helper + String prefix_macro; // for handling multiline macros + + String output; // preprocessed file +// Index usedmacro; + Index namespace_using; // 'using namespace' up to start of file + Vector namespace_stack; // namspace up to start of file + + Index ids; // all ids in the file + + String usings; // usings combined for the purpose of change detection ("CheckFile") + String namespaces; // namespace_stack at the beginning of file, combined, for detection + String includes; // all file includes, combined, for detection + + void Define(const char *s); + + static const char *SkipString(const char *s); + void ParamAdd(Vector& 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, + Index& visited, bool get_macros); + + bool Preprocess(const String& sourcefile, Stream& in, const String& currentfile, + bool just_get_macros = false); + + VectorMap GetDefinedMacros(); + String GetIncludedMacroValues(const Vector& id); + + typedef Cpp CLASSNAME; +}; + +enum tk_Keywords { Tmarker_before_first = 255, #define CPPID(x) tk_##x, #include "keyword.i" #undef CPPID }; -enum { +enum t_Terms { t_eof, t_string = -200, t_integer, @@ -78,10 +207,8 @@ class Lex { const char *pos; Index id; - Index ignore; int endkey; int braceslevel; - int ignore_low, ignore_high; struct Term : Moveable{ const char *ptr; @@ -137,6 +264,7 @@ public: 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); @@ -146,7 +274,7 @@ public: void Dump(int pos); - void Init(const char *s, const Vector& ignore); + void Init(const char *s); void StartStatCollection(); const LexSymbolStat & FinishStatCollection(); @@ -233,14 +361,16 @@ struct CppItem { String tparam; String param; String pname; - String ptype; + String ptype; // fn: types of parameters, struct: base classes String qptype; String tname; String ctname; + String using_namespaces; byte access; byte kind; int16 at; bool virt; + bool decla; bool lvalue; bool isptr; @@ -250,8 +380,7 @@ struct CppItem { int file; int line; - bool qualify_type, qualify_param; - int serial; + bool qualify; bool IsType() const { return IsCppType(kind); } bool IsCode() const { return IsCppCode(kind); } @@ -264,34 +393,35 @@ struct CppItem { void Dump(Stream& s) const; String ToString() const; - CppItem() { at = decla = virt = false; qualify_type = qualify_param = true; serial = -1; isptr = false; } + CppItem() { at = decla = virt = false; qualify = true; isptr = false; } }; String CppItemKindAsString(int kind); int FindItem(const Array& x, const String& qitem); -int GetCount(const Array& x, int i); -int FindNext(const Array& x, int i); +//int GetCount(const Array& x, int i); +//int FindNext(const Array& x, int i); int FindName(const Array& x, const String& name, int i = 0); struct CppBase : ArrayMap > { - int serial; String serial_md5; bool IsType(int i) const; - + void Sweep(const Index& keep_file); + void RemoveFiles(const Index& remove_file); + void RemoveFile(int filei); + void Dump(Stream& s); - - CppBase() { serial = 0; } }; -class Parser { +struct Parser { struct Context { - String scope; - String ctname; - Vector tparam; - Index typenames; - int access; + String scope; + String ctname; + Vector tparam; + Index typenames; + int access; + String namespace_using; void operator<<=(const Context& t); @@ -352,7 +482,9 @@ class Parser { Lex lex; int filei; byte filetype; + String title; bool inbody; + int struct_level; Callback2 err; @@ -367,15 +499,15 @@ class Parser { void Cv(); String TType(); - String SimpleType(Decla& d); + String ReadType(Decla& d, const String& tname, const String& tparam); void Qualifier(); void ParamList(Decl& d); void Declarator(Decl& d, const char *p); void EatInitializers(); - Decl Type(); void Vars(Array& r, const char *p, bool type_def, bool more); - Array Declaration0(bool l0 = false, bool more = false); - Array Declaration(bool l0 = false, bool more = false); + void ReadMods(Decla& d); + Array Declaration0(bool l0, bool more, const String& tname, const String& tparam); + Array 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); @@ -394,12 +526,18 @@ class Parser { void Check(bool b, const char *err); void CheckKey(int c); + bool UsingNamespace(); void SetScopeCurrent(); void ScopeBody(); void Do(); + String AnonymousName(); + String StructDeclaration(const String& tp, const String& tn); + void Enum(); - CppItem& Item(const String& scope, const String& item, const String& name, bool impl); - CppItem& Item(const String& scope, const String& item, const String& name); + 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); @@ -410,6 +548,7 @@ class Parser { void Resume(int bl); void MatchPars(); + bool VCAttribute(); bool TryDecl(); void Statement(); void Locals(const String& type); @@ -443,6 +582,8 @@ public: CppItem current; int currentScopeDepth; int maxScopeDepth; + + String namespace_info; struct Local : Moveable { String type; @@ -456,19 +597,25 @@ public: const SrcFile &getPreprocessedFile() { return file; } - void Do(Stream& s, const Vector& ignore, CppBase& base, const String& fn, - Callback2 err, const Vector& typenames = Vector()); + void Do(Stream& in, CppBase& _base, int file, int filetype, + const String& title, Callback2 _err, + const Vector& typenames, + const Vector& namespace_stack, + const Index& namespace_using); Parser() : dobody(false) { lex.WhenError = THISBACK(ThrowError); } }; String NoTemplatePars(const String& type); -class Scopefo { - bool bvalid, nvalid; - Vector baselist; - Vector scopes; - int scopei; +class ScopeInfo { // information about scope + bool bvalid; // baselist is valid + bool nvalid; // scopes is valid + Vector baselist; // list of all base classes of scope + Vector 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& g); void Init(); @@ -477,25 +624,23 @@ public: VectorMap cache; const Vector& GetBases(); - const Vector& GetScopes(); - int GetScope() const { return scopei; } + const Vector& GetScopes(const String& usings); + int GetScope() const { return scopei; } void NoBases() { baselist.Clear(); bvalid = true; } - Scopefo(const CppBase& base, int scopei = -1); - Scopefo(int scopei, const CppBase& base); - Scopefo(const CppBase& base, const String& scope); - Scopefo(const Scopefo& f); + ScopeInfo(const CppBase& base, int scopei = -1); + ScopeInfo(int scopei, const CppBase& base); + ScopeInfo(const CppBase& base, const String& scope); + ScopeInfo(const ScopeInfo& f); }; -String Qualify(const CppBase& base, const String& scope, const String& type); +String Qualify(const CppBase& base, const String& scope, const String& type, const String& usings); void QualifyTypes(CppBase& base, const String& scope, CppItem& m); -String QualifyKey(const CppBase& base, const String& scope, const String& type); +String QualifyKey(const CppBase& base, const String& scope, const String& type, const String& usings); void Qualify(CppBase& base); -void Parse(Stream& s, const Vector& ignore, CppBase& base, const String& fn, - Callback2 err); -void Remove(CppBase& base, const Vector& fn); +// void Parse(Stream& s, CppBase& base, int file, int filetype, const String& title, Callback2 err); END_UPP_NAMESPACE diff --git a/uppsrc/CppBase/CppBase.upp b/uppsrc/CppBase/CppBase.upp index 730f3f35e..06663c078 100644 --- a/uppsrc/CppBase/CppBase.upp +++ b/uppsrc/CppBase/CppBase.upp @@ -8,11 +8,15 @@ uses file CppBase.h options(BUILDER_OPTION) PCH, keyword.i, + ppconfig.cpp, + macro.cpp, + ppfile.cpp, + cpp.cpp, Pre.cpp, cpplex.cpp, Parser.cpp, Base.cpp, - Scopefo.cpp, + ScopeInfo.cpp, Qualify.cpp, CppItem.cpp, Info readonly separator, diff --git a/uppsrc/CppBase/CppItem.cpp b/uppsrc/CppBase/CppItem.cpp index bb00ff129..e122e625d 100644 --- a/uppsrc/CppBase/CppItem.cpp +++ b/uppsrc/CppBase/CppItem.cpp @@ -56,8 +56,7 @@ void CppItem::Dump(Stream& s) const PUT(lvalue); PUT(isptr); PUT(impl); - PUT(qualify_type); - PUT(qualify_param); + PUT(qualify); #undef PUT s << ' ' << line << '\n'; #define PUT(x) if(x.GetCount()) s << " " << #x << ": " << x << '\n'; diff --git a/uppsrc/CppBase/Parser.cpp b/uppsrc/CppBase/Parser.cpp index 3946910a7..647e0478d 100644 --- a/uppsrc/CppBase/Parser.cpp +++ b/uppsrc/CppBase/Parser.cpp @@ -28,7 +28,7 @@ static inline bool sSpaces(String& res, const char *& s) { if((byte)*s <= ' ') { char c = *s++; - if(c != '\2') { + if(c != '\2' && c != '\x1f') { res.Cat(' '); while((byte)*s <= ' ' && *s) s++; @@ -44,7 +44,13 @@ String FnItem(const char *s, const char *pname, const char *qname, const String& while(*s && (byte)*s <= ' ') s++; while(*s) { // Get the name of function into res while(*s && !iscid(*s) && *s != '~') - s++; + if(*s == '[') { // Skip MSVC attributes + while(*s) + if(*s++ == '[') + break; + } + else + s++; int lvl = 0; int plvl = 0; for(;;) { @@ -83,6 +89,7 @@ String FnItem(const char *s, const char *pname, const char *qname, const String& break; res.Clear(); } + bool wasid = false; while(*s) { const char *w = bew(qname, s); byte c = *s; @@ -91,6 +98,7 @@ String FnItem(const char *s, const char *pname, const char *qname, const String& res.Cat(' '); res.Cat(name); s = w; + wasid = true; } else if(iscid(c)) { @@ -104,17 +112,24 @@ String FnItem(const char *s, const char *pname, const char *qname, const String& } else while((byte)*s <= ' ' && *s) s++; + wasid = true; } else if(c == '=') { s++; int l = 0; - while(*s && !(l == 0 && (*s == ',' || *s == ')'))) { - if(*s == '(') + int tl = 0; + while(*s && !(l == 0 && (*s == ',' && tl == 0 || *s == ')'))) { + if(*s == '(' || *s == '[') l++; else - if(*s == ')') + if(*s == ')' || *s == ']') l--; + if(*s == '<') // we always consider < > to be template bracket, not operator here + tl++; + else + if(*s == '>') + tl--; s++; } } @@ -124,8 +139,16 @@ String FnItem(const char *s, const char *pname, const char *qname, const String& while((byte)*s <= ' ' && *s) s++; } + else + if(c == '[' && !wasid) { // Skip MSVC attribute + while(*s) + if(*s++ == ']') + break; + } else { res.Cat(c); + if(c == ',') + wasid = false; s++; } } @@ -135,11 +158,14 @@ String FnItem(const char *s, const char *pname, const char *qname, const String& String Purify(const char *s, const char *qname, const String& name) { String res; while(*s && (byte)*s <= ' ') s++; + bool wasid = false; + bool firstpar = true; while(*s) { const char *w = bew(qname, s); if(w && w > s) { res.Cat(name); s = w; + wasid = true; } else if(iscid(*s)) { @@ -150,10 +176,27 @@ String Purify(const char *s, const char *qname, const String& name) { res.Cat(q); else while((byte)*s <= ' ' && *s) s++; + wasid = true; } else - if(!sSpaces(res, s)) + if(*s == '[' && !wasid) { // skip MSVC attribute + do { + while(*s) + if(*s++ == ']') + break; + while(*s == ' ' || *s == '\2' || *s == '\x1f') + s++; + } + while(*s == '['); + } + else + if(!sSpaces(res, s)) { + if(*s == ',') + wasid = false; + if(*s == '(' && firstpar) + wasid = firstpar = false; res.Cat(*s++); + } } return TrimRight(res); } @@ -195,6 +238,65 @@ void ScAdd(String& s, const String& a) s << a; } + +void TpSkip(CParser& p) +{ + int lvl = 0; + for(;;) { + if(lvl == 0 && (p.IsChar(',') || p.IsChar('>')) || p.IsEof()) + break; + if(p.Char('<')) + lvl++; + else + if(p.Char('>')) + lvl--; + else + p.SkipTerm(); + } +} + +String Subst(const String& s, const Vector& tpar) +{ + if(tpar.GetCount() == 0) + return s; + String r; + CParser p(s); + while(!p.IsEof()) { + if(p.IsId()) { + String id = p.ReadId(); + int q = FindIndex(tpar, id); + if(q >= 0) + r << AsString(q); + else + r << id; + } + else + r << p.GetChar(); + } + return r; +} + +String CleanTp(const String& tp) +{ + int q = tp.Find('<'); + int w = tp.ReverseFind('>'); + if(q < 0 || w < 0) return tp; + String a = TrimLeft(TrimRight(tp.Mid(q + 1, w - q - 1))); + const char *s = a; + String r; + while(*s) { + if(*s == ',') { + r.Cat(';'); + s++; + while(*s && *s <= ' ') + s++; + } + else + r.Cat(*s++); + } + return r; +} + String Parser::Context::Dump() const { return "Scopeing: " + scope; @@ -221,10 +323,11 @@ inline void ScopeCat(String& scope, const String& s) void Parser::Context::operator<<=(const Context& t) { scope = t.scope; - typenames <<= t.typenames; - tparam <<= t.tparam; + typenames = clone(t.typenames); + tparam = clone(t.tparam); access = t.access; ctname = t.ctname; + namespace_using = t.namespace_using; } Parser::Decla::Decla() @@ -274,8 +377,8 @@ void Parser::ThrowError(const String& e) int i = 0; while(i < 40 && lex[i] != t_eof) i++; - LLOG("ERROR: (" << GetLine(lex.Pos()) << ") " << e << ", scope: " << current_scope << - " " << AsCString(String(lex.Pos(), lex.Pos(i)))); + DLOG("ERROR: (" << GetLine(lex.Pos()) << ") " << e << ", scope: " << current_scope << + ", code: " << AsCString(String(lex.Pos(), lex.Pos(i)))); #endif throw Error(); } @@ -458,8 +561,122 @@ String Parser::TType() return lex.Id(); } -String Parser::SimpleType(Decla& d) +String Parser::StructDeclaration(const String& tn, const String& tp) { + int t = lex.GetCode(); // t is now struct/class/union + context.typenames.FindAdd(lex); + Context cc; + cc <<= context; + CParser p(tp); + Vector tpar; + if(p.Char('<')) { + while(!p.IsEof() && !p.Char('>')) { + if((p.Id("class") || p.Id("typename") || p.Id("struct")) && p.IsId()) { + tpar.Add(p.ReadId()); + context.tparam.Add(lex.Id(tpar.Top())); + } + else + context.tparam.Add(0); + TpSkip(p); + p.Char(','); + } + } + if(Key(t_dblcolon)) + context.scope = Null; + String name; + String new_scope = context.scope; + if(lex.IsId()) + do { + context.typenames.FindAdd(lex); + name = lex.GetId(); // name of structure + if(lex == '<') + name << TemplateParams(); + ScopeCat(new_scope, name); + } + while(Key(t_dblcolon)); + else { + name = AnonymousName(); + ScopeCat(new_scope, name); + } + if(lex.IsId() || lex == '*') { // struct My { struct My *p; } + return name; + } + context.scope = new_scope; + context.access = t == tk_class ? PRIVATE : PUBLIC; + if(tn.GetCount()) { + if(context.ctname.GetCount()) + context.ctname << ';'; + context.ctname << tn; + } + String nn; + if(!tp.IsEmpty()) + nn = "template " + tp + " "; + String key = (t == tk_class ? "class" : t == tk_union ? "union" : "struct"); + nn << key << ' ' << name; + LLOG("Struct " << context.scope << " using " << context.namespace_using); + CppItem& im = Item(context.scope, context.namespace_using, key, name, lex != ';'); + im.kind = tp.IsEmpty() ? STRUCT : STRUCTTEMPLATE; + im.type = name; + im.access = cc.access; + im.tname = tn; + im.ctname = context.ctname; + im.tparam = CleanTp(tp); + im.ptype.Clear(); + im.pname.Clear(); + im.param.Clear(); + if(lex == ';') { // TODO: perhaps could be united with following code + context = pick(cc); + im.natural = Gpurify(nn); + SetScopeCurrent(); + return name; + } + if(Key(':')) { + nn << " : "; + bool c = false; + do { + String access = t == tk_class ? "private" : "public"; + if(Key(tk_public)) access = "public"; + else + if(Key(tk_protected)) access = "protected"; + else + if(Key(tk_private)) access = "private"; + if(Key(tk_virtual)) access << " virtual"; + String h; + bool dummy; + String n = Name(h, dummy, dummy); + ScAdd(im.pname, h); + if(c) + im.ptype << ';'; + im.ptype << Subst(n, tpar); + ScAdd(im.param, access + ' ' + n); + if(c) + nn << ", "; + nn << access + ' ' + n; + c = true; + } + while(Key(',')); + } + if(Key('{')) { + struct_level++; + ScopeBody(); + struct_level--; + im.natural = Gpurify(nn); + im.decla = true; + } + else + if(IsNull(im.natural)) + im.natural = Gpurify(nn); + context = pick(cc); + SetScopeCurrent(); + return name; +} + +String Parser::ReadType(Decla& d, const String& tname, const String& tparam) +{ // returns the name of constructor + if(findarg((int)lex, tk_struct, tk_class, tk_union) >= 0 && !d.isfriend) { + d.type = StructDeclaration(tname, tparam); + return String(); + } Key(tk_typename) || Key(tk_struct) || Key(tk_class) || Key(tk_union) || Key(tk_enum); if(Key(tk_bool) || Key(tk_float) || Key(tk_double) || Key(tk_void)) return Null; @@ -505,8 +722,8 @@ String Parser::SimpleType(Decla& d) void Parser::Qualifier() { - Key(tk_const); - Key(tk_volatile); + while(Key(tk_const) || Key(tk_volatile) || VCAttribute()) + ; if(Key(tk_throw)) { while(lex != t_eof && !Key(')')) ++lex; @@ -528,7 +745,7 @@ void Parser::ParamList(Decl& d) { break; } else - d.param.Add() = pick(Declaration().Top()); + d.param.Add() = pick(Declaration(false, false, Null, Null).Top()); if(Key(t_elipsis)) { Elipsis(d); break; @@ -583,11 +800,7 @@ void Parser::Declarator(Decl& d, const char *p) d.isptr = true; return; } - if(Key('&')) { - Declarator(d, p); - return; - } - if(Key(tk_const)) { + if(Key('&') || Key(t_and) || Key(tk_const) || Key(tk_volatile)) { // t_and is r-value here Declarator(d, p); return; } @@ -609,7 +822,7 @@ void Parser::Declarator(Decl& d, const char *p) } if(Key('(')) { if(inbody || (lex < 256 || lex == tk_true || lex == tk_false) - && lex != ')' && lex != t_dblcolon) { + && lex != ')' && lex != '[' && lex != t_dblcolon) { int level = 0; for(;;) { if(lex == t_eof) break; @@ -644,9 +857,17 @@ void Parser::Declarator(Decl& d, const char *p) } if(Key('=') || (inbody && lex == '(')) { int level = 0; + int tlevel = 0; for(;;) { - if(lex == t_eof || level == 0 && (lex == ',' || lex == ')' || lex == ';')) + if(lex == t_eof || lex == ';' + || level == 0 && ((lex == ',' && tlevel == 0) || lex == ')')) break; + if(Key('<')) // we ignore < > as operators, always consider them template bracket + tlevel++; + else + if(Key('>')) + tlevel--; + else if(Key('(') || Key('{')) level++; else @@ -664,27 +885,13 @@ Parser::Decl& Parser::Finish(Decl& d, const char *s) return d; } -Parser::Decl Parser::Type() { - Decl d; - const char *p = lex.Pos(); - Qualifier(); - SimpleType(d); - Declarator(d, p); - return pick(Finish(d, p)); -} - bool Parser::IsParamList(int q) { return true; } -Array Parser::Declaration0(bool l0, bool more) +void Parser::ReadMods(Decla& d) { - Array r; - Decla d; - const char *p = lex.Pos(); - if(Key(tk_friend)) - d.isfriend = true; for(;;) { if(Key(tk_static)) d.s_static = true; @@ -707,9 +914,19 @@ Array Parser::Declaration0(bool l0, bool more) if(Key(tk_virtual)) d.s_virtual = true; else - if(!(Key(tk_inline) || Key(tk_force_inline) || Key(tk___inline))) + if(!(Key(tk_inline) || Key(tk_force_inline) || Key(tk___inline) || VCAttribute())) break; } +} + +Array Parser::Declaration0(bool l0, bool more, const String& tname, const String& tparam) +{ + Array r; + Decla d; + const char *p = lex.Pos(); + if(Key(tk_friend)) + d.isfriend = true; + ReadMods(d); Qualifier(); if(l0) { if(lex == tk_SKYLARK && lex[1] == '(' && lex.IsId(2)) { @@ -772,7 +989,9 @@ Array Parser::Declaration0(bool l0, bool more) a.oper = true; return r; } - String st = SimpleType(d); + String st = ReadType(d, tname, tparam); + if(!lex.IsGrounded()) // 'static' etc.. can be after type too... (but not allow it on start of line) + ReadMods(d); if(!st.IsEmpty()) { Decl& a = r.Add(); a.name = st; @@ -787,37 +1006,38 @@ Array Parser::Declaration0(bool l0, bool more) return r; } String natural1 = String(p, lex.Pos()); - do { - const char *p1 = lex.Pos(); - Decl& a = r.Add(); - (Decla&)a = d; - Declarator(a, p); - if(a.castoper) - a.name = Filter(natural1, CharFilterNotWhitespace) + a.name; - a.natural = natural1 + String(p1, lex.Pos()); - p = lex.Pos(); - } - while(more && Key(',')); + if(lex != ';') // struct/class declaration without defining variable + do { + const char *p1 = lex.Pos(); + Decl& a = r.Add(); + (Decla&)a = d; + Declarator(a, p); + if(a.castoper) + a.name = Filter(natural1, CharFilterNotWhitespace) + a.name; + a.natural = natural1 + String(p1, lex.Pos()); + p = lex.Pos(); + } + while(more && Key(',')); return r; } -Array Parser::Declaration(bool l0, bool more) +Array Parser::Declaration(bool l0, bool more, const String& tname, const String& tparam) { if(Key(tk_typedef)) { - Array r = Declaration(false, true); + Array r = Declaration0(false, true, tname, tparam); for(int i = 0; i < r.GetCount(); i++) { r[i].type_def = true; r[i].natural = "typedef " + r[i].natural; } return r; } - return Declaration0(l0, more); + return Declaration0(l0, more, tname, tparam); } void Parser::Locals(const String& type) { Line(); - Array d = Declaration(true, true); + Array d = Declaration(true, true, Null, Null); for(int i = 0; i < d.GetCount(); i++) { Local& l = local.Add(d[i].name); l.type = type; @@ -852,18 +1072,38 @@ String NoTemplatePars(const String& s) return q >= 0 ? s.Mid(0, q) : s; } -bool Parser::TryDecl() +bool Parser::VCAttribute() { + if(lex[0] == '[') // Skip Visual C++ attribute + for(;;) { + if(lex[0] == ']') { + ++lex; + return true; + } + if(lex[0] == t_eof) + return false; + ++lex; + } + return false; +} + +bool Parser::TryDecl() +{ // attempt to interpret code as local variable declaration + for(;;) { + if(lex[0] == tk_static || lex[0] == tk_const || lex[0] == tk_auto || + lex[0] == tk_register || lex[0] == tk_volatile) + ++lex; + else + if(!VCAttribute()) + break; + } + int t = lex[0]; int q = 0; - while(lex[0] == tk_static || lex[0] == tk_const || lex[0] == tk_auto || - lex[0] == tk_register || lex[0] == tk_volatile) - ++lex; - int t = lex[q]; 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) { q++; - while(lex[q] == '*' || lex[q] == '&') + while(lex[q] == '*' || lex[q] == '&' || lex[q] == t_and) // t_and is r-value here q++; if(!lex.IsId(q)) return false; @@ -889,11 +1129,11 @@ bool Parser::TryDecl() return false; type << Tparam(q); } - while(lex[q] == '*' || lex[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(*base, current_scope, type); + type = Qualify(*base, current_scope, type, context.namespace_using); if(base->Find(NoTemplatePars(type)) >= 0) { Locals(type); return true; @@ -930,12 +1170,15 @@ void Parser::Statement() ++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 @@ -993,6 +1236,9 @@ void Parser::Statement() local.Trim(l); } else + if(UsingNamespace()) + ; + else if(TryDecl()) Key(';'); else @@ -1035,55 +1281,36 @@ bool Parser::EatBody() return true; } -String CleanTp(const String& tp) -{ - int q = tp.Find('<'); - int w = tp.ReverseFind('>'); - if(q < 0 || w < 0) return tp; - String a = TrimLeft(TrimRight(tp.Mid(q + 1, w - q - 1))); - const char *s = a; - String r; - while(*s) { - if(*s == ',') { - r.Cat(';'); - s++; - while(*s && *s <= ' ') - s++; - } - else - r.Cat(*s++); - } - return r; -} - void Parser::SetScopeCurrent() { current_scope = context.scope; } -CppItem& Parser::Item(const String& scope, const String& item, const String& name, bool impl) +CppItem& Parser::Item(const String& scope, const String& using_namespace, const String& item, + const String& name, bool impl) { current_scope = scope; if(dobody) current = CppItem(); current_key = item; current_name = name; - Array& n = base->GetAdd(current_scope); - CppItem& im = dobody ? current : n.Add(); + CppItem& im = dobody ? current : base->GetAdd(current_scope).Add(); im.item = item; im.name = name; im.file = filei; im.line = line + 1; im.impl = impl; im.filetype = filetype; + im.using_namespaces = using_namespace; LLOG("New item " << GetCppFile(filei) << ' ' << line + 1 << " " << scope << "::" << item); return im; } -CppItem& Parser::Item(const String& scope, const String& item, const String& name) +CppItem& Parser::Item(const String& scope, const String& using_namespace, const String& item, + const String& name) { String h = Purify(item); - CppItem& im = Item(scope, h, name, false); + CppItem& im = Item(scope, using_namespace, h, name, false); im.natural = h; return im; } @@ -1113,163 +1340,87 @@ void Parser::ScopeBody() } } -void TpSkip(CParser& p) +String Parser::AnonymousName() { int lvl = 0; - for(;;) { - if(lvl == 0 && (p.IsChar(',') || p.IsChar('>')) || p.IsEof()) - break; - if(p.Char('<')) - lvl++; + for(int i = 0; lex[i] != t_eof; i++) { + if(lex[i] == '{') lvl++; else - if(p.Char('>')) - lvl--; - else - p.SkipTerm(); + if(lex[i] == '}') + if(--lvl == 0) { + if(lex.IsId(i + 1)) + return "." + lex.Id(i + 1); + break; + } } -} -String Subst(const String& s, const Vector& tpar) -{ - if(tpar.GetCount() == 0) - return s; - String r; - CParser p(s); - while(!p.IsEof()) { - if(p.IsId()) { - String id = p.ReadId(); - int q = FindIndex(tpar, id); - if(q >= 0) - r << AsString(q); - else - r << id; - } - else - r << p.GetChar(); - } - return r; + dword x[4]; + x[0] = Random(); + x[1] = Random(); + x[2] = Random(); + x[3] = Random(); + + return "@" + Base64Encode(String((const char *)&x, sizeof(x))) + "/" + title; } bool Parser::Scope(const String& tp, const String& tn) { if(Key(tk_namespace)) { Check(lex.IsId(), "Expected name of namespace"); String name = lex.GetId(); + LLOG("namespace " << name); + namespace_info << ';' << name; + Context c0; + c0 <<= context; + int struct_level0 = struct_level; + ScopeCat(context.scope, name); if(Key('{')) { Context cc; cc <<= context; - ScopeBody(); - context <<= cc; - } - Key(';'); - SetScopeCurrent(); - return true; - } - if((lex == tk_class || lex == tk_struct || lex == tk_union) && lex[1] != '{') { - int t = lex.GetCode(); // t is now struct/class/union - context.typenames.FindAdd(lex); - Context cc; - cc <<= context; - CParser p(tp); - Vector tpar; - if(p.Char('<')) { - while(!p.IsEof() && !p.Char('>')) { - if((p.Id("class") || p.Id("typename") || p.Id("struct")) && p.IsId()) { - tpar.Add(p.ReadId()); - context.tparam.Add(lex.Id(tpar.Top())); + while(!Key('}')) { + if(lex == t_eof) + ThrowError("Unexpected end of file"); + try { + Do(); + } + catch(Error) { + if(struct_level0) + throw; + context <<= cc; + struct_level = struct_level0; + LLOG("---- Recovery to namespace level"); + ++lex; + lex.SkipToGrounding(); + lex.ClearBracesLevel(); + LLOG("Grounding skipped to " << GetLine(lex.Pos())); + } + catch(Lex::Grounding) { + LLOG("---- Grounding to namespace level"); + context <<= cc; + struct_level = struct_level0; + lex.ClearBracesLevel(); + lex.ClearBody(); } - else - context.tparam.Add(0); - TpSkip(p); - p.Char(','); } } - if(Key(t_dblcolon)) - context.scope = Null; - String name; - do { - Check(lex.IsId(), "Missing identifier"); - context.typenames.FindAdd(lex); - name = lex.GetId(); // name of structure - if(lex == '<') - name << TemplateParams(); - ScopeCat(context.scope, name); - } - while(Key(t_dblcolon)); - context.access = t == tk_class ? PRIVATE : PUBLIC; - if(tn.GetCount()) { - if(context.ctname.GetCount()) - context.ctname << ';'; - context.ctname << tn; - } - String nn; - if(!tp.IsEmpty()) - nn = "template " + tp + " "; - String key = (t == tk_class ? "class" : t == tk_union ? "union" : "struct"); - nn << key << ' ' << name; - CppItem& im = Item(context.scope, key, name, lex != ';'); - im.kind = tp.IsEmpty() ? STRUCT : STRUCTTEMPLATE; - im.type = name; - im.access = cc.access; - im.tname = tn; - im.ctname = context.ctname; - im.tparam = CleanTp(tp); - im.ptype.Clear(); - im.pname.Clear(); - im.param.Clear(); - if(Key(';')) { - context = pick(cc); - im.natural = Gpurify(nn); - SetScopeCurrent(); + LLOG("End namespace"); + Key(';'); + context <<= c0; + SetScopeCurrent(); + namespace_info << ";}"; + return true; + } + // TODO: Remove +#if 0 + if((lex == tk_class || lex == tk_struct || lex == tk_union)/* && lex[1] != '{'*/) { + if(StructDeclaration(tp, tn).GetCount()) { + CheckKey(';'); return true; } - if(Key(':')) { - nn << " : "; - bool c = false; - do { - String access = t == tk_class ? "private" : "public"; - if(Key(tk_public)) access = "public"; - else - if(Key(tk_protected)) access = "protected"; - else - if(Key(tk_private)) access = "private"; - if(Key(tk_virtual)) access << " virtual"; - String h; - bool dummy; - String n = Name(h, dummy, dummy); - ScAdd(im.pname, h); - if(c) - im.ptype << ';'; - im.ptype << Subst(n, tpar); - ScAdd(im.param, access + ' ' + n); - if(c) - nn << ", "; - nn << access + ' ' + n; - c = true; - } - while(Key(',')); - } - if(Key('{')) { - ScopeBody(); - im.natural = Gpurify(nn); - im.decla = true; - } - else - if(IsNull(im.natural)) - im.natural = Gpurify(nn); - context = pick(cc); - CheckKey(';'); - SetScopeCurrent(); - return true; } +#endif return false; } -String DeTemp(const char *s) -{ - String r; - return r; -} - CppItem& Parser::Fn(const Decl& d, const String& templ, bool body, const String& tname, const String& tparam) { @@ -1324,7 +1475,7 @@ CppItem& Parser::Fn(const Decl& d, const String& templ, bool body, while(*s == ':') s++; if(*s) ScopeCat(scope, s); - CppItem& im = Item(scope, item, nm, body); + CppItem& im = Item(scope, context.namespace_using, item, nm, body); im.natural.Clear(); if(!IsNull(templ)) { im.natural = TrimRight(Gpurify(templ)) + ' '; @@ -1354,14 +1505,77 @@ CppItem& Parser::Fn(const Decl& d, const String& templ, bool body, return im; } +void Parser::Enum() +{ + String name; + if(lex.IsId()) + name = lex.GetId(); + if(Key('{')) { + for(;;) { + Line(); + String val; + Check(lex.IsId(), "Expected identifier"); + String id = lex.GetId(); + CppItem& im = Item(context.scope, context.namespace_using, id, id); + im.natural = "enum "; + if(!IsNull(name)) + im.natural << name << ' '; + im.natural << id; + if(Key('=')) + im.natural << " = " << Constant(); + im.kind = ENUM; + im.access = context.access; + Key(','); + if(Key('}')) break; + } + } + while(!Key(';')) { + if(lex.IsId() || lex == ',' || lex == '*') // typedef name ignored here + ++lex; + else + break; + } + Key(';'); + SetScopeCurrent(); +} + +bool Parser::UsingNamespace() +{ + if(Key(tk_using)) { + if(Key(tk_namespace)) + while(lex.IsId()) { + Vector h = Split(context.namespace_using, ';'); + String u; + do { + u << lex.GetId(); + if(Key(t_dblcolon)) + u << "::"; + } + while(lex.IsId()); + if(FindIndex(h, u) < 0) + h.Add(u); + context.namespace_using = Join(h, ";"); + Key(','); + } + while(!Key(';') && lex != t_eof) + ++lex; + namespace_info << ";using " << context.namespace_using; + return true; + } + return false; +} + void Parser::Do() { LLOG("Do, scope: " << current_scope); + if(lex.IsGrounded() && struct_level) + throw Lex::Grounding(); Line(); - if(Key(tk_using)) { - while(!Key(';') && lex != t_eof) - ++lex; - } + if(UsingNamespace()) + ; + else + if(Key(';')) // 'empty' declaraion, result of some ignores + ; else if(Key(tk_extern) && lex == t_string) { // extern "C++" kind ++lex; @@ -1391,7 +1605,7 @@ void Parser::Do() String tnames; String tparam = TemplateParams(tnames); if(!Scope(tparam, tnames)) { - Array r = Declaration(true, true); + Array r = Declaration(true, true, tnames, tparam); CppItem *functionItem = 0; bool body = lex == '{'; for(int i = 0; i < r.GetCount(); i++) { @@ -1419,30 +1633,13 @@ void Parser::Do() else if(lex == tk_enum && (lex[1] == '{' || lex[2] == '{')) { ++lex; - String name; - if(lex.IsId()) - name = lex.GetId(); - if(Key('{')) { - for(;;) { - Line(); - String val; - Check(lex.IsId(), "Expected identifier"); - String id = lex.GetId(); - CppItem& im = Item(context.scope, id, id); - im.natural = "enum "; - if(!IsNull(name)) - im.natural << name << ' '; - im.natural << id; - if(Key('=')) - im.natural << " = " << Constant(); - im.kind = ENUM; - im.access = context.access; - Key(','); - if(Key('}')) break; - } - } - Key(';'); - SetScopeCurrent(); + Enum(); + } + else + if(lex == tk_typedef && lex[1] == tk_enum && (lex[2] == '{' || lex[3] == '{')) { + ++lex; + ++lex; + Enum(); } else if(Key('#')) { @@ -1452,7 +1649,7 @@ void Parser::Do() const char *s = n; while(*s && iscid(*s)) name.Cat(*s++); - CppItem& im = Item(context.scope, n, name); + CppItem& im = Item("", context.namespace_using, n, name); im.kind = MACRO; s = strchr(n, '('); if(s) { @@ -1489,16 +1686,14 @@ void Parser::Do() Key(':'); } else { - Array r = Declaration(true, true); + Array r = Declaration(true, true, Null, Null); CppItem *functionItem = 0; bool body = lex == '{'; for(int i = 0; i < r.GetCount(); i++) { Decl& d = r[i]; if(d.function) { - if(!d.isfriend) { - CppItem &im = Fn(d, Null, body, String(), String()); - functionItem = &im; - } + if(!d.isfriend) + functionItem = &Fn(d, Null, body, String(), String()); } else { String h = d.natural; @@ -1508,9 +1703,10 @@ void Parser::Do() String scope = context.scope; if(d.type_def) ScopeCat(scope, d.name); - CppItem& im = Item(scope, d.isfriend ? "friend class" - : d.type_def ? "typedef" - : d.name, d.name); + CppItem& im = Item(scope, context.namespace_using, + d.isfriend ? "friend class" + : d.type_def ? "typedef" + : d.name, d.name); im.natural = Purify(h); im.type = d.type; im.access = context.access; @@ -1538,34 +1734,27 @@ void Parser::Do() } } -void Parser::Do(Stream& in, const Vector& ignore, CppBase& _base, const String& fn, - Callback2 _err, const Vector& typenames) +void Parser::Do(Stream& in, CppBase& _base, int filei_, int filetype_, + const String& title_, Callback2 _err, + const Vector& typenames, + const Vector& namespace_stack, + const Index& namespace_using) { LLOG("= C++ Parser ==================================== " << fn); base = &_base; file = PreProcess(in); - lex.Init(~file.text, ignore); + lex.Init(~file.text); err = _err; - filei = GetCppFileIndex(fn); - String ext = ToLower(GetFileExt(fn)); - if(ext == ".h") - filetype = FILE_H; - else - if(ext == ".hpp") - filetype = FILE_HPP; - else - if(ext == ".cpp") - filetype = FILE_CPP; - else - if(ext == ".c") - filetype = FILE_C; - else - filetype = FILE_OTHER; + filei = filei_; + filetype = filetype_; + title = title_; lpos = 0; line = 0; if(whenFnEnd) lex.StartStatCollection(); + context.namespace_using = Join(namespace_using.GetKeys(), ";"); + while(lex != t_eof) try { try { @@ -1573,8 +1762,9 @@ void Parser::Do(Stream& in, const Vector& ignore, CppBase& _base, const context.access = PUBLIC; context.typenames.Clear(); context.tparam.Clear(); - context.scope.Clear(); + context.scope = Join(namespace_stack, "::"); inbody = false; + struct_level = 0; for(int i = 0; i < typenames.GetCount(); i++) context.typenames.Add(lex.Id(typenames[i])); Do(); @@ -1601,12 +1791,13 @@ void Parser::Do(Stream& in, const Vector& ignore, CppBase& _base, const } } -void Parse(Stream& s, const Vector& ignore, CppBase& base, const String& fn, - Callback2 _err) +/* +void Parse(Stream& s, CppBase& base, int file, int filetype, const String& title, Callback2 _err) { LTIMING("Parse"); Parser p; - p.Do(s, ignore, base, fn, _err); + p.Do(s, base, file, filetype, title, _err); } +*/ END_UPP_NAMESPACE diff --git a/uppsrc/CppBase/Pre.cpp b/uppsrc/CppBase/Pre.cpp index 2fa5855db..e91ce8ad0 100644 --- a/uppsrc/CppBase/Pre.cpp +++ b/uppsrc/CppBase/Pre.cpp @@ -7,56 +7,6 @@ NAMESPACE_UPP #pragma optimize("t", on) #endif -static StaticMutex cpp_file_mutex; -static Index cpp_file; - -int GetCppFileIndex(const String& path) -{ - INTERLOCKED_(cpp_file_mutex) { - return cpp_file.FindAdd(path); - } - return -1; -} - -const String& GetCppFile(int i) -{ - INTERLOCKED_(cpp_file_mutex) { - return cpp_file[i]; - } - static String x; - return x; -} - -Vector GetCppFiles() -{ - INTERLOCKED_(cpp_file_mutex) { - return clone(cpp_file.GetKeys()); - } - return Vector(); -} - -/* -void CppPos::Serialize(Stream& s) -{ - s % impl % line; - String fn = GetCppFile(file); - s % fn; - file = GetCppFileIndex(fn); -} - -String SSpaces(const char *txt) -{ - StringBuffer r; - while(*txt) - if(*txt == ' ') { - while((byte)*txt <= ' ' && *txt) txt++; - r.Cat(' '); - } - else - r.Cat(*txt++); - return r; -} -*/ void SLPos(SrcFile& res) { res.linepos.Add(res.text.GetLength()); @@ -69,7 +19,7 @@ SrcFile::SrcFile() : { } -SrcFile PreProcess(Stream& in) +SrcFile PreProcess(Stream& in) // This is not really C preprocess, only removes (or processes) comment and directives { SrcFile res; bool include = true; @@ -89,7 +39,7 @@ SrcFile PreProcess(Stream& in) res.text << '\2'; } else - if(*rm == '\x1a') // line started with macro + if(*rm == '\x1f') // line started with macro res.text << '\2'; while(*rm == ' ' || *rm == '\t') rm++; if(*rm == '\0') @@ -109,7 +59,6 @@ SrcFile PreProcess(Stream& in) macro.Cat(*s++); macro << ')'; } -// res.text << '#' << AsCString(SSpaces(macro)); if(include) res.text << '#' << AsCString(macro); } diff --git a/uppsrc/CppBase/Qualify.cpp b/uppsrc/CppBase/Qualify.cpp index d9e6b641c..e6b66a885 100644 --- a/uppsrc/CppBase/Qualify.cpp +++ b/uppsrc/CppBase/Qualify.cpp @@ -5,11 +5,11 @@ NAMESPACE_UPP #define LLOG(x) // DLOG(x) #define LTIMING(x) // RTIMING(x) -bool DoQualify(Scopefo& nf, const String& type, String& qt); +bool DoQualify(ScopeInfo& nf, const String& type, const String& usings, String& qt); -bool Qualify0(Scopefo& nf, const String& type, String& qt) -{ - const Vector& nd = nf.GetScopes(); +bool Qualify0(ScopeInfo& nf, const String& type, const String& usings, String& qt) +{ // Qualify single type based on scoping information + const Vector& nd = nf.GetScopes(usings); if(nd.GetCount()) { LTIMING("First test"); qt = nd[0] + type; @@ -20,7 +20,7 @@ bool Qualify0(Scopefo& nf, const String& type, String& qt) int q = type.ReverseFind(':'); if(q > 0) { LTIMING("Qualifying qualification"); - Scopefo hnf(nf); + ScopeInfo hnf(nf); hnf.NoBases(); String qn; String qs = type.Mid(0, q - 1); @@ -28,7 +28,7 @@ bool Qualify0(Scopefo& nf, const String& type, String& qt) qt = type; return true; } - if(DoQualify(hnf, qs, qn)) { + if(DoQualify(hnf, qs, usings, qn)) { if(nf.base.Find(type) >= 0) { qt = type; return true; @@ -36,7 +36,7 @@ bool Qualify0(Scopefo& nf, const String& type, String& qt) int scopei = nf.base.Find(qn); if(scopei >= 0) { String tp = type.Mid(q + 1); - Scopefo nnf(nf.base, scopei); + ScopeInfo nnf(nf.base, scopei); const Vector& bs = nnf.GetBases(); for(int i = 0; i < bs.GetCount(); i++) { qt = bs[i] + tp; @@ -49,6 +49,9 @@ bool Qualify0(Scopefo& nf, const String& type, String& qt) 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; } @@ -73,10 +76,10 @@ bool Qualify0(Scopefo& nf, const String& type, String& qt) int q = type.Find(':'); if(q < 0) return false; - return Qualify0(nf, type.Mid(q + 1), qt); + return Qualify0(nf, type.Mid(q + 1), usings, qt); } -bool DoQualify(Scopefo& nf, const String& type, String& qt) +bool DoQualify(ScopeInfo& nf, const String& type, const String& usings, String& qt) { LTIMING("Qualify"); int q = nf.cache.Find(type); @@ -85,16 +88,16 @@ bool DoQualify(Scopefo& nf, const String& type, String& qt) return true; } LTIMING("Qualify0"); - if(!Qualify0(nf, type, qt)) + if(!Qualify0(nf, type, usings, qt)) return false; nf.cache.Add(type, qt); return true; } -String DoQualify(Scopefo& nf, const String& type) +String DoQualify(ScopeInfo& nf, const String& type, const String& usings) { String qt; - return DoQualify(nf, type, qt) ? qt : type; + return DoQualify(nf, type, usings, qt) ? qt : type; } static String s_int("int"); @@ -108,7 +111,7 @@ static String s_struct("struct"); static String s_class("class"); static String s_unsigned("unsigned"); -inline void Qualify(String& r, Scopefo& nf, const char *b, const char *s) +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 || @@ -118,10 +121,10 @@ inline void Qualify(String& r, Scopefo& nf, const char *b, const char *s) r << type; return; } - r << DoQualify(nf, type); + r << DoQualify(nf, type, usings); } -String QualifyIds(Scopefo& nf, const String& k, bool all) +String QualifyIds(ScopeInfo& nf, const String& k, const String& usings, bool all) { LTIMING("QualifyIds"); String r; @@ -135,8 +138,8 @@ String QualifyIds(Scopefo& nf, const String& k, bool all) if(all) { if(iscid(*r.Last())) r << ' '; - Scopefo nnf(nf.GetScope(), nf.base); - Qualify(r, nnf, b, s); + ScopeInfo nnf(nf.GetScope(), nf.base); + Qualify(r, nnf, b, s, usings); } else r.Cat(b, s); @@ -163,7 +166,7 @@ String QualifyIds(Scopefo& nf, const String& k, bool all) const char *b = s++; while(*s == ':' || iscid(*s)) s++; if(all) - Qualify(r, nf, b, s); + Qualify(r, nf, b, s, usings); else r.Cat(b, s); } @@ -179,101 +182,61 @@ String QualifyIds(Scopefo& nf, const String& k, bool all) return r; } -String Qualify(const CppBase& base, const String& scope, const String& type) +String Qualify(const CppBase& base, const String& scope, const String& type, const String& usings) { - Scopefo nf(base, scope); - return QualifyIds(nf, type, true); + ScopeInfo nf(base, scope); + return QualifyIds(nf, type, usings, true); } -String QualifyKey(const CppBase& base, const String& scope, const String& type) +String QualifyKey(const CppBase& base, const String& scope, const String& type, const String& usings) { - Scopefo nf(base, scope); - return QualifyIds(nf, type, false); + ScopeInfo nf(base, scope); + return QualifyIds(nf, type, usings, false); } void QualifyTypes(CppBase& base, const String& scope, CppItem& m) { - Scopefo nf(base, scope); - m.qtype = QualifyIds(nf, m.type, true); - m.qptype = QualifyIds(nf, m.ptype, true); + 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 QualifyPass1(CppBase& base) -{ +{ // Qualify types LTIMING("QualifyPass1"); for(int ni = 0; ni < base.GetCount(); ni++) { Array& n = base[ni]; - Scopefo nf(base, ni); + ScopeInfo nf(base, ni); for(int i = 0; i < n.GetCount(); i++) { CppItem& m = n[i]; - if(m.serial != base.serial && m.IsType()) { - m.serial = base.serial; - if(m.qualify_type) { - m.qualify_type = false; - m.qtype = QualifyIds(nf, m.type, true); - } - if(m.qualify_param) { - m.qualify_param = false; - m.qptype = QualifyIds(nf, m.ptype, true); - } - m.qitem = m.item; + 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 } - //LLOG(base.GetKey(ni) << "." << m.item << " " << GetCppFile(m.file) << '(' << m.line << ") " - // << AsCString(m.natural) - // << " impl:" << m.impl << " kind:" << (int)m.kind << " IsType:" << m.IsType() - // << " type: " << m.type << " qtype:" << m.qtype << " tparam:" << m.tparam); } } } -struct CmpCppItem { - bool operator()(const CppItem& a, const CppItem& b) const - { - int q = SgnCompare(a.qitem, b.qitem); - if(q) return q < 0; - q = SgnCompare(a.IsType(), b.IsType()); - if(q) return q < 0; - q = SgnCompare(a.impl, b.impl); - if(q) return a.IsType() ? q > 0 : q < 0; - q = SgnCompare(GetCppFile(a.file), GetCppFile(b.file)); - if(q) return q < 0; - return a.line < b.line; - } -}; - void QualifyPass2(CppBase& base) -{ +{ // Qualify function parameters LTIMING("QualifyPass2"); for(int ni = 0; ni < base.GetCount(); ni++) { Array& n = base[ni]; - Scopefo nf(base, ni); - Index rem; - bool sort = false; + 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.serial != base.serial && !m.IsType()) { - sort = true; - m.serial = base.serial; - if(m.qualify_type) { - m.qualify_type = false; - m.qtype = QualifyIds(nf, m.type, true); - } - if(m.qualify_param) { - m.qualify_param = false; - m.qptype = QualifyIds(nf, m.ptype, true); - m.qitem = m.IsCode() ? QualifyIds(nf, m.item, false) - : m.item; - } + 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; } - LLOG(base.GetKey(ni) << "." << m.item << " -> " << m.qitem << "\n " << GetCppFile(m.file) << '(' << m.line << ") " - << AsCString(m.natural) - << " impl:" << m.impl << " kind:" << (int)m.kind << " IsType:" << m.IsType() - << " qtype:" << m.qtype << " tparam:" << m.tparam); } - if(sort) - Sort(n, CmpCppItem()); } } @@ -293,9 +256,13 @@ void Qualify(CppBase& base) md5 << '\n'; } String c5 = md5.FinishString(); - if(c5 != base.serial_md5) { - base.serial++; + if(c5 != base.serial_md5) { // set of types changed, requalify everything base.serial_md5 = c5; + for(int ni = 0; ni < base.GetCount(); ni++) { + Array& n = base[ni]; + for(int i = 0; i < n.GetCount(); i++) + n[i].qualify = true; + } } QualifyPass1(base); QualifyPass2(base); diff --git a/uppsrc/CppBase/Scopefo.cpp b/uppsrc/CppBase/Scopefo.cpp deleted file mode 100644 index d2b88575b..000000000 --- a/uppsrc/CppBase/Scopefo.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "CppBase.h" - -NAMESPACE_UPP - -#define LLOG(x) -#define LTIMING(x) // RTIMING(x) - -Scopefo::Scopefo(const CppBase& base, int scopei) - : scopei(scopei), base(base) -{ - LTIMING("Scopefo(const CppBase& base, int scopei)"); - Init(); -} - -Scopefo::Scopefo(int scopei, const CppBase& base) - : scopei(scopei), base(base) -{ - LTIMING("Scopefo(int scopei, const CppBase& base)"); - Init(); -} - -Scopefo::Scopefo(const CppBase& base, const String& scope) - : scopei(base.Find(scope)), base(base) -{ - LTIMING("Scopefo(const CppBase& base, const String& scope)"); - Init(); -} - -Scopefo::Scopefo(const Scopefo& f) - : base(f.base) -{ - LTIMING("Scopefo copy contructor"); - scopes <<= f.scopes; - bvalid = nvalid = false; - scopei = f.scopei; -} - -void Scopefo::Init() -{ - bvalid = nvalid = false; -} - -void Scopefo::Bases(int i, Vector& g) -{ - if(base.IsType(i)) { - const Array& 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') - return; - q++; - b = q; - } - else - q++; - } - } - } - } -} - -const Vector& Scopefo::GetBases() -{ - LTIMING("GetBases"); - if(!bvalid) { - bvalid = true; - baselist.Clear(); - if(scopei < 0) - return baselist; - Vector b; - Index bi; - Bases(scopei, b); - while(b.GetCount()) { - Vector 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& Scopefo::GetScopes() -{ - LTIMING("GetScopes"); - if(!nvalid) { - nvalid = true; - scopes.Clear(); - if(scopei < 0) - return scopes; - 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(""); - } - return scopes; -} - -END_UPP_NAMESPACE diff --git a/uppsrc/CppBase/cpplex.cpp b/uppsrc/CppBase/cpplex.cpp index 98bf833d6..251c05d3e 100644 --- a/uppsrc/CppBase/cpplex.cpp +++ b/uppsrc/CppBase/cpplex.cpp @@ -87,16 +87,12 @@ Lex::Lex() for(int i = 0; cppk[i]; i++) id.Add(cppk[i]); endkey = id.GetCount(); - braceslevel = ignore_low = ignore_high = body = 0; + braceslevel = body = 0; } -void Lex::Init(const char *s, const Vector& ig) +void Lex::Init(const char *s) { ptr = s; - ignore_low = id.GetCount(); - for(int i = 0; i < ig.GetCount(); i++) - id.Add(ig[i]); - ignore_high = id.GetCount(); } void Lex::StartStatCollection() @@ -173,21 +169,6 @@ void Lex::Next() AddCode('&'); AddCode('&'); } - else - if(q >= ignore_low && q < ignore_high) - while(*ptr && (byte)*ptr <= ' ') { - ptr++; - if(*ptr == '(') { - int level = 1; - while(*ptr && level) { - if(*ptr == '(') - level++; - if(*ptr == ')') - level--; - ptr++; - } - } - } else AddCode(q + 256); break; diff --git a/uppsrc/TCore/util.cpp b/uppsrc/TCore/util.cpp index 7b7ec38b1..b8d3e9866 100644 --- a/uppsrc/TCore/util.cpp +++ b/uppsrc/TCore/util.cpp @@ -509,7 +509,7 @@ String NlsFormat(int value) { return GetLanguageInfo().FormatInt(value); } */ String NlsFormat(double value, int decimal_places) -{ return GetLanguageInfo().FormatDouble(value, tabs(decimal_places), decimal_places >= 0 ? 0 : FD_ZERO); } +{ return GetLanguageInfo().FormatDouble(value, tabs(decimal_places), decimal_places >= 0 ? 0 : FD_ZEROS); } /* String NlsFormat(double value, int decimal_places) { @@ -518,7 +518,7 @@ String NlsFormat(double value, int decimal_places) */ String NlsFormatRel(double value, int relative_places) -{ return GetLanguageInfo().FormatDouble(value, tabs(relative_places), FD_REL | (relative_places >= 0 ? 0 : FD_ZERO)); } +{ return GetLanguageInfo().FormatDouble(value, tabs(relative_places), FD_REL | (relative_places >= 0 ? 0 : FD_ZEROS)); } /* String NlsFormatRel(double value, int relative_places) diff --git a/uppsrc/ide/Annotations.cpp b/uppsrc/ide/Annotations.cpp index fa7502f4d..eb287f50f 100644 --- a/uppsrc/ide/Annotations.cpp +++ b/uppsrc/ide/Annotations.cpp @@ -2,19 +2,22 @@ void AssistEditor::Annotate(const String& filename) { - int fi = GetCppFileIndex(filename); + int fi = GetSourceFileIndex(filename); CppBase& base = CodeBase(); ClearAnnotations(); for(int j = 0; j < base.GetCount(); j++) { - const Array& n = base[j]; - for(int k = 0; k < n.GetCount(); k++) { - const CppItem& m = n[k]; - if(m.file == fi) { - String coderef = MakeCodeRef(base.GetKey(j), m.qitem); - SetAnnotation(m.line - 1, - GetRefLinks(coderef).GetCount() ? IdeImg::tpp_doc() - : IdeImg::tpp_pen(), - coderef); + String nest = base.GetKey(j); + if(*nest != '@') { // Annotation of anonymous structures not suported + const Array& 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); + } } } } @@ -92,22 +95,31 @@ void AssistEditor::SyncAnnotationPopup() topic_text = ParseQTF(ReadTopic(LoadFile(path)).text); RichText result; - for(int i = 0; i < topic_text.GetPartCount(); i++) - if(IsCodeItem(topic_text, i) && topic_text.Get(i).format.label == coderef) { - while(i > 0 && IsCodeItem(topic_text, i)) i--; - if(!IsCodeItem(topic_text, i)) i++; - while(IsCodeItem(topic_text, i)) - result.Cat(topic_text.Get(i++)); - while(i < topic_text.GetPartCount() && !IsCodeItem(topic_text, i) - && !IsBeginEnd(topic_text, i)) - if(topic_text.IsPara(i)) + String cr = coderef; + for(int pass = 0; pass < 2; pass++) { + for(int i = 0; i < topic_text.GetPartCount(); i++) + if(IsCodeItem(topic_text, i) && 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)) result.Cat(topic_text.Get(i++)); - else { - RichTable table(topic_text.GetTable(i++), 1); - result.CatPick(pick(table)); + while(i < topic_text.GetPartCount() && !IsCodeItem(topic_text, i) + && !IsBeginEnd(topic_text, i)) { + if(topic_text.IsPara(i)) + result.Cat(topic_text.Get(i++)); + else { + RichTable table(topic_text.GetTable(i++), 1); + result.CatPick(pick(table)); + } } + pass = 2; + break; + } + if(pass == 0 && cr.StartsWith("Upp::")) + cr = cr.Mid(5); + else break; - } + } result.SetStyles(topic_text.GetStyles()); annotation_popup.Pick(pick(result), GetRichTextStdScreenZoom()); } diff --git a/uppsrc/ide/Assist.cpp b/uppsrc/ide/Assist.cpp index 6c101ca2a..50c3e21d4 100644 --- a/uppsrc/ide/Assist.cpp +++ b/uppsrc/ide/Assist.cpp @@ -336,20 +336,7 @@ bool AssistEditor::IncludeAssist() } else { p.Char('<'); - theide->SetupDefaultMethod(); - VectorMap bm = GetMethodVars(theide->method); - include = SplitDirs(GetVar("UPP") + ';' + bm.Get("INCLUDE", "") -#ifdef PLATFORM_POSIX - + ";/usr/include;/usr/local/include" -#endif - ); - // Also adding internal includes - const Workspace& wspc = GetIdeWorkspace(); - for(int i = 0; i < wspc.GetCount(); i++) { - const Package& pkg = wspc.GetPackage(i); - for(int j = 0; j < pkg.include.GetCount(); j++) - include.Add(SourcePath(wspc[i], pkg.include[j].text)); - } + include = SplitDirs(theide->GetIncludePath()); include_local = false; } include_path.Clear(); @@ -460,7 +447,7 @@ void AssistEditor::Assist() while(Ch(q - 1) == ':') q--; Vector tparam; - String scope = ParseTemplatedType(Qualify(parser.current_scope, CompleteIdBack(q)), tparam); + String scope = ParseTemplatedType(Qualify(parser.current_scope, CompleteIdBack(q), parser.context.namespace_using), tparam); GatherItems(scope, false, in_types, true); } else { @@ -506,8 +493,9 @@ void AssistEditor::PopUpAssist(bool auto_insert) type.SetCursor(0); if(!assist.GetCount()) return; - int cy = min(300, lcy * max(type.GetCount(), assist.GetCount())); - cy += 4; +// int cy = min(300, lcy * max(type.GetCount(), assist.GetCount())); +// cy += 4; + int cy = VertLayoutZoom(304); cy += HeaderCtrl::GetStdHeight(); assist.SetLineCy(lcy); Point p = GetCaretPoint() + GetScreenView().TopLeft(); @@ -933,9 +921,25 @@ void AssistEditor::DCopy() String txt = Get(l, h - l); StringStream ss(txt); String cls = ctx.current_scope; +/* TODO: remove CppBase cpp; Parser parser; parser.Do(ss, IgnoreList(), cpp, Null, CNULL, Split(cls, ':')); +*/ + CppBase cpp; + Cpp pp; + pp.Preprocess(theide->editfile, ss, GetMasterFile(theide->editfile)); + + Parser parser; + parser.dobody = true; + StringStream pin(pp.output); + parser.Do(ss, cpp, Null, Null, Null, CNULL, Split(cls, ':'), + pp.namespace_stack, pp.namespace_using); + +// QualifyTypes(CodeBase(), parser.current_scope, parser.current); +// inbody = parser.IsInBody(); + + for(int i = 0; i < cpp.GetCount(); i++) { const Array& n = cpp[i]; bool decl = decla; @@ -1221,7 +1225,7 @@ void Ide::ContextGoto0(int pos) t.Trim(t.GetCount() - 2); scope.Add(t); istype.Add(false); - Scopefo f(CodeBase(), t); // Try base classes too! + ScopeInfo f(CodeBase(), t); // Try base classes too! todo.Append(f.GetBases()); } } @@ -1229,7 +1233,7 @@ void Ide::ContextGoto0(int pos) if(qual.GetCount()) { // Ctrl::MOUSELEFT, Vector::Iterator Vector todo; - todo.Add(RemoveTemplateParams(Qualify(CodeBase(), parser.current_scope, qual + "::" + id))); + todo.Add(RemoveTemplateParams(Qualify(CodeBase(), parser.current_scope, qual + "::" + id, parser.context.namespace_using))); while(scope.GetCount() < 100 && todo.GetCount()) { String t = todo[0]; if(t.EndsWith("::")) @@ -1245,7 +1249,7 @@ void Ide::ContextGoto0(int pos) scope.Add(tt); istype.Add(true); } - Scopefo f(CodeBase(), t); // Try base classes too! + ScopeInfo f(CodeBase(), t); // Try base classes too! todo.Append(f.GetBases()); } } @@ -1259,7 +1263,7 @@ void Ide::ContextGoto0(int pos) t.Trim(t.GetCount() - 2); scope.Add(t); istype.Add(false); - Scopefo f(CodeBase(), t); // Try base classes too! + ScopeInfo f(CodeBase(), t); // Try base classes too! todo.Append(f.GetBases()); } q = parser.local.Find(id); @@ -1270,7 +1274,7 @@ void Ide::ContextGoto0(int pos) return; } // Can be unqualified type name like 'String' - String t = RemoveTemplateParams(Qualify(CodeBase(), parser.current_scope, id)); + String t = RemoveTemplateParams(Qualify(CodeBase(), parser.current_scope, id, parser.context.namespace_using)); if(CodeBase().Find(t) >= 0) { scope.Add(t); istype.Add(true); @@ -1322,7 +1326,7 @@ void Ide::JumpToDefinition(const Array& n, int q, const String& scope) String currentfile = editfile; while(i < n.GetCount() && n[i].qitem == qitem) { const CppItem& m = n[i]; - int ml = GetMatchLen(editfile, GetCppFile(m.file)); + int ml = GetMatchLen(editfile, GetSourceFilePath(m.file)); if(m.impl && ml > qimplml) { qimplml = ml; qimpl = i; @@ -1338,7 +1342,7 @@ void Ide::JumpToDefinition(const Array& n, int q, const String& scope) i++; } const CppItem& pos = n[qimpl >= 0 ? qimpl : qcpp >= 0 ? qcpp : q]; - String path = GetCppFile(pos.file); + String path = GetSourceFilePath(pos.file); editastext.RemoveKey(path); editashex.RemoveKey(path); if(ToLower(GetFileExt(path)) == ".lay") { diff --git a/uppsrc/ide/Assist.h b/uppsrc/ide/Assist.h index 085515ea3..6b067fd39 100644 --- a/uppsrc/ide/Assist.h +++ b/uppsrc/ide/Assist.h @@ -181,11 +181,13 @@ struct AssistEditor : CodeEditor, Navigator { void Abbr(); void Context(Parser& parser, int pos); - void ExpressionType(const String& type, const Vector& xp, int ii, + void ExpressionType(const String& type, const String& usings, + const Vector& xp, int ii, Index& typeset, bool variable, bool can_shortcut_operator, Index& visited_bases, int lvl); - void ExpressionType(const String& type, const Vector& xp, int ii, + void ExpressionType(const String& type, const String& usings, + const Vector& xp, int ii, Index& typeset, bool variable, int lvl); // void ExpressionType(const String& type, const Vector& xp, int ii, // Index& typeset); @@ -198,6 +200,9 @@ struct AssistEditor : CodeEditor, Navigator { void DCopy(); void Virtuals(); void Thisbacks(); + void AssistItemAdd(const String& scope, const CppItem& m, int typei); + void GatherItems0(const String& type, bool only_public, Index& in_types, + bool types); void GatherItems(const String& type, bool only_public, Index& in_types, bool types); diff --git a/uppsrc/ide/Browser/Base.cpp b/uppsrc/ide/Browser/Base.cpp index b78d1bd79..de0b95483 100644 --- a/uppsrc/ide/Browser/Base.cpp +++ b/uppsrc/ide/Browser/Base.cpp @@ -1,25 +1,61 @@ #include "Browser.h" -#define LTIMING(x) // RTIMING(x) -#define LLOG(x) +#include -static const char s_dbver[] = "CPP-BASE 2.36"; +#define LTIMING(x) // RTIMING(x) +#define LLOG(x) // DLOG(x) +#define LTIMESTOP(x) // RTIMESTOP(x) -void GC_Cache() +#define LDUMP(x) // DDUMP(x) + + +VectorMap sSrcFile; +ArrayMap source_file; + +void SourceFileInfo::Serialize(Stream& s) { - String cfg = ConfigFile("cfg"); - FindFile ff(AppendFileName(cfg, "*.cache")); - Time tm0 = ToTime(GetSysDate() - 20); + s % time % ids % included_id_macros % namespace_info % using_info + % defined_macros % defined_namespace_info % includes; +} + +String CodeBaseCacheDir() +{ + return ConfigFile("cfg/codebase"); +} + +void ReduceCodeBaseCache() +{ + struct FileInfo { + String path; + Time time; + int64 length; + + bool operator<(const FileInfo& a) const { return time > a.time; } + }; + Array file; + FindFile ff(AppendFileName(CodeBaseCacheDir(), "*.*")); + int64 total = 0; while(ff) { - if(ff.IsFile() && Time(ff.GetLastWriteTime()) > tm0) - FileDelete(AppendFileName(cfg, ff.GetName())); + if(ff.IsFile()) { + 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 > 120000000 && file.GetCount()) { + DeleteFile(file.Top().path); + total -= file.Top().length; + file.Drop(); + } } -String CacheFile(const String& res) +String CodeBaseCacheFile() { - return AppendFileName(ConfigFile("cfg"), MD5String(res) + ".cache"); + return AppendFileName(CodeBaseCacheDir(), GetVarsName() + '.' + GetCurrentMainPackage() + '.' + GetCurrentBuildMethod() + ".codebase"); } CppBase& CodeBase() @@ -28,284 +64,419 @@ CppBase& CodeBase() return b; } -ArrayMap& FileSet() -{ - static ArrayMap x; - return x; -} - -Vector& RBrowser() -{ - static Vector bp; - return bp; -} - static bool s_console; -static String s_file; -void BrowserScanError(int line, const String& text) +void IdePutErrorLine(const String& line); + +void BrowserScanError(int line, const String& text, int file) { if(s_console) - PutConsole(String().Cat() << s_file << " (" << line << "): " << text); + IdePutErrorLine(String().Cat() << source_file.GetKey(file) << " (" << line << "): " << text); } +void SerializeCodeBase(Stream& s) +{ + source_file.Serialize(s); + SerializePPFiles(s); + CodeBase().Serialize(s); +} + +#define CPP_CODEBASE_VERSION 8 + void SaveCodeBase() { LTIMING("SaveCodeBase"); - RealizeDirectory(ConfigFile("cfg")); - GC_Cache(); - CppBase& base = CodeBase(); - if(base.GetCount() == 0) + LLOG("Save code base " << CodeBase().GetCount()); + RealizeDirectory(ConfigFile("cfg/codebase")); + 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) +{ + 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))); + if(Load(callback(SerializeCodeBase), ss, CPP_CODEBASE_VERSION)) { + LLOG("Loaded " << ff.GetPath()); + return true; + } + } + return false; +} + +void LoadCodeBase() +{ + TryLoadCodeBase(CodeBaseCacheFile()) || + TryLoadCodeBase(AppendFileName(CodeBaseCacheDir(), GetVarsName() + ".*." + GetCurrentBuildMethod() + ".codebase")) || + TryLoadCodeBase(AppendFileName(CodeBaseCacheDir(), GetVarsName() + ".*.codebase")) || + TryLoadCodeBase(AppendFileName(CodeBaseCacheDir(), "*.codebase")); + + LLOG("LoadCodeBase: " << CodeBase().GetCount()); +} + +void FinishCodeBase() +{ + LTIMING("FinishBase"); + + Qualify(CodeBase()); +} + +void GatherSources(const String& master_path, const String& path_) +{ + RHITCOUNT("GatherSources"); + String path = NormalizePath(path_); + if(sSrcFile.Find(path) >= 0) return; - ArrayMap& fileset = FileSet(); - ArrayMap out; - String s; - for(int j = 0; j < base.GetCount(); j++) { - Array& n = base[j]; - for(int k = 0; k < n.GetCount(); k++) { - CppItem& m = n[k]; - StringStream& o = out.GetAdd(GetCppFile(m.file)); - s = base.GetKey(j); - o % s; - o % m; - } - } - - const Workspace& wspc = GetIdeWorkspace(); - for(int i = 0; i < wspc.GetCount(); i++) { - String package = wspc[i]; - FileOut fo(CacheFile(package)); - s = s_dbver; - fo % s; - for(int i = 0; i < fileset.GetCount(); i++) - if(fileset[i].package == package) { - String fn = fileset.GetKey(i); - String q = out.GetAdd(fn).GetResult(); - BrowserFileInfo& f = fileset[i]; - fo % fn; - fo % f.file; - fo % f.time; - fo % q; - } + sSrcFile.Add(path, master_path); + const PPFile& f = GetPPFile(path); + for(int i = 0; i < f.includes.GetCount(); i++) { + String p = GetIncludePath(f.includes[i], GetFileFolder(path)); + if(p.GetCount()) + GatherSources(master_path, p); } } -void LoadCodeBase(Progress& pi) -{ - LTIMING("LoadCodeBase"); - CppBase& base = CodeBase(); - ArrayMap& fileset = FileSet(); - String s; +void BaseInfoSync(Progress& pi) +{ // clears temporary caches (file times etc..) + PPSync(TheIde()->IdeGetIncludePath()); + + LTIMESTOP("Gathering files"); + sSrcFile.Clear(); const Workspace& wspc = GetIdeWorkspace(); - pi.SetText("Assist++ loading packages"); + LTIMING("Gathering files"); + pi.SetText("Gathering files"); pi.SetTotal(wspc.GetCount()); - pi.SetPos(0); - for(int i = 0; i < wspc.GetCount(); i++) { - pi.Step(); - String package = wspc[i]; - FileIn in(CacheFile(package)); - in.LoadThrowing(); - if(in) { - try { - in % s; - if(s != s_dbver) - throw LoadingError(); - while(!in.IsEof()) { - String fn; - in % fn; - BrowserFileInfo& f = fileset.GetAdd(fn); - in % f.file; - in % f.time; - f.package = package; - String q; - in % q; - StringStream ss(q); - ss.LoadThrowing(); - while(!ss.IsEof()) { - String s; - ss % s; - CppItem& m = base.GetAdd(s).Add(); - ss % m; - m.file = GetCppFileIndex(fn); - } - } - } - catch(LoadingError) { - CodeBase().Clear(); - fileset.Clear(); - return; + for(int pass = 0; pass < 2; pass++) + 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)) + GatherSources(path, path); } } + + SweepPPFiles(sSrcFile.GetIndex()); +} + +String GetMasterFile(const String& file) +{ + return sSrcFile.Get(file, Null); +} + +int GetSourceFileIndex(const String& path) +{ + return source_file.FindPut(path); +} + +String GetSourceFilePath(int file) +{ + if(file < 0 || file >= source_file.GetCount()) + return Null; + return source_file.GetKey(file); +} + +bool CheckFile(const SourceFileInfo& f, const String& path) +{ + LTIMING("CheckFile"); + LDUMP(f.time); + LDUMP(FileGetTime(path)); + if(f.time != FileGetTime(path)) + return false; + Cpp pp; + FileIn in(path); + pp.Preprocess(path, in, GetMasterFile(path), true); + String included_id_macros = pp.GetIncludedMacroValues(f.ids.GetKeys()); + LDUMP(included_id_macros); + LDUMP(f.included_id_macros); + return f.included_id_macros == included_id_macros; +} + +void ParseFiles(Progress& pi, const Index parse_file) +{ + pi.SetTotal(parse_file.GetCount()); + pi.SetPos(0); + pi.AlignText(ALIGN_LEFT); + for(int i = 0; i < parse_file.GetCount(); i++) { + String path = GetSourceFilePath(parse_file[i]); + pi.SetText(GetFileName(GetFileFolder(path)) + "/" + GetFileName(path)); + pi.Step(); + FileIn fi(path); + LDUMP(path); + LDUMP(parse_file[i]); + bool dummy; + ParseSrc(fi, parse_file[i], callback1(BrowserScanError, i), true, false, dummy, dummy); } } -void FinishBase() +void UpdateCodeBase2(Progress& pi) { - TimeStop tm; - Qualify(CodeBase()); -} + const Workspace& wspc = GetIdeWorkspace(); -void ReQualifyCodeBase() -{ - Qualify(CodeBase()); -} - -Vector SortedNests() -{ - LTIMING("SortedNests()"); + pi.SetText("Checking source files"); + pi.SetTotal(sSrcFile.GetCount()); + pi.SetPos(0); + Index keep_file; + Index parse_file; + for(int i = 0; i < sSrcFile.GetCount(); i++) { + pi.Step(); + String path = sSrcFile.GetKey(i); + int q = GetSourceFileIndex(path); + const SourceFileInfo& f = source_file[q]; + LLOG("== CHECK == " << q << ": " << path); + if(CheckFile(f, path)) + keep_file.Add(q); + else { + LLOG("PARSE!"); + parse_file.Add(q); + } + } + CppBase& base = CodeBase(); - Vector n; - for(int i = 0; i < base.GetCount(); i++) - if(!base.IsUnlinked(i)) - n.Add(base.GetKey(i)); - Sort(n); - return n; + + base.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); + + ParseFiles(pi, parse_file); } void UpdateCodeBase(Progress& pi) { - Index fp; - Vector scan; - ArrayMap& set = FileSet(); - const Workspace& wspc = GetIdeWorkspace(); - CppBase& base = CodeBase(); - pi.SetText("Assist++ checking packages"); - pi.SetTotal(wspc.GetCount()); - pi.SetPos(0); - 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]); - String ext = ToUpper(GetFileExt(path)); - if(ext == ".C" || ext == ".CPP" || ext == ".CC" || ext == ".CXX" || ext == ".ICPP" || - ext == ".H" || ext == ".HPP" || ext == ".HH" || ext == ".HXX" || - ext == ".LAY" || ext == ".SCH" || ext == ".IML") { - fp.Add(path); - int q = set.Find(path); - Time tm = FileGetTime(path); - if(q < 0 || set[q].time != tm) - scan.Add(path); - BrowserFileInfo& bf = set.GetAdd(path); - bf.package = n; - bf.file = pk.file[i]; - bf.time = tm; - } - } - } - - Vector remove(scan, 1); - Vector rm; - for(int i = 0; i < set.GetCount(); i++) - if(fp.Find(set.GetKey(i)) < 0) { - remove.Add(set.GetKey(i)); - rm.Add(i); - } - if(remove.GetCount() == 0) - return; - set.Remove(rm); - Remove(base, remove); - if(scan.GetCount()) { - pi.SetTotal(scan.GetCount()); - pi.SetPos(0); - pi.AlignText(ALIGN_LEFT); - Vector ignore = IgnoreList(); - for(int i = 0; i < scan.GetCount(); i++) { - s_file = scan[i]; - pi.SetText(s_file); - pi.Step(); - String ext = ToUpper(GetFileExt(s_file)); - if(ext == ".LAY") - ScanLayFile(s_file); - else - if(ext == ".IML") - ScanImlFile(s_file); - else - if(ext == ".SCH") - ScanSchFile(s_file); - else { - FileIn fi(s_file); - Parse(fi, ignore, base, s_file, callback(BrowserScanError)); - } - } - } + BaseInfoSync(pi); + + UpdateCodeBase2(pi); } -void CodeBaseScan(Stream& s, const String& fn) +Vector ParseSrc(Stream& in, int file, Callback2 error, + bool do_macros, bool get_changes, + bool& namespace_info_changed, + bool& includes_changed) { + Vector cm; + String path = GetSourceFilePath(file); + LLOG("====== Parse " << file << ": " << path); + Vector pp; + String ext = ToLower(GetFileExt(path)); + int filetype = FILE_OTHER; + SourceFileInfo& sfi = source_file[file]; + Cpp cpp; + bool b = false; + if(ext == ".lay") + pp.Add(PreprocessLayFile(path)); + else + if(ext == ".iml") + pp.Add(PreprocessImlFile(path)); + else + if(ext == ".sch") + pp.Append(PreprocessSchFile(path)); + else { + cpp.Preprocess(path, in, GetMasterFile(GetSourceFilePath(file))); + filetype = decode(ext, ".h", FILE_H, ".hpp", FILE_HPP, + ".cpp",FILE_CPP, ".c", FILE_C, FILE_OTHER); + if(do_macros) { + sfi.ids = cpp.ids.PickKeys(); + sfi.included_id_macros = cpp.GetIncludedMacroValues(sfi.ids.GetKeys()); + LDUMP(sfi.ids); + sfi.time = FileGetTime(path); + LDUMP(sfi.time); + VectorMap dm = cpp.GetDefinedMacros(); + LDUMP(dm); + if(sfi.defined_macros != dm) { + LTIMING("Find changed macros"); + if(get_changes) { + Buffer found(sfi.defined_macros.GetCount(), false); + for(int i = 0; i < dm.GetCount() && cm.GetCount() < 10; i++) { + String id = dm.GetKey(i); + int q = sfi.defined_macros.Find(id); + if(q < 0 || sfi.defined_macros[q] != dm[i]) + cm.Add(id); + if(q >= 0) + found[q] = true; + } + for(int i = 0; i < sfi.defined_macros.GetCount() && cm.GetCount() < 10; i++) + if(!found[i]) + cm.Add(sfi.defined_macros.GetKey(i)); + } + sfi.defined_macros = pick(dm); + } + } + StringStream pin(cpp.output); + Parser p; + p.Do(pin, CodeBase(), file, filetype, GetFileName(path), error, Vector(), + cpp.namespace_stack, cpp.namespace_using); + if(sfi.defined_namespace_info != p.namespace_info) { + p.namespace_info = sfi.defined_namespace_info; + namespace_info_changed = true; + } + if(cpp.includes != sfi.includes) { + sfi.includes = cpp.includes; + includes_changed = true; + } + return cm; + } + + for(int i = 0; i < pp.GetCount(); i++) { + StringStream pin(pp[i]); + Parser p; + p.Do(pin, CodeBase(), file, filetype, GetFileName(path), error, Vector(), + cpp.namespace_stack, cpp.namespace_using); + } + return cm; +} + +bool HasIntersection(const Index& ids, const Vector& cm) +{ + if(cm.GetCount() >= 10) + return true; + for(int i = 0; i < cm.GetCount(); i++) + if(ids.Find(cm[i]) >= 0) + return true; + return false; +} + +void CodeBaseScanFile(Stream& in, const String& fn, bool check_macros) +{ + LLOG("===== CodeBaseScanFile " << fn); + + PPSync(TheIde()->IdeGetIncludePath()); + LTIMING("CodeBaseScan"); - TimeStop tm; + + int file = GetSourceFileIndex(fn); CppBase& base = CodeBase(); - LLOG("Scan2 " << tm); - Vector remove; - remove.Add(fn); - Remove(base, remove); - LLOG("Scan3 " << tm); - if(ToUpper(GetFileExt(fn)) == ".SCH") - ScanSchFile(fn); - else - if(ToUpper(GetFileExt(fn)) == ".IML") - ScanImlFile(fn); - else - Parse(s, IgnoreList(), base, fn, CNULL); - LLOG("Scan4 " << tm); - FinishBase(); - LLOG("Scan total " << tm); - LLOG("---------"); + base.RemoveFile(file); + SourceFileInfo& f = source_file[file]; + bool namespace_info_changed = false; + bool includes_changed = false; + Vector cm = ParseSrc(in, file, CNULL, check_macros, true, + namespace_info_changed, includes_changed); + LDUMP(cm); + LDUMP(f.defined_macros); + LDUMP(check_macros); + if(check_macros && (includes_changed || namespace_info_changed || cm.GetCount())) { + SyncCodeBase(); + return; + } +/* + if( && check_macros) { + } + if((namespace_info_changed || cm.GetCount()) && check_macros) { + SyncCodeBase(); return; _DBG_ + DLOG("Checking files"); + Progress pi; + BaseInfoSync(pi); + pi.SetText("Checking source files"); + pi.SetTotal(sSrcFile.GetCount()); + pi.SetPos(0); + Index parse_file; + for(int i = 0; i < sSrcFile.GetCount(); i++) { + pi.Step(); + String path = sSrcFile.GetKey(i); + DDUMP(path); + int q = GetSourceFileIndex(path); + const SourceFileInfo& f = source_file[q]; + if((namespace_info_changed || HasIntersection(f.ids, cm)) && !CheckFile(f, path)) + parse_file.Add(q); + } + + CodeBase().RemoveFiles(parse_file); + + ParseFiles(pi, parse_file); + } +*/ + FinishCodeBase(); } -void CodeBaseScanLay(const String& fn) +void CodeBaseScanFile(const String& fn, bool check_macros) { - LTIMING("CodeBaseScanLay"); - Vector before = SortedNests(); - CppBase& base = CodeBase(); - Vector remove; - remove.Add(fn); - Remove(base, remove); - ScanLayFile(fn); - FinishBase(); + FileIn in(fn); + CodeBaseScanFile(in, fn, check_macros); } void ClearCodeBase() { + CleanPP(); CodeBase().Clear(); - FileSet().Clear(); -} - -void StartCodeBase() -{ - static int start; - if(start) return; - start++; - if(CodeBase().GetCount() == 0) { - Progress pi; - pi.Title("Assist++"); - LoadCodeBase(pi); - UpdateCodeBase(pi); - FinishBase(); - } - start--; + source_file.Clear(); } void SyncCodeBase() { - if(CodeBase().GetCount()) { - Progress pi; - pi.Title("Assist++"); - UpdateCodeBase(pi); - FinishBase(); - } + LTIMING("SyncCodeBase"); + LTIMESTOP("SyncCodeBase"); + Progress pi; + pi.Title("Parsing source files"); + UpdateCodeBase(pi); + FinishCodeBase(); } +void NewCodeBase() +{ + ReduceCodeBaseCache(); + static int start; + if(start) return; + start++; + LoadCodeBase(); + LOG("NewCodeBase loaded " << CodeBase().GetCount()); + SyncCodeBase(); + LOG("NewCodeBase synced " << CodeBase().GetCount()); + SaveCodeBase(); + LOG("NewCodeBase saved " << CodeBase().GetCount()); + start--; +} + +/* +void CheckCodeBase() +{ + RTIMESTOP("CheckCodeBase"); + Progress pi; + pi.Title("Checking source files"); + BaseInfoSync(pi); + for(int i = 0; i < sSrcFile.GetCount(); i++) + if(source_file.Find(sSrcFile.GetKey(i)) < 0) { + UpdateCodeBase2(pi); + FinishCodeBase(); + return; + } + for(int i = 0; i < source_file.GetCount(); i++) + if(!source_file.IsUnlinked(i)) { + String path = source_file.GetKey(i); + if(sSrcFile.Find(source_file.GetKey(i)) < 0 || source_file[i].time != FileGetTime(path)) { + UpdateCodeBase2(pi); + FinishCodeBase(); + return; + } + } +} +*/ + void RescanCodeBase() { ClearCodeBase(); s_console = true; Progress pi; - pi.Title("Assist++"); + pi.Title("Parsing source files"); UpdateCodeBase(pi); - FinishBase(); + FinishCodeBase(); s_console = false; } diff --git a/uppsrc/ide/Browser/Browser.h b/uppsrc/ide/Browser/Browser.h index 8a3688b81..3060efb8e 100644 --- a/uppsrc/ide/Browser/Browser.h +++ b/uppsrc/ide/Browser/Browser.h @@ -16,22 +16,45 @@ class Browser; -void GC_Cache(); +String GetMasterFile(const String& file); CppBase& CodeBase(); -void StartCodeBase(); -void CodeBaseScan(Stream& s, const String& fn); + +struct SourceFileInfo { + Time time; + Index ids; // all identifiers in the file + String included_id_macros; // included macros from ids set + String namespace_info; // namespace defined at the start of file + String using_info; // using namespace info at the start of file + VectorMap defined_macros; // macros defined by the file (to detect changes) + String defined_namespace_info; // set of usings and namespaces in the file (to detect changes) + String includes; // includes in the file (to detect changes) + + void Serialize(Stream& s); + + SourceFileInfo() { time = Null; } +}; + +void NewCodeBase(); +Vector ParseSrc(Stream& in, int file, Callback2 error, + bool do_macros, bool get_changes, + bool& namespace_info_changed, bool& includes_changed); +void CodeBaseScanFile(Stream& in, const String& fn, bool check_macros); +void CodeBaseScanFile(const String& fn, bool check_macros); void ClearCodeBase(); +// void CheckCodeBase(); void RescanCodeBase(); void SyncCodeBase(); void SaveCodeBase(); bool ExistsBrowserItem(const String& item); -void ReQualifyCodeBase(); +void FinishCodeBase(); -void CodeBaseScanLay(const String& fn); -void ScanLayFile(const char *fn); -void ScanSchFile(const char *fn); -void ScanImlFile(const char *fn); +String PreprocessLayFile(const char *fn); +Vector 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); @@ -58,7 +81,7 @@ struct CppItemInfo : CppItem { bool overed; int inherited; int typei; - + CppItemInfo() { over = overed = virt = false; inherited = line = 0; } }; @@ -92,16 +115,6 @@ Vector ParseItemNatural(const String& name, const CppItem& m, cons Vector ParseItemNatural(const CppItemInfo& m); Vector ParseItemNatural(const CppItemInfo& m); -struct BrowserFileInfo { - Time time; - String package; - String file; - - BrowserFileInfo() { time = Null; } -}; - -ArrayMap& FileSet(); - int GetItemHeight(const CppItem& m, int cx); enum AdditionalKinds { diff --git a/uppsrc/ide/Browser/Browser.upp b/uppsrc/ide/Browser/Browser.upp index b6a82363c..2409f83a5 100644 --- a/uppsrc/ide/Browser/Browser.upp +++ b/uppsrc/ide/Browser/Browser.upp @@ -4,7 +4,8 @@ uses CppBase, ide\Common, PdfDraw, - RichEdit; + RichEdit, + plugin/lz4; file Browser.h options(BUILDER_OPTION) PCH, @@ -12,13 +13,14 @@ file Lay.cpp, Iml.cpp, Sch.cpp, - Base.cpp optimize_speed, Util.cpp, + Base.cpp optimize_speed, Item.cpp, ItemDisplay.cpp, CodeBrowser.cpp optimize_speed, Browser.lay, Browser.iml, + todo.txt, Topic readonly separator, TopicBase.cpp, Reference.cpp, diff --git a/uppsrc/ide/Browser/CodeBrowser.cpp b/uppsrc/ide/Browser/CodeBrowser.cpp index 03f53705d..ab38c2778 100644 --- a/uppsrc/ide/Browser/CodeBrowser.cpp +++ b/uppsrc/ide/Browser/CodeBrowser.cpp @@ -18,7 +18,7 @@ bool MatchPm(int file, const String& pm) { if(IsNull(pm)) return true; - return GetCppFile(file).StartsWith(pm); + return GetSourceFilePath(file).StartsWith(pm); } bool MatchPm(const Array& n, const String& pm) @@ -89,7 +89,7 @@ void CodeBrowser::Load() for(int i = 0; i < n.GetCount(); i++) { int f = n[i].file; if(fi.Find(f) < 0) { - String s = GetFileText(GetCppFile(f)); + String s = GetFileText(GetSourceFilePath(f)); if(s.StartsWith(pm) && MatchCib(s, match) && (IsNull(find) || MatchCib(s, find) || n[i].uname.StartsWith(find))) { txt.Add(s); @@ -110,7 +110,7 @@ void CodeBrowser::Load() String fn = AppendFileName(pp, p[j]); String s = GetFileText(AppendFileName(pn, p[j])); if(fs.Find(s) < 0 && (IsNull(find) || MatchCib(s, find)) && MatchCib(s, match) && MatchPm(fn, pm)) { - int f = GetCppFileIndex(SourcePath(pn, p[j])); + int f = GetSourceFileIndex(SourcePath(pn, p[j])); txt.Add(s); ndx.Add(f); fs.Add(s); @@ -134,7 +134,7 @@ int ItemCompare(const Value& v1, const Value& v2) const CppItemInfo& b = ValueTo(v2); int q = a.inherited - b.inherited; if(q) return q; - q = SgnCompare(GetCppFile(a.file), GetCppFile(b.file)); + q = SgnCompare(GetSourceFilePath(a.file), GetSourceFilePath(b.file)); return q ? q : a.line - b.line; } @@ -156,16 +156,20 @@ void GatherMethods(const String& type, VectorMap& inherited, bool int q = CodeBase().Find(type); if(q < 0) return; const Array& n = CodeBase()[q]; - for(int i = 0; i < n.GetCount(); i = FindNext(n, i)) { + Index set; + for(int i = 0; i < n.GetCount(); i++) { const CppItem& m = n[i]; - if(m.IsType()) { - Vector 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; + if(set.Find(m.qitem) < 0) { + set.Add(m.qitem); + if(m.IsType()) { + Vector 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; + } } } } @@ -188,7 +192,7 @@ void CodeBrowser::LoadScope() int file = IsNumber(x) ? (int)x : -1; String scope = file < 0 ? String(x) : String(); int q = CodeBase().Find(scope); - bool filematch = file >= 0 && MatchCib(GetFileText(GetCppFile(file)), find); + bool filematch = file >= 0 && MatchCib(GetFileText(GetSourceFilePath(file)), find); bool scopematch = !filematch && MatchCib(scope, find); if(q >= 0) { const Array& n = CodeBase()[q]; @@ -196,7 +200,7 @@ void CodeBrowser::LoadScope() if(file < 0) GatherMethods(scope, inherited, false); Index set; - for(int i = 0; i < n.GetCount(); i = file < 0 ? FindNext(n, i) : i + 1) { + for(int i = 0; i < n.GetCount(); i = i++) { CppItemInfo m; (CppItem&) m = n[i]; if((find.GetCount() && m.uname.StartsWith(find) || filematch && m.file == file || scopematch) && set.Find(m.qitem) < 0) { diff --git a/uppsrc/ide/Browser/Iml.cpp b/uppsrc/ide/Browser/Iml.cpp index 75ef1b0ff..ad42f87db 100644 --- a/uppsrc/ide/Browser/Iml.cpp +++ b/uppsrc/ide/Browser/Iml.cpp @@ -2,7 +2,7 @@ #define LDUMP(x) // DDUMP(x) -void ScanImlFile(const char *fn) +String PreprocessImlFile(const char *fn) { String s = LoadFile(fn); @@ -50,7 +50,5 @@ void ScanImlFile(const char *fn) "static void Reset();" "};\n"; LDUMP(r); - StringStream ss(r); - CppBase& base = CodeBase(); - Parse(ss, IgnoreList(), base, fn, CNULL); + return r; } diff --git a/uppsrc/ide/Browser/Item.cpp b/uppsrc/ide/Browser/Item.cpp index ed71eba4c..8771cfdcb 100644 --- a/uppsrc/ide/Browser/Item.cpp +++ b/uppsrc/ide/Browser/Item.cpp @@ -76,8 +76,6 @@ Vector ParseItemNatural(const String& name, const String& ctname, const char *s) { - LLOG("ParseItemNatural " << natural << ", pname: " << pname - << ", tname: " << tname << ", ctname: " << ctname); Vector part; int len = name.GetLength(); if(len == 0) { @@ -112,7 +110,7 @@ Vector ParseItemNatural(const String& name, else { String id; n = 0; - while(IsAlNum(s[n]) || s[n] == '_' || s[n] == ':') + while(iscid(s[n]) || s[n] == ':') id.Cat(s[n++]); if(IsCppType(id)) p.type = ITEM_CPP_TYPE; @@ -172,8 +170,13 @@ Vector ParseItemNatural(const String& name, pari = 0; par = 0; } - while(s[n] && !iscid(s[n])) + while(s[n] && !iscid(s[n])) { // Anonymous structure name + if(s[n] == '@') { + p.len = n; + return part; + } n++; + } } p.len = n; s += n; diff --git a/uppsrc/ide/Browser/ItemDisplay.cpp b/uppsrc/ide/Browser/ItemDisplay.cpp index 8a6217be8..9033e6577 100644 --- a/uppsrc/ide/Browser/ItemDisplay.cpp +++ b/uppsrc/ide/Browser/ItemDisplay.cpp @@ -203,4 +203,3 @@ Size CppItemInfoDisplay::GetStdSize(const Value& q) const return Size(DoPaint(w, Rect(0, 0, INT_MAX, INT_MAX), q, Null, Null, 0), max(16, BrowserFont().Info().GetHeight())); } - diff --git a/uppsrc/ide/Browser/Lay.cpp b/uppsrc/ide/Browser/Lay.cpp index 5488efd4e..bc6bc5111 100644 --- a/uppsrc/ide/Browser/Lay.cpp +++ b/uppsrc/ide/Browser/Lay.cpp @@ -25,7 +25,7 @@ inline void WriteLines(String& r, int count) r << '\n'; } -void ScanLayFile(const char *fn) +String PreprocessLayFile(const char *fn) { LTIMING("Lay file"); String s = LoadFile(fn); @@ -77,7 +77,5 @@ void ScanLayFile(const char *fn) } catch(CParser::Error) {} LDUMP(r); - StringStream ss(r); - CppBase& base = CodeBase(); - Parse(ss, IgnoreList(), base, fn, CNULL); + return r; } diff --git a/uppsrc/ide/Browser/Sch.cpp b/uppsrc/ide/Browser/Sch.cpp index 853897b2e..f4195bffa 100644 --- a/uppsrc/ide/Browser/Sch.cpp +++ b/uppsrc/ide/Browser/Sch.cpp @@ -15,7 +15,7 @@ String ReadId(CParser& p, String& rr) return id; } -void ScanSchFile(const char *fn) +Vector PreprocessSchFile(const char *fn) { String s = LoadFile(fn); CParser p(s); @@ -108,8 +108,5 @@ void ScanSchFile(const char *fn) } catch(CParser::Error) {} - StringStream ss(r), sr(rr); - CppBase& base = CodeBase(); - Parse(sr, IgnoreList(), base, fn, CNULL); - Parse(ss, IgnoreList(), base, fn, CNULL); + return Vector() << r << rr; } diff --git a/uppsrc/ide/Browser/TopicBase.cpp b/uppsrc/ide/Browser/TopicBase.cpp index 8d3d52fa9..77bb847f6 100644 --- a/uppsrc/ide/Browser/TopicBase.cpp +++ b/uppsrc/ide/Browser/TopicBase.cpp @@ -241,6 +241,8 @@ Vector GetRefLinks(const String& ref) { Vector l; int q = ref_ref().Find(ref); + if(q < 0 && ref.StartsWith("Upp::")) // fix old docs + q = ref_ref().Find(ref.Mid(5)); while(q >= 0) { l.Add(ref_link()[q]); q = ref_ref().FindNext(q); diff --git a/uppsrc/ide/Browser/Util.cpp b/uppsrc/ide/Browser/Util.cpp index 753974be0..75d630204 100644 --- a/uppsrc/ide/Browser/Util.cpp +++ b/uppsrc/ide/Browser/Util.cpp @@ -45,7 +45,7 @@ const CppItem *GetCodeRefItem(const String& ref, const String& rfile) int i = q; int qml = 0; while(i < n.GetCount() && n[i].qitem == item) { - int ml = GetMatchLen(GetCppFile(n[i].file), rfile); + int ml = GetMatchLen(GetSourceFilePath(n[i].file), rfile); if(ml > qml) { q = i; qml = ml; diff --git a/uppsrc/ide/Browser/init b/uppsrc/ide/Browser/init index 326e0d9fc..1567bcd59 100644 --- a/uppsrc/ide/Browser/init +++ b/uppsrc/ide/Browser/init @@ -4,6 +4,7 @@ #include "ide\Common/init" #include "PdfDraw/init" #include "RichEdit/init" +#include "plugin/lz4/init" #define BLITZ_INDEX__ Faf5167357a73176b37fced69d194f797 #include "TopicI.icpp" #undef BLITZ_INDEX__ diff --git a/uppsrc/ide/Build.cpp b/uppsrc/ide/Build.cpp index a0d449dfb..7a3b2eca5 100644 --- a/uppsrc/ide/Build.cpp +++ b/uppsrc/ide/Build.cpp @@ -23,7 +23,7 @@ void Ide::DoProcessEvents() void Ide::ReQualifyCodeBase() { - ::ReQualifyCodeBase(); + FinishCodeBase(); } String Ide::GetMain() @@ -155,6 +155,26 @@ void Ide::FileCompile() SetErrorEditor(); } +void Ide::PreprocessInternal() +{ + if(editor.GetLength() >= 1000000) // Sanity... + return; + LOG("===== Preprocess internal"); + int l = editor.GetCurrentLine(); + PPSync(GetIncludePath()); + String pfn = ConfigFile(GetFileTitle(editfile) + ".i.tmp"); + Cpp cpp; + StringStream in(editor.Get()); + cpp.Preprocess(editfile, in, GetMasterFile(editfile)); + Upp::SaveFile(pfn, cpp.output); + HideBottom(); + EditFile(pfn); + EditAsText(); + if(!editor.IsReadOnly()) + ToggleReadOnly(); + editor.SetCursor(editor.GetPos(l)); +} + void Ide::Preprocess(bool asmout) { if(editfile.IsEmpty()) return; diff --git a/uppsrc/ide/Builders/MscBuilder.icpp b/uppsrc/ide/Builders/MscBuilder.icpp index ed2d78553..b68271400 100644 --- a/uppsrc/ide/Builders/MscBuilder.icpp +++ b/uppsrc/ide/Builders/MscBuilder.icpp @@ -41,8 +41,8 @@ static void AddObjectExports(const char *path, Index& out) if(!mapping.Open(path)) return; const byte *begin = mapping.Begin(); -if(!begin) - return; + if(!begin) + return; const COFF_IMAGE_FILE_HEADER *hdr = (const COFF_IMAGE_FILE_HEADER *)begin; if(hdr->Machine != COFF_IMAGE_FILE_MACHINE_I386) return; diff --git a/uppsrc/ide/Builders/init b/uppsrc/ide/Builders/init index 186603321..40b41be61 100644 --- a/uppsrc/ide/Builders/init +++ b/uppsrc/ide/Builders/init @@ -1,19 +1,19 @@ #ifndef _ide_Builders_icpp_init_stub #define _ide_Builders_icpp_init_stub #include "ide\Core/init" -#define BLITZ_INDEX__ F2d0fda314d78470f3dad56fd15b06a6e +#define BLITZ_INDEX__ Fab5aa4644e1c1b5af8ed5faf2d4db317 #include "GccBuilder.icpp" #undef BLITZ_INDEX__ -#define BLITZ_INDEX__ F7230d617f2ab5db4a3338ada4ca8c292 +#define BLITZ_INDEX__ F956ea62c6d598d9abe6fd347ece78faf #include "MscBuilder.icpp" #undef BLITZ_INDEX__ -#define BLITZ_INDEX__ Fa3cd12e35fe189283e40225675f9624c +#define BLITZ_INDEX__ F225ca26733f36a56ba45bd6b48495b2f #include "OwcBuilder.icpp" #undef BLITZ_INDEX__ -#define BLITZ_INDEX__ Fb879a0b9b41c914a5094d17fc0aea869 +#define BLITZ_INDEX__ Fecf66fc39eec6a21e32d6c41cad4d431 #include "JavaBuilder.icpp" #undef BLITZ_INDEX__ -#define BLITZ_INDEX__ F88cdfadd65244c54fcac6ffa7332b0cf +#define BLITZ_INDEX__ Fa99182ca8dccb6e49a9bb75dbfd7c33d #include "ScriptBuilder.icpp" #undef BLITZ_INDEX__ #endif diff --git a/uppsrc/ide/Core/Core.h b/uppsrc/ide/Core/Core.h index b08921ffb..98870618b 100644 --- a/uppsrc/ide/Core/Core.h +++ b/uppsrc/ide/Core/Core.h @@ -81,6 +81,7 @@ public: virtual void IdeFlushFile() = 0; virtual String IdeGetFileName() = 0; virtual String IdeGetNestFolder() = 0; + virtual String IdeGetIncludePath() = 0; virtual String GetDefaultMethod(); virtual VectorMap GetMethodVars(const String& method); @@ -194,6 +195,9 @@ Vector GetUppDirs(); String GetUppDir(); void SetVar(const String& var, const String& val, bool save = true); +String GetCurrentBuildMethod(); +String GetCurrentMainPackage(); + String GetAnyFileName(const char *path); String GetAnyFileTitle(const char *path); String CatAnyPath(String path, const char *more); diff --git a/uppsrc/ide/Core/Core.upp b/uppsrc/ide/Core/Core.upp index 379c5adcb..8d3370549 100644 --- a/uppsrc/ide/Core/Core.upp +++ b/uppsrc/ide/Core/Core.upp @@ -14,6 +14,7 @@ file Host.h, Host.cpp, BinObj.cpp, + src.tpp, Info readonly separator, Copying; diff --git a/uppsrc/ide/Cpp.cpp b/uppsrc/ide/Cpp.cpp index 9571483d1..63f405abf 100644 --- a/uppsrc/ide/Cpp.cpp +++ b/uppsrc/ide/Cpp.cpp @@ -23,13 +23,17 @@ const Array& GetTypeItems(const String& type) Vector GetTypeBases(const String& type) { const Array& n = GetTypeItems(type); - for(int i = 0; i < n.GetCount(); i = FindNext(n, i)) { + String bases; + for(int i = 0; i < n.GetCount(); i++) { const CppItem& im = n[i]; if(im.IsType()) - return Split(im.qptype, ';'); + bases << im.qptype << ';'; } - Vector empty; - return empty; + Index r; + Vector h = Split(bases, ';'); + for(int i = 0; i < h.GetCount(); i++) + r.FindAdd(h[i]); + return r.PickKeys(); } String ParseTemplatedType(const String& type, Vector& tparam) @@ -106,32 +110,43 @@ void ResolveTParam(Vector& type, const Vector& tparam) void AssistScanError(int line, const String& text) { -#ifdef _DEBUG_X_0 +#ifdef _DEBUG PutVerbose(String().Cat() << "(" << line << "): " << text); #endif } void AssistEditor::Context(Parser& parser, int pos) { - theide->ScanFile(); + theide->ScanFile(false); String s = Get(0, pos); StringStream ss(s); + + Cpp cpp; + cpp.Preprocess(theide->editfile, ss, GetMasterFile(theide->editfile)); + parser.dobody = true; - parser.Do(ss, IgnoreList(), CodeBase(), Null, callback(AssistScanError)); - QualifyTypes(CodeBase(), parser.current_scope, parser.current); + StringStream pin(cpp.output); + parser.Do(pin, CodeBase(), Null, Null, GetFileTitle(theide->editfile), callback(AssistScanError), + Vector(), cpp.namespace_stack, cpp.namespace_using); // needs CodeBase to identify type names + +// QualifyTypes(CodeBase(), parser.current_scope, parser.current); inbody = parser.IsInBody(); -#ifdef _DEBUG_X_0 +#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 } -String Qualify(const String& scope, const String& type) +String Qualify(const String& scope, const String& type, const String& usings) { - return Qualify(CodeBase(), scope, type); + return Qualify(CodeBase(), scope, type, usings); } -void AssistEditor::ExpressionType(const String& ttype, const Vector& xp, int ii, +void AssistEditor::ExpressionType(const String& ttype, const String& usings, + const Vector& xp, int ii, Index& typeset, bool variable, bool can_shortcut_operator, Index& visited_bases, int lvl) @@ -153,12 +168,12 @@ void AssistEditor::ExpressionType(const String& ttype, const Vector& xp, String id = xp[ii]; int q = id.ReverseFind(':'); if(q > 0 && id[q - 1] == ':') { - type = ResolveTParam(Qualify(ttype, id.Mid(0, q - 1)), tparam); + type = ResolveTParam(Qualify(ttype, id.Mid(0, q - 1), usings), tparam); id = id.Mid(q + 1); } LLOG("ExpressionType " << type << " ii: " << ii << " id:" << id << " variable:" << variable); if(*id == '.' || (!variable && !iscid(*id))) { - ExpressionType(ttype, xp, ii + 1, typeset, false, lvl + 1); + ExpressionType(ttype, usings, xp, ii + 1, typeset, false, lvl + 1); return; } bool shortcut_oper = false; @@ -168,7 +183,7 @@ void AssistEditor::ExpressionType(const String& ttype, const Vector& xp, LLOG("id as: " << id); } Index< Tuple2 > mtype; - for(int i = 0; i < n.GetCount(); i = ::FindNext(n, i)) { + for(int i = 0; i < n.GetCount(); i++) { const CppItem& m = n[i]; if(m.name == id) { LLOG("Member " << m.qtype << "'" << m.name << "'"); @@ -176,7 +191,7 @@ void AssistEditor::ExpressionType(const String& ttype, const Vector& xp, } } for(int i = 0; i < mtype.GetCount(); i++) - ExpressionType(ResolveTParam(mtype[i].a, tparam), xp, ii + 1, typeset, mtype[i].b, lvl + 1); + ExpressionType(ResolveTParam(mtype[i].a, tparam), usings, xp, ii + 1, typeset, mtype[i].b, lvl + 1); if(typeset.GetCount() != c0 || IsNull(type)) return; @@ -187,19 +202,19 @@ void AssistEditor::ExpressionType(const String& ttype, const Vector& xp, for(int i = 0; i < base.GetCount(); i++) if(visited_bases.Find(base[i]) < 0) { visited_bases.Add(base[i]); - ExpressionType(base[i], xp, ii, typeset, variable, false, visited_bases, lvl + 1); + ExpressionType(base[i], usings, xp, ii, typeset, variable, false, visited_bases, lvl + 1); if(typeset.GetCount() != c0) return; } if(shortcut_oper) - ExpressionType(ttype, xp, ii + 1, typeset, false, lvl + 1); + ExpressionType(ttype, usings, xp, ii + 1, typeset, false, lvl + 1); } -void AssistEditor::ExpressionType(const String& type, const Vector& xp, int ii, +void AssistEditor::ExpressionType(const String& type, const String& usings, const Vector& xp, int ii, Index& typeset, bool variable, int lvl) { Index visited_bases; - ExpressionType(type, xp, ii, typeset, variable, true, visited_bases, lvl + 1); + ExpressionType(type, usings, xp, ii, typeset, variable, true, visited_bases, lvl + 1); } /* void AssistEditor::ExpressionType(const String& type, const Vector& xp, int ii, @@ -216,29 +231,29 @@ Index AssistEditor::ExpressionType(const Parser& parser, const Vector= 0) { - String type = Qualify(parser.current_scope, parser.local[q].type); + String type = Qualify(parser.current_scope, parser.local[q].type, parser.context.namespace_using); LLOG("Found type local: " << type << " in scope: " << parser.current_scope); - ExpressionType(type, xp, 1, typeset, !parser.local[q].isptr, 0); + ExpressionType(type, parser.context.namespace_using, xp, 1, typeset, !parser.local[q].isptr, 0); return typeset; } - ExpressionType(parser.current_scope, xp, 0, typeset, false, 0); + ExpressionType(parser.current_scope, parser.context.namespace_using, xp, 0, typeset, false, 0); if(typeset.GetCount()) return typeset; if(xp.GetCount() >= 2 && xp[1] == "()") { - String qtype = Qualify(parser.current_scope, xp[0]); + String qtype = Qualify(parser.current_scope, xp[0], parser.context.namespace_using); Vector tparam; if(CodeBase().Find(ParseTemplatedType(qtype, tparam)) >= 0) { LLOG("Is constructor " << qtype); - ExpressionType(qtype, xp, 2, typeset, false, 0); + ExpressionType(qtype, parser.context.namespace_using, xp, 2, typeset, false, 0); return typeset; } } - ExpressionType("", xp, 0, typeset, false, 0); + ExpressionType("", parser.context.namespace_using, xp, 0, typeset, false, 0); return typeset; } @@ -253,7 +268,15 @@ int CharFilterT(int c) return c >= '0' && c <= '9' ? "TUVWXYZMNO"[c - '0'] : c; } -void AssistEditor::GatherItems(const String& type, bool only_public, Index& in_types, bool types) +void AssistEditor::AssistItemAdd(const String& scope, const CppItem& m, int typei) +{ + CppItemInfo& f = assist_item.Add(m.name); + f.typei = typei; + f.scope = scope; + (CppItem&)f = m; +} + +void AssistEditor::GatherItems0(const String& type, bool only_public, Index& in_types, bool types) { LLOG("GatherItems " << type); if(in_types.Find(type) >= 0) { @@ -270,17 +293,13 @@ void AssistEditor::GatherItems(const String& type, bool only_public, Index"); for(int i = 0; i < CodeBase().GetCount(); i++) { - String n = CodeBase().GetKey(i); - if(n.GetLength() > ntp.GetLength() && memcmp(~ntp, ~n, ntp.GetLength()) == 0) { + String nest = CodeBase().GetKey(i); + if(nest.GetLength() > ntp.GetLength() && memcmp(~ntp, ~nest, ntp.GetLength()) == 0) { Array& n = CodeBase()[i]; - for(int i = 0; i < n.GetCount(); i = ::FindNext(n, i)) { + for(int i = 0; i < n.GetCount(); i++) { const CppItem& m = n[i]; - if(m.IsType()) { - CppItemInfo& f = assist_item.Add(m.name); - f.typei = typei; - (CppItem&)f = m; - break; - } + if(m.IsType()) + AssistItemAdd(nest, m, typei); } } } @@ -289,13 +308,13 @@ void AssistEditor::GatherItems(const String& type, bool only_public, Index b = Split(base, ';'); + Index 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); + GatherItems0(b[i], only_public, in_types, types); } } in_types.Drop(); } + +bool OrderAssistItems(const CppItemInfo& a, const CppItemInfo& b) +{ + if(a.impl != b.impl) + return b.impl; + return a.qitem < b.qitem; +} + +void AssistEditor::GatherItems(const String& type, bool only_public, Index& in_types, bool types) +{ + int i0 = assist_item.GetCount(); + GatherItems0(type, only_public, in_types, types); + StableSort(assist_item.Begin() + i0, assist_item.End(), OrderAssistItems); + Vector remove; + int i = i0; + while(i < assist_item.GetCount()) { + int ii = i; + i++; + while(i < assist_item.GetCount() && assist_item[i].qitem == assist_item[ii].qitem) + remove.Add(i++); + i++; + } + assist_item.Remove(remove); +} diff --git a/uppsrc/ide/Errors.cpp b/uppsrc/ide/Errors.cpp index 7ab5bf6a6..a8e25b7ec 100644 --- a/uppsrc/ide/Errors.cpp +++ b/uppsrc/ide/Errors.cpp @@ -62,7 +62,7 @@ bool Ide::FindLineError(const String& ln, FindLineErrorCache& cache, ErrorInfo& } } file = FollowCygwinSymlink(file); - if(IsFullPath(file) && FileExists(f.file) && IsTextFile(f.file)) { + if(IsFullPath(file) && FileExists(file) && IsTextFile(file)) { f.file = file; while(*s && !IsDigit(*s)) { if(*s == '/' || IsAlpha(*s)) @@ -95,8 +95,7 @@ bool Ide::FindLineError(const String& ln, FindLineErrorCache& cache, ErrorInfo& if(is_java && f.file.GetLength() > upplen && !MemICmp(f.file, uppout, upplen) && f.file[upplen] == DIR_SEP) { // check for preprocessed file FileIn fi(f.file); - if(fi.IsOpen()) - { + if(fi.IsOpen()) { String fake_file = f.file; int fake_line = 1; int file_line = 1; @@ -464,7 +463,7 @@ void ElepDisplay::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color DoPaint(w, r, q, ink, paper, style); } -void Ide::ConsoleLine(const String& line) +void Ide::ConsoleLine(const String& line, bool assist) { if(linking) { linking_line.Add(line); @@ -472,6 +471,8 @@ void Ide::ConsoleLine(const String& line) } ErrorInfo f; if(FindLineError(line, error_cache, f)) { + if(assist) + f.kind = 1; if(findarg(f.kind, 1, 2) >= 0 || error.GetCount() == 0) { Color paper = HighlightSetup::GetHlStyle(f.kind == 1 ? HighlightSetup::PAPER_ERROR : HighlightSetup::PAPER_WARNING).color; diff --git a/uppsrc/ide/FindInFiles.cpp b/uppsrc/ide/FindInFiles.cpp index b03b27ed3..54c9e9d96 100644 --- a/uppsrc/ide/FindInFiles.cpp +++ b/uppsrc/ide/FindInFiles.cpp @@ -429,6 +429,9 @@ void FindInFilesDlg::Sync() FindInFilesDlg::FindInFilesDlg() { regexp <<= style <<= THISBACK(Sync); + readonly.Add(Null, "All files"); + readonly.Add(0, "Writable"); + readonly.Add(1, "Read only"); readonly <<= Null; workspace <<= THISBACK(Sync); } diff --git a/uppsrc/ide/Goto.cpp b/uppsrc/ide/Goto.cpp index 3f203e804..91c609d63 100644 --- a/uppsrc/ide/Goto.cpp +++ b/uppsrc/ide/Goto.cpp @@ -56,7 +56,7 @@ void GotoDlg::SyncList() for(int i = 0; i < item.GetCount(); i++) { const CppItemInfo& f = item[i]; if(ToLower(f.name).Find(n) >= 0 && (IsNull(typei) || typei == f.typei) && (IsNull(scope) || scope == f.scope)) { - list.Add(f.scope, RawToValue(f), f.item, f.line, GetCppFile(f.file), f.scope); + list.Add(f.scope, RawToValue(f), f.item, f.line, GetSourceFilePath(f.file), f.scope); nc.FindAdd(f.scope); } } @@ -69,7 +69,7 @@ void GotoDlg::SyncList() (ci ? q && memcmp_i(n, f.name, n.GetLength()) == 0 : q == 0)) && (IsNull(typei) || typei == f.typei) && (IsNull(scope) || scope == f.scope)) { - list.Add(f.scope, RawToValue(f), f.item, f.line, GetCppFile(f.file), f.scope); + list.Add(f.scope, RawToValue(f), f.item, f.line, GetSourceFilePath(f.file), f.scope); nc.FindAdd(f.scope); } } @@ -118,7 +118,7 @@ struct CppItemInfoSortLine { struct CppItemInfoSortGlobal { bool operator()(const CppItemInfo& a, const CppItemInfo& b) const { return CombineCompare(a.scope, b.scope) - (GetCppFile(a.file), GetCppFile(b.file)) + (GetSourceFilePath(a.file), GetSourceFilePath(b.file)) (a.line, b.line) < 0; } }; @@ -143,7 +143,7 @@ GotoDlg::GotoDlg(const String& s) mf.scope = base.GetKey(i); mf.virt = false; mf.access = m.impl ? (int)WITHBODY : (int)PUBLIC; - mf.item = global ? String().Cat() << GetFileName(GetCppFile(m.file)) << " (" << m.line << ')' + mf.item = global ? String().Cat() << GetFileName(GetSourceFilePath(m.file)) << " (" << m.line << ')' : AsString(m.line); mf.typei = 0; item.Add(mf); @@ -243,11 +243,14 @@ bool Ide::SwapSIf(const char *cref) if(q < 0) return false; const Array& n = CodeBase()[q]; - String qitem = QualifyKey(CodeBase(), p.current_scope, p.current_key); + String qitem = QualifyKey(CodeBase(), p.current_scope, p.current_key, p.context.namespace_using); if(cref && MakeCodeRef(p.current_scope, p.current_key) != cref) return false; q = FindItem(n, qitem); - int count = q >= 0 ? GetCount(n, q) : 0; + int count = 0; + for(int i = 0; i < n.GetCount(); i++) + if(n[i].qitem == qitem) + count++; if(!cref && count < 2) { int typei = -1; for(int i = 0; i < n.GetCount(); i++) { @@ -262,14 +265,14 @@ bool Ide::SwapSIf(const char *cref) GotoCpp(n[typei]); return false; } - if(count < 1) + if(count < 1 || IsNull(editfile)) return false; - int file = GetCppFileIndex(editfile); + int file = GetSourceFileIndex(editfile); int line = p.current.line; LLOG("SwapS line: " << line); int i; for(i = 0; i < count; i++) { - LLOG("file: " << GetCppFile(n[q + i].file) << ", line: " << n[q + i].line); + LLOG("file: " << GetSourceFilePath(n[q + i].file) << ", line: " << n[q + i].line); if(n[q + i].file == file && n[q + i].line == line) { i++; break; diff --git a/uppsrc/ide/Jump.cpp b/uppsrc/ide/Jump.cpp index 66051e69c..4dd983e72 100644 --- a/uppsrc/ide/Jump.cpp +++ b/uppsrc/ide/Jump.cpp @@ -35,7 +35,7 @@ void JumpDlg::GoTo() { if(navlines.IsCursor()) { const NavLine& l = navlines.Get(0).To(); - theide->GotoPos(GetCppFile(l.file), l.line); + theide->GotoPos(GetSourceFilePath(l.file), l.line); } } diff --git a/uppsrc/ide/Methods.cpp b/uppsrc/ide/Methods.cpp index 9ebfff7dd..0cd05958d 100644 --- a/uppsrc/ide/Methods.cpp +++ b/uppsrc/ide/Methods.cpp @@ -423,6 +423,32 @@ void Ide::SetupBuildMethods() break; } } + SyncCodeBase(); SyncBuildMode(); SetBar(); } + +String Ide::GetIncludePath() +{ + SetupDefaultMethod(); + VectorMap bm = GetMethodVars(method); + String include = GetVar("UPP") + ';' + bm.Get("INCLUDE", "") +#ifdef PLATFORM_POSIX + + ";/usr/include;/usr/local/include" +#endif + ; + + const Workspace& wspc = GetIdeWorkspace(); + for(int i = 0; i < wspc.GetCount(); i++) { + const Package& pkg = wspc.GetPackage(i); + for(int j = 0; j < pkg.include.GetCount(); j++) + MergeWith(include, ";", SourcePath(wspc[i], pkg.include[j].text)); + } + + return include; +} + +String Ide::IdeGetIncludePath() +{ + return GetIncludePath(); +} diff --git a/uppsrc/ide/Navigator.cpp b/uppsrc/ide/Navigator.cpp index 26710c8d3..78b42d92d 100644 --- a/uppsrc/ide/Navigator.cpp +++ b/uppsrc/ide/Navigator.cpp @@ -2,6 +2,19 @@ #define LTIMING(x) // RTIMING(x) +String FormatNest(const String& nest) +{ + if(nest.StartsWith("@")) { + String h = "[anonymous] ("; + int q = nest.ReverseFind('/'); + if(q >= 0) + h << nest.Mid(q + 1); + h << ")"; + return h; + } + return nest; +} + int CharFilterNavigator(int c) { return c == ':' ? '.' : IsAlNum(c) || c == '_' || c == '.' ? ToUpper(c) : 0; @@ -81,9 +94,9 @@ void Navigator::SyncCursor() search.NullText("Symbol/lineno " + k); search.Tip(IsNull(search) ? String() : "Clear " + k); - if(!navigating) { + if(!navigating && theide->editfile.GetCount()) { navlines.KillCursor(); - int q = linefo.Find(GetCppFileIndex(theide->editfile)); + int q = linefo.Find(GetSourceFileIndex(theide->editfile)); if(q < 0) return; navigating = true; @@ -98,8 +111,10 @@ void Navigator::SyncCursor() void Navigator::SyncLines() { + if(IsNull(theide->editfile)) + return; int ln = GetCurrentLine() + 1; - int fi = GetCppFileIndex(theide->editfile); + int fi = GetSourceFileIndex(theide->editfile); int q = -1; for(int i = 0; i < navlines.GetCount(); i++) { const NavLine& l = navlines.Get(i, 0).To(); @@ -121,7 +136,7 @@ void Navigator::SyncNavLines() if(ii >= 0 && ii < litem.GetCount()) { Vector l = GetNavLines(*litem[ii]); for(int i = 0; i < l.GetCount(); i++) { - String p = GetCppFile(l[i].file); + String p = GetSourceFilePath(l[i].file); navlines.Add(RawToValue(l[i])); } navlines.ScrollTo(sc); @@ -134,7 +149,7 @@ int Navigator::LineDisplay::DoPaint(Draw& w, const Rect& r, const Value& q, Colo w.DrawRect(r, paper); const NavLine& l = q.To(); x += r.left; - String p = GetCppFile(l.file); + String p = GetSourceFilePath(l.file); int y = r.top + (r.GetHeight() - StdFont().GetCy()) / 2; PaintTeXt(w, x, y, GetFileName(GetFileFolder(p)) + "/", StdFont(), ink); PaintTeXt(w, x, y, GetFileName(p), StdFont().Bold(), ink); @@ -162,14 +177,14 @@ void Navigator::GoToNavLine() int ii = navlines.GetClickPos().y; if(ii >= 0 && ii < navlines.GetCount() && theide) { const NavLine& l = navlines.Get(ii, 0).To(); - theide->GotoPos(GetCppFile(l.file), l.line); + theide->GotoPos(GetSourceFilePath(l.file), l.line); } } bool Navigator::NavLine::operator<(const NavLine& b) const { - String p1 = GetCppFile(file); - String p2 = GetCppFile(b.file); + String p1 = GetSourceFilePath(file); + String p2 = GetSourceFilePath(b.file); return CombineCompare(!impl, !b.impl) (GetFileExt(p1), GetFileExt(p2)) // .h > .c (GetFileName(p1), GetFileName(p2)) @@ -212,12 +227,12 @@ void Navigator::Navigate() Vector l = GetNavLines(m); int q = l.GetCount() - 1; for(int i = q; i >= 0; i--) - if(GetCppFile(l[i].file) == theide->editfile && l[i].line == ln) { + if(GetSourceFilePath(l[i].file) == theide->editfile && l[i].line == ln) { q = (i + l.GetCount() - 1) % l.GetCount(); break; } if(q >= 0 && q < l.GetCount()) - theide->GotoPos(GetCppFile(l[q].file), l[q].line); + theide->GotoPos(GetSourceFilePath(l[q].file), l[q].line); } } navigating = false; @@ -326,8 +341,9 @@ int Navigator::NavigatorDisplay::DoPaint(Draw& w, const Rect& r, const Value& q, : SColorFace); if(m.kind == KIND_FILE) return PaintFileName(w, r, m.type, ink); - w.DrawText(x, y, m.type, StdFont().Bold(), ink); - return GetTextSize(m.type, StdFont().Bold()).cx; + String h = FormatNest(m.type); + w.DrawText(x, y, h, StdFont().Bold(), ink); + return GetTextSize(h, StdFont().Bold()).cx; } w.DrawRect(r, paper); @@ -381,7 +397,7 @@ void Navigator::NavGroup(bool local) if(m.kind == TYPEDEF) g.Trim(max(g.ReverseFind("::"), 0)); if(IsNull(g)) - g = "\xff" + GetCppFile(m.decl_file); + g = "\xff" + GetSourceFilePath(m.decl_file); if(local) if(gitem.GetCount() && gitem.TopKey() == g) gitem.Top().Add(&m); @@ -433,7 +449,9 @@ void Navigator::Search() int lineno = StrInt(s); gitem.Clear(); nitem.Clear(); - int fileii = GetCppFileIndex(theide->editfile); + if(IsNull(theide->editfile)) + return; + int fileii = GetSourceFileIndex(theide->editfile); if(!IsNull(lineno)) { NavItem& m = nitem.Add(); m.type = "Go to line " + AsString(lineno); @@ -473,13 +491,13 @@ void Navigator::Search() bool local = sorting && IsNull(s); for(int i = 0; i < b.GetCount(); i++) { String nest = b.GetKey(i); - bool foundnest = wholeclass ? ToUpper(nest) == search_nest - : ToUpper(nest).Find(search_nest) >= 0; + bool foundnest = (wholeclass ? ToUpper(nest) == search_nest + : ToUpper(nest).Find(search_nest) >= 0) && *nest != '@'; if(local || foundnest || both) { const Array& ci = b[i]; for(int j = 0; j < ci.GetCount(); j++) { const CppItem& m = ci[j]; - if(local ? m.file == fileii : m.uname.Find(search_name) >= 0 || both && foundnest) { + if(local ? m.file == fileii : *m.uname != '@' && m.uname.Find(search_name) >= 0 || both && foundnest) { String key = nest + '\1' + m.qitem; int q = imap.Find(key); if(q < 0) { @@ -497,8 +515,6 @@ void Navigator::Search() else { NavItem& mm = imap[q]; String n = mm.natural; - if(m.natural.GetCount() > mm.natural.GetCount()) - mm.natural = m.natural; if(!m.impl && (!mm.decl || CombineCompare(mm.decl_file, m.file)(mm.decl_line, m.line) < 0)) { @@ -549,6 +565,8 @@ int Navigator::ScopeDisplay::DoPaint(Draw& w, const Rect& r, const Value& q, Col String h = q; if(*h == '\xff') return PaintFileName(w, r, h, ink); + else + h = FormatNest(h); w.DrawText(r.left, r.top, h, StdFont().Bold(), ink); return GetTextSize(h, StdFont().Bold()).cx; } @@ -580,7 +598,7 @@ void Navigator::Scope() if(all) { NavItem& m = nest_item.Add(); m.kind = kind; - m.type = grp; + m.type = FormatNest(grp); litem.Add(&m); } else diff --git a/uppsrc/ide/OutputMode.cpp b/uppsrc/ide/OutputMode.cpp index f9f4d5d25..8a4fb5ce4 100644 --- a/uppsrc/ide/OutputMode.cpp +++ b/uppsrc/ide/OutputMode.cpp @@ -450,6 +450,7 @@ void Ide::SetMethod(const String& m) { method = m; current_builder = GetMethodVars(method).Get("BUILDER", ""); + NewCodeBase(); } void Ide::SelectMethod() diff --git a/uppsrc/ide/Thisbacks.cpp b/uppsrc/ide/Thisbacks.cpp index e57c9ec88..d6102fd81 100644 --- a/uppsrc/ide/Thisbacks.cpp +++ b/uppsrc/ide/Thisbacks.cpp @@ -54,8 +54,8 @@ ThisbacksDlg::ThisbacksDlg(const String& scope) if(q < 0) return; const Array& n = CodeBase()[q]; - for(int i = 0; i < n.GetCount(); i = FindNext(n, i)) - nname.Add(n[i].name); + for(int i = 0; i < n.GetCount(); i++) + nname.FindAdd(n[i].name); Index done; GatherCallbacks("", done, scope, PRIVATE); } diff --git a/uppsrc/ide/Virtuals.cpp b/uppsrc/ide/Virtuals.cpp index 90c37aa38..c2d8e78a6 100644 --- a/uppsrc/ide/Virtuals.cpp +++ b/uppsrc/ide/Virtuals.cpp @@ -19,7 +19,7 @@ void GatherVirtuals(ArrayMap& item, const String& scope, if(q < 0) return; const Array& m = CodeBase()[q]; - for(int i = 0; i < m.GetCount(); i = FindNext(m, i)) { + for(int i = 0; i < m.GetCount(); i++) { const CppItem& im = m[i]; if(im.IsType()) { Vector b = Split(im.qptype, ';'); @@ -38,7 +38,7 @@ void GatherVirtuals(ArrayMap& item, const String& scope, item[q].overed = scope; else if(im.virt) { - AssistItemInfo& f = item.Add(k); + AssistItemInfo& f = item.GetAdd(k); f.defined = f.overed = scope; f.name = im.name; (CppItem&)f = im; diff --git a/uppsrc/ide/ide.cpp b/uppsrc/ide/ide.cpp index d5ffe6e87..cb7ae0483 100644 --- a/uppsrc/ide/ide.cpp +++ b/uppsrc/ide/ide.cpp @@ -133,7 +133,6 @@ void Ide::SetMain(const String& package) mainconfigname.Clear(); mainconfigparam.Clear(); ScanWorkspace(); - SyncWorkspace(); LoadFromFile(THISBACK(SerializeWorkspace), WorkspaceFile()); editorsplit.Zoom(0); UpdateFormat(); @@ -147,9 +146,10 @@ void Ide::SetMain(const String& package) SetHdependDirs(); SetBar(); HideBottom(); + SyncUsc(); + NewCodeBase(); if(IsNull(e)) e = GetFirstFile(); - StartCodeBase(); EditFile(e); } diff --git a/uppsrc/ide/ide.h b/uppsrc/ide/ide.h index b0df247dc..eda6355c2 100644 --- a/uppsrc/ide/ide.h +++ b/uppsrc/ide/ide.h @@ -283,7 +283,7 @@ int memcmp_i(const char *s, const char *t, int n); String ParseTemplatedType(const String& type, Vector& tparam); String ResolveTParam(const String& type, const Vector& tparam); void ResolveTParam(Vector& type, const Vector& tparam); -String Qualify(const String& scope, const String& type); +String Qualify(const String& scope, const String& type, const String& usings); int CharFilterMacro(int c); int CharFilterFileName(int c); @@ -379,6 +379,8 @@ public: virtual String IdeGetFileName(); virtual String IdeGetNestFolder(); + virtual String IdeGetIncludePath(); + virtual bool IsPersistentFindReplace(); virtual void ConsoleShow(); @@ -834,6 +836,7 @@ public: void ToggleStopOnErrors(); One CreateHostRunDir(); void OpenOutputFolder(); + void PreprocessInternal(); void DebugMenu(Bar& menu); void RunArgs(); @@ -876,7 +879,7 @@ public: void SearchCode(); void Goto(); void GotoGlobal(); - void ScanFile(); + void ScanFile(bool check_macros); bool SwapSIf(const char *cref); void SwapS(); void FindId(const String& id); @@ -947,7 +950,7 @@ public: }; FindLineErrorCache error_cache; - void ConsoleLine(const String& line); + void ConsoleLine(const String& line, bool assist = false); void ConsoleRunEnd(); void SyncErrorsMessage(); void ShowError(); @@ -1034,6 +1037,8 @@ public: void ShowTopics(); void ShowTopicsWin(); + String GetIncludePath(); + void TopicBack(); void SetupBars(); diff --git a/uppsrc/ide/ide.key b/uppsrc/ide/ide.key index 93241bdee..2298e3033 100644 --- a/uppsrc/ide/ide.key +++ b/uppsrc/ide/ide.key @@ -17,7 +17,7 @@ KEY(FINDINFILES, "Find in Files..", K_CTRL_F|K_SHIFT) KEY(REPLACEINFILES, "Replace in Files..", K_CTRL_H|K_SHIFT) KEY(FINDFILE, "Find file..", K_ALT_F|K_SHIFT) KEY(EDITASTEXT, "Edit as text", K_CTRL_T) -KEY(EDITASHEX, "View as binary", 0) +KEY(EDITASHEX, "View as binary", K_CTRL_B) KEY(DESIGNER, "Edit using the designer", K_CTRL_T) KEY2(CUTLINE, "Cut line", K_CTRL_Y, K_CTRL_L) KEY(DELLINE, "Delete line", 0) diff --git a/uppsrc/ide/ide.lay b/uppsrc/ide/ide.lay index 7aec6e38b..2ad1e16ee 100644 --- a/uppsrc/ide/ide.lay +++ b/uppsrc/ide/ide.lay @@ -86,7 +86,7 @@ LAYOUT(FindInFilesLayout, 568, 152) ITEM(Option, ignorecase, SetLabel(t_("&Ignore case")).LeftPosZ(208, 84).BottomPosZ(34, 18)) ITEM(Option, samecase, SetLabel(t_("Mimic case")).LeftPosZ(288, 100).BottomPosZ(34, 18)) ITEM(Option, regexp, SetLabel(t_("RegEx")).LeftPosZ(368, 112).BottomPosZ(34, 18)) - ITEM(Option, readonly, ThreeState(true).SetLabel(t_("Read-only files")).LeftPosZ(464, 142).BottomPosZ(34, 18)) + ITEM(DropList, readonly, LeftPosZ(452, 112).BottomPosZ(34, 18)) ITEM(Button, ok, SetLabel(t_("OK")).RightPosZ(76, 64).BottomPosZ(6, 22)) ITEM(Button, cancel, SetLabel(t_("Cancel")).RightPosZ(8, 64).BottomPosZ(6, 22)) ITEM(Option, workspace, SetLabel(t_("In workspace folders")).LeftPosZ(428, 136).TopPosZ(52, 20)) diff --git a/uppsrc/ide/idebar.cpp b/uppsrc/ide/idebar.cpp index 69f1443fe..1eb74461d 100644 --- a/uppsrc/ide/idebar.cpp +++ b/uppsrc/ide/idebar.cpp @@ -443,6 +443,8 @@ void Ide::BuildFileMenu(Bar& menu) menu.Add(b, "Show assembler code for " + GetFileName(editfile), THISBACK1(Preprocess, true)) .Key(AK_ASSEMBLERCODE) .Help("Compile the file into assembler code"); + if(console.verbosebuild) + menu.Add(b, "Internal Preprocess " + GetFileName(editfile), IdeImg::Header(), THISBACK(PreprocessInternal)); } void Ide::BuildPackageMenu(Bar& menu) @@ -575,7 +577,8 @@ void Ide::BrowseMenu(Bar& menu) menu.Add(!designer, AK_ABBR, callback(&editor, &AssistEditor::Abbr)); menu.Add(!designer, "Insert", THISBACK(InsertMenu)); menu.MenuSeparator(); - menu.Add("Rescan code", THISBACK(RescanCode)); + menu.Add("Check source files for changes", callback(SyncCodeBase)); + menu.Add("Reparse source files", THISBACK(RescanCode)); menu.MenuSeparator(); } menu.AddMenu(AK_CALC, IdeImg::calc(), THISBACK1(ToggleBottom, BCALC)) diff --git a/uppsrc/ide/idefile.cpp b/uppsrc/ide/idefile.cpp index 318127920..84c37ae4f 100644 --- a/uppsrc/ide/idefile.cpp +++ b/uppsrc/ide/idefile.cpp @@ -208,12 +208,12 @@ bool Ide::IsProjectFile(const String& f) const return false; } -void Ide::ScanFile() +void Ide::ScanFile(bool check_macros) { if(IsCppBaseFile()) { String s = ~editor; StringStream ss(s); - CodeBaseScan(ss, editfile); + CodeBaseScanFile(ss, editfile, check_macros); } } @@ -274,7 +274,7 @@ void Ide::SaveFile0(bool always) if(tm != FileGetTime(fn)) TouchFile(fn); if(IsProjectFile(fn) && ToUpper(GetFileExt(fn)) == ".LAY") - CodeBaseScanLay(fn); + CodeBaseScanFile(fn, true); return; } @@ -378,8 +378,10 @@ void Ide::SaveFile0(bool always) fd.filetime = edittime = ff.GetLastWriteTime(); } - if(editor.IsDirty()) - ScanFile(); + if(editor.IsDirty()) { + text_updated.Kill(); + ScanFile(true); + } editor.ClearDirty(); @@ -569,7 +571,7 @@ void Ide::EditFile0(const String& path, byte charset, bool astext, const String& void Ide::EditFileAssistSync() { - ScanFile(); + ScanFile(false); editor.Annotate(editfile); editor.SyncNavigator(); } @@ -687,10 +689,8 @@ void Ide::CheckFileUpdate() "Would you like to reload the file or to keep changes made in the IDE ?", "Reload", "Keep")) return; - if(IsCppBaseFile()) { - FileIn in(editfile); - CodeBaseScan(in, editfile); - } + if(IsCppBaseFile()) + CodeBaseScanFile(editfile, false); ReloadFile(); } diff --git a/uppsrc/ide/idetool.cpp b/uppsrc/ide/idetool.cpp index d23daacf0..87c39f626 100644 --- a/uppsrc/ide/idetool.cpp +++ b/uppsrc/ide/idetool.cpp @@ -57,7 +57,7 @@ void Ide::GotoPos(String path, int line) void Ide::GotoCpp(const CppItem& pos) { - GotoPos(GetCppFile(pos.file), pos.line); + GotoPos(GetSourceFilePath(pos.file), pos.line); } void Ide::RescanCode() diff --git a/uppsrc/ide/idewin.cpp b/uppsrc/ide/idewin.cpp index a6aaa2c5e..d0dcf0a13 100644 --- a/uppsrc/ide/idewin.cpp +++ b/uppsrc/ide/idewin.cpp @@ -58,6 +58,16 @@ void Ide::SwapPackagesFiles() wesplit.Zoom(wesplit.GetZoom() == 1 ? -1 : 1); } +void IdePutErrorLine(const String& line) +{ + Ide *ide = dynamic_cast(TheIde()); + if(ide && ide->console.verbosebuild) { + ide->SetBottom(Ide::BERRORS); + ide->ConsoleRunEnd(); + ide->ConsoleLine(line, true); + } +} + void Ide::ConsoleClear() { console <<= Null; @@ -185,6 +195,18 @@ bool Ide::IdeIsDebug() const return debugger; } +String GetCurrentBuildMethod() +{ + Ide *ide = dynamic_cast(TheIde()); + return ide ? ide->method : String(); +} + +String GetCurrentMainPackage() +{ + Ide *ide = dynamic_cast(TheIde()); + return ide ? ide->main : String(); +} + void Ide::IdeEndDebug() { console.Kill(); @@ -401,7 +423,7 @@ Ide::Ide() error.WhenSel = THISBACK(SelError); error.WhenLeftClick = THISBACK(ShowError); ffound.WhenSel = ffound.WhenLeftClick = THISBACK(ShowFound); - console.WhenLine = THISBACK(ConsoleLine); + console.WhenLine = THISBACK1(ConsoleLine, false); console.WhenRunEnd = THISBACK(ConsoleRunEnd); addnotes = false; @@ -1040,6 +1062,14 @@ void AppMain___() Ini::user_log = true; } + String ppcfg = ConfigFile("pp_config.json"); + #ifndef _DEBUG + if(!FileExists(ppcfg)) + #endif + SaveFile(ppcfg, GetStdConfig()); + + LoadPPConfig(LoadFile(ppcfg)); + ide.LoadLastMain(); if(clset || ide.OpenMainPackage()) { ide.SaveLastMain(); diff --git a/uppsrc/plugin/lz4/lz4upp.cpp b/uppsrc/plugin/lz4/lz4upp.cpp index dad4ab656..ab65ab893 100644 --- a/uppsrc/plugin/lz4/lz4upp.cpp +++ b/uppsrc/plugin/lz4/lz4upp.cpp @@ -26,7 +26,7 @@ void Lz4::Decompress() void Lz4::PutOut(const void *ptr, int size) { - LLOG("ZLIB PutOut " << out.GetCount()); + LLOG("LZ4 PutOut " << out.GetCount()); out.Cat((const char *)ptr, (int)size); }