mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
669 lines
22 KiB
Nim
669 lines
22 KiB
Nim
type VarKind = enum
|
|
Local
|
|
Global
|
|
Threadvar
|
|
Const
|
|
AlwaysConst ## const even on C++
|
|
|
|
proc addVarHeader(builder: var Builder, kind: VarKind) =
|
|
## adds modifiers for given var kind:
|
|
## Local has no modifier
|
|
## Global has `static` modifier
|
|
## Const has `static NIM_CONST` modifier
|
|
## AlwaysConst has `static const` modifier (NIM_CONST is no-op on C++)
|
|
## Threadvar is unimplemented
|
|
case kind
|
|
of Local: discard
|
|
of Global:
|
|
builder.add("static ")
|
|
of Const:
|
|
builder.add("static NIM_CONST ")
|
|
of AlwaysConst:
|
|
builder.add("static const ")
|
|
of Threadvar:
|
|
doAssert false, "unimplemented"
|
|
|
|
proc addVar(builder: var Builder, kind: VarKind = Local, name: string, typ: Snippet, initializer: Snippet = "") =
|
|
## adds a variable declaration to the builder
|
|
builder.addVarHeader(kind)
|
|
builder.add(typ)
|
|
builder.add(" ")
|
|
builder.add(name)
|
|
if initializer.len != 0:
|
|
builder.add(" = ")
|
|
builder.add(initializer)
|
|
builder.addLineEnd(";")
|
|
|
|
template addVarWithType(builder: var Builder, kind: VarKind = Local, name: string, body: typed) =
|
|
## adds a variable declaration to the builder, with the `body` building the type
|
|
builder.addVarHeader(kind)
|
|
body
|
|
builder.add(" ")
|
|
builder.add(name)
|
|
builder.addLineEnd(";")
|
|
|
|
template addVarWithInitializer(builder: var Builder, kind: VarKind = Local, name: string,
|
|
typ: Snippet, initializerBody: typed) =
|
|
## adds a variable declaration to the builder, with
|
|
## `initializerBody` building the initializer. initializer must be provided
|
|
builder.addVarHeader(kind)
|
|
builder.add(typ)
|
|
builder.add(" ")
|
|
builder.add(name)
|
|
builder.add(" = ")
|
|
initializerBody
|
|
builder.addLineEnd(";")
|
|
|
|
template addVarWithTypeAndInitializer(builder: var Builder, kind: VarKind = Local, name: string,
|
|
typeBody, initializerBody: typed) =
|
|
## adds a variable declaration to the builder, with `typeBody` building the type, and
|
|
## `initializerBody` building the initializer. initializer must be provided
|
|
builder.addVarHeader(kind)
|
|
typeBody
|
|
builder.add(" ")
|
|
builder.add(name)
|
|
builder.add(" = ")
|
|
initializerBody
|
|
builder.addLineEnd(";")
|
|
|
|
proc addArrayVar(builder: var Builder, kind: VarKind = Local, name: string, elementType: Snippet, len: int, initializer: Snippet = "") =
|
|
## adds an array variable declaration to the builder
|
|
builder.addVarHeader(kind)
|
|
builder.add(elementType)
|
|
builder.add(" ")
|
|
builder.add(name)
|
|
builder.add("[")
|
|
builder.addIntValue(len)
|
|
builder.add("]")
|
|
if initializer.len != 0:
|
|
builder.add(" = ")
|
|
builder.add(initializer)
|
|
builder.addLineEnd(";")
|
|
|
|
template addArrayVarWithInitializer(builder: var Builder, kind: VarKind = Local, name: string, elementType: Snippet, len: int, body: typed) =
|
|
## adds an array variable declaration to the builder with the initializer built according to `body`
|
|
builder.addVarHeader(kind)
|
|
builder.add(elementType)
|
|
builder.add(" ")
|
|
builder.add(name)
|
|
builder.add("[")
|
|
builder.addIntValue(len)
|
|
builder.add("] = ")
|
|
body
|
|
builder.addLineEnd(";")
|
|
|
|
template addTypedef(builder: var Builder, name: string, typeBody: typed) =
|
|
## adds a typedef declaration to the builder with name `name` and type as
|
|
## built in `typeBody`
|
|
builder.add("typedef ")
|
|
typeBody
|
|
builder.add(" ")
|
|
builder.add(name)
|
|
builder.addLineEnd(";")
|
|
|
|
proc addProcTypedef(builder: var Builder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
|
|
builder.add("typedef ")
|
|
builder.add(CallingConvToStr[callConv])
|
|
builder.add("_PTR(")
|
|
builder.add(rettype)
|
|
builder.add(", ")
|
|
builder.add(name)
|
|
builder.add(")")
|
|
builder.add(params)
|
|
builder.addLineEnd(";")
|
|
|
|
template addArrayTypedef(builder: var Builder, name: string, len: BiggestInt, typeBody: typed) =
|
|
## adds an array typedef declaration to the builder with name `name`,
|
|
## length `len`, and element type as built in `typeBody`
|
|
builder.add("typedef ")
|
|
typeBody
|
|
builder.add(" ")
|
|
builder.add(name)
|
|
builder.add("[")
|
|
builder.addIntValue(len)
|
|
builder.addLineEnd("];")
|
|
|
|
type
|
|
StructInitializerKind = enum
|
|
siOrderedStruct ## struct constructor, but without named fields on C
|
|
siNamedStruct ## struct constructor, with named fields i.e. C99 designated initializer
|
|
siArray ## array constructor
|
|
siWrapper ## wrapper for a single field, generates it verbatim
|
|
|
|
StructInitializer = object
|
|
## context for building struct initializers, i.e. `{ field1, field2 }`
|
|
kind: StructInitializerKind
|
|
## if true, fields will not be named, instead values are placed in order
|
|
needsComma: bool
|
|
|
|
proc initStructInitializer(builder: var Builder, kind: StructInitializerKind): StructInitializer =
|
|
## starts building a struct initializer, i.e. braced initializer list
|
|
result = StructInitializer(kind: kind, needsComma: false)
|
|
if kind != siWrapper:
|
|
builder.add("{")
|
|
|
|
template addField(builder: var Builder, constr: var StructInitializer, name: string, valueBody: typed) =
|
|
## adds a field to a struct initializer, with the value built in `valueBody`
|
|
if constr.needsComma:
|
|
assert constr.kind != siWrapper, "wrapper constructor cannot have multiple fields"
|
|
builder.add(", ")
|
|
else:
|
|
constr.needsComma = true
|
|
case constr.kind
|
|
of siArray, siWrapper:
|
|
# no name, can just add value
|
|
valueBody
|
|
of siOrderedStruct:
|
|
# no name, can just add value on C
|
|
assert name.len != 0, "name has to be given for struct initializer field"
|
|
valueBody
|
|
of siNamedStruct:
|
|
assert name.len != 0, "name has to be given for struct initializer field"
|
|
builder.add(".")
|
|
builder.add(name)
|
|
builder.add(" = ")
|
|
valueBody
|
|
|
|
proc finishStructInitializer(builder: var Builder, constr: StructInitializer) =
|
|
## finishes building a struct initializer
|
|
if constr.kind != siWrapper:
|
|
builder.add("}")
|
|
|
|
template addStructInitializer(builder: var Builder, constr: out StructInitializer, kind: StructInitializerKind, body: typed) =
|
|
## builds a struct initializer, i.e. `{ field1, field2 }`
|
|
## a `var StructInitializer` must be declared and passed as a parameter so
|
|
## that it can be used with `addField`
|
|
constr = builder.initStructInitializer(kind)
|
|
body
|
|
builder.finishStructInitializer(constr)
|
|
|
|
proc addField(obj: var Builder; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
|
|
## adds a field inside a struct/union type
|
|
obj.add('\t')
|
|
obj.add(typ)
|
|
obj.add(" ")
|
|
obj.add(name)
|
|
if isFlexArray:
|
|
obj.add("[SEQ_DECL_SIZE]")
|
|
if initializer.len != 0:
|
|
obj.add(initializer)
|
|
obj.add(";\n")
|
|
|
|
proc addArrayField(obj: var Builder; name, elementType: Snippet; len: int; initializer: Snippet = "") =
|
|
## adds an array field inside a struct/union type
|
|
obj.add('\t')
|
|
obj.add(elementType)
|
|
obj.add(" ")
|
|
obj.add(name)
|
|
obj.add("[")
|
|
obj.addIntValue(len)
|
|
obj.add("]")
|
|
if initializer.len != 0:
|
|
obj.add(initializer)
|
|
obj.add(";\n")
|
|
|
|
proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
|
|
## adds an field inside a struct/union type, based on an `skField` symbol
|
|
obj.add('\t')
|
|
if field.alignment > 0:
|
|
obj.add("NIM_ALIGN(")
|
|
obj.addIntValue(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.addIntValue(field.bitsize)
|
|
if initializer.len != 0:
|
|
obj.add(initializer)
|
|
obj.add(";\n")
|
|
|
|
proc addProcField(obj: var Builder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
|
|
obj.add(CallingConvToStr[callConv])
|
|
obj.add("_PTR(")
|
|
obj.add(rettype)
|
|
obj.add(", ")
|
|
obj.add(name)
|
|
obj.add(")")
|
|
obj.add(params)
|
|
obj.add(";\n")
|
|
|
|
type
|
|
BaseClassKind = enum
|
|
## denotes how and whether or not the base class/RTTI should be stored
|
|
bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
|
|
StructBuilderInfo = object
|
|
## context for building `struct` types
|
|
baseKind: BaseClassKind
|
|
named: bool
|
|
preFieldsLen: int
|
|
|
|
proc structOrUnion(t: PType): Snippet =
|
|
let t = t.skipTypes({tyAlias, tySink})
|
|
if tfUnion in t.flags: "union"
|
|
else: "struct"
|
|
|
|
proc startSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet): StructBuilderInfo =
|
|
result = StructBuilderInfo(baseKind: bcNone, named: name.len != 0)
|
|
obj.add("struct")
|
|
if result.named:
|
|
obj.add(" ")
|
|
obj.add(name)
|
|
if baseType.len != 0:
|
|
if m.compileToCpp:
|
|
result.baseKind = bcCppInherit
|
|
else:
|
|
result.baseKind = bcSupField
|
|
if result.baseKind == bcCppInherit:
|
|
obj.add(" : public ")
|
|
obj.add(baseType)
|
|
obj.add(" ")
|
|
obj.add("{\n")
|
|
result.preFieldsLen = obj.buf.len
|
|
if result.baseKind == bcSupField:
|
|
obj.addField(name = "Sup", typ = baseType)
|
|
|
|
proc finishSimpleStruct(obj: var Builder; m: BModule; info: StructBuilderInfo) =
|
|
if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len:
|
|
# no fields were added, add dummy field
|
|
obj.addField(name = "dummy", typ = CChar)
|
|
if info.named:
|
|
obj.add("};\n")
|
|
else:
|
|
obj.add("}")
|
|
|
|
template addSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet; body: typed) =
|
|
## builds a struct type not based on a Nim type with fields according to `body`,
|
|
## `name` can be empty to build as a type expression and not a statement
|
|
let info = startSimpleStruct(obj, m, name, baseType)
|
|
body
|
|
finishSimpleStruct(obj, m, info)
|
|
|
|
proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType: Snippet): StructBuilderInfo =
|
|
result = StructBuilderInfo(baseKind: bcNone, named: name.len != 0)
|
|
if tfPacked in t.flags:
|
|
if hasAttribute in CC[m.config.cCompiler].props:
|
|
obj.add(structOrUnion(t))
|
|
obj.add(" __attribute__((__packed__))")
|
|
else:
|
|
obj.add("#pragma pack(push, 1)\n")
|
|
obj.add(structOrUnion(t))
|
|
else:
|
|
obj.add(structOrUnion(t))
|
|
if result.named:
|
|
obj.add(" ")
|
|
obj.add(name)
|
|
if t.kind == tyObject:
|
|
if t.baseClass == nil:
|
|
if lacksMTypeField(t):
|
|
result.baseKind = bcNone
|
|
elif optTinyRtti in m.config.globalOptions:
|
|
result.baseKind = bcNoneTinyRtti
|
|
else:
|
|
result.baseKind = bcNoneRtti
|
|
elif m.compileToCpp:
|
|
result.baseKind = bcCppInherit
|
|
else:
|
|
result.baseKind = bcSupField
|
|
elif baseType.len != 0:
|
|
if m.compileToCpp:
|
|
result.baseKind = bcCppInherit
|
|
else:
|
|
result.baseKind = bcSupField
|
|
if result.baseKind == bcCppInherit:
|
|
obj.add(" : public ")
|
|
obj.add(baseType)
|
|
obj.add(" ")
|
|
obj.add("{\n")
|
|
result.preFieldsLen = obj.buf.len
|
|
case result.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 t.itemId notin m.g.graph.memberProcsPerType and
|
|
t.n != nil and t.n.len == 1 and t.n[0].kind == nkSym and
|
|
t.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
|
|
# only consists of flexible array field, add *initial* dummy field
|
|
obj.addField(name = "dummy", typ = CChar)
|
|
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)
|
|
|
|
proc finishStruct(obj: var Builder; m: BModule; t: PType; info: StructBuilderInfo) =
|
|
if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len and
|
|
t.itemId notin m.g.graph.memberProcsPerType:
|
|
# no fields were added, add dummy field
|
|
obj.addField(name = "dummy", typ = CChar)
|
|
if info.named:
|
|
obj.add("};\n")
|
|
else:
|
|
obj.add("}")
|
|
if tfPacked in t.flags and hasAttribute notin CC[m.config.cCompiler].props:
|
|
obj.add("#pragma pack(pop)\n")
|
|
|
|
template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: Snippet; body: typed) =
|
|
## builds a struct type directly based on `typ` with fields according to `body`,
|
|
## `name` can be empty to build as a type expression and not a statement
|
|
let info = startStruct(obj, m, typ, name, baseType)
|
|
body
|
|
finishStruct(obj, m, typ, info)
|
|
|
|
template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) =
|
|
## adds a field with a `struct { ... }` type, building the fields 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:
|
|
obj.add("#pragma pack(pop)\n")
|
|
|
|
template addAnonUnion(obj: var Builder; body: typed) =
|
|
## adds an anonymous union i.e. `union { ... };` with fields according to `body`
|
|
obj.add "union{\n"
|
|
body
|
|
obj.add("};\n")
|
|
|
|
template addUnionType(obj: var Builder; body: typed) =
|
|
## adds a union type i.e. `union { ... }` with fields according to `body`
|
|
obj.add "union{\n"
|
|
body
|
|
obj.add("}")
|
|
|
|
type DeclVisibility = enum
|
|
None
|
|
Extern
|
|
ExternC
|
|
ImportLib
|
|
ExportLib
|
|
ExportLibVar
|
|
Private
|
|
StaticProc
|
|
|
|
proc addVisibilityPrefix(builder: var Builder, visibility: DeclVisibility) =
|
|
# internal proc
|
|
case visibility
|
|
of None: discard
|
|
of Extern:
|
|
builder.add("extern ")
|
|
of ExternC:
|
|
builder.add("NIM_EXTERNC ")
|
|
of ImportLib:
|
|
builder.add("N_LIB_IMPORT ")
|
|
of ExportLib:
|
|
builder.add("N_LIB_EXPORT ")
|
|
of ExportLibVar:
|
|
builder.add("N_LIB_EXPORT_VAR ")
|
|
of Private:
|
|
builder.add("N_LIB_PRIVATE ")
|
|
of StaticProc:
|
|
builder.add("static ")
|
|
|
|
template addDeclWithVisibility(builder: var Builder, visibility: DeclVisibility, declBody: typed) =
|
|
## adds a declaration as in `declBody` with the given visibility
|
|
builder.addVisibilityPrefix(visibility)
|
|
declBody
|
|
|
|
type ProcParamBuilder = object
|
|
needsComma: bool
|
|
|
|
proc initProcParamBuilder(builder: var Builder): ProcParamBuilder =
|
|
result = ProcParamBuilder(needsComma: false)
|
|
builder.add("(")
|
|
|
|
proc finishProcParamBuilder(builder: var Builder, params: ProcParamBuilder) =
|
|
if params.needsComma:
|
|
builder.add(")")
|
|
else:
|
|
builder.add("void)")
|
|
|
|
template cgDeclFrmt*(s: PSym): string =
|
|
s.constraint.strVal
|
|
|
|
proc addParam(builder: var Builder, params: var ProcParamBuilder, name: string, typ: Snippet) =
|
|
if params.needsComma:
|
|
builder.add(", ")
|
|
else:
|
|
params.needsComma = true
|
|
builder.add(typ)
|
|
builder.add(" ")
|
|
builder.add(name)
|
|
|
|
proc addParam(builder: var Builder, params: var ProcParamBuilder, param: PSym, typ: Snippet) =
|
|
if params.needsComma:
|
|
builder.add(", ")
|
|
else:
|
|
params.needsComma = true
|
|
var modifiedTyp = typ
|
|
if sfNoalias in param.flags:
|
|
modifiedTyp.add(" NIM_NOALIAS")
|
|
if sfCodegenDecl notin param.flags:
|
|
builder.add(modifiedTyp)
|
|
builder.add(" ")
|
|
builder.add(param.loc.snippet)
|
|
else:
|
|
builder.add runtimeFormat(param.cgDeclFrmt, [modifiedTyp, param.loc.snippet])
|
|
|
|
proc addUnnamedParam(builder: var Builder, params: var ProcParamBuilder, typ: Snippet) =
|
|
if params.needsComma:
|
|
builder.add(", ")
|
|
else:
|
|
params.needsComma = true
|
|
builder.add(typ)
|
|
|
|
proc addProcTypedParam(builder: var Builder, paramBuilder: var ProcParamBuilder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
|
|
if paramBuilder.needsComma:
|
|
builder.add(", ")
|
|
else:
|
|
paramBuilder.needsComma = true
|
|
builder.add(CallingConvToStr[callConv])
|
|
builder.add("_PTR(")
|
|
builder.add(rettype)
|
|
builder.add(", ")
|
|
builder.add(name)
|
|
builder.add(")")
|
|
builder.add(params)
|
|
|
|
proc addVarargsParam(builder: var Builder, params: var ProcParamBuilder) =
|
|
# does not exist in NIFC, needs to be proc pragma
|
|
if params.needsComma:
|
|
builder.add(", ")
|
|
else:
|
|
params.needsComma = true
|
|
builder.add("...")
|
|
|
|
template addProcParams(builder: var Builder, params: out ProcParamBuilder, body: typed) =
|
|
params = initProcParamBuilder(builder)
|
|
body
|
|
finishProcParamBuilder(builder, params)
|
|
|
|
type SimpleProcParam = tuple
|
|
name, typ: string
|
|
|
|
proc cProcParams(params: varargs[SimpleProcParam]): Snippet =
|
|
if params.len == 0: return "(void)"
|
|
result = "("
|
|
for i in 0 ..< params.len:
|
|
if i != 0: result.add(", ")
|
|
result.add(params[i].typ)
|
|
if params[i].name.len != 0:
|
|
result.add(" ")
|
|
result.add(params[i].name)
|
|
result.add(")")
|
|
|
|
template addProcHeaderWithParams(builder: var Builder, callConv: TCallingConvention,
|
|
name: string, rettype: Snippet, paramBuilder: typed) =
|
|
# on nifc should build something like (proc name params type pragmas
|
|
# with no body given
|
|
# or enforce this with secondary builder object
|
|
builder.add(CallingConvToStr[callConv])
|
|
builder.add("(")
|
|
builder.add(rettype)
|
|
builder.add(", ")
|
|
builder.add(name)
|
|
builder.add(")")
|
|
paramBuilder
|
|
|
|
proc addProcHeader(builder: var Builder, callConv: TCallingConvention,
|
|
name: string, rettype, params: Snippet) =
|
|
# on nifc should build something like (proc name params type pragmas
|
|
# with no body given
|
|
# or enforce this with secondary builder object
|
|
addProcHeaderWithParams(builder, callConv, name, rettype):
|
|
builder.add(params)
|
|
|
|
proc addProcHeader(builder: var Builder, name: string, rettype, params: Snippet, isConstructor = false) =
|
|
# no callconv
|
|
builder.add(rettype)
|
|
builder.add(" ")
|
|
if isConstructor:
|
|
builder.add("__attribute__((constructor)) ")
|
|
builder.add(name)
|
|
builder.add(params)
|
|
|
|
proc addProcHeader(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet, addAttributes: bool) =
|
|
# on nifc should build something like (proc name params type pragmas
|
|
# with no body given
|
|
# or enforce this with secondary builder object
|
|
let noreturn = isNoReturn(m, prc)
|
|
if sfPure in prc.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
|
builder.add("__declspec(naked) ")
|
|
if noreturn and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
|
builder.add("__declspec(noreturn) ")
|
|
builder.add(CallingConvToStr[prc.typ.callConv])
|
|
builder.add("(")
|
|
builder.add(rettype)
|
|
builder.add(", ")
|
|
builder.add(name)
|
|
builder.add(")")
|
|
builder.add(params)
|
|
if addAttributes:
|
|
if sfPure in prc.flags and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
|
builder.add(" __attribute__((naked))")
|
|
if noreturn and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
|
builder.add(" __attribute__((noreturn))")
|
|
|
|
proc finishProcHeaderAsProto(builder: var Builder) =
|
|
builder.addLineEnd(";")
|
|
|
|
template finishProcHeaderWithBody(builder: var Builder, body: typed) =
|
|
builder.addLineEndIndent(" {")
|
|
body
|
|
builder.addLineEndDedent("}")
|
|
builder.addNewline
|
|
|
|
proc addProcVar(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet,
|
|
isStatic = false, ignoreAttributes = false) =
|
|
# on nifc, builds full variable
|
|
if isStatic:
|
|
builder.add("static ")
|
|
let noreturn = isNoReturn(m, prc)
|
|
if not ignoreAttributes:
|
|
if sfPure in prc.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
|
builder.add("__declspec(naked) ")
|
|
if noreturn and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
|
builder.add("__declspec(noreturn) ")
|
|
builder.add(CallingConvToStr[prc.typ.callConv])
|
|
builder.add("_PTR(")
|
|
builder.add(rettype)
|
|
builder.add(", ")
|
|
builder.add(name)
|
|
builder.add(")")
|
|
builder.add(params)
|
|
if not ignoreAttributes:
|
|
if sfPure in prc.flags and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
|
builder.add(" __attribute__((naked))")
|
|
if noreturn and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
|
builder.add(" __attribute__((noreturn))")
|
|
# ensure we are just adding a variable:
|
|
builder.addLineEnd(";")
|
|
|
|
proc addProcVar(builder: var Builder, callConv: TCallingConvention,
|
|
name: string, params, rettype: Snippet,
|
|
isStatic = false, isVolatile = false) =
|
|
# on nifc, builds full variable
|
|
if isStatic:
|
|
builder.add("static ")
|
|
builder.add(CallingConvToStr[callConv])
|
|
builder.add("_PTR(")
|
|
builder.add(rettype)
|
|
builder.add(", ")
|
|
if isVolatile:
|
|
builder.add("volatile ")
|
|
builder.add(name)
|
|
builder.add(")")
|
|
builder.add(params)
|
|
# ensure we are just adding a variable:
|
|
builder.addLineEnd(";")
|
|
|
|
proc addProcVar(builder: var Builder,
|
|
name: string, params, rettype: Snippet,
|
|
isStatic = false, isVolatile = false) =
|
|
# no callconv
|
|
if isStatic:
|
|
builder.add("static ")
|
|
builder.add(rettype)
|
|
builder.add(" (*")
|
|
if isVolatile:
|
|
builder.add("volatile ")
|
|
builder.add(name)
|
|
builder.add(")")
|
|
builder.add(params)
|
|
# ensure we are just adding a variable:
|
|
builder.addLineEnd(";")
|
|
|
|
type VarInitializerKind = enum
|
|
Assignment, CppConstructor
|
|
|
|
proc addVar(builder: var Builder, m: BModule, s: PSym, name: string, typ: Snippet, kind = Local, visibility: DeclVisibility = None, initializer: Snippet = "", initializerKind: VarInitializerKind = Assignment) =
|
|
if sfCodegenDecl in s.flags:
|
|
builder.add(runtimeFormat(s.cgDeclFrmt, [typ, name]))
|
|
if initializer.len != 0:
|
|
if initializerKind == Assignment:
|
|
builder.add(" = ")
|
|
builder.add(initializer)
|
|
builder.addLineEnd(";")
|
|
return
|
|
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
|
builder.add("NIM_ALIGN(" & $s.alignment & ") ")
|
|
builder.addVisibilityPrefix(visibility)
|
|
if kind == Threadvar:
|
|
if optThreads in m.config.globalOptions:
|
|
let sym = s.typ.sym
|
|
if sym != nil and sfCppNonPod in sym.flags:
|
|
builder.add("NIM_THREAD_LOCAL ")
|
|
else: builder.add("NIM_THREADVAR ")
|
|
else:
|
|
builder.addVarHeader(kind)
|
|
builder.add(typ)
|
|
if sfRegister in s.flags: builder.add(" register")
|
|
if sfVolatile in s.flags: builder.add(" volatile")
|
|
if sfNoalias in s.flags: builder.add(" NIM_NOALIAS")
|
|
builder.add(" ")
|
|
builder.add(name)
|
|
if initializer.len != 0:
|
|
if initializerKind == Assignment:
|
|
builder.add(" = ")
|
|
builder.add(initializer)
|
|
builder.addLineEnd(";")
|
|
|
|
proc addInclude(builder: var Builder, value: Snippet) =
|
|
builder.addLineEnd("#include " & value)
|