mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-16 08:04:20 +00:00
use cbuilder for default proc generation (#24390)
C++ member procs are not implemented, and `codegenDecl` in general is also not adapted, although it had to be included in the generation of proc params for simplicity. Guessing `codegenDecl` and C++ stuff are supposed to map to pragmas on NIFC, or are just not supported.
This commit is contained in:
@@ -89,6 +89,17 @@ template addTypedef(builder: var Builder, name: string, typeBody: typed) =
|
||||
builder.add(name)
|
||||
builder.add(";\n")
|
||||
|
||||
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.add(";\n")
|
||||
|
||||
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`
|
||||
@@ -200,6 +211,16 @@ proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bo
|
||||
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
|
||||
@@ -349,17 +370,23 @@ template addAnonUnion(obj: var Builder; body: typed) =
|
||||
obj.add("};\n")
|
||||
|
||||
type DeclVisibility = enum
|
||||
None
|
||||
Extern
|
||||
ExternC
|
||||
ImportLib
|
||||
ExportLib
|
||||
ExportLibVar
|
||||
Private
|
||||
StaticProc
|
||||
|
||||
template addDeclWithVisibility(builder: var Builder, visibility: DeclVisibility, declBody: typed) =
|
||||
## adds a declaration as in `declBody` with the given visibility
|
||||
case visibility
|
||||
of None: discard
|
||||
of Extern:
|
||||
builder.add("extern ")
|
||||
of ExternC:
|
||||
builder.add("extern \"C\" ")
|
||||
of ImportLib:
|
||||
builder.add("N_LIB_IMPORT ")
|
||||
of ExportLib:
|
||||
@@ -368,4 +395,121 @@ template addDeclWithVisibility(builder: var Builder, visibility: DeclVisibility,
|
||||
builder.add("N_LIB_EXPORT_VAR ")
|
||||
of Private:
|
||||
builder.add("N_LIB_PRIVATE ")
|
||||
of StaticProc:
|
||||
builder.add("static ")
|
||||
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 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)
|
||||
|
||||
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
|
||||
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.add(";\n")
|
||||
|
||||
template finishProcHeaderWithBody(builder: var Builder, body: typed) =
|
||||
builder.add(" {\n")
|
||||
body
|
||||
builder.add("}\n\n")
|
||||
|
||||
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.add(";\n")
|
||||
|
||||
@@ -23,8 +23,11 @@ const
|
||||
"N_NOCONV" #ccMember is N_NOCONV
|
||||
]
|
||||
|
||||
proc procPtrType(conv: TCallingConvention, rettype: Snippet, name: string): Snippet =
|
||||
CallingConvToStr[conv] & "_PTR(" & rettype & ", " & name & ")"
|
||||
proc procPtrTypeUnnamed(rettype, params: Snippet): Snippet =
|
||||
rettype & "(*)" & params
|
||||
|
||||
proc procPtrTypeUnnamedNimCall(rettype, params: Snippet): Snippet =
|
||||
rettype & "(N_RAW_NIMCALL*)" & params
|
||||
|
||||
proc cCast(typ, value: Snippet): Snippet =
|
||||
"((" & typ & ") " & value & ")"
|
||||
|
||||
@@ -92,3 +92,20 @@ template addElseBranch(builder: var Builder, stmt: var IfStmt, body: typed) =
|
||||
builder.add(" else {\n")
|
||||
body
|
||||
builder.add("}")
|
||||
|
||||
template addScope(builder: var Builder, body: typed) =
|
||||
builder.add("{")
|
||||
body
|
||||
builder.add("\t}")
|
||||
|
||||
proc addLabel(builder: var Builder, name: TLabel) =
|
||||
builder.add(name)
|
||||
builder.add(": ;\n")
|
||||
|
||||
proc addReturn(builder: var Builder) =
|
||||
builder.add("return;\n")
|
||||
|
||||
proc addReturn(builder: var Builder, value: string) =
|
||||
builder.add("return ")
|
||||
builder.add(value)
|
||||
builder.add(";\n")
|
||||
|
||||
@@ -511,9 +511,6 @@ proc multiFormat*(frmt: var string, chars: static openArray[char], args: openArr
|
||||
res.add(substr(frmt, start, i - 1))
|
||||
frmt = res
|
||||
|
||||
template cgDeclFrmt*(s: PSym): string =
|
||||
s.constraint.strVal
|
||||
|
||||
proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params: var string,
|
||||
check: var IntSet, declareEnvironment=true;
|
||||
weakDep=false;) =
|
||||
@@ -590,79 +587,65 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
|
||||
params.delete(params.len()-1..params.len()-1)
|
||||
params.add("...)")
|
||||
|
||||
proc genProcParams(m: BModule; t: PType, rettype, params: var Rope,
|
||||
proc genProcParams(m: BModule; t: PType, rettype: var Rope, params: var Builder,
|
||||
check: var IntSet, declareEnvironment=true;
|
||||
weakDep=false;) =
|
||||
params = "("
|
||||
if t.returnType == nil or isInvalidReturnType(m.config, t):
|
||||
rettype = "void"
|
||||
else:
|
||||
rettype = getTypeDescAux(m, t.returnType, check, dkResult)
|
||||
for i in 1..<t.n.len:
|
||||
if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
|
||||
var param = t.n[i].sym
|
||||
var descKind = dkParam
|
||||
if m.config.backend == backendCpp and optByRef in param.options:
|
||||
if param.typ.kind == tyGenericInst:
|
||||
descKind = dkRefGenericParam
|
||||
var paramBuilder: ProcParamBuilder
|
||||
params.addProcParams(paramBuilder):
|
||||
for i in 1..<t.n.len:
|
||||
if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
|
||||
var param = t.n[i].sym
|
||||
var descKind = dkParam
|
||||
if m.config.backend == backendCpp and optByRef in param.options:
|
||||
if param.typ.kind == tyGenericInst:
|
||||
descKind = dkRefGenericParam
|
||||
else:
|
||||
descKind = dkRefParam
|
||||
if isCompileTimeOnly(param.typ): continue
|
||||
fillParamName(m, param)
|
||||
fillLoc(param.loc, locParam, t.n[i],
|
||||
param.paramStorageLoc)
|
||||
var typ: Rope
|
||||
if ccgIntroducedPtr(m.config, param, t.returnType) and descKind == dkParam:
|
||||
typ = ptrType(getTypeDescWeak(m, param.typ, check, descKind))
|
||||
incl(param.loc.flags, lfIndirect)
|
||||
param.loc.storage = OnUnknown
|
||||
elif weakDep:
|
||||
typ = (getTypeDescWeak(m, param.typ, check, descKind))
|
||||
else:
|
||||
descKind = dkRefParam
|
||||
if isCompileTimeOnly(param.typ): continue
|
||||
if params != "(": params.add(", ")
|
||||
fillParamName(m, param)
|
||||
fillLoc(param.loc, locParam, t.n[i],
|
||||
param.paramStorageLoc)
|
||||
var typ: Rope
|
||||
if ccgIntroducedPtr(m.config, param, t.returnType) and descKind == dkParam:
|
||||
typ = (getTypeDescWeak(m, param.typ, check, descKind))
|
||||
typ.add("*")
|
||||
incl(param.loc.flags, lfIndirect)
|
||||
param.loc.storage = OnUnknown
|
||||
elif weakDep:
|
||||
typ = (getTypeDescWeak(m, param.typ, check, descKind))
|
||||
else:
|
||||
typ = (getTypeDescAux(m, param.typ, check, descKind))
|
||||
typ.add(" ")
|
||||
if sfNoalias in param.flags:
|
||||
typ.add("NIM_NOALIAS ")
|
||||
if sfCodegenDecl notin param.flags:
|
||||
params.add(typ)
|
||||
params.add(param.loc.snippet)
|
||||
else:
|
||||
params.add runtimeFormat(param.cgDeclFrmt, [typ, param.loc.snippet])
|
||||
# declare the len field for open arrays:
|
||||
var arr = param.typ.skipTypes({tyGenericInst})
|
||||
if arr.kind in {tyVar, tyLent, tySink}: arr = arr.elementType
|
||||
var j = 0
|
||||
while arr.kind in {tyOpenArray, tyVarargs}:
|
||||
# this fixes the 'sort' bug:
|
||||
if param.typ.kind in {tyVar, tyLent}: param.loc.storage = OnUnknown
|
||||
# need to pass hidden parameter:
|
||||
params.addf(", NI $1Len_$2", [param.loc.snippet, j.rope])
|
||||
inc(j)
|
||||
arr = arr[0].skipTypes({tySink})
|
||||
if t.returnType != nil and isInvalidReturnType(m.config, t):
|
||||
var arr = t.returnType
|
||||
if params != "(": params.add(", ")
|
||||
if mapReturnType(m.config, arr) != ctArray:
|
||||
if isHeaderFile in m.flags:
|
||||
# still generates types for `--header`
|
||||
params.add(getTypeDescAux(m, arr, check, dkResult))
|
||||
params.add("*")
|
||||
typ = (getTypeDescAux(m, param.typ, check, descKind))
|
||||
params.addParam(paramBuilder, param, typ = typ)
|
||||
# declare the len field for open arrays:
|
||||
var arr = param.typ.skipTypes({tyGenericInst})
|
||||
if arr.kind in {tyVar, tyLent, tySink}: arr = arr.elementType
|
||||
var j = 0
|
||||
while arr.kind in {tyOpenArray, tyVarargs}:
|
||||
# this fixes the 'sort' bug:
|
||||
if param.typ.kind in {tyVar, tyLent}: param.loc.storage = OnUnknown
|
||||
# need to pass hidden parameter:
|
||||
params.addParam(paramBuilder, name = param.loc.snippet & "Len_" & $j, typ = "NI")
|
||||
inc(j)
|
||||
arr = arr[0].skipTypes({tySink})
|
||||
if t.returnType != nil and isInvalidReturnType(m.config, t):
|
||||
var arr = t.returnType
|
||||
var typ: Snippet
|
||||
if mapReturnType(m.config, arr) != ctArray:
|
||||
if isHeaderFile in m.flags:
|
||||
# still generates types for `--header`
|
||||
typ = ptrType(getTypeDescAux(m, arr, check, dkResult))
|
||||
else:
|
||||
typ = ptrType(getTypeDescWeak(m, arr, check, dkResult))
|
||||
else:
|
||||
params.add(getTypeDescWeak(m, arr, check, dkResult))
|
||||
params.add("*")
|
||||
else:
|
||||
params.add(getTypeDescAux(m, arr, check, dkResult))
|
||||
params.addf(" Result", [])
|
||||
if t.callConv == ccClosure and declareEnvironment:
|
||||
if params != "(": params.add(", ")
|
||||
params.add("void* ClE_0")
|
||||
if tfVarargs in t.flags:
|
||||
if params != "(": params.add(", ")
|
||||
params.add("...")
|
||||
if params == "(": params.add("void)")
|
||||
else: params.add(")")
|
||||
typ = getTypeDescAux(m, arr, check, dkResult)
|
||||
params.addParam(paramBuilder, name = "Result", typ = typ)
|
||||
if t.callConv == ccClosure and declareEnvironment:
|
||||
params.addParam(paramBuilder, name = "ClE_0", typ = "void*")
|
||||
if tfVarargs in t.flags:
|
||||
params.addVarargsParam(paramBuilder)
|
||||
|
||||
proc mangleRecFieldName(m: BModule; field: PSym): Rope =
|
||||
if {sfImportc, sfExportc} * field.flags != {}:
|
||||
@@ -959,18 +942,17 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
|
||||
of tyProc:
|
||||
result = getTypeName(m, origTyp, sig)
|
||||
m.typeCache[sig] = result
|
||||
var rettype, desc: Rope = ""
|
||||
var rettype: Snippet = ""
|
||||
var desc = newBuilder("")
|
||||
genProcParams(m, t, rettype, desc, check, true, true)
|
||||
if not isImportedType(t):
|
||||
var typedef = newBuilder("")
|
||||
if t.callConv != ccClosure: # procedure vars may need a closure!
|
||||
typedef.addTypedef(name = desc):
|
||||
typedef.add(procPtrType(t.callConv, rettype = rettype, name = result))
|
||||
typedef.addProcTypedef(callConv = t.callConv, name = result, rettype = rettype, params = desc)
|
||||
else:
|
||||
typedef.addTypedef(name = result):
|
||||
typedef.addSimpleStruct(m, name = "", baseType = ""):
|
||||
typedef.addField(name = desc, typ =
|
||||
procPtrType(ccNimCall, rettype = rettype, name = "ClP_0"))
|
||||
typedef.addProcField(name = "ClP_0", callConv = ccNimCall, rettype = rettype, params = desc)
|
||||
typedef.addField(name = "ClE_0", typ = "void*")
|
||||
m.s[cfsTypes].add(typedef)
|
||||
of tySequence:
|
||||
@@ -1124,18 +1106,17 @@ proc getClosureType(m: BModule; t: PType, kind: TClosureTypeKind): Rope =
|
||||
assert t.kind == tyProc
|
||||
var check = initIntSet()
|
||||
result = getTempName(m)
|
||||
var rettype, desc: Rope = ""
|
||||
var rettype: Snippet = ""
|
||||
var desc = newBuilder("")
|
||||
genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
|
||||
if not isImportedType(t):
|
||||
var typedef = newBuilder("")
|
||||
if t.callConv != ccClosure or kind != clFull:
|
||||
typedef.addTypedef(name = desc):
|
||||
typedef.add(procPtrType(t.callConv, rettype = rettype, name = result))
|
||||
typedef.addProcTypedef(callConv = t.callConv, name = result, rettype = rettype, params = desc)
|
||||
else:
|
||||
typedef.addTypedef(name = result):
|
||||
typedef.addSimpleStruct(m, name = "", baseType = ""):
|
||||
typedef.addField(name = desc, typ =
|
||||
procPtrType(ccNimCall, rettype = rettype, name = "ClP_0"))
|
||||
typedef.addProcField(name = "ClP_0", callConv = ccNimCall, rettype = rettype, params = desc)
|
||||
typedef.addField(name = "ClE_0", typ = "void*")
|
||||
m.s[cfsTypes].add(typedef)
|
||||
|
||||
@@ -1228,34 +1209,38 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
|
||||
[rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name,
|
||||
params, fnConst, override, superCall])
|
||||
|
||||
proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false) =
|
||||
proc genProcHeader(m: BModule; prc: PSym; result: var Rope; visibility: var DeclVisibility, asPtr: bool, addAttributes: bool) =
|
||||
# using static is needed for inline procs
|
||||
var check = initIntSet()
|
||||
fillBackendName(m, prc)
|
||||
fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
|
||||
var rettype, params: Rope = ""
|
||||
var rettype: Snippet = ""
|
||||
var params = newBuilder("")
|
||||
genProcParams(m, prc.typ, rettype, params, check, true, false)
|
||||
# handle the 2 options for hotcodereloading codegen - function pointer
|
||||
# (instead of forward declaration) or header for function body with "_actual" postfix
|
||||
let asPtrStr = rope(if asPtr: "_PTR" else: "")
|
||||
var name = prc.loc.snippet
|
||||
if not asPtr and isReloadable(m, prc):
|
||||
name.add("_actual")
|
||||
# careful here! don't access ``prc.ast`` as that could reload large parts of
|
||||
# the object graph!
|
||||
if sfCodegenDecl notin prc.flags:
|
||||
var isStaticVar = false
|
||||
if lfExportLib in prc.loc.flags:
|
||||
if isHeaderFile in m.flags:
|
||||
result.add "N_LIB_IMPORT "
|
||||
visibility = ImportLib
|
||||
else:
|
||||
result.add "N_LIB_EXPORT "
|
||||
elif prc.typ.callConv == ccInline or asPtr or isNonReloadable(m, prc):
|
||||
result.add "static "
|
||||
visibility = ExportLib
|
||||
elif asPtr:
|
||||
isStaticVar = true
|
||||
elif prc.typ.callConv == ccInline or isNonReloadable(m, prc):
|
||||
visibility = StaticProc
|
||||
elif sfImportc notin prc.flags:
|
||||
result.add "N_LIB_PRIVATE "
|
||||
result.addf("$1$2($3, $4)$5",
|
||||
[rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name,
|
||||
params])
|
||||
visibility = Private
|
||||
if asPtr:
|
||||
result.addProcVar(m, prc, name, params, rettype, isStatic = isStaticVar, ignoreAttributes = true)
|
||||
else:
|
||||
result.addProcHeader(m, prc, name, params, rettype, addAttributes)
|
||||
else:
|
||||
let asPtrStr = if asPtr: (rope("(*") & name & ")") else: name
|
||||
result.add runtimeFormat(prc.cgDeclFrmt, [rettype, asPtrStr, params])
|
||||
@@ -1573,8 +1558,13 @@ include ccgtrav
|
||||
|
||||
proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
|
||||
genProc(m, s)
|
||||
m.s[cfsTypeInit3].addf("$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
|
||||
[result, s.loc.snippet])
|
||||
var params = newBuilder("")
|
||||
var paramBuilder: ProcParamBuilder
|
||||
params.addProcParams(paramBuilder):
|
||||
params.addUnnamedParam(paramBuilder, typ = "void*")
|
||||
let pt = procPtrTypeUnnamedNimCall(rettype = "void*", params = params)
|
||||
m.s[cfsTypeInit3].addFieldAssignmentWithValue(result, "deepcopy"):
|
||||
m.s[cfsTypeInit3].add(cCast(pt, s.loc.snippet))
|
||||
|
||||
proc declareNimType(m: BModule; name: string; str: Rope, module: int) =
|
||||
let nr = rope(name)
|
||||
@@ -1590,7 +1580,8 @@ proc declareNimType(m: BModule; name: string; str: Rope, module: int) =
|
||||
m.s[cfsTypeInit1].addArgument(hcrGlobal):
|
||||
m.s[cfsTypeInit1].add("\"" & str & "\"")
|
||||
else:
|
||||
m.s[cfsStrData].addf("extern $2 $1;$n", [str, nr])
|
||||
m.s[cfsStrData].addDeclWithVisibility(Extern):
|
||||
m.s[cfsStrData].addVar(kind = Local, name = str, typ = nr)
|
||||
|
||||
proc genTypeInfo2Name(m: BModule; t: PType): Rope =
|
||||
var it = t
|
||||
|
||||
@@ -337,6 +337,9 @@ proc getTempName(m: BModule): Rope =
|
||||
result = m.tmpBase & rope(m.labels)
|
||||
inc m.labels
|
||||
|
||||
proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
|
||||
sfNoReturn in s.flags and m.config.exc != excGoto
|
||||
|
||||
include cbuilderbase
|
||||
include cbuilderexprs
|
||||
include cbuilderdecls
|
||||
@@ -759,7 +762,7 @@ proc getLabel(p: BProc): TLabel =
|
||||
result = "LA" & rope(p.labels) & "_"
|
||||
|
||||
proc fixLabel(p: BProc, labl: TLabel) =
|
||||
p.s(cpsStmts).add("$1: ;$n" % [labl])
|
||||
p.s(cpsStmts).addLabel(labl)
|
||||
|
||||
proc genVarPrototype(m: BModule, n: PNode)
|
||||
proc requestConstImpl(p: BProc, sym: PSym)
|
||||
@@ -1181,29 +1184,30 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
|
||||
proc getProcTypeCast(m: BModule, prc: PSym): Rope =
|
||||
result = getTypeDesc(m, prc.loc.t)
|
||||
if prc.typ.callConv == ccClosure:
|
||||
var rettype, params: Rope = ""
|
||||
var rettype: Snippet = ""
|
||||
var params = newBuilder("")
|
||||
var check = initIntSet()
|
||||
genProcParams(m, prc.typ, rettype, params, check)
|
||||
result = "$1(*)$2" % [rettype, params]
|
||||
result = procPtrTypeUnnamed(rettype = rettype, params = params)
|
||||
|
||||
proc genProcBody(p: BProc; procBody: PNode) =
|
||||
genStmts(p, procBody) # modifies p.locals, p.init, etc.
|
||||
if {nimErrorFlagAccessed, nimErrorFlagDeclared, nimErrorFlagDisabled} * p.flags == {nimErrorFlagAccessed}:
|
||||
p.flags.incl nimErrorFlagDeclared
|
||||
p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", []))
|
||||
p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", []))
|
||||
|
||||
proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
|
||||
sfNoReturn in s.flags and m.config.exc != excGoto
|
||||
p.blocks[0].sections[cpsLocals].addVar(kind = Local,
|
||||
name = "nimErr_", typ = ptrType("NIM_BOOL"))
|
||||
p.blocks[0].sections[cpsInit].addAssignmentWithValue("nimErr_"):
|
||||
p.blocks[0].sections[cpsInit].addCall(cgsymValue(p.module, "nimErrorFlag"))
|
||||
|
||||
proc genProcAux*(m: BModule, prc: PSym) =
|
||||
var p = newProc(prc, m)
|
||||
var header = newRopeAppender()
|
||||
let isCppMember = m.config.backend == backendCpp and sfCppMember * prc.flags != {}
|
||||
var visibility: DeclVisibility = None
|
||||
if isCppMember:
|
||||
genMemberProcHeader(m, prc, header)
|
||||
else:
|
||||
genProcHeader(m, prc, header)
|
||||
genProcHeader(m, prc, header, visibility, asPtr = false, addAttributes = false)
|
||||
var returnStmt: Rope = ""
|
||||
assert(prc.ast != nil)
|
||||
|
||||
@@ -1224,7 +1228,8 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
|
||||
var decl = localVarDecl(p, resNode)
|
||||
var a: TLoc = initLocExprSingleUse(p, val)
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", [decl, rdLoc(a)])
|
||||
let ra = rdLoc(a)
|
||||
p.s(cpsStmts).addAssignment(decl, ra)
|
||||
else:
|
||||
# declare the result symbol:
|
||||
assignLocalVar(p, resNode)
|
||||
@@ -1236,7 +1241,9 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
discard "result init optimized out"
|
||||
else:
|
||||
initLocalVar(p, res, immediateAsgn=false)
|
||||
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
|
||||
returnStmt = "\t"
|
||||
let rres = rdLoc(res.loc)
|
||||
returnStmt.addReturn(rres)
|
||||
elif sfConstructor in prc.flags:
|
||||
resNode.sym.loc.flags.incl lfIndirect
|
||||
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
|
||||
@@ -1267,45 +1274,56 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
|
||||
prc.info = tmpInfo
|
||||
|
||||
var generatedProc: Rope = ""
|
||||
var generatedProc = newBuilder("")
|
||||
generatedProc.genCLineDir prc.info, m.config
|
||||
if isNoReturn(p.module, prc):
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
|
||||
header = "__declspec(noreturn) " & header
|
||||
if sfPure in prc.flags:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
|
||||
header = "__declspec(naked) " & header
|
||||
generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N",
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
||||
else:
|
||||
if m.hcrOn and isReloadable(m, prc):
|
||||
# Add forward declaration for "_actual"-suffixed functions defined in the same module (or inline).
|
||||
# This fixes the use of methods and also the case when 2 functions within the same module
|
||||
# call each other using directly the "_actual" versions (an optimization) - see issue #11608
|
||||
m.s[cfsProcHeaders].addf("$1;\n", [header])
|
||||
generatedProc.add ropecg(p.module, "$1 {$n", [header])
|
||||
if optStackTrace in prc.options:
|
||||
generatedProc.add(p.s(cpsLocals))
|
||||
var procname = makeCString(prc.name.s)
|
||||
generatedProc.add(initFrame(p, procname, quotedFilename(p.config, prc.info)))
|
||||
generatedProc.addDeclWithVisibility(visibility):
|
||||
if sfPure in prc.flags:
|
||||
generatedProc.add(header)
|
||||
generatedProc.finishProcHeaderWithBody():
|
||||
generatedProc.add(p.s(cpsLocals))
|
||||
generatedProc.add(p.s(cpsInit))
|
||||
generatedProc.add(p.s(cpsStmts))
|
||||
else:
|
||||
generatedProc.add(p.s(cpsLocals))
|
||||
if optProfiler in prc.options:
|
||||
# invoke at proc entry for recursion:
|
||||
appcg(p, cpsInit, "\t#nimProfile();$n", [])
|
||||
# this pair of {} is required for C++ (C++ is weird with its
|
||||
# control flow integrity checks):
|
||||
if beforeRetNeeded in p.flags: generatedProc.add("{")
|
||||
generatedProc.add(p.s(cpsInit))
|
||||
generatedProc.add(p.s(cpsStmts))
|
||||
if beforeRetNeeded in p.flags: generatedProc.add("\t}BeforeRet_: ;\n")
|
||||
if optStackTrace in prc.options: generatedProc.add(deinitFrame(p))
|
||||
generatedProc.add(returnStmt)
|
||||
generatedProc.add("}\n")
|
||||
if m.hcrOn and isReloadable(m, prc):
|
||||
m.s[cfsProcHeaders].addDeclWithVisibility(visibility):
|
||||
# Add forward declaration for "_actual"-suffixed functions defined in the same module (or inline).
|
||||
# This fixes the use of methods and also the case when 2 functions within the same module
|
||||
# call each other using directly the "_actual" versions (an optimization) - see issue #11608
|
||||
m.s[cfsProcHeaders].add(header)
|
||||
m.s[cfsProcHeaders].finishProcHeaderAsProto()
|
||||
generatedProc.add(header)
|
||||
generatedProc.finishProcHeaderWithBody():
|
||||
if optStackTrace in prc.options:
|
||||
generatedProc.add(p.s(cpsLocals))
|
||||
var procname = makeCString(prc.name.s)
|
||||
generatedProc.add(initFrame(p, procname, quotedFilename(p.config, prc.info)))
|
||||
else:
|
||||
generatedProc.add(p.s(cpsLocals))
|
||||
if optProfiler in prc.options:
|
||||
# invoke at proc entry for recursion:
|
||||
p.s(cpsInit).add('\t')
|
||||
p.s(cpsInit).addCallStmt(cgsymValue(m, "nimProfile"))
|
||||
if beforeRetNeeded in p.flags:
|
||||
# this pair of {} is required for C++ (C++ is weird with its
|
||||
# control flow integrity checks):
|
||||
generatedProc.addScope():
|
||||
generatedProc.add(p.s(cpsInit))
|
||||
generatedProc.add(p.s(cpsStmts))
|
||||
generatedProc.addLabel("BeforeRet_")
|
||||
else:
|
||||
generatedProc.add(p.s(cpsInit))
|
||||
generatedProc.add(p.s(cpsStmts))
|
||||
if optStackTrace in prc.options: generatedProc.add(deinitFrame(p))
|
||||
generatedProc.add(returnStmt)
|
||||
m.s[cfsProcs].add(generatedProc)
|
||||
if isReloadable(m, prc):
|
||||
m.s[cfsDynLibInit].addf("\t$1 = ($3) hcrRegisterProc($4, \"$1\", (void*)$2);$n",
|
||||
[prc.loc.snippet, prc.loc.snippet & "_actual", getProcTypeCast(m, prc), getModuleDllPath(m, prc)])
|
||||
m.s[cfsDynLibInit].add('\t')
|
||||
m.s[cfsDynLibInit].addAssignmentWithValue(prc.loc.snippet):
|
||||
m.s[cfsDynLibInit].addCast(getProcTypeCast(m, prc)):
|
||||
m.s[cfsDynLibInit].addCall("hcrRegisterProc",
|
||||
getModuleDllPath(m, prc),
|
||||
'"' & prc.loc.snippet & '"',
|
||||
cCast("void*", prc.loc.snippet & "_actual"))
|
||||
|
||||
proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
|
||||
result = (sfCompileToCpp in m.module.flags and
|
||||
@@ -1322,26 +1340,39 @@ proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
if lfDynamicLib in sym.loc.flags:
|
||||
if sym.itemId.module != m.module.position and
|
||||
not containsOrIncl(m.declaredThings, sym.id):
|
||||
m.s[cfsVars].add(ropecg(m, "$1 $2 $3;$n",
|
||||
[(if isReloadable(m, sym): "static" else: "extern"),
|
||||
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)]))
|
||||
let vis = if isReloadable(m, sym): StaticProc else: Extern
|
||||
let name = mangleDynLibProc(sym)
|
||||
let t = getTypeDesc(m, sym.loc.t)
|
||||
m.s[cfsVars].addDeclWithVisibility(vis):
|
||||
m.s[cfsVars].addVar(kind = Local,
|
||||
name = name,
|
||||
typ = t)
|
||||
if isReloadable(m, sym):
|
||||
m.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
|
||||
[mangleDynLibProc(sym), getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)])
|
||||
m.s[cfsDynLibInit].add('\t')
|
||||
m.s[cfsDynLibInit].addAssignmentWithValue(name):
|
||||
m.s[cfsDynLibInit].addCast(t):
|
||||
m.s[cfsDynLibInit].addCall("hcrGetProc",
|
||||
getModuleDllPath(m, sym),
|
||||
'"' & name & '"')
|
||||
elif not containsOrIncl(m.declaredProtos, sym.id):
|
||||
let asPtr = isReloadable(m, sym)
|
||||
var header = newRopeAppender()
|
||||
genProcHeader(m, sym, header, asPtr)
|
||||
if not asPtr:
|
||||
if isNoReturn(m, sym) and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
||||
header = "__declspec(noreturn) " & header
|
||||
if sym.typ.callConv != ccInline and requiresExternC(m, sym):
|
||||
header = "extern \"C\" " & header
|
||||
if sfPure in sym.flags and hasAttribute in CC[m.config.cCompiler].props:
|
||||
header.add(" __attribute__((naked))")
|
||||
if isNoReturn(m, sym) and hasAttribute in CC[m.config.cCompiler].props:
|
||||
header.add(" __attribute__((noreturn))")
|
||||
m.s[cfsProcHeaders].add(ropecg(m, "$1;$N", [header]))
|
||||
var visibility: DeclVisibility = None
|
||||
genProcHeader(m, sym, header, visibility, asPtr = asPtr, addAttributes = true)
|
||||
if asPtr:
|
||||
m.s[cfsProcHeaders].addDeclWithVisibility(visibility):
|
||||
# genProcHeader would give variable declaration, add it directly
|
||||
m.s[cfsProcHeaders].add(header)
|
||||
else:
|
||||
let extraVis =
|
||||
if sym.typ.callConv != ccInline and requiresExternC(m, sym):
|
||||
ExternC
|
||||
else:
|
||||
None
|
||||
m.s[cfsProcHeaders].addDeclWithVisibility(extraVis):
|
||||
m.s[cfsProcHeaders].addDeclWithVisibility(visibility):
|
||||
m.s[cfsProcHeaders].add(header)
|
||||
m.s[cfsProcHeaders].finishProcHeaderAsProto()
|
||||
|
||||
# TODO: figure out how to rename this - it DOES generate a forward declaration
|
||||
proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
|
||||
Reference in New Issue
Block a user