summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2013-05-11 22:47:37 +0300
committerZahary Karadjov <zahary@gmail.com>2013-05-11 22:47:37 +0300
commitf44a4362bbb74255b8781951c6b1286100176ef3 (patch)
tree02793b12db243c31e8d0136833cb7621c9f1c0a7
parent40b411fb1c319a74daedce524c5d821b6bdc0e45 (diff)
downloadNim-f44a4362bbb74255b8781951c6b1286100176ef3.tar.gz
added a ``noforward`` pragma that enables a new compilation strategy
not requiring forward declarations on a per-module basis
-rw-r--r--compiler/ast.nim3
-rw-r--r--compiler/cgen.nim4
-rw-r--r--compiler/passes.nim6
-rw-r--r--compiler/pragmas.nim9
-rw-r--r--compiler/procfind.nim3
-rw-r--r--compiler/semcall.nim3
-rw-r--r--compiler/semstmts.nim51
-rw-r--r--compiler/wordrecg.nim4
-rw-r--r--examples/hallo.nim15
9 files changed, 76 insertions, 22 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index eb12c977f..3622f0e7a 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -284,6 +284,9 @@ const
       
   sfHoist* = sfVolatile ## proc return value can be hoisted
 
+  sfNoForward* = sfRegister
+    # forward declarations are not required (per module)
+
 const
   # getting ready for the future expr/stmt merge
   nkWhen* = nkWhenStmt
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index f034f6675..ddb9ec0ad 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -842,8 +842,10 @@ proc requestConstImpl(p: BProc, sym: PSym) =
     if sfExportc in sym.flags and generatedHeader != nil:
       app(generatedHeader.s[cfsData], headerDecl)
 
+proc isActivated(prc: PSym): bool = prc.typ != nil
+
 proc genProc(m: BModule, prc: PSym) = 
-  if sfBorrow in prc.flags: return 
+  if sfBorrow in prc.flags or not isActivated(prc): return
   fillProcLoc(prc)
   if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc)
   else: 
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 8d228fe9a..22249edaf 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -177,6 +177,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
       s = stream
     while true: 
       openParsers(p, fileIdx, s)
+      var code = p.parseAll
 
       if sfSystemModule notin module.flags:
         # XXX what about caching? no processing then? what if I change the 
@@ -186,10 +187,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
         processImplicits implicitImports, nkImportStmt, a
         processImplicits implicitIncludes, nkIncludeStmt, a
 
-      while true: 
-        var n = parseTopLevelStmt(p)
-        if n.kind == nkEmpty: break 
-        if not processTopLevelStmt(n, a): break
+      processTopLevelStmt(code, a)
 
       closeParsers(p)
       if s.kind != llsStdIn: break 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index ba761739a..ed3c44e1c 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -42,7 +42,7 @@ const
     wFatal, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop,
     wBreakpoint, wWatchpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated,
     wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
-    wLinearScanEnd, wPatterns, wEffects}
+    wLinearScanEnd, wPatterns, wEffects, wNoForward}
   lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, 
     wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, 
     wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame,
@@ -182,7 +182,11 @@ proc onOff(c: PContext, n: PNode, op: TOptions) =
 proc pragmaDeadCodeElim(c: PContext, n: PNode) = 
   if IsTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
   else: excl(c.module.flags, sfDeadCodeElim)
-  
+
+proc pragmaNoForward(c: PContext, n: PNode) =
+  if IsTurnedOn(c, n): incl(c.module.flags, sfNoForward)
+  else: excl(c.module.flags, sfNoForward)
+
 proc processCallConv(c: PContext, n: PNode) = 
   if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent): 
     var sw = whichKeyword(n.sons[1].ident)
@@ -552,6 +556,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           noVal(it)
           incl(sym.flags, sfThread)
         of wDeadCodeElim: pragmaDeadCodeElim(c, it)
+        of wNoForward: pragmaNoForward(c, it)
         of wMagic: processMagic(c, it, sym)
         of wCompileTime: 
           noVal(it)
diff --git a/compiler/procfind.nim b/compiler/procfind.nim
index 2db6247e1..cfb9ee2ca 100644
--- a/compiler/procfind.nim
+++ b/compiler/procfind.nim
@@ -31,7 +31,8 @@ proc equalGenericParams(procA, procB: PNode): bool =
   result = true
 
 proc SearchForProc*(c: PContext, fn: PSym, tos: int): PSym = 
-  # Searchs for the fn in the symbol table. If the parameter lists are exactly
+  # Searchs for a forward declaration or a "twin" symbol of fn
+  # in the symbol table. If the parameter lists are exactly
   # the same the sym in the symbol table is returned, else nil.
   var it: TIdentIter
   result = initIdentIter(it, c.tab.stack[tos], fn.Name)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index be41299ad..6c58d609c 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -32,6 +32,8 @@ proc sameMethodDispatcher(a, b: PSym): bool =
       # be disambiguated by the programmer; this way the right generic is
       # instantiated.
   
