cpp: C++11 for(auto x: v) now supported

git-svn-id: svn://ultimatepp.org/upp/trunk@8705 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2015-07-19 16:27:03 +00:00
parent 117c9ffdca
commit 241d02d67a
5 changed files with 224 additions and 212 deletions

211
uppsrc/CppBase/Body.cpp Normal file
View file

@ -0,0 +1,211 @@
#include "CppBase.h"
NAMESPACE_UPP
bool Parser::TryDecl()
{ // attempt to interpret code as local variable declaration
for(;;) {
if(lex[0] == tk_static || lex[0] == tk_const ||
lex[0] == tk_register || lex[0] == tk_volatile)
++lex;
else
if(!VCAttribute())
break;
}
int t = lex[0];
int q = 0;
if(t == tk_int || t == tk_bool || t == tk_float || t == tk_double || t == tk_void ||
t == tk_long || t == tk_signed || t == tk_unsigned || t == tk_short ||
t == tk_char || t == tk___int8 || t == tk___int16 || t == tk___int32 || t == tk___int64 ||
t == tk_auto) {
q++;
while(lex[q] == '*' || lex[q] == '&' || lex[q] == t_and || lex[q] == tk_const) // t_and is r-value here
q++;
if(!lex.IsId(q))
return false;
static String aut("*"), empty;
Locals(t == tk_auto ? aut : empty);
return true;
}
String type;
if(lex[q] == t_dblcolon) {
type << "::";
q++;
}
if(lex.IsId(q)) {
type << lex.Id(q++);
type << Tparam(q);
}
else
return false;
while(lex[q] == t_dblcolon) {
type << "::";
if(lex.IsId(++q))
type << lex.Id(q++);
else
return false;
type << Tparam(q);
}
while(lex[q] == '*' || lex[q] == '&' || lex[q] == t_and) // t_and is r-value here
q++;
if(!lex.IsId(q))
return false;
type = Qualify(*base, current_scope, type, context.namespace_using);
if(base->Find(NoTemplatePars(type)) >= 0) {
Locals(type);
return true;
}
return false;
}
void Parser::MatchPars()
{
int level = 1;
while(level && lex != t_eof) {
if(Key('(')) level++;
else
if(Key(')')) level--;
else
++lex;
}
}
void Parser::Statement()
{
RecursionCounter recursionCounter(currentScopeDepth, lex == '{' ? 0 : 1);
maxScopeDepth = max(maxScopeDepth, currentScopeDepth);
if(Key(tk_case)) {
if(lex.IsId())
++lex;
Key(':');
}
if(Key(tk_default))
Key(':');
if(lex.IsId() && lex[1] == ':') {
++lex;
++lex;
}
if(Key('{')) {
Context cc;
cc <<= context;
int l = local.GetCount();
while(!Key('}')) {
if(lex == t_eof)
ThrowError("eof");
Statement();
}
context <<= cc;
local.Trim(l);
}
else
if(Key(tk_if)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
if(Key(tk_else))
Statement();
local.Trim(l);
}
else
if(Key(tk_for)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
local.Trim(l);
}
else
if(Key(tk_while)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
local.Trim(l);
}
else
if(Key(tk_try))
Statement();
else
if(Key(tk_catch)) {
Key('(');
MatchPars();
Statement();
}
else
if(Key(tk_do)) {
Statement();
Key(tk_while);
Key('(');
MatchPars();
}
else
if(Key(tk_switch)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
local.Trim(l);
}
else
if(UsingNamespace())
;
else
if(TryDecl())
Key(';');
else
for(;;) {
if(lex == t_eof)
ThrowError("");
if(Key(';') || lex == '{' || lex == '}' || lex >= tk_if && lex <= tk_do)
break;
++lex;
}
}
bool Parser::EatBody()
{
if(lex != '{') {
local.Clear();
return false;
}
lex.BeginBody();
maxScopeDepth = currentScopeDepth = dobody ? 0 : 1;
if(dobody) {
inbody = true;
Statement();
inbody = false;
local.Clear();
}
else {
Key('{');
int level = 1;
while(level && lex != t_eof) {
if(Key('{')) level++;
else
if(Key('}')) level--;
else
++lex;
maxScopeDepth = max(level, maxScopeDepth);
}
}
lex.EndBody();
return true;
}
String Parser::ResolveAutoType()
{
Vector<String> xp = MakeXP(lex.Pos());
if(lex == ':') // resolve for declaration, like 'for(auto i: vector)'
xp << "." << "begin" << "()" << "->"; // incorrect, should rather use operator*(), but sufficient for now
Index<String> s = GetExpressionType(*base, *this, xp);
int i = FindMin(s); // Ugly hack: we are not resolving overloading at all, so just choose stable type if there are more
return i < 0 ? String() : s[i];
}
END_UPP_NAMESPACE

