CiClass ParseClass()
{
CiClass klass = new CiClass();
klass.SourceFilename = this.Filename;
if (Eat(CiToken.Abstract))
klass.IsAbstract = true;
Expect(CiToken.Class);
klass.Name = ParseId();
if (Eat(CiToken.Colon))
klass.BaseClass = new CiUnknownClass { Name = ParseId() };
Expect(CiToken.LeftBrace);
OpenScope();
this.CurrentClass = klass;
klass.Members = this.Symbols;
while (!Eat(CiToken.RightBrace)) {
CiCodeDoc doc = ParseDoc();
CiVisibility visibility = CiVisibility.Private;
if (Eat(CiToken.Public))
visibility = CiVisibility.Public;
else if (Eat(CiToken.Internal))
visibility = CiVisibility.Internal;
CiSymbol symbol;
if (See(CiToken.Const)) {
symbol = ParseConst();
((CiConst) symbol).Class = klass;
}
else if (Eat(CiToken.Macro)) {
if (visibility != CiVisibility.Private)
throw new ParseException("Macros must be private");
symbol = ParseMacro();
}
else {
CiCallType callType;
if (Eat(CiToken.Static))
callType = CiCallType.Static;
else if (Eat(CiToken.Abstract)) {
if (!klass.IsAbstract)
throw new ParseException("Abstract methods only allowed in abstract classes");
callType = CiCallType.Abstract;
if (visibility == CiVisibility.Private)
visibility = CiVisibility.Internal;
}
else if (Eat(CiToken.Virtual)) {
callType = CiCallType.Virtual;
if (visibility == CiVisibility.Private)
visibility = CiVisibility.Internal;
}
else if (Eat(CiToken.Override)) {
callType = CiCallType.Override;
if (visibility == CiVisibility.Private)
visibility = CiVisibility.Internal;
}
else
callType = CiCallType.Normal;
CiType type = ParseReturnType();
if (type is CiClassStorageType && See(CiToken.LeftBrace)) {
if (type.Name != klass.Name)
throw new ParseException("{0}() looks like a constructor, but it is in a different class {1}", type.Name, klass.Name);
if (callType != CiCallType.Normal)
throw new ParseException("Constructor cannot be static, abstract, virtual or override");
if (klass.Constructor != null)
throw new ParseException("Duplicate constructor");
klass.Constructor = ParseConstructor();
continue;
}
string name = ParseId();
if (See(CiToken.LeftParenthesis)) {
CiMethod method = new CiMethod(type, name) {
Class = klass,
CallType = callType
};
ParseMethod(method);
symbol = method;
}
else {
if (visibility != CiVisibility.Private)
throw new ParseException("Fields must be private");
if (callType != CiCallType.Normal)
throw new ParseException("Fields cannot be static, abstract, virtual or override");
if (type == CiType.Void)
throw new ParseException("Field is void");
Expect(CiToken.Semicolon);
symbol = new CiField { Class = klass, Type = type, Name = name };
}
}
symbol.Documentation = doc;
symbol.Visibility = visibility;
klass.Members.Add(symbol);
}
this.CurrentClass = null;
CloseScope();
klass.ConstArrays = this.ConstArrays.ToArray();
this.ConstArrays.Clear();
return klass;
}