summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2014-06-26 17:19:28 +0200
committerAraq <rumpf_a@web.de>2014-06-26 17:19:28 +0200
commit85a1d896c2ccb69d81003673b00ac21b53133b06 (patch)
tree673fdbe85f8291a658282a885d0d80f90d9e230c /compiler
parenteed443d4b390b10e710d80619f5a7bc19fefb8d1 (diff)
parentf793523ade7aa48dcf13ede123a0a434e39e54e0 (diff)
downloadNim-85a1d896c2ccb69d81003673b00ac21b53133b06.tar.gz
Merge branch 'devel' of https://github.com/Araq/Nimrod into new_spawn
Conflicts:
	lib/system.nim
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/ccgexprs.nim24
-rw-r--r--compiler/ccgtypes.nim5
-rw-r--r--compiler/cgen.nim1
-rw-r--r--compiler/cgendata.nim1
-rw-r--r--compiler/guards.nim2
-rw-r--r--compiler/llstream.nim3
-rw-r--r--compiler/parser.nim44
-rw-r--r--compiler/sem.nim10
-rw-r--r--compiler/semdata.nim4
-rw-r--r--compiler/seminst.nim8
-rw-r--r--compiler/semstmts.nim10
-rw-r--r--compiler/semtypes.nim5
-rw-r--r--compiler/suggest.nim9
-rw-r--r--compiler/vmdeps.nim2
15 files changed, 84 insertions, 45 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 1755dcce9..461854496 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -511,6 +511,7 @@ const
   tfUncheckedArray* = tfVarargs
   tfUnion* = tfNoSideEffect
   tfGcSafe* = tfThread
+  tfObjHasKids* = tfEnumHasHoles
   skError* = skUnknown
   
   # type flags that are essential for type equality:
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 69e382f8d..e6b22819f 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1144,6 +1144,24 @@ proc genNewFinalize(p: BProc, e: PNode) =
   genObjectInit(p, cpsStmts, bt, a, false)
   gcUsage(e)
 
+proc genOfHelper(p: BProc; dest: PType; a: PRope): PRope =
+  # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
+  # have to call it here first:
+  let ti = genTypeInfo(p.module, dest)
+  if tfFinal in dest.flags or (p.module.objHasKidsValid and
+                               tfObjHasKids notin dest.flags):
+    result = ropef("$1.m_type == $2", a, ti)
+  else:
+    discard cgsym(p.module, "TNimType")
+    inc p.module.labels
+    let cache = con("Nim_OfCheck_CACHE", p.module.labels.toRope)
+    appf(p.module.s[cfsVars], "static TNimType* $#[2];$n", cache)
+    result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
+  when false:
+    # former version:
+    result = rfmt(p.module, "#isObj($1.m_type, $2)",
+                  a, genTypeInfo(p.module, dest))
+
 proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
   var a: TLoc
   initLocExpr(p, x, a)
@@ -1163,11 +1181,9 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
     globalError(x.info, errGenerated, 
       "no 'of' operator available for pure objects")
   if nilCheck != nil:
-    r = rfmt(p.module, "(($1) && #isObj($2.m_type, $3))",
-             nilCheck, r, genTypeInfo(p.module, dest))
+    r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r))
   else:
-    r = rfmt(p.module, "#isObj($1.m_type, $2)",
-             r, genTypeInfo(p.module, dest))
+    r = rfmt(p.module, "($1)", genOfHelper(p, dest, r))
   putIntoDest(p, d, getSysType(tyBool), r)
 
 proc genOf(p: BProc, n: PNode, d: var TLoc) =
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 7a490082f..8e762ce27 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -796,6 +796,11 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) =
   var tmp = getNimNode(m)
   genObjectFields(m, typ, typ.n, tmp)
   appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
+  var t = typ.sons[0]
+  while t != nil:
+    t = t.skipTypes(abstractInst)
+    t.flags.incl tfObjHasKids
+    t = t.sons[0]
 
 proc genTupleInfo(m: BModule, typ: PType, name: PRope) =
   genTypeInfoAuxBase(m, typ, name, toRope("0"))
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 314af7784..a5852c735 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1384,6 +1384,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
   registerModuleToMain(m.module)
 
   if sfMainModule in m.module.flags: 
+    m.objHasKidsValid = true
     var disp = generateMethodDispatchers()
     for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
     genMainProc(m)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index e7d818556..12041c55b 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -96,6 +96,7 @@ type
                               # a frame var twice in an init proc
     isHeaderFile*: bool       # C source file is the header file
     includesStringh*: bool    # C source file already includes ``<string.h>``
+    objHasKidsValid*: bool    # whether we can rely on tfObjHasKids
     cfilename*: string        # filename of the module (including path,
                               # without extension)
     typeCache*: TIdTable      # cache the generated types
