mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-21 06:45:39 -06:00
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:
parent
117c9ffdca
commit
241d02d67a
5 changed files with 224 additions and 212 deletions
211
uppsrc/CppBase/Body.cpp
Normal file
211
uppsrc/CppBase/Body.cpp
Normal 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
|
||||||
|
|
@ -512,6 +512,7 @@ struct Parser {
|
||||||
|
|
||||||
bool Key(int code);
|
bool Key(int code);
|
||||||
bool EatBody();
|
bool EatBody();
|
||||||
|
String ResolveAutoType();
|
||||||
|
|
||||||
void Cv();
|
void Cv();
|
||||||
String TType();
|
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);
|
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 Vector<String>& xp);
|
||||||
Index<String> GetExpressionType(const CppBase& codebase, const Parser& parser, const char *s);
|
Vector<String> MakeXP(const char *s);
|
||||||
|
|
||||||
END_UPP_NAMESPACE
|
END_UPP_NAMESPACE
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ file
|
||||||
Pre.cpp,
|
Pre.cpp,
|
||||||
cpplex.cpp,
|
cpplex.cpp,
|
||||||
Parser.cpp,
|
Parser.cpp,
|
||||||
|
Body.cpp,
|
||||||
Base.cpp,
|
Base.cpp,
|
||||||
ScopeInfo.cpp,
|
ScopeInfo.cpp,
|
||||||
Qualify.cpp,
|
Qualify.cpp,
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,6 @@ String ParseTemplatedType(const String& type, Vector<String>& tparam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tparam.Add(t);
|
tparam.Add(t);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
r.Cat(*s++);
|
r.Cat(*s++);
|
||||||
|
|
@ -213,6 +212,8 @@ void ExpressionTyper::ExpressionType(const String& ttype, int ii,
|
||||||
String t = ResolveReturnType(m, tparam);
|
String t = ResolveReturnType(m, tparam);
|
||||||
if(done.Find(t) < 0) {
|
if(done.Find(t) < 0) {
|
||||||
bool skipfnpars = m.IsCode() && ii + 1 < xp.GetCount() && xp[ii + 1] == "()";
|
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,
|
ExpressionType(ResolveTParam(codebase, t, tparam), ii + skipfnpars + 1,
|
||||||
m.IsData() && !m.isptr, lvl + 1);
|
m.IsData() && !m.isptr, lvl + 1);
|
||||||
}
|
}
|
||||||
|
|
@ -361,9 +362,4 @@ Vector<String> MakeXP(const char *s)
|
||||||
return xp;
|
return xp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Index<String> GetExpressionType(const CppBase& codebase, const Parser& parser, const char *s)
|
|
||||||
{
|
|
||||||
return GetExpressionType(codebase, parser, MakeXP(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -821,10 +821,10 @@ void Parser::Declarator(Decl& d, const char *p)
|
||||||
// else
|
// else
|
||||||
if(lex.IsId() || lex == t_dblcolon || lex == tk_operator) {
|
if(lex.IsId() || lex == t_dblcolon || lex == tk_operator) {
|
||||||
d.name = Name(d.castoper, d.oper);
|
d.name = Name(d.castoper, d.oper);
|
||||||
bool dummy;
|
if(IsNull(d.type) && lex == ':' && lex[1] == t_integer) { // Bitfield, like 'unsigned x:5'
|
||||||
if(Key(':'))
|
++lex;
|
||||||
if(!Key(t_integer))
|
++lex;
|
||||||
Name(dummy, dummy);
|
}
|
||||||
}
|
}
|
||||||
if(Key('(')) {
|
if(Key('(')) {
|
||||||
if(inbody || (lex < 256 || lex == tk_true || lex == tk_false)
|
if(inbody || (lex < 256 || lex == tk_true || lex == tk_false)
|
||||||
|
|
@ -852,12 +852,10 @@ void Parser::Declarator(Decl& d, const char *p)
|
||||||
++lex;
|
++lex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(*d.type == '*') { // C++11 auto declaration
|
if(*d.type == '*') // C++11 auto declaration
|
||||||
Index<String> s = GetExpressionType(*base, *this, lex.Pos());
|
d.type = ResolveAutoType();
|
||||||
int i = FindMin(s); // Ugly hack: we are not resolving overloading at all, so just choose stable type if there are more
|
else
|
||||||
d.type = i < 0 ? String() : s[i];
|
EatInitializers();
|
||||||
}
|
|
||||||
EatInitializers();
|
|
||||||
while(Key('[')) {
|
while(Key('[')) {
|
||||||
d.isptr = true;
|
d.isptr = true;
|
||||||
int level = 1;
|
int level = 1;
|
||||||
|
|
@ -1098,201 +1096,6 @@ bool Parser::VCAttribute()
|
||||||
return false;
|
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()
|
void Parser::SetScopeCurrent()
|
||||||
{
|
{
|
||||||
current_scope = context.scope;
|
current_scope = context.scope;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue