Skip to content

Commit

Permalink
transparent fields for both structs and raw unions now work
Browse files Browse the repository at this point in the history
  • Loading branch information
zhiayang committed Apr 28, 2019
1 parent 9f4d700 commit 08779e7
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 67 deletions.
39 changes: 7 additions & 32 deletions build/supertiny.flx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import std::opt

@raw union ipv4
{
// _: struct {
// _: union {
// bytes: [u8: 4]
// raw3: u32
// }
// }
_: struct {
_: @raw union {
bytes2: [u8: 4]
raw3: u32
}
}

_: struct {
bytes: [u8: 4]
Expand All @@ -41,34 +41,9 @@ struct foo
{
do {
var addr: ipv4
addr.raw2 = 0xff01a8c0;
addr.raw3 = 0xff01a8c0;

printf("%d.%d.%d.%d\n", addr.bytes[0], addr.bytes[1], addr.bytes[2], addr.bytes[3]);

/*
todo list

1. implement the collapseAndCollectTransparentFields() function.

2. check for duplicate fields in totality

3. figure out the modifications necessary to dotops to achieve transparent access

4. figure out how to coerce the codegen/ir type layer to handle this crap
stuff like duplicate names of "_" in the IR need to be handled somehow
("transparent_field_0" anonymous name?)

ir codegen currently grabs fields using names, which obviously won't work well
here... we could legitimise transparent fields in the IR, but that's quite pointless
and useless, definitely smells like a frontend feature, not a backend one.
*/

// addr._.bytes[0] = 192
// addr._.bytes[1] = 168
// addr._.bytes[2] = 1
// addr._.bytes[3] = 1


}


Expand Down
2 changes: 0 additions & 2 deletions source/frontend/parser/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,6 @@ namespace parser
error(st.loc(), "expected newline after union variant");
}



if(name == "_")
{
if(!israw)
Expand Down
112 changes: 80 additions & 32 deletions source/typecheck/dotop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,24 +62,34 @@ static ErrorMsg* wrongDotOpError(ErrorMsg* e, sst::StructDefn* str, const Locati



struct search_result_t
{
search_result_t() { }
search_result_t(fir::Type* t, size_t i, bool tr) : type(t), fieldIdx(i), isTransparent(tr) { }

fir::Type* type = 0;
size_t fieldIdx = 0;
bool isTransparent = false;
};


static sst::FieldDotOp* resolveFieldNameDotOp(sst::TypecheckState* fs, sst::TypeDefn* defn, sst::Expr* lhs,
static std::vector<search_result_t> searchTransparentFields(sst::TypecheckState* fs, std::vector<search_result_t> stack,
const std::vector<sst::StructFieldDefn*>& fields, const Location& loc, const std::string& name)
{
size_t idx = 0;
// search for them by name first, instead of doing a super-depth-first-search.
for(auto df : fields)
{
if(df->id.name == name)
{
auto ret = util::pool<sst::FieldDotOp>(loc, df->type);
ret->lhs = lhs;
ret->rhsIdent = name;

return ret;
stack.push_back(search_result_t(df->type, 0, false));
return stack;
}
else if(df->isTransparentField)
}


size_t idx = 0;
for(auto df : fields)
{
if(df->isTransparentField)
{
auto ty = df->type;
assert(ty->isRawUnionType() || ty->isStructType());
Expand All @@ -97,42 +107,80 @@ static sst::FieldDotOp* resolveFieldNameDotOp(sst::TypecheckState* fs, sst::Type
else
error(loc, "what kind of type is this? '%s'", ty);

stack.push_back(search_result_t(ty, idx, true));
auto ret = searchTransparentFields(fs, stack, flds, loc, name);

// hmm.
auto hmm = sst::FieldDotOp(loc, df->type);
if(!ret.empty()) return ret;
else stack.pop_back();
}

hmm.lhs = lhs;
hmm.rhsIdent = "";
hmm.isTransparentField = true;
hmm.indexOfTransparentField = idx;
idx += 1;
}

auto hmm2 = resolveFieldNameDotOp(fs, defn, &hmm, flds, loc, name);
if(hmm2)
{
// make 'hmm' into a pool node.
iceAssert(hmm2->lhs == &hmm);
// if we've reached the end of the line, return nothing.
return { };
}

auto real = util::pool<sst::FieldDotOp>(hmm.loc, hmm.type);
real->lhs = lhs;
real->rhsIdent = "";
real->isTransparentField = true;
real->indexOfTransparentField = idx;

hmm2->lhs = real;
static sst::FieldDotOp* resolveFieldNameDotOp(sst::TypecheckState* fs, sst::Expr* lhs, const std::vector<sst::StructFieldDefn*>& fields,
const Location& loc, const std::string& name)
{
for(auto df : fields)
{
if(df->id.name == name)
{
auto ret = util::pool<sst::FieldDotOp>(loc, df->type);
ret->lhs = lhs;
ret->rhsIdent = name;

return hmm2;
}
return ret;
}
}

idx += 1;
// sad. search for the field, recursively, in transparent members.
auto ops = searchTransparentFields(fs, { }, fields, loc, name);
if(ops.empty())
return nullptr;

// ok, now we just need to make a link of fielddotops...
sst::Expr* cur = lhs;
for(const auto& x : ops)
{
auto op = util::pool<sst::FieldDotOp>(loc, x.type);

op->lhs = cur;
op->isTransparentField = x.isTransparent;
op->indexOfTransparentField = x.fieldIdx;

// don't set a name if we're transparent.
op->rhsIdent = (x.isTransparent ? "" : name);

cur = op;
}

return nullptr;
auto ret = dcast(sst::FieldDotOp, cur);
assert(ret);

return ret;
}


















static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* dotop, fir::Type* infer)
{
auto lhs = dotop->left->typecheck(fs).expr();
Expand Down Expand Up @@ -532,7 +580,7 @@ static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* d

while(copy)
{
auto hmm = resolveFieldNameDotOp(fs, copy, lhs, copy->fields, dotop->loc, name);
auto hmm = resolveFieldNameDotOp(fs, lhs, copy->fields, dotop->loc, name);
if(hmm) return hmm;

// ok, we didn't find it.
Expand Down Expand Up @@ -623,7 +671,7 @@ static sst::Expr* doExpressionDotOp(sst::TypecheckState* fs, ast::DotOperator* d
if(auto fld = dcast(ast::Ident, dotop->right))
{
auto flds = util::map(util::pairs(rnn->fields), [](const auto& x) -> auto { return x.second; }) + rnn->transparentFields;
auto hmm = resolveFieldNameDotOp(fs, rnn, lhs, flds, dotop->loc, fld->name);
auto hmm = resolveFieldNameDotOp(fs, lhs, flds, dotop->loc, fld->name);
if(hmm)
{
return hmm;
Expand Down
13 changes: 12 additions & 1 deletion source/typecheck/structs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ static void _checkTransparentFieldRedefinition(sst::TypecheckState* fs, sst::Typ
if(fld->isTransparentField)
{
auto ty = fld->type;
assert(ty->isRawUnionType() || ty->isStructType());
if(!ty->isRawUnionType() && !ty->isStructType())
{
// you can't have a transparentl field if it's not an aggregate type, lmao
error(fld, "transparent fields must have either a struct or raw-union type.");
}

auto defn = fs->typeDefnMap[ty];
iceAssert(defn);
Expand Down Expand Up @@ -193,6 +197,9 @@ TCResult ast::StructDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, c
auto v = dcast(sst::StructFieldDefn, vdef->typecheck(fs).defn());
iceAssert(v);

if(v->id.name == "_")
v->isTransparentField = true;

defn->fields.push_back(v);
tys.push_back({ v->id.name, v->type });

Expand All @@ -215,6 +222,10 @@ TCResult ast::StructDefn::typecheck(sst::TypecheckState* fs, fir::Type* infer, c
for(auto m : this->methods)
m->typecheck(fs, str, { });
}

checkTransparentFieldRedefinition(fs, defn, defn->fields);


fs->leaveStructBody();


Expand Down

0 comments on commit 08779e7

Please sign in to comment.