diff --git a/compiler/guards.nim b/compiler/guards.nim
index 813a30014..4cf06fe02 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -625,7 +625,7 @@ proc factImplies(fact, prop: PNode): TImplication =
     #  == not a or not b == not (a and b)
     let arg = fact.sons[1]
     case arg.getMagic
-    of mIsNil:
+    of mIsNil, mEqRef:
       return ~factImplies(arg, prop)
     of mAnd:
       # not (a and b)  means  not a or not b:
diff --git a/compiler/llstream.nim b/compiler/llstream.nim
index 510880ffd..86bfeaabd 100644
--- a/compiler/llstream.nim
+++ b/compiler/llstream.nim
@@ -82,6 +82,9 @@ when not defined(readLineFromStdin):
   proc readLineFromStdin(prompt: string, line: var string): bool =
     stdout.write(prompt)
     result = readLine(stdin, line)
+    if not result:
+      stdout.write("\n")
+      quit(0)
 
 proc endsWith*(x: string, s: set[char]): bool =
   var i = x.len-1
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 2f9deb6b3..18de1570a 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -147,8 +147,10 @@ proc expectIdent(p: TParser) =
 proc eat(p: var TParser, tokType: TTokType) =
   ## Move the parser to the next token if the current token is of type
   ## `tokType`, otherwise error.
-  if p.tok.tokType == tokType: getTok(p)
-  else: lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType])
+  if p.tok.tokType == tokType:
+    getTok(p)
+  else:
+    lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType])
   
 proc parLineInfo(p: TParser): TLineInfo =
   ## Retrieve the line information associated with the parser's current state.
@@ -285,7 +287,7 @@ proc colcom(p: var TParser, n: PNode) =
   skipComment(p, n)
 
 proc parseSymbol(p: var TParser, allowNil = false): PNode =
-  #| symbol = '`' (KEYW|IDENT|operator|'(' ')'|'[' ']'|'{' '}'|'='|literal)+ '`'
+  #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
   #|        | IDENT
   case p.tok.tokType
   of tkSymbol: 
@@ -296,31 +298,22 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
     getTok(p)
     while true:
       case p.tok.tokType
-      of tkBracketLe: 
-        add(result, newIdentNodeP(getIdent"[]", p))
-        getTok(p)
-        eat(p, tkBracketRi)
-      of tkEquals:
-        add(result, newIdentNodeP(getIdent"=", p))
-        getTok(p)
-      of tkParLe:
-        add(result, newIdentNodeP(getIdent"()", p))
-        getTok(p)
-        eat(p, tkParRi)
-      of tkCurlyLe:
-        add(result, newIdentNodeP(getIdent"{}", p))
-        getTok(p)
-        eat(p, tkCurlyRi)
-      of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDot, tkDotDot:
-        add(result, newIdentNodeP(p.tok.ident, p))
-        getTok(p)
-      of tkIntLit..tkCharLit:
-        add(result, newIdentNodeP(getIdent(tokToStr(p.tok)), p))
-        getTok(p)
-      else:
+      of tkAccent:
         if result.len == 0: 
           parMessage(p, errIdentifierExpected, p.tok)
         break
+      of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi:
+        var accm = ""
+        while p.tok.tokType in {tkOpr, tkDot, tkDotDot, tkEquals,
+                                tkParLe..tkParDotRi}:
+          accm.add(tokToStr(p.tok))
+          getTok(p)
+        result.add(newIdentNodeP(getIdent(accm), p))
+      of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCharLit:
+        result.add(newIdentNodeP(getIdent(tokToStr(p.tok)), p))
+        getTok(p)
+      else:
+        parMessage(p, errIdentifierExpected, p.tok)
     eat(p, tkAccent)
   else:
     if allowNil and p.tok.tokType == tkNil:
@@ -993,6 +986,7 @@ proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) =
 
 proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
                        mode: TPrimaryMode): PNode =
+  #| distinct = 'distinct' optInd typeDesc
   result = newNodeP(kind, p)
   getTok(p)
   optInd(p, result)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 2e3b10a40..e4ef6473f 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -269,11 +269,15 @@ include hlo, seminst, semcall
 
 proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
                        flags: TExprFlags): PNode =
+  ## Semantically check the output of a macro.
+  ## This involves processes such as re-checking the macro output for type
+  ## coherence, making sure that variables declared with 'let' aren't
+  ## reassigned, and binding the unbound identifiers that the macro output
+  ## contains.
   inc(evalTemplateCounter)
   if evalTemplateCounter > 100:
     globalError(s.info, errTemplateInstantiationTooNested)
-  let oldFriend = c.friendModule
-  c.friendModule = s.owner.getModule
+  c.friendModules.add(s.owner.getModule)
 
   result = n
   if s.typ.sons[0] == nil:
@@ -297,7 +301,7 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
       result = fitNode(c, s.typ.sons[0], result)
       #GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
   dec(evalTemplateCounter)
-  c.friendModule = oldFriend
+  discard c.friendModules.pop()
 
 proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
                   flags: TExprFlags = {}): PNode =
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 19181d98e..abecc1b6d 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -52,7 +52,7 @@ type
     importTable*: PScope       # scope for all imported symbols
     topLevelScope*: PScope     # scope for all top-level symbols
     p*: PProcCon               # procedure context
-    friendModule*: PSym        # current friend module; may access private data;
+    friendModules*: seq[PSym]  # friend modules; may access private data;
                                # this is used so that generic instantiations
                                # can access private object fields
     instCounter*: int          # to prevent endless instantiations
@@ -169,7 +169,7 @@ proc newContext(module: PSym): PContext =
   initLinkedList(result.libs)
   append(result.optionStack, newOptionEntry())
   result.module = module
-  result.friendModule = module
+  result.friendModules = @[module]
   result.converters = @[]
   result.patterns = @[]
   result.includedFiles = initIntSet()
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index f7d5fa6f8..b93d7ca15 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -190,6 +190,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
 
 proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
                       info: TLineInfo): PSym =
+  ## Generates a new instance of a generic procedure.
+  ## The `pt` parameter is a type-unsafe mapping table used to link generic
+  ## parameters to their concrete types within the generic instance.
   # no need to instantiate generic templates/macros:
   if fn.kind in {skTemplate, skMacro}: return fn
   # generates an instantiated proc
@@ -199,8 +202,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   var n = copyTree(fn.ast)
   # NOTE: for access of private fields within generics from a different module
   # we set the friend module:
-  var oldFriend = c.friendModule
-  c.friendModule = getModule(fn)
+  c.friendModules.add(getModule(fn))
   #let oldScope = c.currentScope
   #c.currentScope = fn.scope
   result = copySym(fn, false)
@@ -236,6 +238,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   closeScope(c)           # close scope for parameters
   popOwner()
   #c.currentScope = oldScope
-  c.friendModule = oldFriend
+  discard c.friendModules.pop()
   dec(c.instCounter)
   if result.kind == skMethod: finishMethod(c, result)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 43c7bf3fe..d17351988 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -66,10 +66,16 @@ proc toCover(t: PType): BiggestInt =
     result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
 
 proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
+  ## Checks that the given symbol is a proper procedure variable, meaning
+  ## that it 
   var smoduleId = getModule(s).id
   if sfProcvar notin s.flags and s.typ.callConv == ccDefault and
-      smoduleId != c.module.id and smoduleId != c.friendModule.id: 
-    localError(n.info, errXCannotBePassedToProcVar, s.name.s)
+      smoduleId != c.module.id:
+    block outer:
+      for module in c.friendModules:
+        if smoduleId == module.id:
+          break outer
+      localError(n.info, errXCannotBePassedToProcVar, s.name.s)
 
 proc semProcvarCheck(c: PContext, n: PNode) =
   let n = n.skipConv
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 3b9e82261..9d38c4619 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -70,9 +70,10 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       counter = x
     of nkSym: 
       e = n.sons[i].sym
-    of nkIdent: 
+    of nkIdent, nkAccQuoted: 
       e = newSymS(skEnumField, n.sons[i], c)
-    else: illFormedAst(n)
+    else:
+      illFormedAst(n[i])
     e.typ = result
     e.position = int(counter)
     if e.position == 0: hasNull = true
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index fc6ba2f77..db95c480f 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -63,8 +63,11 @@ proc filterSym(s: PSym): bool {.inline.} =
 
 proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
   let fmoduleId = getModule(f).id
-  result = sfExported in f.flags or fmoduleId == c.module.id or
-      fmoduleId == c.friendModule.id
+  result = sfExported in f.flags or fmoduleId == c.module.id
+  for module in c.friendModules:
+    if fmoduleId == module.id:
+      result = true
+      break
 
 proc suggestField(c: PContext, s: PSym, outputs: var int) = 
   if filterSym(s) and fieldVisible(c, s):
@@ -319,7 +322,7 @@ proc suggestSym*(n: PNode, s: PSym) {.inline.} =
     findUsages(n, s)
   if optDef in gGlobalOptions:
     findDefinition(n, s)
-  if isServing:
+  if isServing and not n.isNil:
     addToSourceMap(s, n.info)
 
 proc markUsed(n: PNode, s: PSym) =
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 0e01f5031..9a213d813 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -15,6 +15,8 @@ proc readOutput(p: PProcess): string =
   discard p.waitForExit
   while not output.atEnd:
     result.add(output.readLine)
+    result.add("\n")
+  result.setLen(result.len - "\n".len)
 
 proc opGorge*(cmd, input: string): string =
   var p = startCmd(cmd)