diff --git a/build/ultratiny.flx b/build/ultratiny.flx index 6af29bf9..909c3d87 100644 --- a/build/ultratiny.flx +++ b/build/ultratiny.flx @@ -4,9 +4,9 @@ export ultratiny -import libc as _ -import std::math - +// import libc as _ +// import std::math +/* @compiler_support["raii_trait::drop"] trait Drop { fn deinit() } @compiler_support["raii_trait::copy"] trait Copy { fn copy(other: &self) } @compiler_support["raii_trait::move"] trait Move { fn move(other: &mut self) } @@ -49,12 +49,30 @@ fn stuff2() -> Bar { return Bar(x: 57) } + */ + +ffi fn printf(fmt: &i8, ...) -> i32 + +struct Thicc +{ + x: i64 + y: i8 +} + +@packed struct Flat +{ + x: i64 + y: i8 +} @entry fn main() { - let q = stuff() - let p = stuff2() - printf("q = %d\n", q) + // let q = stuff() + // let p = stuff2() + // printf("q = %d\n", q) + let x = Flat(x: 3, y: 20) + + printf("%d, %d, %d\n", sizeof(x), sizeof(Thicc), sizeof(Flat)) } diff --git a/source/fir/Types/Type.cpp b/source/fir/Types/Type.cpp index 8a88f0f1..b0a491e5 100644 --- a/source/fir/Types/Type.cpp +++ b/source/fir/Types/Type.cpp @@ -1005,28 +1005,44 @@ namespace fir - static size_t getAggregateSize(const std::vector& tys) + static size_t getAggregateSize(const std::vector& tys, bool packed = false) { size_t ptr = 0; size_t aln = 0; - for(auto ty : tys) + if(packed) { - auto a = getAlignmentOfType(ty); - iceAssert(a > 0); + // gg + // return util::foldl(0, tys, [](Type* a, Type* b) -> size_t { + // return getSizeOfType(a) + getSizeOfType(b); + // }); - if(ptr % a > 0) - ptr += (a - (ptr % a)); + size_t ret = 0; + for(const auto& t : tys) + ret += getSizeOfType(t); - ptr += getSizeOfType(ty); - aln = std::max(aln, a); + return ret; } + else + { + for(auto ty : tys) + { + auto a = getAlignmentOfType(ty); + iceAssert(a > 0); - iceAssert(aln > 0); - if(ptr % aln > 0) - ptr += (aln - (ptr % aln)); + if(ptr % a > 0) + ptr += (a - (ptr % a)); - return ptr; + ptr += getSizeOfType(ty); + aln = std::max(aln, a); + } + + iceAssert(aln > 0); + if(ptr % aln > 0) + ptr += (aln - (ptr % aln)); + + return ptr; + } } size_t getSizeOfType(Type* type) @@ -1058,6 +1074,7 @@ namespace fir } else if(type->isClassType() || type->isStructType() || type->isTupleType()) { + bool packed = false; std::vector tys; if(type->isClassType()) @@ -1067,6 +1084,7 @@ namespace fir } else if(type->isStructType()) { + packed = type->toStructType()->isPackedStruct(); tys = type->toStructType()->getElements(); } else @@ -1074,7 +1092,7 @@ namespace fir tys = type->toTupleType()->getElements(); } - return getAggregateSize(tys); + return getAggregateSize(tys, packed); } else if(type->isUnionType() ) { diff --git a/source/frontend/lexer.cpp b/source/frontend/lexer.cpp index 9660b107..c5eebfe6 100644 --- a/source/frontend/lexer.cpp +++ b/source/frontend/lexer.cpp @@ -401,6 +401,12 @@ namespace lexer tok.text = "@entry"; read = 6; } + else if(hasPrefix(stream, "@packed")) + { + tok.type = TokenType::Attr_Packed; + tok.text = "@packed"; + read = 7; + } else if(hasPrefix(stream, "@raw")) { tok.type = TokenType::Attr_Raw; diff --git a/source/frontend/parser/expr.cpp b/source/frontend/parser/expr.cpp index b1597ba5..9e761845 100644 --- a/source/frontend/parser/expr.cpp +++ b/source/frontend/parser/expr.cpp @@ -113,6 +113,10 @@ namespace parser if((attrs.flags & FN_ENTRYPOINT) && !(allowed.flags & FN_ENTRYPOINT)) error(ret, "unsupported attribute '@entry' on %s", ret->readableName); + if((attrs.flags & PACKED) && !(allowed.flags & PACKED)) + error(ret, "unsupported attribute '@packed' on %s", ret->readableName); + + // here let's check the arguments and stuff for default attributes. // note: due to poor API design on my part, if there is no attribute with that name then ::get() // returns an empty UA, which has a blank name -- so we check that instead. @@ -155,7 +159,7 @@ namespace parser return enforceAttrs(parseUnion(st, attrs.has(attr::RAW), /* nameless: */ false), AttribSet::of(attr::RAW)); case TT::Struct: - return enforceAttrs(parseStruct(st, /* nameless: */ false)); + return enforceAttrs(parseStruct(st, /* nameless: */ false), AttribSet::of(attr::PACKED)); case TT::Class: return enforceAttrs(parseClass(st)); diff --git a/source/frontend/parser/misc.cpp b/source/frontend/parser/misc.cpp index bbf10265..bc74bab0 100644 --- a/source/frontend/parser/misc.cpp +++ b/source/frontend/parser/misc.cpp @@ -104,11 +104,14 @@ namespace parser { using UA = AttribSet::UserAttrib; - if(st.front() <= TT::Attr_ATTRS_BEGIN || st.front() >= TT::Attr_ATTRS_END) + if(st.front() != TT::At && (st.front() <= TT::Attr_ATTRS_BEGIN || st.front() >= TT::Attr_ATTRS_END)) return AttribSet::of(attr::NONE); auto parseUA = [](State& st) -> UA { + iceAssert(st.front() == TT::At); + st.pop(); + auto ret = UA(st.eat().str(), {}); if(st.front() == TT::LSquare) @@ -142,23 +145,29 @@ namespace parser AttribSet ret; - while(st.front() > TT::Attr_ATTRS_BEGIN && st.front() < TT::Attr_ATTRS_END) + while(true) { // i would love me some static reflection right now switch(st.front()) { case TT::Attr_Raw: ret.set(attr::RAW); st.pop(); break; + case TT::Attr_Packed: ret.set(attr::PACKED); st.pop(); break; case TT::Attr_NoMangle: ret.set(attr::NO_MANGLE); st.pop(); break; case TT::Attr_EntryFn: ret.set(attr::FN_ENTRYPOINT); st.pop(); break; case TT::Attr_Platform: unexpected(st.loc(), "@platform definition"); case TT::Attr_Operator: unexpected(st.loc(), "@operator declaration"); - default: + case TT::At: ret.add(parseUA(st)); break; + + default: + goto out; } } + // sue me + out: return ret; } diff --git a/source/include/lexer.h b/source/include/lexer.h index a942f66c..4b0fb0d9 100644 --- a/source/include/lexer.h +++ b/source/include/lexer.h @@ -121,6 +121,7 @@ namespace lexer Attr_ATTRS_BEGIN, Attr_Raw, + Attr_Packed, Attr_EntryFn, Attr_NoMangle, Attr_Operator, diff --git a/source/include/stcommon.h b/source/include/stcommon.h index d43698f5..14128dfc 100644 --- a/source/include/stcommon.h +++ b/source/include/stcommon.h @@ -23,6 +23,7 @@ namespace attr constexpr FlagTy FN_ENTRYPOINT = 0x1; constexpr FlagTy NO_MANGLE = 0x2; constexpr FlagTy RAW = 0x4; + constexpr FlagTy PACKED = 0x8; } struct AttribSet diff --git a/source/include/utils.h b/source/include/utils.h index 93c9382b..2a0d7b57 100644 --- a/source/include/utils.h +++ b/source/include/utils.h @@ -83,6 +83,18 @@ namespace util } + template + U foldl(const U& i, const std::vector& xs, FoldOp fn) + { + auto ret = i; + for(const auto& x : xs) + ret = fn(ret, x); + + return ret; + } + + + template ::type> std::vector map(const std::vector& input, UnaryOp fn) { diff --git a/source/typecheck/structs.cpp b/source/typecheck/structs.cpp index b8213ddb..d2fc73be 100644 --- a/source/typecheck/structs.cpp +++ b/source/typecheck/structs.cpp @@ -147,7 +147,7 @@ TCResult ast::StructDefn::generateDeclaration(sst::TypecheckState* fs, fir::Type for(auto m : this->methods) m->parentType = this, m->realScope = this->realScope + defn->id.name; - auto str = fir::StructType::createWithoutBody(defn->id); + auto str = fir::StructType::createWithoutBody(defn->id, /* isPacked: */ this->attrs.has(attr::PACKED)); defn->type = str; fs->checkForShadowingOrConflictingDefinition(defn, [](sst::TypecheckState* fs, sst::Defn* other) -> bool { return true; });