summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-07-28 14:16:08 +0200
committerAraq <rumpf_a@web.de>2012-07-28 14:16:08 +0200
commit538b06a12360f15c6240e3b05bcb5f1bdb1618dc (patch)
tree70b13d34b5cf64d5055d72ae24681b1dbcc297af
parent2ff8d17369eff133292009acd0866aa32d2912d0 (diff)
downloadNim-538b06a12360f15c6240e3b05bcb5f1bdb1618dc.tar.gz
implements #173
-rwxr-xr-xcompiler/ccgtypes.nim5
-rwxr-xr-xcompiler/cgen.nim94
-rw-r--r--compiler/cgendata.nim3
-rwxr-xr-xcompiler/commands.nim5
-rwxr-xr-xcompiler/msgs.nim9
-rwxr-xr-xcompiler/options.nim4
-rwxr-xr-xcompiler/ropes.nim2
-rwxr-xr-xcompiler/semexprs.nim16
-rwxr-xr-xcompiler/transf.nim2
-rwxr-xr-xcompiler/types.nim1
-rwxr-xr-xdoc/advopt.txt2
11 files changed, 109 insertions, 34 deletions
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index e3efe2d13..219c791e2 100755
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -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()
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index bcc7615ce..e4286f5de 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -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,15 +795,37 @@ 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 = 
+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:
+    appff(result, 
+          "$ntypedef short int NI;$n" & "typedef unsigned short int NU;$n", 
+          "$n%NI = type i16$n", [])
+  of 32: 
+    appff(result, 
+          "$ntypedef long int NI;$n" & "typedef unsigned long int NU;$n", 
+          "$n%NI = type i32$n", [])
+  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", 
+        "/*   (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: 
     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" &
@@ -801,20 +836,10 @@ proc getFileHeader(cfilenoext: string): PRope =
         toRope(platform.CPU[targetCPU].name), 
         toRope(extccomp.CC[extccomp.ccompiler].name), 
         toRope(getCompileCFileCmd(cfilenoext))])
-  case platform.CPU[targetCPU].intSize
-  of 16: 
-    appff(result, 
-          "$ntypedef short int NI;$n" & "typedef unsigned short int NU;$n", 
-          "$n%NI = type i16$n", [])
-  of 32: 
-    appff(result, 
-          "$ntypedef long int NI;$n" & "typedef unsigned long int NU;$n", 
-          "$n%NI = type i32$n", [])
-  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 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)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index fabad86ab..f42381e59 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -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]
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 508106cca..db0469e94 100755
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -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)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index de29a4a40..034fd38d8 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -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 
diff --git a/compiler/options.nim b/compiler/options.nim
index 5238e839f..91f7f778d 100755
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -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
diff --git a/compiler/ropes.nim b/compiler/ropes.nim
index 545e27b41..ef1211b01 100755
--- a/compiler/ropes.nim
+++ b/compiler/ropes.nim
@@ -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: 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index c63544ed0..db61ff79e 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -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: 
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 284958e77..a31ad2c18 100755
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -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, 
diff --git a/compiler/types.nim b/compiler/types.nim
index 8b99c00e8..23ba85325 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -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
diff --git a/doc/advopt.txt b/doc/advopt.txt
index 7aba243ed..5077de4db 100755
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -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