View file

@ -512,6 +512,7 @@ struct Parser {
bool Key(int code);
bool EatBody();
String ResolveAutoType();
void Cv();
String TType();
@ -667,7 +668,7 @@ String ResolveTParam(const CppBase& codebase, const String& type,
void ResolveTParam(const CppBase& codebase, Vector<String>& type, const Vector<String>& tparam);
Index<String> GetExpressionType(const CppBase& codebase, const Parser& parser, const Vector<String>& xp);
Index<String> GetExpressionType(const CppBase& codebase, const Parser& parser, const char *s);
Vector<String> MakeXP(const char *s);
END_UPP_NAMESPACE

View file

@ -16,6 +16,7 @@ file
Pre.cpp,
cpplex.cpp,
Parser.cpp,
Body.cpp,
Base.cpp,
ScopeInfo.cpp,
Qualify.cpp,

View file

@ -50,7 +50,6 @@ String ParseTemplatedType(const String& type, Vector<String>& tparam)
}
}
tparam.Add(t);
break;
}
else
r.Cat(*s++);
@ -213,6 +212,8 @@ void ExpressionTyper::ExpressionType(const String& ttype, int ii,
String t = ResolveReturnType(m, tparam);
if(done.Find(t) < 0) {
bool skipfnpars = m.IsCode() && ii + 1 < xp.GetCount() && xp[ii + 1] == "()";
if(t.StartsWith(type + "::")) // Resolve Vector::Iterator -> Vector<String>::Iterator
t.Insert(type.GetCount(), "<" + Join(tparam, ",") + ">");
ExpressionType(ResolveTParam(codebase, t, tparam), ii + skipfnpars + 1,
m.IsData() && !m.isptr, lvl + 1);
}
@ -361,9 +362,4 @@ Vector<String> MakeXP(const char *s)
return xp;
}
Index<String> GetExpressionType(const CppBase& codebase, const Parser& parser, const char *s)
{
return GetExpressionType(codebase, parser, MakeXP(s));
}
};

View file