+proc determineType(c: PContext, s: PSym)
+
 proc resolveOverloads(c: PContext, n, orig: PNode, 
                       filter: TSymKinds): TCandidate =
   var initialBinding: PNode
@@ -58,6 +60,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
   while sym != nil:
     if sym.kind in filter:
+      determineType(c, sym)
       initCandidate(z, sym, initialBinding, o.lastOverloadScope)
       z.calleeSym = sym
       matches(c, n, orig, z)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 2c3adfeda..cf954af92 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -884,15 +884,37 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
     addResult(c, s.typ.sons[0], n.info, s.kind)
     addResultNode(c, n)
 
-proc semProcAux(c: PContext, n: PNode, kind: TSymKind, 
-                validPragmas: TSpecialWords): PNode = 
+type
+  TProcActivationSteps = enum
+    stepRegisterSymbol,
+    stepDetermineType,
+    stepActivate
+
+proc isForwardDecl(s: PSym): bool =
+  InternalAssert s.kind == skProc
+  result = s.ast[bodyPos].kind != nkEmpty
+
+proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
+                validPragmas: TSpecialWords,
+                phase = stepRegisterSymbol): PNode =
   result = semProcAnnotation(c, n)
   if result != nil: return result
   result = n
   checkSonsLen(n, bodyPos + 1)
-  var s = semIdentDef(c, n.sons[0], kind)
-  n.sons[namePos] = newSymNode(s)
-  s.ast = n
+  var s: PSym
+  var usesAutoForwarding = false
+  if n[namePos].kind != nkSym:
+    s = semIdentDef(c, n.sons[0], kind)
+    n.sons[namePos] = newSymNode(s)
+    s.ast = n
+
+    if sfNoForward in c.module.flags and
+       sfSystemModule notin c.module.flags:
+      addInterfaceOverloadableSymAt(c, s, c.tab.tos - 1)
+      return
+  else:
+    s = n[namePos].sym
+    usesAutoForwarding = s.typ == nil
   pushOwner(s)
   openScope(c.tab)
   var gp: PNode
@@ -924,10 +946,12 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     # add it here, so that recursive procs are possible:
     # -2 because we have a scope open for parameters
     if sfGenSym in s.flags: nil
-    elif kind in OverloadableSyms: 
-      addInterfaceOverloadableSymAt(c, s, c.tab.tos - 2)
-    else: 
-      addInterfaceDeclAt(c, s, c.tab.tos - 2)
+    elif kind in OverloadableSyms:
+      if not usesAutoForwarding:
+        addInterfaceOverloadableSymAt(c, s, c.tab.tos - 2)
+    else:
+      if not usesAutoForwarding:
+        addInterfaceDeclAt(c, s, c.tab.tos - 2)
     if n.sons[pragmasPos].kind != nkEmpty:
       pragma(c, s, n.sons[pragmasPos], validPragmas)
     else:
@@ -992,7 +1016,12 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   popOwner()
   if n.sons[patternPos].kind != nkEmpty:
     c.patterns.add(s)
-  
+
+proc determineType(c: PContext, s: PSym) =
+  if s.typ != nil: return
+  #if s.magic != mNone: return
+  discard semProcAux(c, s.ast, s.kind, {}, stepDetermineType)
+
 proc semIterator(c: PContext, n: PNode): PNode =
   result = semProcAux(c, n, skIterator, iteratorPragmas)
   var s = result.sons[namePos].sym
@@ -1055,7 +1084,7 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
   if n.sons[bodyPos].kind == nkEmpty:
     LocalError(n.info, errImplOfXexpected, s.name.s)
   
-proc evalInclude(c: PContext, n: PNode): PNode = 
+proc evalInclude(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
   addSon(result, n)
   for i in countup(0, sonsLen(n) - 1): 
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 3ad2f45ca..36d08c718 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -53,7 +53,7 @@ type
     wFloatchecks, wNanChecks, wInfChecks,
     wAssertions, wPatterns, wWarnings,
     wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags,
-    wDeadCodeElim, wSafecode, 
+    wDeadCodeElim, wSafecode, wNoForward,
     wPragma,
     wCompileTime, wNoInit,
     wPassc, wPassl, wBorrow, wDiscardable,
@@ -135,7 +135,7 @@ const
 
     "assertions", "patterns", "warnings", "hints", 
     "optimization", "raises", "writes", "reads", "size", "effects", "tags",
-    "deadcodeelim", "safecode", 
+    "deadcodeelim", "safecode", "noforward",
     "pragma",
     "compiletime", "noinit",
     "passc", "passl", "borrow", "discardable", "fieldchecks",
diff --git a/examples/hallo.nim b/examples/hallo.nim
index d94da8c1f..220e9c623 100644
--- a/examples/hallo.nim
+++ b/examples/hallo.nim
@@ -1,3 +1,16 @@
 # Hello world program
 
-echo "Hello World"
+import macros, strutils
+
+{. noforward: on .}
+
+proc hola(x: int) =
+  echo "HOLA"
+  comuEsta(x)
+
+proc comuEsta(x: int) =
+  echo "COMU ESTA"
+  echo x
+
+hola(10)
+