mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
based on #24127 Needs some tweaks to replace the other `struct` type generations, e.g. seqs, maybe by exposing `BaseTypeKind` as a parameter. C++ and codegenDecl etc seem like they are going to need attention. Also `Builder` should really be `distinct string` that one has to call `extract` on, but for this to be optimal in the current codegen, we would need something like: ```nim template buildInto(s: var string, builderName: untyped, body) = template `builderName`: untyped = Builder(s) body buildInto(result, builder): builder.add ... ``` but this could be a separate PR since it might not work with the compiler. The possibly-not-optimal alternative is to do: ```nim template build(builderName: untyped, body): string = var `builderName` = Builder("") body extract(`builderName`) result = build(builder): builder.add ... ``` where the compiler maybe copies the built string but shouldn't. --------- Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
122 lines
3.7 KiB
Nim
122 lines
3.7 KiB
Nim
type
|
|
Snippet = string
|
|
Builder = string
|
|
|
|
template newBuilder(s: string): Builder =
|
|
s
|
|
|
|
proc addField(obj: var Builder; name, typ: Snippet) =
|
|
obj.add('\t')
|
|
obj.add(typ)
|
|
obj.add(" ")
|
|
obj.add(name)
|
|
obj.add(";\n")
|
|
|
|
proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool; initializer: Snippet) =
|
|
obj.add('\t')
|
|
if field.alignment > 0:
|
|
obj.add("NIM_ALIGN(")
|
|
obj.addInt(field.alignment)
|
|
obj.add(") ")
|
|
obj.add(typ)
|
|
if sfNoalias in field.flags:
|
|
obj.add(" NIM_NOALIAS")
|
|
obj.add(" ")
|
|
obj.add(name)
|
|
if isFlexArray:
|
|
obj.add("[SEQ_DECL_SIZE]")
|
|
if field.bitsize != 0:
|
|
obj.add(":")
|
|
obj.addInt(field.bitsize)
|
|
if initializer.len != 0:
|
|
obj.add(initializer)
|
|
obj.add(";\n")
|
|
|
|
proc structOrUnion(t: PType): Snippet =
|
|
let t = t.skipTypes({tyAlias, tySink})
|
|
if tfUnion in t.flags: "union"
|
|
else: "struct"
|
|
|
|
proc ptrType(t: Snippet): Snippet =
|
|
t & "*"
|
|
|
|
template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: string; body: typed) =
|
|
if tfPacked in typ.flags:
|
|
if hasAttribute in CC[m.config.cCompiler].props:
|
|
obj.add(structOrUnion(typ))
|
|
obj.add(" __attribute__((__packed__))")
|
|
else:
|
|
obj.add("#pragma pack(push, 1)\n")
|
|
obj.add(structOrUnion(typ))
|
|
else:
|
|
obj.add(structOrUnion(typ))
|
|
obj.add(" ")
|
|
obj.add(name)
|
|
type BaseClassKind = enum
|
|
bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
|
|
var baseKind = bcNone
|
|
if typ.kind == tyObject:
|
|
if typ.baseClass == nil:
|
|
if lacksMTypeField(typ):
|
|
baseKind = bcNone
|
|
elif optTinyRtti in m.config.globalOptions:
|
|
baseKind = bcNoneTinyRtti
|
|
else:
|
|
baseKind = bcNoneRtti
|
|
elif m.compileToCpp:
|
|
baseKind = bcCppInherit
|
|
else:
|
|
baseKind = bcSupField
|
|
if baseKind == bcCppInherit:
|
|
obj.add(" : public ")
|
|
obj.add(baseType)
|
|
obj.add(" ")
|
|
obj.add("{\n")
|
|
let currLen = obj.len
|
|
case baseKind
|
|
of bcNone:
|
|
# rest of the options add a field or don't need it due to inheritance,
|
|
# we need to add the dummy field for uncheckedarray ahead of time
|
|
# so that it remains trailing
|
|
if typ.itemId notin m.g.graph.memberProcsPerType and
|
|
typ.n != nil and typ.n.len == 1 and typ.n[0].kind == nkSym and
|
|
typ.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
|
|
# only consists of flexible array field, add *initial* dummy field
|
|
obj.addField(name = "dummy", typ = "char")
|
|
of bcCppInherit: discard
|
|
of bcNoneRtti:
|
|
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimType")))
|
|
of bcNoneTinyRtti:
|
|
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimTypeV2")))
|
|
of bcSupField:
|
|
obj.addField(name = "Sup", typ = baseType)
|
|
body
|
|
if baseKind == bcNone and currLen == obj.len and typ.itemId notin m.g.graph.memberProcsPerType:
|
|
# no fields were added, add dummy field
|
|
obj.addField(name = "dummy", typ = "char")
|
|
obj.add("};\n")
|
|
if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props:
|
|
result.add("#pragma pack(pop)\n")
|
|
|
|
template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) =
|
|
## adds a field with a `struct { ... }` type, building it according to `body`
|
|
obj.add('\t')
|
|
if tfPacked in parentTyp.flags:
|
|
if hasAttribute in CC[m.config.cCompiler].props:
|
|
obj.add("struct __attribute__((__packed__)) {\n")
|
|
else:
|
|
obj.add("#pragma pack(push, 1)\nstruct {")
|
|
else:
|
|
obj.add("struct {\n")
|
|
body
|
|
obj.add("} ")
|
|
obj.add(fieldName)
|
|
obj.add(";\n")
|
|
if tfPacked in parentTyp.flags and hasAttribute notin CC[m.config.cCompiler].props:
|
|
result.add("#pragma pack(pop)\n")
|
|
|
|
template addAnonUnion(obj: var Builder; body: typed) =
|
|
obj.add "union{\n"
|
|
body
|
|
obj.add("};\n")
|