@ -821,10 +821,10 @@ void Parser::Declarator(Decl& d, const char *p)
// else
if(lex.IsId() || lex == t_dblcolon || lex == tk_operator) {
d.name = Name(d.castoper, d.oper);
bool dummy;
if(Key(':'))
if(!Key(t_integer))
Name(dummy, dummy);
if(IsNull(d.type) && lex == ':' && lex[1] == t_integer) { // Bitfield, like 'unsigned x:5'
++lex;
++lex;
}
}
if(Key('(')) {
if(inbody || (lex < 256 || lex == tk_true || lex == tk_false)
@ -852,11 +852,9 @@ void Parser::Declarator(Decl& d, const char *p)
++lex;
}
}
if(*d.type == '*') { // C++11 auto declaration
Index<String> s = GetExpressionType(*base, *this, lex.Pos());
int i = FindMin(s); // Ugly hack: we are not resolving overloading at all, so just choose stable type if there are more
d.type = i < 0 ? String() : s[i];
}
if(*d.type == '*') // C++11 auto declaration
d.type = ResolveAutoType();
else
EatInitializers();
while(Key('[')) {
d.isptr = true;
@ -1098,201 +1096,6 @@ bool Parser::VCAttribute()
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_register || lex[0] == tk_volatile)
++lex;
else
if(!VCAttribute())
break;
}
int t = lex[0];
int q = 0;
if(t == tk_int || t == tk_bool || t == tk_float || t == tk_double || t == tk_void ||
t == tk_long || t == tk_signed || t == tk_unsigned || t == tk_short ||
t == tk_char || t == tk___int8 || t == tk___int16 || t == tk___int32 || t == tk___int64 ||
t == tk_auto) {
q++;
while(lex[q] == '*' || lex[q] == '&' || lex[q] == t_and || lex[q] == tk_const) // t_and is r-value here
q++;
if(!lex.IsId(q))
return false;
Locals(t == tk_auto ? "*" : String());
return true;
}
String type;
if(lex[q] == t_dblcolon) {
type << "::";
q++;
}
if(lex.IsId(q)) {
type << lex.Id(q++);
type << Tparam(q);
}
else
return false;
while(lex[q] == t_dblcolon) {
type << "::";
if(lex.IsId(++q))
type << lex.Id(q++);
else
return false;
type << Tparam(q);
}
while(lex[q] == '*' || lex[q] == '&' || lex[q] == t_and) // t_and is r-value here
q++;
if(!lex.IsId(q))
return false;
type = Qualify(*base, current_scope, type, context.namespace_using);
if(base->Find(NoTemplatePars(type)) >= 0) {
Locals(type);
return true;
}
return false;
}
void Parser::MatchPars()
{
int level = 1;
while(level && lex != t_eof) {
if(Key('(')) level++;
else
if(Key(')')) level--;
else
++lex;
}
}
void Parser::Statement()
{
RecursionCounter recursionCounter(currentScopeDepth, lex == '{' ? 0 : 1);
maxScopeDepth = max(maxScopeDepth, currentScopeDepth);
if(Key(tk_case)) {
if(lex.IsId())
++lex;
Key(':');
}
if(Key(tk_default))
Key(':');
if(lex.IsId() && lex[1] == ':') {
++lex;
++lex;
}
if(Key('{')) {
Context cc;
cc <<= context;
int l = local.GetCount();
while(!Key('}')) {
if(lex == t_eof)
ThrowError("eof");
Statement();
}
context <<= cc;
local.Trim(l);
}
else
if(Key(tk_if)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
if(Key(tk_else))
Statement();
local.Trim(l);
}
else
if(Key(tk_for)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
local.Trim(l);
}
else
if(Key(tk_while)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
local.Trim(l);
}
else
if(Key(tk_try))
Statement();
else
if(Key(tk_catch)) {
Key('(');
MatchPars();
Statement();
}
else
if(Key(tk_do)) {
Statement();
Key(tk_while);
Key('(');
MatchPars();
}
else
if(Key(tk_switch)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
local.Trim(l);
}
else
if(UsingNamespace())
;
else
if(TryDecl())
Key(';');
else
for(;;) {
if(lex == t_eof)
ThrowError("");
if(Key(';') || lex == '{' || lex == '}' || lex >= tk_if && lex <= tk_do)
break;
++lex;
}
}
bool Parser::EatBody()
{
if(lex != '{') {
local.Clear();
return false;
}
lex.BeginBody();
maxScopeDepth = currentScopeDepth = dobody ? 0 : 1;
if(dobody) {
inbody = true;
Statement();
inbody = false;
local.Clear();
}
else {
Key('{');
int level = 1;
while(level && lex != t_eof) {
if(Key('{')) level++;
else
if(Key('}')) level--;
else
++lex;
maxScopeDepth = max(level, maxScopeDepth);
}
}
lex.EndBody();
return true;
}
void Parser::SetScopeCurrent()
{
current_scope = context.scope;