From 4ec77506fb9da07412a7e3490399fbb3be8e1687 Mon Sep 17 00:00:00 2001 From: cxl Date: Sat, 18 Jul 2015 12:49:23 +0000 Subject: [PATCH] cpp: Expression refactored git-svn-id: svn://ultimatepp.org/upp/trunk@8700 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/CppBase/CppBase.h | 9 +- uppsrc/CppBase/CppBase.upp | 1 + uppsrc/CppBase/Expression.cpp | 289 ++++++++++++++++++++++++++++++++++ uppsrc/CppBase/Parser.cpp | 16 +- uppsrc/ide/Assist.cpp | 2 +- uppsrc/ide/Assist.h | 2 - uppsrc/ide/ContextGoto.cpp | 2 +- uppsrc/ide/Cpp.cpp | 266 +------------------------------ uppsrc/ide/ide.h | 3 +- 9 files changed, 320 insertions(+), 270 deletions(-) create mode 100644 uppsrc/CppBase/Expression.cpp diff --git a/uppsrc/CppBase/CppBase.h b/uppsrc/CppBase/CppBase.h index 5cbfe0733..c331c9435 100644 --- a/uppsrc/CppBase/CppBase.h +++ b/uppsrc/CppBase/CppBase.h @@ -617,6 +617,8 @@ public: const SrcFile &getPreprocessedFile() { return file; } + Vector GetNamespaces() const; + void Do(Stream& in, CppBase& _base, int file, int filetype, const String& title, Callback2 _err, const Vector& typenames, @@ -660,7 +662,12 @@ String QualifyKey(const CppBase& base, const String& scope, const String& type, void Qualify(CppBase& base); -// void Parse(Stream& s, CppBase& base, int file, int filetype, const String& title, Callback2 err); +const Array& GetTypeItems(const CppBase& codebase, const String& type); +String ParseTemplatedType(const String& type, Vector& tparam); +String ResolveTParam(const CppBase& codebase, const String& type, const Vector& tparam); +void ResolveTParam(const CppBase& codebase, Vector& type, const Vector& tparam); + +Index GetExpressionType(const CppBase& codebase, const Parser& parser, const Vector& xp); END_UPP_NAMESPACE diff --git a/uppsrc/CppBase/CppBase.upp b/uppsrc/CppBase/CppBase.upp index 7df05bbf9..a605790d3 100644 --- a/uppsrc/CppBase/CppBase.upp +++ b/uppsrc/CppBase/CppBase.upp @@ -20,6 +20,7 @@ file ScopeInfo.cpp, Qualify.cpp, CppItem.cpp, + Expression.cpp, Info readonly separator, Copying; diff --git a/uppsrc/CppBase/Expression.cpp b/uppsrc/CppBase/Expression.cpp new file mode 100644 index 000000000..5dc39f17c --- /dev/null +++ b/uppsrc/CppBase/Expression.cpp @@ -0,0 +1,289 @@ +#include "CppBase.h" + +#if 0 +#define LDUMP(x) DDUMP(x) +#define LDUMPC(x) DDUMPC(x) +#define LLOG(x) DLOG(x) +#else +#define LDUMP(x) +#define LDUMPC(x) +#define LLOG(x) +#endif + +#define LTIMING(x) // DTIMING(x) + +namespace Upp { + +const Array& GetTypeItems(const CppBase& codebase, const String& type) +{ + static Array sEmpty; + int q = codebase.Find(type); + if(q < 0) + return sEmpty; + return codebase[q]; +} + +String ParseTemplatedType(const String& type, Vector& tparam) +{ + const char *s = type; + String r; + while(*s) { + if(*s == '<') { + s++; + int lvl = 0; + String t; + while(*s) { + int c = *s++; + if(c == ',' && lvl == 0) { + tparam.Add(t); + t.Clear(); + } + else { + if(c == '>') { + if(lvl == 0) + break; + lvl--; + } + if(c == '<') + lvl++; + t.Cat(c); + } + } + tparam.Add(t); + break; + } + else + r.Cat(*s++); + } + LLOG("ParseTemplatedType " << type << " -> " << r); + LDUMPC(tparam); + return r; +} + +String ResolveTParam(const CppBase& codebase, const String& type, const Vector& tparam) +{ + LLOG("ResolveTParam " << type << ' ' << tparam); + String r; + const char *s = type; + while(*s) { + if(IsDigit(*s)) { + int i = *s++ - '0'; + if(i >= 0 && i < tparam.GetCount()) + r.Cat(tparam[i]); + } + else + if(iscib(*s)) + while(iscid(*s)) + r.Cat(*s++); + else + r.Cat(*s++); + } + LLOG("Resolved " << type << " -> " << r); + const Array& x = GetTypeItems(codebase, r); + if(x.GetCount() && x[0].kind == TYPEDEF) { + LLOG("Is typedef " << x[0].qtype << ';' << x[0].type << ';' << x[0].natural); + String h = x[0].qtype; + if(h != type && h != r) + return ResolveTParam(codebase, h, tparam); + return h; + } + return r; +} + +void ResolveTParam(const CppBase& codebase, Vector& type, const Vector& tparam) +{ + for(int i = 0; i < type.GetCount(); i++) + type[i] = ResolveTParam(codebase, type[i], tparam); +} + +struct ExpressionTyper { + const CppBase& codebase; + int scan_counter; // limit permutations + String context_type; + String usings; + const Vector& xp; + Index typeset; + const Parser& parser; + + Vector GetTypeBases(const String& type); + String ResolveReturnType(const CppItem& m, const Vector& tparam); + + void ExpressionType(const String& ttype, int ii, + bool variable, bool can_shortcut_operator, + Index& visited_bases, int lvl); + void ExpressionType(const String& ttype, int ii, bool variable, int lvl); + + Index ExpressionType(); + + ExpressionTyper(const CppBase& codebase, const Parser& parser, const Vector& xp); +}; + +ExpressionTyper::ExpressionTyper(const CppBase& codebase, const Parser& parser, const Vector& xp) +: codebase(codebase), parser(parser), xp(xp) +{ + scan_counter = 0; + context_type = parser.current_scope; + usings = parser.context.namespace_using; +} + +Vector ExpressionTyper::GetTypeBases(const String& type) +{ + const Array& n = GetTypeItems(codebase, type); + String bases; + for(int i = 0; i < n.GetCount(); i++) { + const CppItem& im = n[i]; + if(im.IsType()) + bases << im.qptype << ';'; + } + Index r; + Vector h = Split(bases, ';'); + for(int i = 0; i < h.GetCount(); i++) + r.FindAdd(h[i]); + return r.PickKeys(); +} + +String ExpressionTyper::ResolveReturnType(const CppItem& m, const Vector& tparam) +{ + if(m.tparam.GetCount()) { + int q = InScListIndex(m.qtype, m.tname); + if(q >= 0 && q < tparam.GetCount()) + return tparam[q]; + } + return m.qtype; +} + +void ExpressionTyper::ExpressionType(const String& ttype, int ii, + bool variable, bool can_shortcut_operator, + Index& visited_bases, int lvl) +{ + LLOG("--- ExpressionType " << scan_counter << ", lvl " << lvl << ", ttype " << ttype); + if(++scan_counter > 1000 || lvl > 100) // sort of ugly limitation of parsing permutations + return; + if(ii >= xp.GetCount()) { + LLOG("--- Final type: " << ttype); + typeset.FindAdd(ttype); + return; + } + LDUMP(ii); + LDUMP(xp[ii]); + LDUMP(can_shortcut_operator); + Vector tparam; + String type = ParseTemplatedType(ttype, tparam); + int c0 = typeset.GetCount(); + const Array& n = GetTypeItems(codebase, type); + LDUMP(type); + LDUMP(tparam); + if(codebase.namespaces.Find(ttype) < 0 && ttype.GetCount()) // do not search for namespace typedefs + for(int i = 0; i < n.GetCount(); i++) + if(n[i].kind == TYPEDEF) { + LLOG("typedef -> " << n[i].qtype); + ExpressionType(n[i].qtype, ii, variable, can_shortcut_operator, visited_bases, lvl + 1); + return; + } + String id = xp[ii]; + int q = id.ReverseFind(':'); + if(q > 0 && id[q - 1] == ':') { + type = ResolveTParam(codebase, Qualify(codebase, ttype, id.Mid(0, q - 1), usings), tparam); + id = id.Mid(q + 1); + } + if(id.Find('<') >= 0) // as in Single + id = ParseTemplatedType(id, tparam); + LLOG("ExpressionType " << type << " ii: " << ii << " id:" << id << " variable:" << variable); + + for(int i = 0; i < tparam.GetCount(); i++) // need to qualify template parameters + tparam[i] = Qualify(codebase, context_type, tparam[i], usings); + + bool shortcut_oper = false; + if(!iscid(*id) && *id != '.') { + shortcut_oper = can_shortcut_operator; + id = "operator" + id; + LLOG("id as: " << id); + } + if(*id == '.' || (!variable && !iscid(*id))) { + LLOG(". " << ttype); + ExpressionType(ttype, ii + 1, false, lvl + 1); + return; + } + LDUMP(id); + Index done; + for(int i = 0; i < n.GetCount(); i++) { + const CppItem& m = n[i]; + if(m.name == id) { + LLOG("Member " << m.qtype << " " << m.name); + String t = ResolveReturnType(m, tparam); + if(done.Find(t) < 0) { + bool skipfnpars = m.IsCode() && ii + 1 < xp.GetCount() && xp[ii + 1] == "()"; + ExpressionType(ResolveTParam(codebase, t, tparam), ii + skipfnpars + 1, + m.IsData() && !m.isptr, lvl + 1); + } + } + } + + if(typeset.GetCount() != c0 || IsNull(type)) + return; + Vector base = GetTypeBases(type); + LDUMPC(base); + ResolveTParam(codebase, base, tparam); + LDUMPC(base); + for(int i = 0; i < base.GetCount(); i++) + if(visited_bases.Find(base[i]) < 0) { + visited_bases.Add(base[i]); + ExpressionType(base[i], ii, variable, false, visited_bases, lvl + 1); + if(typeset.GetCount() != c0) + return; + } + + if(shortcut_oper) { + LLOG("Shortcut " << xp[ii] << ", ttype " << ttype); + ExpressionType(ttype, ii + 1, false, lvl + 1); + } +} + +void ExpressionTyper::ExpressionType(const String& ttype, int ii, bool variable, int lvl) +{ + Index bases; + ExpressionType(ttype, ii, false, true, bases, 0); +} + +Index ExpressionTyper::ExpressionType() +{ + LLOG("**** ExpressionType " << xp); + String type; + if(xp.GetCount() == 0) + return typeset; + if(xp[0] == "this") { + LLOG("this: " << type); + ExpressionType(context_type, 1, false, 0); + return typeset; + } + int q = parser.local.FindLast(xp[0]); + if(q >= 0) { + String type = Qualify(codebase, context_type, parser.local[q].type, parser.context.namespace_using); + LLOG("Found type local: " << type << " in scope: " << context_type); + ExpressionType(type, 1, !parser.local[q].isptr, 0); + return typeset; + } + ExpressionType(context_type, 0, false, 0); + if(typeset.GetCount()) + return typeset; + if(xp.GetCount() >= 2 && xp[1] == "()") { + String qtype = Qualify(codebase, context_type, xp[0], parser.context.namespace_using); + Vector tparam; + if(codebase.Find(ParseTemplatedType(qtype, tparam)) >= 0) { + LLOG("Is constructor " << qtype); + ExpressionType(qtype, 2, false, 0); + return typeset; + } + } + Vector ns = parser.GetNamespaces(); + for(int i = 0; i < ns.GetCount(); i++) + ExpressionType(ns[i], 0, false, 0); + return typeset; +} + +Index GetExpressionType(const CppBase& codebase, const Parser& parser, const Vector& xp) +{ // xp is a list of meaningful parts like "foo", "." , "Fn", "()", "->", "m", "[]" + return ExpressionTyper(codebase, parser, xp).ExpressionType(); +} + +}; \ No newline at end of file diff --git a/uppsrc/CppBase/Parser.cpp b/uppsrc/CppBase/Parser.cpp index 40e1b8ee2..75c496332 100644 --- a/uppsrc/CppBase/Parser.cpp +++ b/uppsrc/CppBase/Parser.cpp @@ -1798,13 +1798,17 @@ void Parser::Do(Stream& in, CppBase& _base, int filei_, int filetype_, } } -/* -void Parse(Stream& s, CppBase& base, int file, int filetype, const String& title, Callback2 _err) +Vector Parser::GetNamespaces() const { - LTIMING("Parse"); - Parser p; - p.Do(s, base, file, filetype, title, _err); + Vector ns; + Vector h = Split(current_scope, ':'); + while(h.GetCount()) { + ns.Add(Join(h, "::")); + h.Drop(); + } + ns.Append(Split(context.namespace_using, ';')); + ns.Add(""); // Add global namespace too + return ns; } -*/ END_UPP_NAMESPACE diff --git a/uppsrc/ide/Assist.cpp b/uppsrc/ide/Assist.cpp index 27344eaf6..fd0f24945 100644 --- a/uppsrc/ide/Assist.cpp +++ b/uppsrc/ide/Assist.cpp @@ -476,7 +476,7 @@ void AssistEditor::Assist() } else { GatherItems(parser.current_scope, false, in_types, true); - Vector ns = GetNamespaces(parser); + Vector ns = parser.GetNamespaces(); for(int i = 0; i < ns.GetCount(); i++) if(parser.current_scope != ns[i]) // Do not scan namespace already scanned GatherItems(ns[i], false, in_types, true); diff --git a/uppsrc/ide/Assist.h b/uppsrc/ide/Assist.h index 87eee89ae..4450f62eb 100644 --- a/uppsrc/ide/Assist.h +++ b/uppsrc/ide/Assist.h @@ -1,5 +1,3 @@ -Vector GetNamespaces(const Parser& parser); - struct Navigator { virtual int GetCurrentLine() = 0; diff --git a/uppsrc/ide/ContextGoto.cpp b/uppsrc/ide/ContextGoto.cpp index 6e4cd5a03..7958f2708 100644 --- a/uppsrc/ide/ContextGoto.cpp +++ b/uppsrc/ide/ContextGoto.cpp @@ -233,7 +233,7 @@ void Ide::ContextGoto0(int pos) } } - Vector ns = GetNamespaces(parser); + Vector ns = parser.GetNamespaces(); if(qual.GetCount()) { // Ctrl::MOUSELEFT, Vector::Iterator Vector todo; diff --git a/uppsrc/ide/Cpp.cpp b/uppsrc/ide/Cpp.cpp index 7ee7f635d..ded283285 100644 --- a/uppsrc/ide/Cpp.cpp +++ b/uppsrc/ide/Cpp.cpp @@ -12,103 +12,19 @@ #define LTIMING(x) // DTIMING(x) -static Array sEmpty; - -const Array& GetTypeItems(const String& type) -{ - int q = CodeBase().Find(type); - if(q < 0) - return sEmpty; - return CodeBase()[q]; -} - -Vector GetTypeBases(const String& type) -{ - const Array& n = GetTypeItems(type); - String bases; - for(int i = 0; i < n.GetCount(); i++) { - const CppItem& im = n[i]; - if(im.IsType()) - bases << im.qptype << ';'; - } - 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) -{ - const char *s = type; - String r; - while(*s) { - if(*s == '<') { - s++; - int lvl = 0; - String t; - while(*s) { - int c = *s++; - if(c == ',' && lvl == 0) { - tparam.Add(t); - t.Clear(); - } - else { - if(c == '>') { - if(lvl == 0) - break; - lvl--; - } - if(c == '<') - lvl++; - t.Cat(c); - } - } - tparam.Add(t); - break; - } - else - r.Cat(*s++); - } - LLOG("ParseTemplatedType " << type << " -> " << r); - LDUMPC(tparam); - return r; -} - String ResolveTParam(const String& type, const Vector& tparam) { - LLOG("ResolveTParam " << type << ' ' << tparam); - String r; - const char *s = type; - while(*s) { - if(IsDigit(*s)) { - int i = *s++ - '0'; - if(i >= 0 && i < tparam.GetCount()) - r.Cat(tparam[i]); - } - else - if(iscib(*s)) - while(iscid(*s)) - r.Cat(*s++); - else - r.Cat(*s++); - } - LLOG("Resolved " << type << " -> " << r); - const Array& x = GetTypeItems(r); - if(x.GetCount() && x[0].kind == TYPEDEF) { - LLOG("Is typedef " << x[0].qtype << ';' << x[0].type << ';' << x[0].natural); - String h = x[0].qtype; - if(h != type && h != r) - return ResolveTParam(h, tparam); - return h; - } - return r; + return ResolveTParam(CodeBase(), type, tparam); } void ResolveTParam(Vector& type, const Vector& tparam) { - for(int i = 0; i < type.GetCount(); i++) - type[i] = ResolveTParam(type[i], tparam); + return ResolveTParam(CodeBase(), type, tparam); +} + +String Qualify(const String& scope, const String& type, const String& usings) +{ + return Qualify(CodeBase(), scope, type, usings); } void AssistScanError(int line, const String& text) @@ -149,175 +65,9 @@ void AssistEditor::Context(Parser& parser, int pos) #endif } - -Vector GetNamespaces(const Parser& parser) -{ - Vector ns; - Vector h = Split(parser.current_scope, ':'); - while(h.GetCount()) { - ns.Add(Join(h, "::")); - h.Drop(); - } - ns.Append(Split(parser.context.namespace_using, ';')); - ns.Add(""); // Add global namespace too - return ns; -} - -String Qualify(const String& scope, const String& type, const String& usings) -{ - return Qualify(CodeBase(), scope, type, usings); -} - -String ResolveReturnType(const CppItem& m, const Vector& tparam) -{ - if(m.tparam.GetCount()) { - int q = InScListIndex(m.qtype, m.tname); - if(q >= 0 && q < tparam.GetCount()) - return tparam[q]; - } - return m.qtype; -} - -void AssistEditor::ExpressionType(const String& ttype, - const String& context_type, - const String& usings, - const Vector& xp, int ii, - Index& typeset, bool variable, - bool can_shortcut_operator, Index& visited_bases, - int lvl) -{ - LLOG("--- ExpressionType " << scan_counter << ", lvl " << lvl << ", ttype " << ttype); - if(++scan_counter > 1000 || lvl > 100) // sort of ugly limitation of parsing permutations - return; - if(ii >= xp.GetCount()) { - LLOG("--- Final type: " << ttype); - typeset.FindAdd(ttype); - return; - } - LDUMP(ii); - LDUMP(xp[ii]); - LDUMP(can_shortcut_operator); - Vector tparam; - String type = ParseTemplatedType(ttype, tparam); - int c0 = typeset.GetCount(); - const Array& n = GetTypeItems(type); - LDUMP(type); - LDUMP(tparam); - if(CodeBase().namespaces.Find(ttype) < 0 && ttype.GetCount()) // do not search for namespace typedefs - for(int i = 0; i < n.GetCount(); i++) - if(n[i].kind == TYPEDEF) { - LLOG("typedef -> " << n[i].qtype); - ExpressionType(n[i].qtype, context_type, usings, xp, ii, typeset, variable, can_shortcut_operator, visited_bases, lvl + 1); - return; - } - String id = xp[ii]; - int q = id.ReverseFind(':'); - if(q > 0 && id[q - 1] == ':') { - type = ResolveTParam(Qualify(ttype, id.Mid(0, q - 1), usings), tparam); - id = id.Mid(q + 1); - } - if(id.Find('<') >= 0) // as in Single - id = ParseTemplatedType(id, tparam); - LLOG("ExpressionType " << type << " ii: " << ii << " id:" << id << " variable:" << variable); - - for(int i = 0; i < tparam.GetCount(); i++) // need to qualify template parameters - tparam[i] = Qualify(context_type, tparam[i], usings); - - bool shortcut_oper = false; - if(!iscid(*id) && *id != '.') { - shortcut_oper = can_shortcut_operator; - id = "operator" + id; - LLOG("id as: " << id); - } - if(*id == '.' || (!variable && !iscid(*id))) { - LLOG(". " << ttype); - ExpressionType(ttype, context_type, usings, xp, ii + 1, typeset, false, lvl + 1); - return; - } - LDUMP(id); - Index done; - for(int i = 0; i < n.GetCount(); i++) { - const CppItem& m = n[i]; - if(m.name == id) { - LLOG("Member " << m.qtype << " " << m.name); - String t = ResolveReturnType(m, tparam); - if(done.Find(t) < 0) { - bool skipfnpars = m.IsCode() && ii + 1 < xp.GetCount() && xp[ii + 1] == "()"; - ExpressionType(ResolveTParam(t, tparam), context_type, usings, xp, ii + skipfnpars + 1, - typeset, m.IsData() && !m.isptr, lvl + 1); - } - } - } - - if(typeset.GetCount() != c0 || IsNull(type)) - return; - Vector base = GetTypeBases(type); - LDUMPC(base); - ResolveTParam(base, tparam); - LDUMPC(base); - for(int i = 0; i < base.GetCount(); i++) - if(visited_bases.Find(base[i]) < 0) { - visited_bases.Add(base[i]); - ExpressionType(base[i], context_type, usings, xp, ii, typeset, variable, false, visited_bases, lvl + 1); - if(typeset.GetCount() != c0) - return; - } - - if(shortcut_oper) { - LLOG("Shortcut " << xp[ii] << ", ttype " << ttype); - ExpressionType(ttype, context_type, usings, xp, ii + 1, typeset, false, lvl + 1); - } -} - -void AssistEditor::ExpressionType(const String& type, const String& context_type, - const String& usings, const Vector& xp, int ii, - Index& typeset, bool variable, int lvl) -{ - Index visited_bases; - ExpressionType(type, context_type, usings, xp, ii, typeset, variable, true, visited_bases, lvl); -} - -Index AssistEditor::ExpressionType(const Parser& parser, const Vector& xp) -{ - LLOG("**** ExpressionType " << xp); - String type; - Index typeset; - if(xp.GetCount() == 0) - return typeset; - if(xp[0] == "this") { - LLOG("this: " << type); - ExpressionType(parser.current_scope, parser.current_scope, parser.context.namespace_using, xp, 1, typeset, false, 0); - return typeset; - } - int q = parser.local.FindLast(xp[0]); - if(q >= 0) { - 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, parser.current_scope, parser.context.namespace_using, xp, 1, typeset, !parser.local[q].isptr, 0); - return typeset; - } - ExpressionType(parser.current_scope, 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], parser.context.namespace_using); - Vector tparam; - if(CodeBase().Find(ParseTemplatedType(qtype, tparam)) >= 0) { - LLOG("Is constructor " << qtype); - ExpressionType(qtype, parser.current_scope, parser.context.namespace_using, xp, 2, typeset, false, 0); - return typeset; - } - } - Vector ns = GetNamespaces(parser); - for(int i = 0; i < ns.GetCount(); i++) - ExpressionType(ns[i], parser.current_scope, parser.context.namespace_using, xp, 0, typeset, false, 0); - return typeset; -} - Index AssistEditor::EvaluateExpressionType(const Parser& parser, const Vector& xp) { - scan_counter = 0; - return ExpressionType(parser, xp); + return GetExpressionType(CodeBase(), parser, xp); } void AssistEditor::AssistItemAdd(const String& scope, const CppItem& m, int typei) diff --git a/uppsrc/ide/ide.h b/uppsrc/ide/ide.h index cab3e8b2f..5682757ba 100644 --- a/uppsrc/ide/ide.h +++ b/uppsrc/ide/ide.h @@ -284,10 +284,11 @@ public: }; 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, const String& usings); + int CharFilterMacro(int c); int CharFilterFileName(int c);