mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 14:00:35 +00:00
implements #173
This commit is contained in:
@@ -653,7 +653,10 @@ proc genProcHeader(m: BModule, prc: PSym): PRope =
|
||||
genCLineDir(result, prc.info)
|
||||
# using static is needed for inline procs
|
||||
if gCmd != cmdCompileToLLVM and lfExportLib in prc.loc.flags:
|
||||
result.app "N_LIB_EXPORT "
|
||||
if m.isHeaderFile:
|
||||
result.app "N_LIB_IMPORT "
|
||||
else:
|
||||
result.app "N_LIB_EXPORT "
|
||||
elif prc.typ.callConv == ccInline:
|
||||
result.app "static "
|
||||
var check = initIntSet()
|
||||
|
||||
@@ -22,6 +22,9 @@ when options.hasTinyCBackend:
|
||||
proc cgenPass*(): TPass
|
||||
# implementation
|
||||
|
||||
var
|
||||
generatedHeader: BModule
|
||||
|
||||
proc ropeff(cformat, llvmformat: string, args: openarray[PRope]): PRope =
|
||||
if gCmd == cmdCompileToLLVM: result = ropef(llvmformat, args)
|
||||
else: result = ropef(cformat, args)
|
||||
@@ -721,7 +724,7 @@ proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
# dependency to a compilerproc:
|
||||
discard cgsym(m, prc.name.s)
|
||||
return
|
||||
genProcPrototype(m, prc)
|
||||
genProcPrototype(m, prc)
|
||||
if lfNoDecl in prc.loc.Flags: nil
|
||||
elif prc.typ.callConv == ccInline:
|
||||
# We add inline procs to the calling module to enable C based inlining.
|
||||
@@ -754,16 +757,26 @@ proc requestConstImpl(p: BProc, sym: PSym) =
|
||||
# declare header:
|
||||
if q != m and not ContainsOrIncl(m.declaredThings, sym.id):
|
||||
assert(sym.loc.r != nil)
|
||||
appf(m.s[cfsData], "extern NIM_CONST $1 $2;$n",
|
||||
let headerDecl = ropef("extern NIM_CONST $1 $2;$n",
|
||||
[getTypeDesc(m, sym.loc.t), sym.loc.r])
|
||||
app(m.s[cfsData], headerDecl)
|
||||
if sfExportc in sym.flags and generatedHeader != nil:
|
||||
app(generatedHeader.s[cfsData], headerDecl)
|
||||
|
||||
proc genProc(m: BModule, prc: PSym) =
|
||||
if sfBorrow in prc.flags: return
|
||||
fillProcLoc(prc)
|
||||
if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc)
|
||||
else: genProcNoForward(m, prc)
|
||||
|
||||
proc genVarPrototype(m: BModule, sym: PSym) =
|
||||
else:
|
||||
genProcNoForward(m, prc)
|
||||
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
|
||||
generatedHeader != nil and lfNoDecl notin prc.loc.Flags:
|
||||
genProcPrototype(generatedHeader, prc)
|
||||
if prc.typ.callConv == ccInline:
|
||||
if not ContainsOrIncl(generatedHeader.declaredThings, prc.id):
|
||||
genProcAux(generatedHeader, prc)
|
||||
|
||||
proc genVarPrototypeAux(m: BModule, sym: PSym) =
|
||||
assert(sfGlobal in sym.flags)
|
||||
useHeader(m, sym)
|
||||
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
|
||||
@@ -782,27 +795,14 @@ proc genVarPrototype(m: BModule, sym: PSym) =
|
||||
if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile")
|
||||
appf(m.s[cfsVars], " $1;$n", [sym.loc.r])
|
||||
|
||||
proc getFileHeader(cfilenoext: string): PRope =
|
||||
if optCompileOnly in gGlobalOptions:
|
||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
|
||||
"/* (c) 2012 Andreas Rumpf */$n",
|
||||
"; Generated by Nimrod Compiler v$1$n" &
|
||||
"; (c) 2012 Andreas Rumpf$n", [toRope(versionAsString)])
|
||||
else:
|
||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
|
||||
"/* (c) 2012 Andreas Rumpf */$n" &
|
||||
"/* Compiled for: $2, $3, $4 */$n" &
|
||||
"/* Command for C compiler:$n $5 */$n",
|
||||
"; Generated by Nimrod Compiler v$1$n" &
|
||||
"; (c) 2012 Andreas Rumpf$n" &
|
||||
"; Compiled for: $2, $3, $4$n" &
|
||||
"; Command for LLVM compiler:$n $5$n", [toRope(versionAsString),
|
||||
toRope(platform.OS[targetOS].name),
|
||||
toRope(platform.CPU[targetCPU].name),
|
||||
toRope(extccomp.CC[extccomp.ccompiler].name),
|
||||
toRope(getCompileCFileCmd(cfilenoext))])
|
||||
proc genVarPrototype(m: BModule, sym: PSym) =
|
||||
genVarPrototypeAux(m, sym)
|
||||
if sfExportc in sym.flags and generatedHeader != nil:
|
||||
genVarPrototypeAux(generatedHeader, sym)
|
||||
|
||||
proc addIntTypes(result: var PRope) =
|
||||
case platform.CPU[targetCPU].intSize
|
||||
of 16:
|
||||
of 16:
|
||||
appff(result,
|
||||
"$ntypedef short int NI;$n" & "typedef unsigned short int NU;$n",
|
||||
"$n%NI = type i16$n", [])
|
||||
@@ -813,8 +813,33 @@ proc getFileHeader(cfilenoext: string): PRope =
|
||||
of 64:
|
||||
appff(result, "$ntypedef long long int NI;$n" &
|
||||
"typedef unsigned long long int NU;$n", "$n%NI = type i64$n", [])
|
||||
else: nil
|
||||
|
||||
proc getCopyright(cfilenoext: string): PRope =
|
||||
if optCompileOnly in gGlobalOptions:
|
||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
|
||||
"/* (c) 2012 Andreas Rumpf */$n" &
|
||||
"/* The generated code is subject to the original license. */$n",
|
||||
"; Generated by Nimrod Compiler v$1$n" &
|
||||
"; (c) 2012 Andreas Rumpf$n", [toRope(versionAsString)])
|
||||
else:
|
||||
nil
|
||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
|
||||
"/* (c) 2012 Andreas Rumpf */$n" &
|
||||
"/* The generated code is subject to the original license. */$n" &
|
||||
"/* Compiled for: $2, $3, $4 */$n" &
|
||||
"/* Command for C compiler:$n $5 */$n",
|
||||
"; Generated by Nimrod Compiler v$1$n" &
|
||||
"; (c) 2012 Andreas Rumpf$n" &
|
||||
"; Compiled for: $2, $3, $4$n" &
|
||||
"; Command for LLVM compiler:$n $5$n", [toRope(versionAsString),
|
||||
toRope(platform.OS[targetOS].name),
|
||||
toRope(platform.CPU[targetCPU].name),
|
||||
toRope(extccomp.CC[extccomp.ccompiler].name),
|
||||
toRope(getCompileCFileCmd(cfilenoext))])
|
||||
|
||||
proc getFileHeader(cfilenoext: string): PRope =
|
||||
result = getCopyright(cfilenoext)
|
||||
addIntTypes(result)
|
||||
|
||||
proc genMainProc(m: BModule) =
|
||||
const
|
||||
@@ -1008,6 +1033,31 @@ proc newModule(module: PSym, filename: string): BModule =
|
||||
|
||||
proc myOpen(module: PSym, filename: string): PPassContext =
|
||||
result = newModule(module, filename)
|
||||
if optGenIndex in gGlobalOptions and generatedHeader == nil:
|
||||
let f = if headerFile.len > 0: headerFile else: gProjectFull
|
||||
generatedHeader = rawNewModule(module,
|
||||
changeFileExt(completeCFilePath(f), hExt))
|
||||
generatedHeader.isHeaderFile = true
|
||||
|
||||
proc writeHeader(m: BModule) =
|
||||
var result = getCopyright(m.filename)
|
||||
var guard = ropef("__$1__", m.filename.splitFile.name.toRope)
|
||||
result.appf("#ifndef $1$n#define $1$n", guard)
|
||||
addIntTypes(result)
|
||||
generateHeaders(m)
|
||||
|
||||
generateThreadLocalStorage(m)
|
||||
for i in countup(cfsHeaders, cfsProcs):
|
||||
app(result, genSectionStart(i))
|
||||
app(result, m.s[i])
|
||||
app(result, genSectionEnd(i))
|
||||
app(result, m.s[cfsInitProc])
|
||||
|
||||
if optGenDynLib in gGlobalOptions:
|
||||
result.app("N_LIB_IMPORT ")
|
||||
result.appf("N_CDECL(void, NimMain)(void);$n")
|
||||
result.appf("#endif /* $1 */$n", guard)
|
||||
writeRope(result, m.filename)
|
||||
|
||||
proc getCFile(m: BModule): string =
|
||||
result = changeFileExt(completeCFilePath(m.cfilename), cExt)
|
||||
@@ -1106,12 +1156,14 @@ proc myClose(b: PPassContext, n: PNode): PNode =
|
||||
# we need to process the transitive closure because recursive module
|
||||
# deps are allowed (and the system module is processed in the wrong
|
||||
# order anyway)
|
||||
if generatedHeader != nil: finishModule(generatedHeader)
|
||||
while gForwardedProcsCounter > 0:
|
||||
for i in countup(0, high(gModules)):
|
||||
finishModule(gModules[i])
|
||||
for i in countup(0, high(gModules)):
|
||||
writeModule(gModules[i], pending=true)
|
||||
writeMapping(gMapping)
|
||||
if generatedHeader != nil: writeHeader(generatedHeader)
|
||||
|
||||
proc cgenPass(): TPass =
|
||||
initPass(result)
|
||||
|
||||
@@ -91,6 +91,7 @@ type
|
||||
usesThreadVars*: bool # true if the module uses a thread var
|
||||
FrameDeclared*: bool # hack for ROD support so that we don't declare
|
||||
# a frame var twice in an init proc
|
||||
isHeaderFile*: bool # C source file is the header file
|
||||
cfilename*: string # filename of the module (including path,
|
||||
# without extension)
|
||||
typeCache*: TIdTable # cache the generated types
|
||||
@@ -119,7 +120,7 @@ var
|
||||
# finished with code generation
|
||||
gModules*: seq[BModule] = @[] # list of all compiled modules
|
||||
gForwardedProcsCounter*: int = 0
|
||||
|
||||
|
||||
proc s*(p: BProc, s: TCProcSection): var PRope {.inline.} =
|
||||
# section in the current block
|
||||
result = p.blocks[p.blocks.len - 1].sections[s]
|
||||
|
||||
@@ -365,7 +365,10 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
of "clib":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: cLinkedLibs.add arg
|
||||
of "index":
|
||||
of "header":
|
||||
headerFile = arg
|
||||
incl(gGlobalOptions, optGenIndex)
|
||||
of "index":
|
||||
ProcessOnOffSwitchG({optGenIndex}, arg, pass, info)
|
||||
of "import":
|
||||
expectArg(switch, arg, pass, info)
|
||||
|
||||
@@ -107,7 +107,9 @@ type
|
||||
hintSuccess, hintSuccessX,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, hintUser
|
||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||
hintConditionAlwaysTrue,
|
||||
hintUser
|
||||
|
||||
const
|
||||
MsgKindToStr*: array[TMsgKind, string] = [
|
||||
@@ -361,6 +363,7 @@ const
|
||||
hintCodeEnd: "end of listing [CodeEnd]",
|
||||
hintConf: "used config file \'$1\' [Conf]",
|
||||
hintPath: "added path: '$1' [Path]",
|
||||
hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]",
|
||||
hintUser: "$1 [User]"]
|
||||
|
||||
const
|
||||
@@ -373,10 +376,10 @@ const
|
||||
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
|
||||
"ImplicitClosure", "EachIdentIsTuple", "User"]
|
||||
|
||||
HintsToStr*: array[0..13, string] = ["Success", "SuccessX", "LineTooLong",
|
||||
HintsToStr*: array[0..14, string] = ["Success", "SuccessX", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||
"Path",
|
||||
"Path", "CondTrue",
|
||||
"User"]
|
||||
|
||||
const
|
||||
|
||||
@@ -54,7 +54,8 @@ type # please make sure we have under 32 options
|
||||
optThreadAnalysis, # thread analysis pass
|
||||
optTaintMode, # taint mode turned on
|
||||
optTlsEmulation, # thread var emulation turned on
|
||||
optGenIndex # generate index file for documentation
|
||||
optGenIndex # generate index file for documentation;
|
||||
# also: generate header file
|
||||
|
||||
TGlobalOptions* = set[TGlobalOption]
|
||||
TCommands* = enum # Nimrod's commands
|
||||
@@ -85,6 +86,7 @@ var
|
||||
gExitcode*: int8
|
||||
searchPaths*: TLinkedList
|
||||
outFile*: string = ""
|
||||
headerFile*: string = ""
|
||||
gCmd*: TCommands = cmdNone # the command
|
||||
gVerbosity*: int # how verbose the compiler is
|
||||
gNumberOfProcessors*: int # number of processors
|
||||
|
||||
@@ -112,7 +112,7 @@ proc freezeMutableRope*(r: PRope) {.inline.} =
|
||||
r.length = r.data.len
|
||||
|
||||
var
|
||||
cache: array[0..2048 -1, PRope]
|
||||
cache: array[0..2048*2 -1, PRope]
|
||||
|
||||
proc RopeInvariant(r: PRope): bool =
|
||||
if r == nil:
|
||||
|
||||
@@ -238,7 +238,6 @@ proc semSizeof(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
n.sons[1] = semExprWithType(c, n.sons[1])
|
||||
restoreOldStyleType(n.sons[1])
|
||||
|
||||
n.typ = getSysType(tyInt)
|
||||
result = n
|
||||
|
||||
@@ -252,8 +251,19 @@ proc semOf(c: PContext, n: PNode): PNode =
|
||||
var b = skipTypes(n.sons[2].typ, abstractPtrs)
|
||||
if b.kind != tyObject or a.kind != tyObject:
|
||||
GlobalError(n.info, errXExpectsObjectTypes, "of")
|
||||
while b != nil and b.id != a.id: b = b.sons[0]
|
||||
if b == nil:
|
||||
let diff = inheritanceDiff(a, b)
|
||||
# | returns: 0 iff `a` == `b`
|
||||
# | returns: -x iff `a` is the x'th direct superclass of `b`
|
||||
# | returns: +x iff `a` is the x'th direct subclass of `b`
|
||||
# | returns: `maxint` iff `a` and `b` are not compatible at all
|
||||
if diff <= 0:
|
||||
# optimize to true:
|
||||
Message(n.info, hintConditionAlwaysTrue, renderTree(n))
|
||||
result = newIntNode(nkIntLit, 1)
|
||||
result.info = n.info
|
||||
result.typ = getSysType(tyBool)
|
||||
return result
|
||||
elif diff == high(int):
|
||||
GlobalError(n.info, errXcanNeverBeOfThisSubtype, typeToString(a))
|
||||
n.typ = getSysType(tyBool)
|
||||
else:
|
||||
|
||||
@@ -49,7 +49,6 @@ type
|
||||
nestedProcs: int # > 0 if we are in a nested proc
|
||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||
inLoop: int # > 0 if we are in a loop
|
||||
transformedInnerProcs: TIntSet
|
||||
PTransf = ref TTransfContext
|
||||
|
||||
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
||||
@@ -753,7 +752,6 @@ proc openTransf(module: PSym, filename: string): PPassContext =
|
||||
n.contSyms = @[]
|
||||
n.breakSyms = @[]
|
||||
n.module = module
|
||||
n.transformedInnerProcs = initIntSet()
|
||||
result = n
|
||||
|
||||
proc openTransfCached(module: PSym, filename: string,
|
||||
|
||||
@@ -59,6 +59,7 @@ const
|
||||
abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal}
|
||||
|
||||
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable}
|
||||
typeclassPtrs* = abstractPtrs + {tyTypeClass}
|
||||
|
||||
proc skipTypes*(t: PType, kinds: TTypeKinds): PType
|
||||
proc containsObject*(t: PType): bool
|
||||
|
||||
@@ -29,6 +29,8 @@ Advanced options:
|
||||
--import:PATH add an automatically imported module
|
||||
--include:PATH add an automatically included module
|
||||
--nimcache:PATH set the path used for generated files
|
||||
--header:FILE the compiler should produce a .h file (FILE
|
||||
is optional)
|
||||
-c, --compileOnly compile only; do not assemble or link
|
||||
--noLinking compile but do not link
|
||||
--noMain do not generate a main procedure
|
||||
|
||||
Reference in New Issue
Block a user