public override ISemantReturn<ExprType> GetExprType(Env env) {
StructOrUnionType type;
// If no members provided, then we need to find the Type in the current environment.
if (this.MemberDeclns.IsNone) {
if (this.Name.IsNone) {
throw new InvalidProgramException("This should not pass the parser");
}
var name = this.Name.Value;
var typeName = (this.StructOrUnion == StructOrUnion.STRUCT ? "struct" : "union") + $" {name}";
// Try to find Type name in the current environment.
var entryOpt = env.Find(typeName);
// If name not found: create an incomplete Type and add it into the environment.
if (entryOpt.IsNone) {
type = StructOrUnionType.CreateIncompleteType(this.StructOrUnion, name);
env = env.PushEntry(Env.EntryKind.TYPEDEF, typeName, type);
return SemantReturn.Create(env, type);
}
// If name found: fetch it.
if (entryOpt.Value.Kind != Env.EntryKind.TYPEDEF) {
throw new InvalidProgramException("A struct or union in env that is not typedef? This should not appear.");
}
return SemantReturn.Create(env, entryOpt.Value.Type);
}
// If members are provided, the user is trying to define a new struct/union.
if (this.Name.IsSome) {
var name = this.Name.Value;
var typeName = (this.StructOrUnion == StructOrUnion.STRUCT ? "struct" : "union") + $" {name}";
// Try to find Type name in the current environment.
// Notice we need to search the current **scope** only.
var entryOpt = env.FindInCurrentScope(typeName);
// If name not found: create an incomplete Type and add it into the environment.
if (entryOpt.IsNone) {
type = StructOrUnionType.CreateIncompleteType(this.StructOrUnion, name);
env = env.PushEntry(Env.EntryKind.TYPEDEF, typeName, type);
} else {
if (entryOpt.Value.Kind != Env.EntryKind.TYPEDEF) {
throw new InvalidProgramException(
"A struct or union in env that is not typedef? This should not appear.");
}
type = entryOpt.Value.Type as StructOrUnionType;
if (type == null) {
throw new InvalidProgramException(
$"{typeName} is not a struct or union? This should not appear.");
}
}
// Current Type mustn't be already complete.
if (type.IsComplete) {
throw new InvalidOperationException($"Redifinition of {typeName}");
}
} else {
var typeName = (this.StructOrUnion == StructOrUnion.STRUCT ? "struct" : "union") + " <unnamed>";
type = StructOrUnionType.CreateIncompleteType(this.StructOrUnion, typeName);
}
var members = Semant(GetMembers, this.MemberDeclns.Value, ref env);
type.Define(this.StructOrUnion, members);
return SemantReturn.Create(env, type);
}
}