diff options
Diffstat (limited to 'compiler')
104 files changed, 1601 insertions, 1085 deletions
diff --git a/compiler/aliases.nim b/compiler/aliases.nim index a26b94303..3f3d45ff7 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -16,9 +16,9 @@ type TAnalysisResult* = enum arNo, arMaybe, arYes -proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult +proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult -proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult = +proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult = result = arNo case n.kind of nkRecList: @@ -39,7 +39,7 @@ proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult = result = isPartOfAux(n.sym.typ, b, marker) else: internalError(n.info, "isPartOfAux()") -proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult = +proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult = result = arNo if a == nil or b == nil: return if containsOrIncl(marker, a.id): return diff --git a/compiler/ast.nim b/compiler/ast.nim index 0c828a6d9..db6003b87 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -681,7 +681,6 @@ type heapRoot*: PRope # keeps track of the enclosing heap object that # owns this location (required by GC algorithms # employing heap snapshots or sliding views) - a*: int # ---------------- end of backend information ------------------------------ @@ -772,6 +771,7 @@ type # it won't cause problems TTypeSeq* = seq[PType] + TLockLevel* = distinct int16 TType* {.acyclic.} = object of TIdObj # \ # types are identical iff they have the # same id; there may be multiple copies of a type @@ -798,11 +798,12 @@ type deepCopy*: PSym # overriden 'deepCopy' operation size*: BiggestInt # the size of the type in bytes # -1 means that the size is unkwown - align*: int # the type's alignment requirements + align*: int16 # the type's alignment requirements + lockLevel*: TLockLevel # lock level as required for deadlock checking loc*: TLoc TPair*{.final.} = object - key*, val*: PObject + key*, val*: RootRef TPairSeq* = seq[TPair] TTable*{.final.} = object # the same as table[PObject] of PObject @@ -811,7 +812,7 @@ type TIdPair*{.final.} = object key*: PIdObj - val*: PObject + val*: RootRef TIdPairSeq* = seq[TIdPair] TIdTable*{.final.} = object # the same as table[PIdent] of PObject @@ -838,7 +839,7 @@ type counter*: int data*: TNodePairSeq - TObjectSeq* = seq[PObject] + TObjectSeq* = seq[RootRef] TObjectSet*{.final.} = object counter*: int data*: TObjectSeq @@ -1166,6 +1167,16 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode, result.sons = @[name, pattern, genericParams, params, pragmas, exceptions, body] +const + UnspecifiedLockLevel* = TLockLevel(-1'i16) + MaxLockLevel* = 1000'i16 + UnknownLockLevel* = TLockLevel(1001'i16) + +proc `$`*(x: TLockLevel): string = + if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>" + elif x.ord == UnknownLockLevel.ord: result = "<unknown>" + else: result = $int16(x) + proc newType(kind: TTypeKind, owner: PSym): PType = new(result) result.kind = kind @@ -1173,6 +1184,7 @@ proc newType(kind: TTypeKind, owner: PSym): PType = result.size = - 1 result.align = 2 # default alignment result.id = getID() + result.lockLevel = UnspecifiedLockLevel when debugIds: registerId(result) #if result.id < 2000: @@ -1184,7 +1196,7 @@ proc mergeLoc(a: var TLoc, b: TLoc) = a.flags = a.flags + b.flags if a.t == nil: a.t = b.t if a.r == nil: a.r = b.r - if a.a == 0: a.a = b.a + #if a.a == 0: a.a = b.a proc assignType(dest, src: PType) = dest.kind = src.kind @@ -1195,6 +1207,7 @@ proc assignType(dest, src: PType) = dest.align = src.align dest.destructor = src.destructor dest.deepCopy = src.deepCopy + dest.lockLevel = src.lockLevel # this fixes 'type TLock = TSysLock': if src.sym != nil: if dest.sym != nil: diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index eb7ffc63e..110b0c26e 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -14,7 +14,7 @@ import ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils -proc hashNode*(p: PObject): THash +proc hashNode*(p: RootRef): THash proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope # Convert a tree into its YAML representation; this is used by the # YAML code generator and it is invaluable for debugging purposes. @@ -24,21 +24,21 @@ proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope proc lineInfoToStr*(info: TLineInfo): PRope # ----------------------- node sets: --------------------------------------- -proc objectSetContains*(t: TObjectSet, obj: PObject): bool +proc objectSetContains*(t: TObjectSet, obj: RootRef): bool # returns true whether n is in t -proc objectSetIncl*(t: var TObjectSet, obj: PObject) +proc objectSetIncl*(t: var TObjectSet, obj: RootRef) # include an element n in the table t -proc objectSetContainsOrIncl*(t: var TObjectSet, obj: PObject): bool +proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool # more are not needed ... # ----------------------- (key, val)-Hashtables ---------------------------- -proc tablePut*(t: var TTable, key, val: PObject) -proc tableGet*(t: TTable, key: PObject): PObject +proc tablePut*(t: var TTable, key, val: RootRef) +proc tableGet*(t: TTable, key: RootRef): RootRef type - TCmpProc* = proc (key, closure: PObject): bool {.nimcall.} # true if found + TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found -proc tableSearch*(t: TTable, key, closure: PObject, - comparator: TCmpProc): PObject +proc tableSearch*(t: TTable, key, closure: RootRef, + comparator: TCmpProc): RootRef # return val as soon as comparator returns true; if this never happens, # nil is returned @@ -79,9 +79,9 @@ proc debug*(n: PType) {.deprecated.} proc debug*(n: PNode) {.deprecated.} # --------------------------- ident tables ---------------------------------- -proc idTableGet*(t: TIdTable, key: PIdObj): PObject -proc idTableGet*(t: TIdTable, key: int): PObject -proc idTablePut*(t: var TIdTable, key: PIdObj, val: PObject) +proc idTableGet*(t: TIdTable, key: PIdObj): RootRef +proc idTableGet*(t: TIdTable, key: int): RootRef +proc idTablePut*(t: var TIdTable, key: PIdObj, val: RootRef) proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool # checks if `t` contains the `key` (compared by the pointer value, not only # `key`'s id) @@ -196,7 +196,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym = else: internalError(list.info, "getSymFromList") result = nil -proc hashNode(p: PObject): THash = +proc hashNode(p: RootRef): THash = result = hash(cast[pointer](p)) proc mustRehash(length, counter: int): bool = @@ -245,13 +245,13 @@ proc lineInfoToStr(info: TLineInfo): PRope = toRope(toLinenumber(info)), toRope(toColumn(info))]) -proc treeToYamlAux(n: PNode, marker: var TIntSet, +proc treeToYamlAux(n: PNode, marker: var IntSet, indent, maxRecDepth: int): PRope -proc symToYamlAux(n: PSym, marker: var TIntSet, +proc symToYamlAux(n: PSym, marker: var IntSet, indent, maxRecDepth: int): PRope -proc typeToYamlAux(n: PType, marker: var TIntSet, +proc typeToYamlAux(n: PType, marker: var IntSet, indent, maxRecDepth: int): PRope -proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int, +proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int, maxRecDepth: int): PRope = var istr = spaces(indent + 2) result = toRope("[") @@ -277,13 +277,13 @@ proc ropeConstr(indent: int, c: openArray[PRope]): PRope = inc(i, 2) appf(result, "$N$1}", [spaces(indent)]) -proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int, +proc symToYamlAux(n: PSym, marker: var IntSet, indent: int, maxRecDepth: int): PRope = if n == nil: result = toRope("null") elif containsOrIncl(marker, n.id): result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope( - strutils.toHex(cast[TAddress](n), sizeof(n) * 2))]) + strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]) else: var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1) result = ropeConstr(indent, [toRope("kind"), @@ -298,13 +298,13 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int, flagsToStr(n.options), toRope("position"), toRope(n.position)]) -proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int, +proc typeToYamlAux(n: PType, marker: var IntSet, indent: int, maxRecDepth: int): PRope = if n == nil: result = toRope("null") elif containsOrIncl(marker, n.id): result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope( - strutils.toHex(cast[TAddress](n), sizeof(n) * 2))]) + strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]) else: if sonsLen(n) > 0: result = toRope("[") @@ -326,7 +326,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int, toRope("align"), toRope(n.align), toRope("sons"), result]) -proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int, +proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int, maxRecDepth: int): PRope = if n == nil: result = toRope("null") @@ -469,7 +469,7 @@ proc nextTry(h, maxHash: THash): THash = # generates each int in range(maxHash) exactly once (see any text on # random-number generation for proof). -proc objectSetContains(t: TObjectSet, obj: PObject): bool = +proc objectSetContains(t: TObjectSet, obj: RootRef): bool = # returns true whether n is in t var h: THash = hashNode(obj) and high(t.data) # start with real hash value while t.data[h] != nil: @@ -478,7 +478,7 @@ proc objectSetContains(t: TObjectSet, obj: PObject): bool = h = nextTry(h, high(t.data)) result = false -proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) = +proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) = var h: THash = hashNode(obj) and high(data) while data[h] != nil: assert(data[h] != obj) @@ -493,12 +493,12 @@ proc objectSetEnlarge(t: var TObjectSet) = if t.data[i] != nil: objectSetRawInsert(n, t.data[i]) swap(t.data, n) -proc objectSetIncl(t: var TObjectSet, obj: PObject) = +proc objectSetIncl(t: var TObjectSet, obj: RootRef) = if mustRehash(len(t.data), t.counter): objectSetEnlarge(t) objectSetRawInsert(t.data, obj) inc(t.counter) -proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool = +proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool = # returns true if obj is already in the string table: var h: THash = hashNode(obj) and high(t.data) while true: @@ -516,7 +516,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool = inc(t.counter) result = false -proc tableRawGet(t: TTable, key: PObject): int = +proc tableRawGet(t: TTable, key: RootRef): int = var h: THash = hashNode(key) and high(t.data) # start with real hash value while t.data[h].key != nil: if t.data[h].key == key: @@ -524,8 +524,8 @@ proc tableRawGet(t: TTable, key: PObject): int = h = nextTry(h, high(t.data)) result = -1 -proc tableSearch(t: TTable, key, closure: PObject, - comparator: TCmpProc): PObject = +proc tableSearch(t: TTable, key, closure: RootRef, + comparator: TCmpProc): RootRef = var h: THash = hashNode(key) and high(t.data) # start with real hash value while t.data[h].key != nil: if t.data[h].key == key: @@ -535,12 +535,12 @@ proc tableSearch(t: TTable, key, closure: PObject, h = nextTry(h, high(t.data)) result = nil -proc tableGet(t: TTable, key: PObject): PObject = +proc tableGet(t: TTable, key: RootRef): RootRef = var index = tableRawGet(t, key) if index >= 0: result = t.data[index].val else: result = nil -proc tableRawInsert(data: var TPairSeq, key, val: PObject) = +proc tableRawInsert(data: var TPairSeq, key, val: RootRef) = var h: THash = hashNode(key) and high(data) while data[h].key != nil: assert(data[h].key != key) @@ -556,7 +556,7 @@ proc tableEnlarge(t: var TTable) = if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val) swap(t.data, n) -proc tablePut(t: var TTable, key, val: PObject) = +proc tablePut(t: var TTable, key, val: RootRef) = var index = tableRawGet(t, key) if index >= 0: t.data[index].val = val @@ -626,6 +626,12 @@ proc strTableAdd(t: var TStrTable, n: PSym) = strTableRawInsert(t.data, n) inc(t.counter) +proc reallySameIdent(a, b: string): bool {.inline.} = + when defined(nimfix): + result = a[0] == b[0] + else: + result = true + proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} = # returns true if n is already in the string table: # It is essential that `n` is written nevertheless! @@ -635,7 +641,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} = while true: var it = t.data[h] if it == nil: break - if it.name.id == n.name.id: + if it.name.id == n.name.id and reallySameIdent(it.name.s, n.name.s): t.data[h] = n # overwrite it with newer definition! return true # found it h = nextTry(h, high(t.data)) @@ -677,7 +683,7 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym = ti.h = nextTry(h, high(tab.data)) proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, - excluding: TIntSet): PSym = + excluding: IntSet): PSym = var h: THash = ti.h and high(tab.data) var start = h result = tab.data[h] @@ -693,7 +699,7 @@ proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, if result != nil and contains(excluding, result.id): result = nil proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent, - excluding: TIntSet): PSym = + excluding: IntSet): PSym = ti.h = s.h ti.name = s if tab.counter == 0: result = nil @@ -740,22 +746,22 @@ proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool = if index >= 0: result = t.data[index].key == key else: result = false -proc idTableGet(t: TIdTable, key: PIdObj): PObject = +proc idTableGet(t: TIdTable, key: PIdObj): RootRef = var index = idTableRawGet(t, key.id) if index >= 0: result = t.data[index].val else: result = nil -proc idTableGet(t: TIdTable, key: int): PObject = +proc idTableGet(t: TIdTable, key: int): RootRef = var index = idTableRawGet(t, key) if index >= 0: result = t.data[index].val else: result = nil -iterator pairs*(t: TIdTable): tuple[key: int, value: PObject] = +iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] = for i in 0..high(t.data): if t.data[i].key != nil: yield (t.data[i].key.id, t.data[i].val) -proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) = +proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) = var h: THash h = key.id and high(data) while data[h].key != nil: @@ -765,7 +771,7 @@ proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) = data[h].key = key data[h].val = val -proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) = +proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) = var index: int n: TIdPairSeq @@ -784,7 +790,7 @@ proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) = idTableRawInsert(t.data, key, val) inc(t.counter) -iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] = +iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] = for i in 0 .. high(t.data): if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val) diff --git a/compiler/bitsets.nim b/compiler/bitsets.nim index 740bdd5ef..a2324f4e2 100644 --- a/compiler/bitsets.nim +++ b/compiler/bitsets.nim @@ -1,14 +1,14 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# this unit handles Nimrod sets; it implements bit sets -# the code here should be reused in the Nimrod standard library +# this unit handles Nim sets; it implements bit sets +# the code here should be reused in the Nim standard library type TBitSet* = seq[int8] # we use byte here to avoid issues with diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim index 3bc4eb029..14448f0e8 100644 --- a/compiler/canonicalizer.nim +++ b/compiler/canonicalizer.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -370,7 +370,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) = # the last entry of a symbol: if s.ast != nil: # we used to attempt to save space here by only storing a dummy AST if - # it is not necessary, but Nimrod's heavy compile-time evaluation features + # it is not necessary, but Nim's heavy compile-time evaluation features # make that unfeasible nowadays: encodeNode(w, s.info, s.ast, result) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index adcc95e84..b01a81c5e 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -103,9 +103,9 @@ proc openArrayLoc(p: BProc, n: PNode): PRope = result = ropef("$1, $1Len0", [rdLoc(a)]) of tyString, tySequence: if skipTypes(n.typ, abstractInst).kind == tyVar: - result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField()]) + result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)]) else: - result = ropef("$1->data, $1->$2", [a.rdLoc, lenField()]) + result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)]) of tyArray, tyArrayConstr: result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]) else: internalError("openArrayLoc: " & typeToString(a.t)) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b5817de05..75f0f3a42 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -15,7 +15,7 @@ proc intLiteral(i: BiggestInt): PRope = if (i > low(int32)) and (i <= high(int32)): result = toRope(i) elif i == low(int32): - # Nimrod has the same bug for the same reasons :-) + # Nim has the same bug for the same reasons :-) result = ~"(-2147483647 -1)" elif i > low(int64): result = rfmt(nil, "IL64($1)", toRope(i)) @@ -409,7 +409,6 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) = d.k = locData d.t = getUniqueType(t) d.r = r - d.a = -1 proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) = var a: TLoc @@ -425,7 +424,6 @@ proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) = d.k = locExpr d.t = getUniqueType(t) d.r = r - d.a = -1 proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = var a, b: TLoc @@ -723,7 +721,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) = internalError(e.info, "genRecordField") field = lookupInRecord(ty.n, f.name) if field != nil: break - if gCmd != cmdCompileToCpp: app(r, ".Sup") + if not p.module.compileToCpp: app(r, ".Sup") ty = getUniqueType(ty.sons[0]) if field == nil: internalError(e.info, "genRecordField 2 ") if field.loc.r == nil: internalError(e.info, "genRecordField 3") @@ -775,7 +773,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = assert(ty.kind in {tyTuple, tyObject}) field = lookupInRecord(ty.n, f.name) if field != nil: break - if gCmd != cmdCompileToCpp: app(r, ".Sup") + if not p.module.compileToCpp: app(r, ".Sup") ty = getUniqueType(ty.sons[0]) if field == nil: internalError(e.info, "genCheckedRecordField") if field.loc.r == nil: @@ -842,11 +840,11 @@ proc genSeqElem(p: BProc, e: PNode, d: var TLoc) = if ty.kind == tyString: linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", - rdLoc(b), rdLoc(a), lenField()) + rdLoc(b), rdLoc(a), lenField(p)) else: linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", - rdLoc(b), rdLoc(a), lenField()) + rdLoc(b), rdLoc(a), lenField(p)) if d.k == locNone: d.s = OnHeap d.heapRoot = a.r if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: @@ -908,7 +906,7 @@ proc gcUsage(n: PNode) = if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree) proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = - # <Nimrod code> + # <Nim code> # s = 'Hello ' & name & ', how do you feel?' & 'z' # # <generated C code> @@ -939,7 +937,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}: inc(L, len(e.sons[i + 1].strVal)) else: - appf(lens, "$1->$2 + ", [rdLoc(a), lenField()]) + appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)]) app(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a))) linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, toRope(L)) app(p.s(cpsStmts), appends) @@ -951,7 +949,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = gcUsage(e) proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = - # <Nimrod code> + # <Nim code> # s &= 'Hello ' & name & ', how do you feel?' & 'z' # // BUG: what if s is on the left side too? # <generated C code> @@ -979,7 +977,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}: inc(L, len(e.sons[i + 2].strVal)) else: - appf(lens, "$1->$2 + ", [rdLoc(a), lenField()]) + appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)]) app(appends, rfmt(p.module, "#appendString($1, $2);$n", rdLoc(dest), rdLoc(a))) linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", @@ -992,7 +990,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq &= x --> # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq->data[seq->len-1] = x; - let seqAppendPattern = if gCmd != cmdCompileToCpp: + let seqAppendPattern = if not p.module.compileToCpp: "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n" else: "$1 = ($2) #incrSeq($1, sizeof($3));$n" @@ -1005,7 +1003,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))]) keepAlive(p, a) initLoc(dest, locExpr, b.t, OnHeap) - dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField()) + dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField(p)) genAssignment(p, dest, b, {needToCopy, afDestIsNil}) gcUsage(e) @@ -1099,7 +1097,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = while ty != nil: field = lookupInRecord(ty.n, it.sons[0].sym.name) if field != nil: break - if gCmd != cmdCompileToCpp: app(tmp2.r, ".Sup") + if not p.module.compileToCpp: app(tmp2.r, ".Sup") ty = getUniqueType(ty.sons[0]) if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr") if it.len == 3 and optFieldCheck in p.options: @@ -1200,8 +1198,8 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = if t.kind != tyVar: nilCheck = r r = rfmt(nil, "(*$1)", r) t = skipTypes(t.lastSon, typedescInst) - if gCmd != cmdCompileToCpp: - while (t.kind == tyObject) and (t.sons[0] != nil): + if not p.module.compileToCpp: + while t.kind == tyObject and t.sons[0] != nil: app(r, ~".Sup") t = skipTypes(t.sons[0], typedescInst) if isObjLackingTypeField(t): @@ -1246,7 +1244,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)])) of tyString, tySequence: putIntoDest(p, b, e.typ, - ropef("$1->data, $1->$2", [rdLoc(a), lenField()])) + ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)])) of tyArray, tyArrayConstr: putIntoDest(p, b, e.typ, ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])) @@ -1289,7 +1287,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)") else: unaryExpr(p, e, d, "strlen($1)") of tyString, tySequence: - if gCmd != cmdCompileToCpp: + if not p.module.compileToCpp: if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)") else: unaryExpr(p, e, d, "$1->Sup.len") else: @@ -1307,7 +1305,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) var t = skipTypes(e.sons[1].typ, abstractVar) - let setLenPattern = if gCmd != cmdCompileToCpp: + let setLenPattern = if not p.module.compileToCpp: "$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n" else: "$1 = ($3) #setLengthSeq($1, sizeof($4), $2);$n" @@ -1508,7 +1506,6 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) = linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n", getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl) tmp.k = locExpr - tmp.a = -1 tmp.t = srct tmp.s = OnStack tmp.flags = {} @@ -1564,11 +1561,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""): initLocExpr(p, e.sons[2], x) putIntoDest(p, d, e.typ, - rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField())) + rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p))) elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""): initLocExpr(p, e.sons[1], x) putIntoDest(p, d, e.typ, - rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField())) + rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p))) else: binaryExpr(p, e, d, "#eqStrings($1, $2)") @@ -1827,7 +1824,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = if t.kind != tyVar: nilCheck = r r = ropef("(*$1)", [r]) t = skipTypes(t.lastSon, abstractInst) - if gCmd != cmdCompileToCpp: + if not p.module.compileToCpp: while t.kind == tyObject and t.sons[0] != nil: app(r, ".Sup") t = skipTypes(t.sons[0], abstractInst) @@ -1845,7 +1842,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = [getTypeDesc(p.module, dest), addrLoc(a)])) proc downConv(p: BProc, n: PNode, d: var TLoc) = - if gCmd == cmdCompileToCpp: + if p.module.compileToCpp: expr(p, n.sons[0], d) # downcast does C++ for us else: var dest = skipTypes(n.typ, abstractPtrs) @@ -2031,7 +2028,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = initLocExpr(p, n.sons[0], a) of nkAsmStmt: genAsmStmt(p, n) of nkTryStmt: - if gCmd == cmdCompileToCpp: genTryCpp(p, n, d) + if p.module.compileToCpp: genTryCpp(p, n, d) else: genTry(p, n, d) of nkRaiseStmt: genRaiseStmt(p, n) of nkTypeSection: @@ -2043,6 +2040,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = nkFromStmt, nkTemplateDef, nkMacroDef: discard of nkPragma: genPragma(p, n) + of nkPragmaBlock: expr(p, n.lastSon, d) of nkProcDef, nkMethodDef, nkConverterDef: if (n.sons[genericParamsPos].kind == nkEmpty): var prc = n.sons[namePos].sym diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index 2d27257ce..36da68d23 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -83,7 +83,7 @@ proc writeTypeCache(a: TIdTable, s: var string) = inc i s.add('}') -proc writeIntSet(a: TIntSet, s: var string) = +proc writeIntSet(a: IntSet, s: var string) = var i = 0 for x in items(a): if i == 10: @@ -200,7 +200,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) = idTablePut(result, newFakeType(key), value.toRope) inc L.bufpos -proc readIntSet(L: var TBaseLexer, result: var TIntSet) = +proc readIntSet(L: var TBaseLexer, result: var IntSet) = if ^L.bufpos != '{': internalError("ccgmerge: '{' expected") inc L.bufpos while ^L.bufpos != '}': @@ -249,7 +249,7 @@ proc readMergeInfo*(cfilename: string, m: BModule) = break type - TMergeSections = object {.pure.} + TMergeSections = object f: TCFileSections p: TCProcSections diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 037594e89..0898f0b03 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -46,7 +46,6 @@ proc genVarTuple(p: BProc, n: PNode) = if useLowering: genStmts(p, lowerTupleUnpacking(n, p.prc)) return - genLineDir(p, n) initLocExpr(p, n.sons[L-1], tup) var t = tup.t @@ -294,8 +293,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = var alreadyPoppedCnt = p.inExceptBlock for i in countup(1, howManyTrys): - - if gCmd != cmdCompileToCpp: + if not p.module.compileToCpp: # Pop safe points generated by try if alreadyPoppedCnt > 0: dec alreadyPoppedCnt @@ -317,7 +315,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = for i in countdown(howManyTrys-1, 0): p.nestedTryStmts.add(stack[i]) - if gCmd != cmdCompileToCpp: + if not p.module.compileToCpp: # Pop exceptions that was handled by the # except-blocks we are in for i in countdown(howManyExcepts-1, 0): @@ -448,7 +446,7 @@ proc genBlock(p: BProc, t: PNode, d: var TLoc) = assert(t.sons[0].kind == nkSym) var sym = t.sons[0].sym sym.loc.k = locOther - sym.loc.a = p.breakIdx + sym.position = p.breakIdx+1 expr(p, t.sons[1], d) endBlock(p) @@ -487,7 +485,7 @@ proc genBreakStmt(p: BProc, t: PNode) = assert(t.sons[0].kind == nkSym) var sym = t.sons[0].sym assert(sym.loc.k == locOther) - idx = sym.loc.a + idx = sym.position-1 else: # an unnamed 'break' can only break a loop after 'transf' pass: while idx >= 0 and not p.blocks[idx].isLoop: dec idx @@ -501,8 +499,10 @@ proc genBreakStmt(p: BProc, t: PNode) = lineF(p, cpsStmts, "goto $1;$n", [label]) proc getRaiseFrmt(p: BProc): string = - if gCmd == cmdCompileToCpp: + if p.module.compileToCpp: result = "throw NimException($1, $2);$n" + elif getCompilerProc("Exception") != nil: + result = "#raiseException((#Exception*)$1, $2);$n" else: result = "#raiseException((#E_Base*)$1, $2);$n" @@ -520,10 +520,10 @@ proc genRaiseStmt(p: BProc, t: PNode) = var typ = skipTypes(t.sons[0].typ, abstractPtrs) genLineDir(p, t) lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)]) - else: + else: genLineDir(p, t) # reraise the last exception: - if gCmd == cmdCompileToCpp: + if p.module.compileToCpp: line(p, cpsStmts, ~"throw;$n") else: linefmt(p, cpsStmts, "#reraiseException();$n") @@ -559,7 +559,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc, proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc, rangeFormat, eqFormat: TFormatStr, until: int, a: TLoc): TLabel = - # generate a C-if statement for a Nimrod case statement + # generate a C-if statement for a Nim case statement var labId = p.labels for i in 1..until: inc(p.labels) @@ -747,7 +747,10 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = i, length, blen: int genLineDir(p, t) exc = getTempName() - discard cgsym(p.module, "E_Base") + if getCompilerProc("Exception") != nil: + discard cgsym(p.module, "Exception") + else: + discard cgsym(p.module, "E_Base") add(p.nestedTryStmts, t) startBlock(p, "try {$n") expr(p, t.sons[0], d) @@ -829,7 +832,10 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = discard lists.includeStr(p.module.headerFiles, "<setjmp.h>") genLineDir(p, t) var safePoint = getTempName() - discard cgsym(p.module, "E_Base") + if getCompilerProc("Exception") != nil: + discard cgsym(p.module, "Exception") + else: + discard cgsym(p.module, "E_Base") linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint) linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint) if isDefined("nimStdSetjmp"): diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index c00b931ef..c24dd5c41 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -57,6 +57,9 @@ proc generateThreadLocalStorage(m: BModule) = proc generateThreadVarsSize(m: BModule) = if nimtv != nil: - app(m.s[cfsProcs], - "NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}" & tnl) - + let externc = if gCmd != cmdCompileToCpp and + sfCompileToCpp in m.module.flags: "extern \"C\"" + else: "" + appf(m.s[cfsProcs], + "$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n", + [externc.toRope]) diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index a5bf9e7a7..8bb820283 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -49,8 +49,8 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) = genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t) else: internalError(n.info, "genTraverseProc()") -proc parentObj(accessor: PRope): PRope {.inline.} = - if gCmd != cmdCompileToCpp: +proc parentObj(accessor: PRope; m: BModule): PRope {.inline.} = + if not m.compileToCpp: result = ropef("$1.Sup", accessor) else: result = accessor @@ -71,7 +71,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) = lineF(p, cpsStmts, "}$n") of tyObject: for i in countup(0, sonsLen(typ) - 1): - genTraverseProc(c, accessor.parentObj, typ.sons[i]) + genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i]) if typ.n != nil: genTraverseProc(c, accessor, typ.n) of tyTuple: let typ = getUniqueType(typ) @@ -91,7 +91,7 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) = var i: TLoc getTemp(p, getSysType(tyInt), i) lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n", - i.r, accessor, toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len")) + i.r, accessor, toRope(if c.p.module.compileToCpp: "len" else: "Sup.len")) genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0]) lineF(p, cpsStmts, "}$n") diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index fc6febc6f..fbdea7e66 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -162,7 +162,7 @@ proc mapReturnType(typ: PType): TCTypeKind = if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr else: result = mapType(typ) -proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope +proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope proc needsComplexAssignment(typ: PType): bool = result = containsGarbageCollectedRef(typ) @@ -228,7 +228,7 @@ proc fillResult(param: PSym) = incl(param.loc.flags, lfIndirect) param.loc.s = OnUnknown -proc getParamTypeDesc(m: BModule, t: PType, check: var TIntSet): PRope = +proc getParamTypeDesc(m: BModule, t: PType, check: var IntSet): PRope = when false: if t.Kind in {tyRef, tyPtr, tyVar}: var b = skipTypes(t.lastson, typedescInst) @@ -243,7 +243,7 @@ proc paramStorageLoc(param: PSym): TStorageLoc = result = OnUnknown proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, - check: var TIntSet, declareEnvironment=true) = + check: var IntSet, declareEnvironment=true) = params = nil if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]): rettype = ~"void" @@ -342,8 +342,8 @@ proc getTypePre(m: BModule, typ: PType): PRope = proc structOrUnion(t: PType): PRope = (if tfUnion in t.flags: toRope("union") else: toRope("struct")) -proc getForwardStructFormat(): string = - if gCmd == cmdCompileToCpp: result = "$1 $2;$n" +proc getForwardStructFormat(m: BModule): string = + if m.compileToCpp: result = "$1 $2;$n" else: result = "typedef $1 $2 $2;$n" proc getTypeForward(m: BModule, typ: PType): PRope = @@ -355,7 +355,7 @@ proc getTypeForward(m: BModule, typ: PType): PRope = of tySequence, tyTuple, tyObject: result = getTypeName(typ) if not isImportedType(typ): - appf(m.s[cfsForwardTypes], getForwardStructFormat(), + appf(m.s[cfsForwardTypes], getForwardStructFormat(m), [structOrUnion(typ), result]) idTablePut(m.forwTypeCache, typ, result) else: internalError("getTypeForward(" & $typ.kind & ')') @@ -370,7 +370,7 @@ proc mangleRecFieldName(field: PSym, rectype: PType): PRope = proc genRecordFieldsAux(m: BModule, n: PNode, accessExpr: PRope, rectype: PType, - check: var TIntSet): PRope = + check: var IntSet): PRope = var ae, uname, sname, a: PRope k: PNode @@ -419,19 +419,19 @@ proc genRecordFieldsAux(m: BModule, n: PNode, appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname]) else: internalError(n.info, "genRecordFieldsAux()") -proc getRecordFields(m: BModule, typ: PType, check: var TIntSet): PRope = +proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope = result = genRecordFieldsAux(m, typ.n, nil, typ, check) proc getRecordDesc(m: BModule, typ: PType, name: PRope, - check: var TIntSet): PRope = + check: var IntSet): PRope = # declare the record: var hasField = false var attribute: PRope = - if tfPacked in typ.flags: toRope(CC[ccompiler].packedPragma) + if tfPacked in typ.flags: toRope(CC[cCompiler].packedPragma) else: nil - result = ropecg(m, CC[ccompiler].structStmtFmt, + result = ropecg(m, CC[cCompiler].structStmtFmt, [structOrUnion(typ), name, attribute]) if typ.kind == tyObject: @@ -442,7 +442,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope, else: appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute]) hasField = true - elif gCmd == cmdCompileToCpp: + elif m.compileToCpp: appcg(m, result, " : public $1 {$n", [getTypeDescAux(m, typ.sons[0], check)]) hasField = true @@ -461,7 +461,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope, app(result, "};" & tnl) proc getTupleDesc(m: BModule, typ: PType, name: PRope, - check: var TIntSet): PRope = + check: var IntSet): PRope = result = ropef("$1 $2 {$n", [structOrUnion(typ), name]) var desc: PRope = nil for i in countup(0, sonsLen(typ) - 1): @@ -474,7 +474,7 @@ proc getTupleDesc(m: BModule, typ: PType, name: PRope, proc pushType(m: BModule, typ: PType) = add(m.typeStack, typ) -proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope = +proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = # returns only the type's name var name, rettype, desc, recdesc: PRope @@ -538,7 +538,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope = if result == nil: result = getTypeName(t) if not isImportedType(t): - appf(m.s[cfsForwardTypes], getForwardStructFormat(), + appf(m.s[cfsForwardTypes], getForwardStructFormat(m), [structOrUnion(t), result]) idTablePut(m.forwTypeCache, t, result) assert(cacheGetType(m.typeCache, t) == nil) @@ -550,7 +550,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope = cSeq = "struct $2 {$n" & " #TGenericSeq Sup;$n" appcg(m, m.s[cfsSeqTypes], - (if gCmd == cmdCompileToCpp: cppSeq else: cSeq) & + (if m.compileToCpp: cppSeq else: cSeq) & " $1 data[SEQ_DECL_SIZE];$n" & "};$n", [getTypeDescAux(m, t.sons[0], check), result]) else: @@ -570,7 +570,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope = if result == nil: result = getTypeName(t) if not isImportedType(t): - appf(m.s[cfsForwardTypes], getForwardStructFormat(), + appf(m.s[cfsForwardTypes], getForwardStructFormat(m), [structOrUnion(t), result]) idTablePut(m.forwTypeCache, t, result) idTablePut(m.typeCache, t, result) # always call for sideeffects: @@ -898,7 +898,7 @@ include ccgtrav proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) = genProc(m, s) - appf(m.s[cfsTypeInit3], "$1.deepcopy = (N_NIMCALL_PTR(void*, void*)) $2;$n", + appf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n", [result, s.loc.r]) proc genTypeInfo(m: BModule, t: PType): PRope = diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 65957584a..7396c0bf8 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -149,7 +149,7 @@ proc getUniqueType*(key: PType): PType = idTablePut(gTypeTable[k], key, key) result = key -proc tableGetType*(tab: TIdTable, key: PType): PObject = +proc tableGetType*(tab: TIdTable, key: PType): RootRef = # returns nil if we need to declare this type result = idTableGet(tab, key) if (result == nil) and (tab.counter > 0): @@ -171,7 +171,7 @@ proc mangle*(name: string): string = ## Lowercases the given name and manges any non-alphanumeric characters ## so they are represented as `HEX____`. If the name starts with a number, ## `N` is prepended - result = "" + result = newStringOfCap(name.len) case name[0] of Letters: result.add(name[0].toLower) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 359fa3309..afeac8c88 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -55,7 +55,7 @@ proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) = result.s = s result.t = getUniqueType(typ) result.r = nil - result.a = - 1 + #result.a = - 1 result.flags = {} proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) = @@ -63,7 +63,7 @@ proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) = if a.k == locNone: a.k = k a.t = getUniqueType(typ) - a.a = - 1 + #a.a = - 1 a.s = s if a.r == nil: a.r = r @@ -139,7 +139,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope = if i - 1 >= start: app(result, substr(frmt, start, i - 1)) -const compileTimeRopeFmt = not defined(booting) +const compileTimeRopeFmt = false when compileTimeRopeFmt: import macros @@ -186,7 +186,7 @@ when compileTimeRopeFmt: while s[i] in IdentChars: inc i yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0) start = i - else: nil + else: discard while i < length: if s[i] != '$' and s[i] != '#': inc i @@ -201,7 +201,7 @@ when compileTimeRopeFmt: ## the compilation of nimrod itself or will the macro execution time ## offset the gains? result = newCall(bindSym"ropeConcat") - for frag in fmtStringFragments(fmt.strVal): + for frag in fmtStringFragments(fmt): case frag.kind of ffSym: result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value))) @@ -297,6 +297,9 @@ proc accessThreadLocalVar(p: BProc, s: PSym) proc emulatedThreadVars(): bool {.inline.} proc genProc(m: BModule, prc: PSym) +template compileToCpp(m: BModule): expr = + gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags + include "ccgtypes.nim" # ------------------------------ Manager of temporaries ------------------ @@ -326,7 +329,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, var r = rdLoc(a) if not takeAddr: r = ropef("(*$1)", [r]) var s = skipTypes(t, abstractInst) - if gCmd != cmdCompileToCpp: + if not p.module.compileToCpp: while (s.kind == tyObject) and (s.sons[0] != nil): app(r, ".Sup") s = skipTypes(s.sons[0], abstractInst) @@ -407,7 +410,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = result.r = con("LOC", toRope(p.labels)) linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) result.k = locTemp - result.a = - 1 + #result.a = - 1 result.t = getUniqueType(t) result.s = OnStack result.flags = {} @@ -425,7 +428,7 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) = [getTypeDesc(p.module, toKeepAlive.t), fid]) inc(p.gcFrameId) result.k = locTemp - result.a = -1 + #result.a = -1 result.t = toKeepAlive.t result.s = OnStack result.flags = {} @@ -506,7 +509,7 @@ proc assignLocalVar(p: BProc, s: PSym) = #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: # app(decl, " GC_GUARD") if sfVolatile in s.flags or (p.nestedTryStmts.len > 0 and - gCmd != cmdCompileToCpp): + not p.module.compileToCpp): app(decl, " volatile") appf(decl, " $1;$n", [s.loc.r]) else: @@ -587,8 +590,8 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) = initLoc(result, locNone, e.typ, OnUnknown) expr(p, e, result) -proc lenField: PRope {.inline.} = - result = toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len") +proc lenField(p: BProc): PRope = + result = toRope(if p.module.compileToCpp: "len" else: "Sup.len") include ccgcalls, "ccgstmts.nim", "ccgexprs.nim" @@ -812,7 +815,12 @@ proc genProcAux(m: BModule, prc: PSym) = app(generatedProc, returnStmt) app(generatedProc, ~"}$N") app(m.s[cfsProcs], generatedProc) - + +proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} = + result = sfCompileToCpp in m.module.flags and + sfCompileToCpp notin sym.getModule().flags and + gCmd != cmdCompileToCpp + proc genProcPrototype(m: BModule, sym: PSym) = useHeader(m, sym) if lfNoDecl in sym.loc.flags: return @@ -824,6 +832,8 @@ proc genProcPrototype(m: BModule, sym: PSym) = if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect) elif not containsOrIncl(m.declaredProtos, sym.id): var header = genProcHeader(m, sym) + if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): + header = con("extern \"C\" ", header) if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props: header.app(" __attribute__((naked))") app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header)) @@ -915,30 +925,30 @@ proc addIntTypes(result: var PRope) {.inline.} = appf(result, "#define NIM_INTBITS $1", [ platform.CPU[targetCPU].intSize.toRope]) -proc getCopyright(cfilenoext: string): PRope = +proc getCopyright(cfile: string): PRope = if optCompileOnly in gGlobalOptions: - result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" & + result = ropeff("/* Generated by Nim Compiler v$1 */$N" & "/* (c) 2014 Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N", - "; Generated by Nimrod Compiler v$1$N" & + "; Generated by Nim Compiler v$1$N" & "; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)]) else: - result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" & + result = ropeff("/* Generated by Nim Compiler v$1 */$N" & "/* (c) 2014 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" & + "; Generated by Nim Compiler v$1$N" & "; (c) 2014 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))]) + toRope(getCompileCFileCmd(cfile))]) -proc getFileHeader(cfilenoext: string): PRope = - result = getCopyright(cfilenoext) +proc getFileHeader(cfile: string): PRope = + result = getCopyright(cfile) addIntTypes(result) proc genFilenames(m: BModule): PRope = @@ -1078,9 +1088,9 @@ proc registerModuleToMain(m: PSym) = var init = m.getInitName datInit = m.getDatInitName - appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N", + appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", "declare void $1() noinline$N", [init]) - appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N", + appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", "declare void $1() noinline$N", [datInit]) if sfSystemModule notin m.flags: appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit]) @@ -1092,7 +1102,7 @@ proc registerModuleToMain(m: PSym) = proc genInitCode(m: BModule) = var initname = getInitName(m.module) - var prc = ropeff("N_NOINLINE(void, $1)(void) {$N", + var prc = ropeff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", "define void $1() noinline {$n", [initname]) if m.typeNodes > 0: appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", @@ -1135,7 +1145,7 @@ proc genInitCode(m: BModule) = app(prc, deinitGCFrame(m.initProc)) appf(prc, "}$N$N") - prc.appff("N_NOINLINE(void, $1)(void) {$N", + prc.appff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", "define void $1() noinline {$n", [getDatInitName(m.module)]) for i in cfsTypeInit1..cfsDynLibInit: @@ -1155,8 +1165,8 @@ proc genInitCode(m: BModule) = (i.ord - '0'.ord).toRope, el) app(m.s[cfsInitProc], ex) -proc genModule(m: BModule, cfilenoext: string): PRope = - result = getFileHeader(cfilenoext) +proc genModule(m: BModule, cfile: string): PRope = + result = getFileHeader(cfile) result.app(genMergeInfo(m)) generateHeaders(m) @@ -1297,7 +1307,11 @@ proc writeHeader(m: BModule) = writeRope(result, m.filename) proc getCFile(m: BModule): string = - result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), cExt) + let ext = + if m.compileToCpp: ".cpp" + elif gCmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m" + else: ".c" + result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext) proc myOpenCached(module: PSym, rd: PRodReader): PPassContext = assert optSymbolFiles in gGlobalOptions @@ -1326,10 +1340,10 @@ proc finishModule(m: BModule) = dec(gForwardedProcsCounter, i) setLen(m.forwardedProcs, 0) -proc shouldRecompile(code: PRope, cfile, cfilenoext: string): bool = +proc shouldRecompile(code: PRope, cfile: string): bool = result = true if optForceFullMake notin gGlobalOptions: - var objFile = toObjFile(cfilenoext) + var objFile = toObjFile(cfile) if writeRopeIfNotEqual(code, cfile): return if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false else: @@ -1354,26 +1368,26 @@ proc writeModule(m: BModule, pending: bool) = app(m.s[cfsProcHeaders], mainModProcs) generateThreadVarsSize(m) - var code = genModule(m, cfilenoext) + var code = genModule(m, cfile) when hasTinyCBackend: if gCmd == cmdRun: tccgen.compileCCode(ropeToStr(code)) return - if shouldRecompile(code, cfile, cfilenoext): - addFileToCompile(cfilenoext) + if shouldRecompile(code, cfile): + addFileToCompile(cfile) elif pending and mergeRequired(m) and sfMainModule notin m.module.flags: mergeFiles(cfile, m) genInitCode(m) finishTypeDescriptions(m) - var code = genModule(m, cfilenoext) + var code = genModule(m, cfile) writeRope(code, cfile) - addFileToCompile(cfilenoext) + addFileToCompile(cfile) elif not existsFile(toObjFile(cfilenoext)): # Consider: first compilation compiles ``system.nim`` and produces # ``system.c`` but then compilation fails due to an error. This means # that ``system.o`` is missing, so we need to call the C compiler for it: - addFileToCompile(cfilenoext) + addFileToCompile(cfile) addFileToLink(cfilenoext) @@ -1385,9 +1399,9 @@ proc updateCachedModule(m: BModule) = mergeFiles(cfile, m) genInitCode(m) finishTypeDescriptions(m) - var code = genModule(m, cfilenoext) + var code = genModule(m, cfile) writeRope(code, cfile) - addFileToCompile(cfilenoext) + addFileToCompile(cfile) addFileToLink(cfilenoext) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 12041c55b..508f98074 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -62,7 +62,7 @@ type frameLen*: int16 TCProc{.final.} = object # represents C proc that is currently generated - prc*: PSym # the Nimrod proc that this C proc belongs to + prc*: PSym # the Nim proc that this C proc belongs to beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed threadVarAccessed*: bool # true if the proc already accessed some threadvar nestedTryStmts*: seq[PNode] # in how many nested try statements we are @@ -101,10 +101,10 @@ type # without extension) typeCache*: TIdTable # cache the generated types forwTypeCache*: TIdTable # cache for forward declarations of types - declaredThings*: TIntSet # things we have declared in this .c file - declaredProtos*: TIntSet # prototypes we have declared in this .c file + declaredThings*: IntSet # things we have declared in this .c file + declaredProtos*: IntSet # prototypes we have declared in this .c file headerFiles*: TLinkedList # needed headers to include - typeInfoMarker*: TIntSet # needed for generating type information + typeInfoMarker*: IntSet # needed for generating type information initProc*: BProc # code for init procedure postInitProc*: BProc # code to be executed after the init proc preInitProc*: BProc # code executed before the init proc diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index d881226d4..6c997b983 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -155,7 +155,7 @@ proc relevantCol(methods: TSymSeq, col: int): bool = if not sameType(t2, t): return true -proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int = +proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int = for col in countup(1, sonsLen(a.typ) - 1): if contains(relevantCols, col): var aa = skipTypes(a.typ.sons[col], skipPtrs) @@ -164,7 +164,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int = if (d != high(int)): return d -proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) = +proc sortBucket(a: var TSymSeq, relevantCols: IntSet) = # we use shellsort here; fast and simple var n = len(a) var h = 1 @@ -183,7 +183,7 @@ proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) = a[j] = v if h == 1: break -proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym = +proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym = var base = lastSon(methods[0].ast).sym result = base var paramLen = sonsLen(base.typ) diff --git a/compiler/commands.nim b/compiler/commands.nim index cea965f5c..f26d1d6c7 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -26,7 +26,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none") import os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, - wordrecg, parseutils, babelcmd, idents + wordrecg, parseutils, nimblecmd, idents, parseopt # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") @@ -43,7 +43,7 @@ type TCmdLinePass* = enum passCmd1, # first pass over the command line passCmd2, # second pass over the command line - passPP # preprocessor called ProcessCommand() + passPP # preprocessor called processCommand() proc processCommand*(switch: string, pass: TCmdLinePass) proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) @@ -51,7 +51,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) # implementation const - HelpMessage = "Nimrod Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" & + HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" & "Copyright (c) 2006-2014 by Andreas Rumpf\n" const @@ -234,7 +234,9 @@ proc processPath(path: string, notRelativeToProj = false): string = path else: options.gProjectPath / path - result = unixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath, + result = unixToNativePath(p % ["nimrod", getPrefixDir(), + "nim", getPrefixDir(), + "lib", libpath, "home", removeTrailingDirSep(os.getHomeDir()), "projectname", options.gProjectName, "projectpath", options.gProjectPath]) @@ -280,14 +282,15 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "path", "p": expectArg(switch, arg, pass, info) addPath(processPath(arg), info) - of "babelpath": - if pass in {passCmd2, passPP} and not options.gNoBabelPath: + of "nimblepath", "babelpath": + # keep the old name for compat + if pass in {passCmd2, passPP} and not options.gNoNimblePath: expectArg(switch, arg, pass, info) let path = processPath(arg, notRelativeToProj=true) - babelpath(path, info) - of "nobabelpath": + nimblePath(path, info) + of "nonimblepath", "nobabelpath": expectNoArg(switch, arg, pass, info) - options.gNoBabelPath = true + options.gNoNimblePath = true of "excludepath": expectArg(switch, arg, pass, info) let path = processPath(arg) @@ -307,8 +310,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = expectArg(switch, arg, pass, info) options.docSeeSrcUrl = arg of "mainmodule", "m": - expectArg(switch, arg, pass, info) - optMainModule = arg + discard "allow for backwards compatibility, but don't do anything" of "define", "d": expectArg(switch, arg, pass, info) defineSymbol(arg) @@ -574,3 +576,33 @@ proc processCommand(switch: string, pass: TCmdLinePass) = var cmd, arg: string splitSwitch(switch, cmd, arg, pass, gCmdLineInfo) processSwitch(cmd, arg, pass, gCmdLineInfo) + + +var + arguments* = "" + # the arguments to be passed to the program that + # should be run + +proc processSwitch*(pass: TCmdLinePass; p: OptParser) = + # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") + # we fix this here + var bracketLe = strutils.find(p.key, '[') + if bracketLe >= 0: + var key = substr(p.key, 0, bracketLe - 1) + var val = substr(p.key, bracketLe + 1) & ':' & p.val + processSwitch(key, val, pass, gCmdLineInfo) + else: + processSwitch(p.key, p.val, pass, gCmdLineInfo) + +proc processArgument*(pass: TCmdLinePass; p: OptParser; + argsCount: var int): bool = + if argsCount == 0: + options.command = p.key + else: + if pass == passCmd1: options.commandArgs.add p.key + if argsCount == 1: + # support UNIX style filenames anywhere for portable build scripts: + options.gProjectName = unixToNativePath(p.key) + arguments = cmdLineRest(p) + result = true + inc argsCount diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 6d144ad96..9c07972cf 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -14,7 +14,7 @@ import # We need to use a PStringTable here as defined symbols are always guaranteed # to be style insensitive. Otherwise hell would break lose. -var gSymbols: PStringTable +var gSymbols: StringTableRef proc defineSymbol*(symbol: string) = gSymbols[symbol] = "true" @@ -41,7 +41,7 @@ proc countDefinedSymbols*(): int = for key, val in pairs(gSymbols): if val == "true": inc(result) -# For ease of bootstrapping, we keep there here and not in the global config +# For ease of bootstrapping, we keep them here and not in the global config # file for now: const additionalSymbols = """ @@ -88,6 +88,7 @@ proc initDefines*() = defineSymbol("nimrequiresnimframe") defineSymbol("nimparsebiggestfloatmagic") defineSymbol("nimalias") + defineSymbol("nimlocks") # add platform specific symbols: for c in low(CPU)..high(CPU): diff --git a/compiler/crc.nim b/compiler/crc.nim index ae1df3ff1..a8b61f2a5 100644 --- a/compiler/crc.nim +++ b/compiler/crc.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -102,7 +102,7 @@ proc crcFromFile(filename: string): TCrc32 = const bufSize = 8000 # don't use 8K for the memory allocator! var - bin: TFile + bin: File result = InitCrc32 if not open(bin, filename): return # not equal if file does not exist diff --git a/compiler/depends.nim b/compiler/depends.nim index a43eaf844..115a98f84 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 434e2a65b..8bd0bb490 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -23,7 +23,7 @@ type id: int # for generating IDs toc, section: TSections indexValFilename: string - seenSymbols: PStringTable # avoids duplicate symbol generation for HTML. + seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML. PDoc* = ref TDocumentor ## Alias to type less. @@ -55,7 +55,7 @@ proc parseRst(text, filename: string, result = rstParse(text, filename, line, column, hasToc, rstOptions, docgenFindFile, compilerMsgHandler) -proc newDocumentor*(filename: string, config: PStringTable): PDoc = +proc newDocumentor*(filename: string, config: StringTableRef): PDoc = new(result) initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex), options.gConfigVars, filename, {roSupportRawDirective}, @@ -374,11 +374,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = cleanPlainSymbol = renderPlainSymbolName(nameNode) complexSymbol = complexName(k, n, cleanPlainSymbol) plainSymbolRope = toRope(cleanPlainSymbol) - plainSymbolEncRope = toRope(URLEncode(cleanPlainSymbol)) + plainSymbolEncRope = toRope(encodeUrl(cleanPlainSymbol)) itemIDRope = toRope(d.id) symbolOrId = d.newUniquePlainSymbol(complexSymbol) symbolOrIdRope = symbolOrId.toRope - symbolOrIdEncRope = URLEncode(symbolOrId).toRope + symbolOrIdEncRope = encodeUrl(symbolOrId).toRope var seeSrcRope: PRope = nil let docItemSeeSrc = getConfigVar("doc.item.seesrc") @@ -413,7 +413,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = setIndexTerm(d[], symbolOrId, name, linkTitle, xmltree.escape(plainDocstring.docstringSummary)) -proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode = +proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = if not isVisible(nameNode): return var name = getName(d, nameNode) @@ -473,7 +473,7 @@ proc generateDoc*(d: PDoc, n: PNode) = of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0]) else: discard -proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode = +proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode = case n.kind of nkCommentStmt: if n.comment != nil and startsWith(n.comment, "##"): diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index d76be8e3c..aa832b6df 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -26,7 +26,7 @@ proc close(p: PPassContext, n: PNode): PNode = writeOutput(g.doc, g.module.filename, HtmlExt, useWarning) try: generateIndex(g.doc) - except EIO: + except IOError: discard proc processNode(c: PPassContext, n: PNode): PNode = diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index f798a43ac..d6b3a1aa5 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This file implements the FFI part of the evaluator for Nimrod code. +## This file implements the FFI part of the evaluator for Nim code. import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 78cdbb45f..78cc691c0 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index f0e5dad11..ad9c38904 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -1,14 +1,16 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# module for calling the different external C compilers -# some things are read in from the configuration file +# Module providing functions for calling the different external C compilers +# Uses some hard-wired facts about each C/C++ compiler, plus options read +# from a configuration file, to provide generalized procedures to compile +# nim files. import lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc @@ -59,6 +61,7 @@ type template compiler(name: expr, settings: stmt): stmt {.immediate.} = proc name: TInfoCC {.compileTime.} = settings +# GNU C and C++ Compiler compiler gcc: result = ( name: "gcc", @@ -84,21 +87,24 @@ compiler gcc: props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, hasNakedAttribute}) +# LLVM Frontend for GCC/G++ compiler llvmGcc: - result = gcc() - + result = gcc() # Uses settings from GCC + result.name = "llvm_gcc" result.compilerExe = "llvm-gcc" result.cppCompiler = "llvm-g++" result.buildLib = "llvm-ar rcs $libfile $objfiles" +# Clang (LLVM) C/C++ Compiler compiler clang: - result = llvmGcc() + result = llvmGcc() # Uses settings from llvmGcc result.name = "clang" result.compilerExe = "clang" result.cppCompiler = "clang++" +# Microsoft Visual C/C++ Compiler compiler vcc: result = ( name: "vcc", @@ -123,6 +129,7 @@ compiler vcc: packedPragma: "#pragma pack(1)", props: {hasCpp, hasAssume, hasNakedDeclspec}) +# Intel C/C++ Compiler compiler icl: # Intel compilers try to imitate the native ones (gcc and msvc) when defined(windows): @@ -134,6 +141,7 @@ compiler icl: result.compilerExe = "icl" result.linkerExe = "icl" +# Local C Compiler compiler lcc: result = ( name: "lcc", @@ -158,6 +166,7 @@ compiler lcc: packedPragma: "", # XXX: not supported yet props: {}) +# Borland C Compiler compiler bcc: result = ( name: "bcc", @@ -182,6 +191,7 @@ compiler bcc: packedPragma: "", # XXX: not supported yet props: {hasCpp}) +# Digital Mars C Compiler compiler dmc: result = ( name: "dmc", @@ -206,6 +216,7 @@ compiler dmc: packedPragma: "#pragma pack(1)", props: {hasCpp}) +# Watcom C Compiler compiler wcc: result = ( name: "wcc", @@ -230,6 +241,7 @@ compiler wcc: packedPragma: "", # XXX: not supported yet props: {hasCpp}) +# Tiny C Compiler compiler tcc: result = ( name: "tcc", @@ -254,6 +266,7 @@ compiler tcc: packedPragma: "", # XXX: not supported yet props: {hasSwitchRange, hasComputedGoto}) +# Pelles C Compiler compiler pcc: # Pelles C result = ( @@ -279,6 +292,7 @@ compiler pcc: packedPragma: "", # XXX: not supported yet props: {}) +# Your C Compiler compiler ucc: result = ( name: "ucc", @@ -323,10 +337,7 @@ const var cCompiler* = ccGcc # the used compiler - - cExt* = ".c" # extension of generated C/C++ files - # (can be changed to .cpp later) - + gMixedMode*: bool # true if some module triggered C++ codegen cIncludes*: seq[string] = @[] # directories to search for included files cLibs*: seq[string] = @[] # directories to search for lib files cLinkedLibs*: seq[string] = @[] # libraries to link @@ -342,7 +353,9 @@ var compileOptions: string = "" ccompilerpath: string = "" -proc nameToCC*(name: string): TSystemCC = +proc nameToCC*(name: string): TSystemCC = + ## Returns the kind of compiler referred to by `name`, or ccNone + ## if the name doesn't refer to any known compiler. for i in countup(succ(ccNone), high(TSystemCC)): if cmpIgnoreStyle(name, CC[i].name) == 0: return i @@ -351,17 +364,18 @@ proc nameToCC*(name: string): TSystemCC = proc getConfigVar(c: TSystemCC, suffix: string): string = # use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given # for niminst support + let fullSuffix = (if gCmd == cmdCompileToCpp: ".cpp" & suffix else: suffix) if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and optCompileOnly notin gGlobalOptions: let fullCCname = platform.CPU[targetCPU].name & '.' & platform.OS[targetOS].name & '.' & - CC[c].name & suffix + CC[c].name & fullSuffix result = getConfigVar(fullCCname) if result.len == 0: # not overriden for this cross compilation setting? - result = getConfigVar(CC[c].name & suffix) + result = getConfigVar(CC[c].name & fullSuffix) else: - result = getConfigVar(CC[c].name & suffix) + result = getConfigVar(CC[c].name & fullSuffix) proc setCC*(ccname: string) = cCompiler = nameToCC(ccname) @@ -387,8 +401,6 @@ proc initVars*() = # we need to define the symbol here, because ``CC`` may have never been set! for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name) defineSymbol(CC[cCompiler].name) - if gCmd == cmdCompileToCpp: cExt = ".cpp" - elif gCmd == cmdCompileToOC: cExt = ".m" addCompileOption(getConfigVar(cCompiler, ".options.always")) addLinkOption(getConfigVar(cCompiler, ".options.linker")) if len(ccompilerpath) == 0: @@ -397,9 +409,9 @@ proc initVars*() = proc completeCFilePath*(cfile: string, createSubDir: bool = true): string = result = completeGeneratedFilePath(cfile, createSubDir) -proc toObjFile*(filenameWithoutExt: string): string = +proc toObjFile*(filename: string): string = # Object file for compilation - result = changeFileExt(filenameWithoutExt, CC[cCompiler].objExt) + result = changeFileExt(filename, CC[cCompiler].objExt) proc addFileToCompile*(filename: string) = appendStr(toCompile, filename) @@ -417,8 +429,12 @@ proc addFileToLink*(filename: string) = prependStr(toLink, filename) # BUGFIX: was ``appendStr`` -proc execExternalProgram*(cmd: string) = - if optListCmd in gGlobalOptions or gVerbosity > 0: msgWriteln(cmd) +proc execExternalProgram*(cmd: string, prettyCmd = "") = + if optListCmd in gGlobalOptions or gVerbosity > 0: + if prettyCmd != "": + msgWriteln(prettyCmd) + else: + msgWriteln(cmd) if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "") proc generateScript(projectFile: string, script: PRope) = @@ -487,7 +503,7 @@ proc getLinkOptions: string = proc needsExeExt(): bool {.inline.} = result = (optGenScript in gGlobalOptions and targetOS == osWindows) or - (platform.hostOS == osWindows) + (platform.hostOS == osWindows) proc getCompilerExe(compiler: TSystemCC): string = result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler @@ -497,6 +513,7 @@ proc getCompilerExe(compiler: TSystemCC): string = proc getLinkerExe(compiler: TSystemCC): string = result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe + elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler else: compiler.getCompilerExe proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = @@ -507,11 +524,11 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = if needsExeExt(): exe = addFileExt(exe, "exe") if optGenDynLib in gGlobalOptions and - ospNeedsPIC in platform.OS[targetOS].props: + ospNeedsPIC in platform.OS[targetOS].props: add(options, ' ' & CC[c].pic) var includeCmd, compilePattern: string - if not noAbsolutePaths(): + if not noAbsolutePaths(): # compute include paths: includeCmd = CC[c].includeCmd & quoteShell(libpath) @@ -519,29 +536,31 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = includeCmd.add([CC[c].includeCmd, includeDir.quoteShell]) compilePattern = joinPath(ccompilerpath, exe) - else: + else: includeCmd = "" compilePattern = c.getCompilerExe - var cfile = if noAbsolutePaths(): extractFilename(cfilename) + var cfile = if noAbsolutePaths(): extractFilename(cfilename) else: cfilename - var objfile = if not isExternal or noAbsolutePaths(): - toObjFile(cfile) - else: + var objfile = if not isExternal or noAbsolutePaths(): + toObjFile(cfile) + else: completeCFilePath(toObjFile(cfile)) - cfile = quoteShell(addFileExt(cfile, cExt)) objfile = quoteShell(objfile) result = quoteShell(compilePattern % [ - "file", cfile, "objfile", objfile, "options", options, - "include", includeCmd, "nimrod", getPrefixDir(), "lib", libpath]) + "file", cfile, "objfile", objfile, "options", options, + "include", includeCmd, "nimrod", getPrefixDir(), + "nim", getPrefixDir(), "lib", libpath]) add(result, ' ') addf(result, CC[c].compileTmpl, [ - "file", cfile, "objfile", objfile, - "options", options, "include", includeCmd, - "nimrod", quoteShell(getPrefixDir()), + "file", cfile, "objfile", objfile, + "options", options, "include", includeCmd, + "nimrod", quoteShell(getPrefixDir()), + "nim", quoteShell(getPrefixDir()), "lib", quoteShell(libpath)]) proc footprint(filename: string): TCrc32 = + # note, '><' further modifies a crc value with a string. result = crcFromFile(filename) >< platform.OS[targetOS].name >< platform.CPU[targetCPU].name >< @@ -551,7 +570,7 @@ proc footprint(filename: string): TCrc32 = proc externalFileChanged(filename: string): bool = var crcFile = toGeneratedFile(filename.withPackageName, "crc") var currentCrc = int(footprint(filename)) - var f: TFile + var f: File if open(f, crcFile, fmRead): var line = newStringOfCap(40) if not f.readLine(line): line = "0" @@ -569,14 +588,16 @@ proc addExternalFileToCompile*(filename: string) = if optForceFullMake in gGlobalOptions or externalFileChanged(filename): appendStr(externalToCompile, filename) -proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq, - isExternal: bool) = +proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq, + prettyCmds: var TStringSeq, isExternal: bool) = var it = PStrEntry(list.head) while it != nil: inc(fileCounter) # call the C compiler for the .c file: var compileCmd = getCompileCFileCmd(it.data, isExternal) if optCompileOnly notin gGlobalOptions: add(cmds, compileCmd) + let (dir, name, ext) = splitFile(it.data) + add(prettyCmds, "CC: " & name) if optGenScript in gGlobalOptions: app(script, compileCmd) app(script, tnl) @@ -592,18 +613,24 @@ proc callCCompiler*(projectfile: string) = var c = cCompiler var script: PRope = nil var cmds: TStringSeq = @[] - compileCFile(toCompile, script, cmds, false) - compileCFile(externalToCompile, script, cmds, true) + var prettyCmds: TStringSeq = @[] + let prettyCb = proc (idx: int) = + echo prettyCmds[idx] + compileCFile(toCompile, script, cmds, prettyCmds, false) + compileCFile(externalToCompile, script, cmds, prettyCmds, true) if optCompileOnly notin gGlobalOptions: if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors() var res = 0 if gNumberOfProcessors <= 1: for i in countup(0, high(cmds)): res = max(execCmd(cmds[i]), res) - elif optListCmd in gGlobalOptions or gVerbosity > 0: - res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams}, + elif optListCmd in gGlobalOptions or gVerbosity > 1: + res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams}, gNumberOfProcessors) - else: - res = execProcesses(cmds, {poUseShell, poParentStreams}, + elif gVerbosity == 1: + res = execProcesses(cmds, {poUseShell, poParentStreams}, + gNumberOfProcessors, prettyCb) + else: + res = execProcesses(cmds, {poUseShell, poParentStreams}, gNumberOfProcessors) if res != 0: if gNumberOfProcessors <= 1: @@ -625,7 +652,6 @@ proc callCCompiler*(projectfile: string) = if optGenStaticLib in gGlobalOptions: linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName), "objfiles", objfiles] - if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd) else: var linkerExe = getConfigVar(c, ".linkerexe") if len(linkerExe) == 0: linkerExe = c.getLinkerExe @@ -657,7 +683,11 @@ proc callCCompiler*(projectfile: string) = "objfiles", objfiles, "exefile", exefile, "nimrod", quoteShell(getPrefixDir()), "lib", quoteShell(libpath)]) - if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd) + if optCompileOnly notin gGlobalOptions: + if gVerbosity == 1: + execExternalProgram(linkCmd, "[Linking]") + else: + execExternalProgram(linkCmd) else: linkCmd = "" if optGenScript in gGlobalOptions: @@ -668,7 +698,7 @@ proc callCCompiler*(projectfile: string) = proc genMappingFiles(list: TLinkedList): PRope = var it = PStrEntry(list.head) while it != nil: - appf(result, "--file:r\"$1\"$N", [toRope(addFileExt(it.data, cExt))]) + appf(result, "--file:r\"$1\"$N", [toRope(it.data)]) it = PStrEntry(it.next) proc writeMapping*(gSymbolMapping: PRope) = diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index 0014e9c78..7b975dbaa 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# This module implements Nimrod's standard template filter. +# This module implements Nim's standard template filter. import llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, @@ -148,7 +148,7 @@ proc parseLine(p: var TTmplParser) = inc(j) else: if p.x[j] == p.subsChar: - # parse Nimrod expression: + # parse Nim expression: inc(j) case p.x[j] of '{': diff --git a/compiler/filters.nim b/compiler/filters.nim index ce0ffd196..783a320a4 100644 --- a/compiler/filters.nim +++ b/compiler/filters.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# This module implements Nimrod's simple filters and helpers for filters. +# This module implements Nim's simple filters and helpers for filters. import llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, diff --git a/compiler/guards.nim b/compiler/guards.nim index 431de6156..cd0aaf296 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -838,6 +838,22 @@ proc addAsgnFact*(m: var TModel, key, value: PNode) = fact.sons[2] = value m.add fact +proc sameSubexprs*(m: TModel; a, b: PNode): bool = + # This should be used to check whether two *path expressions* refer to the + # same memory location according to 'm'. This is tricky: + # lock a[i].guard: + # ... + # access a[i].guarded + # + # Here a[i] is the same as a[i] iff 'i' and 'a' are not changed via '...'. + # However, nil checking requires exactly the same mechanism! But for now + # we simply use sameTree and live with the unsoundness of the analysis. + var check = newNodeI(nkCall, a.info, 3) + check.sons[0] = newSymNode(opEq) + check.sons[1] = a + check.sons[2] = b + result = m.doesImply(check) == impYes + proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) = let branch = n.sons[i] if branch.kind == nkOfBranch: diff --git a/compiler/hlo.nim b/compiler/hlo.nim index c75d6519f..363d100be 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/idents.nim b/compiler/idents.nim index ec903826a..775bffa00 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -15,7 +15,7 @@ import hashes, strutils type - TIdObj* = object of TObject + TIdObj* = object of RootObj id*: int # unique id; use this for comparisons and not the pointers PIdObj* = ref TIdObj diff --git a/compiler/idgen.nim b/compiler/idgen.nim index d932e3d9d..3c5669b54 100644 --- a/compiler/idgen.nim +++ b/compiler/idgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -53,7 +53,7 @@ proc saveMaxIds*(project: string) = f.close() proc loadMaxIds*(project: string) = - var f: TFile + var f: File if open(f, project.toGid, fmRead): var line = newStringOfCap(20) if f.readLine(line): diff --git a/compiler/importer.nim b/compiler/importer.nim index 33ed7e055..fbf3be4f2 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -113,7 +113,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = e = nextIdentIter(it, fromMod.tab) else: rawImportSymbol(c, s) -proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) = +proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) = var i: TTabIter var s = initTabIter(i, fromMod.tab) while s != nil: @@ -126,10 +126,10 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) = s = nextIter(i, fromMod.tab) proc importAllSymbols*(c: PContext, fromMod: PSym) = - var exceptSet: TIntSet + var exceptSet: IntSet importAllSymbolsExcept(c, fromMod, exceptSet) -proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) = +proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) = if n.isNil: return case n.kind of nkExportStmt: @@ -166,7 +166,7 @@ proc myImportModule(c: PContext, n: PNode): PSym = proc evalImport(c: PContext, n: PNode): PNode = result = n - var emptySet: TIntSet + var emptySet: IntSet for i in countup(0, sonsLen(n) - 1): var m = myImportModule(c, n.sons[i]) if m != nil: diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index dfe498e47..4772aecb5 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -71,8 +71,8 @@ type TGlobals = object typeInfo, code: PRope forwarded: seq[PSym] - generatedSyms: TIntSet - typeInfoGenerated: TIntSet + generatedSyms: IntSet + typeInfoGenerated: IntSet PGlobals = ref TGlobals PProc = ref TProc @@ -724,7 +724,7 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) = if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock") var sym = n.sons[0].sym sym.loc.k = locOther - sym.loc.a = idx + sym.position = idx+1 setLen(p.blocks, idx + 1) p.blocks[idx].id = - p.unique # negative because it isn't used yet let labl = p.unique @@ -741,7 +741,7 @@ proc genBreakStmt(p: PProc, n: PNode) = assert(n.sons[0].kind == nkSym) let sym = n.sons[0].sym assert(sym.loc.k == locOther) - idx = sym.loc.a + idx = sym.position-1 else: # an unnamed 'break' can only break a loop after 'transf' pass: idx = len(p.blocks) - 1 @@ -1654,6 +1654,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = r.res = nil of nkGotoState, nkState: internalError(n.info, "first class iterators not implemented") + of nkPragmaBlock: gen(p, n.lastSon, r) else: internalError(n.info, "gen: unknown node type: " & $n.kind) var globals: PGlobals @@ -1664,7 +1665,7 @@ proc newModule(module: PSym): BModule = if globals == nil: globals = newGlobals() proc genHeader(): PRope = - result = ropef("/* Generated by the Nimrod Compiler v$1 */$n" & + result = ropef("/* Generated by the Nim Compiler v$1 */$n" & "/* (c) 2014 Andreas Rumpf */$n$n" & "$nvar Globals = this;$n" & "var framePtr = null;$n" & diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index 009fc7935..8b032c3ce 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 62e13b9c4..194396ddd 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -128,7 +128,7 @@ type obj: PType PEnv = ref TEnv - TEnv {.final.} = object of TObject + TEnv {.final.} = object of RootObj attachedNode, replacementNode: PNode createdVar: PNode # if != nil it is a used environment; for closure # iterators this can be 'envParam.env' @@ -140,12 +140,12 @@ type fn: PSym # function that belongs to this scope; # if up.fn != fn then we cross function boundaries. # This is an important case to consider. - vars: TIntSet # variables belonging to this environment + vars: IntSet # variables belonging to this environment TOuterContext = object fn: PSym # may also be a module! head: PEnv - capturedVars, processed: TIntSet + capturedVars, processed: IntSet localsToAccess: TIdNodeTable lambdasToEnv: TIdTable # PSym->PEnv mapping diff --git a/compiler/lexer.nim b/compiler/lexer.nim index ea51a1399..cbc87972d 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -21,10 +21,10 @@ import const MaxLineLength* = 80 # lines longer than this lead to a warning - numChars*: TCharSet = {'0'..'9', 'a'..'z', 'A'..'Z'} - SymChars*: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'} - SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} - OpChars*: TCharSet = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', + numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'} + SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'} + SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} + OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', '|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'} # don't forget to update the 'highlite' module if these charsets should change @@ -102,7 +102,7 @@ type # so that it is the correct default value base2, base8, base16 - TToken* = object # a Nimrod token + TToken* = object # a Nim token tokType*: TTokType # the type of the token indent*: int # the indentation; != -1 if the token has been # preceeded with indentation @@ -148,7 +148,7 @@ proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") proc isKeyword(kind: TTokType): bool = result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh) -proc isNimrodIdentifier*(s: string): bool = +proc isNimIdentifier*(s: string): bool = if s[0] in SymStartChars: var i = 1 while i < s.len: @@ -229,7 +229,7 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") = var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart) msgs.message(info, msg, arg) -proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) = +proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) = var pos = L.bufpos # use registers for pos, buf var buf = L.buf while true: @@ -246,7 +246,7 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) = inc(pos) L.bufpos = pos -proc matchTwoChars(L: TLexer, first: char, second: TCharSet): bool = +proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool = result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second) proc isFloatLiteral(s: string): bool = @@ -429,9 +429,9 @@ proc getNumber(L: var TLexer): TToken = elif result.tokType == tkInt16Lit and (result.iNumber < int16.low or result.iNumber > int16.high): lexMessage(L, errNumberOutOfRange, result.literal) - except EInvalidValue: + except ValueError: lexMessage(L, errInvalidNumber, result.literal) - except EOverflow, EOutOfRange: + except OverflowError, RangeError: lexMessage(L, errNumberOutOfRange, result.literal) L.bufpos = endpos @@ -482,7 +482,7 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) = add(tok.literal, VT) inc(L.bufpos) of 't', 'T': - add(tok.literal, Tabulator) + add(tok.literal, '\t') inc(L.bufpos) of '\'', '\"': add(tok.literal, L.buf[L.bufpos]) @@ -519,7 +519,7 @@ proc handleCRLF(L: var TLexer, pos: int): int = lexMessagePos(L, hintLineTooLong, pos) if optEmbedOrigSrc in gGlobalOptions: - let lineStart = cast[TAddress](L.buf) + L.lineStart + let lineStart = cast[ByteAddress](L.buf) + L.lineStart let line = newString(cast[cstring](lineStart), col) addSourceLine(L.fileIdx, line) @@ -659,28 +659,32 @@ proc getOperator(L: var TLexer, tok: var TToken) = if buf[pos] in {CR, LF, nimlexbase.EndOfFile}: tok.strongSpaceB = -1 -proc scanComment(L: var TLexer, tok: var TToken) = +proc scanComment(L: var TLexer, tok: var TToken) = var pos = L.bufpos - var buf = L.buf - # a comment ends if the next line does not start with the # on the same - # column after only whitespace + var buf = L.buf + when not defined(nimfix): + assert buf[pos+1] == '#' + if buf[pos+2] == '[': + lexMessagePos(L, warnDeprecated, pos, "use '## [' instead; '##['") tok.tokType = tkComment # iNumber contains the number of '\n' in the token tok.iNumber = 0 - var col = getColNumber(L, pos) + when defined(nimfix): + var col = getColNumber(L, pos) while true: var lastBackslash = -1 while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: if buf[pos] == '\\': lastBackslash = pos+1 add(tok.literal, buf[pos]) inc(pos) - if lastBackslash > 0: - # a backslash is a continuation character if only followed by spaces - # plus a newline: - while buf[lastBackslash] == ' ': inc(lastBackslash) - if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}: - # false positive: - lastBackslash = -1 + when defined(nimfix): + if lastBackslash > 0: + # a backslash is a continuation character if only followed by spaces + # plus a newline: + while buf[lastBackslash] == ' ': inc(lastBackslash) + if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}: + # false positive: + lastBackslash = -1 pos = handleCRLF(L, pos) buf = L.buf @@ -688,9 +692,16 @@ proc scanComment(L: var TLexer, tok: var TToken) = while buf[pos] == ' ': inc(pos) inc(indent) - if buf[pos] == '#' and (col == indent or lastBackslash > 0): + + when defined(nimfix): + template doContinue(): expr = + buf[pos] == '#' and (col == indent or lastBackslash > 0) + else: + template doContinue(): expr = + buf[pos] == '#' and buf[pos+1] == '#' + if doContinue(): tok.literal.add "\n" - col = indent + when defined(nimfix): col = indent inc tok.iNumber else: if buf[pos] > ' ': @@ -707,7 +718,7 @@ proc skip(L: var TLexer, tok: var TToken) = of ' ': inc(pos) inc(tok.strongSpaceA) - of Tabulator: + of '\t': lexMessagePos(L, errTabulatorsAreNotAllowed, pos) inc(pos) of CR, LF: @@ -718,10 +729,24 @@ proc skip(L: var TLexer, tok: var TToken) = inc(pos) inc(indent) tok.strongSpaceA = 0 - if buf[pos] > ' ': + when defined(nimfix): + template doBreak(): expr = buf[pos] > ' ' + else: + template doBreak(): expr = + buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#') + if doBreak(): tok.indent = indent L.currLineIndent = indent break + of '#': + when defined(nimfix): + break + else: + # do not skip documentation comment: + if buf[pos+1] == '#': break + if buf[pos+1] == '[': + lexMessagePos(L, warnDeprecated, pos, "use '# [' instead; '#['") + while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos) else: break # EndOfFile also leaves the loop L.bufpos = pos diff --git a/compiler/lists.nim b/compiler/lists.nim index efffe60fe..1b2b91bff 100644 --- a/compiler/lists.nim +++ b/compiler/lists.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,7 +12,7 @@ import os type PListEntry* = ref TListEntry - TListEntry* = object of TObject + TListEntry* = object of RootObj prev*, next*: PListEntry TStrEntry* = object of TListEntry diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 5aefd468a..be469548d 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -21,9 +21,9 @@ type llsString, # stream encapsulates a string llsFile, # stream encapsulates a file llsStdIn # stream encapsulates stdin - TLLStream* = object of TObject + TLLStream* = object of RootObj kind*: TLLStreamKind # accessible for low-level access (lexbase uses this) - f*: TFile + f*: File s*: string rd*, wr*: int # for string streams lineOffset*: int # for fake stdin line numbers @@ -31,8 +31,8 @@ type PLLStream* = ref TLLStream proc llStreamOpen*(data: string): PLLStream -proc llStreamOpen*(f: var TFile): PLLStream -proc llStreamOpen*(filename: string, mode: TFileMode): PLLStream +proc llStreamOpen*(f: var File): PLLStream +proc llStreamOpen*(filename: string, mode: FileMode): PLLStream proc llStreamOpen*(): PLLStream proc llStreamOpenStdIn*(): PLLStream proc llStreamClose*(s: PLLStream) @@ -50,12 +50,12 @@ proc llStreamOpen(data: string): PLLStream = result.s = data result.kind = llsString -proc llStreamOpen(f: var TFile): PLLStream = +proc llStreamOpen(f: var File): PLLStream = new(result) result.f = f result.kind = llsFile -proc llStreamOpen(filename: string, mode: TFileMode): PLLStream = +proc llStreamOpen(filename: string, mode: FileMode): PLLStream = new(result) result.kind = llsFile if not open(result.f, filename, mode): result = nil diff --git a/compiler/lookups.nim b/compiler/lookups.nim index d486585ef..fa1837296 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -114,7 +114,7 @@ type mode*: TOverloadIterMode symChoiceIndex*: int scope*: PScope - inSymChoice: TIntSet + inSymChoice: IntSet proc getSymRepr*(s: PSym): string = case s.kind diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index e1fb09e44..8e5ffd48a 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -261,7 +261,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner, barrier.typ, barrier) body.add varSection2 - body.add callCodeGenProc("barrierEnter", threadLocalBarrier.newSymNode) + body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode) var threadLocalProm: PSym if spawnKind == srByVar: threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv) @@ -276,7 +276,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, "owner", fv.info), threadParam.newSymNode) - body.add callCodeGenProc("nimArgsPassingDone", threadParam.newSymNode) + body.add callCodegenProc("nimArgsPassingDone", threadParam.newSymNode) if spawnKind == srByVar: body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call) elif fv != nil: @@ -289,11 +289,11 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; if barrier == nil: # by now 'fv' is shared and thus might have beeen overwritten! we need # to use the thread-local view instead: - body.add callCodeGenProc("nimFlowVarSignal", threadLocalProm.newSymNode) + body.add callCodegenProc("nimFlowVarSignal", threadLocalProm.newSymNode) else: body.add call if barrier != nil: - body.add callCodeGenProc("barrierLeave", threadLocalBarrier.newSymNode) + body.add callCodegenProc("barrierLeave", threadLocalBarrier.newSymNode) var params = newNodeI(nkFormalParams, f.info) params.add emptyNode @@ -543,7 +543,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; # create flowVar: result.add newFastAsgnStmt(fvField, callProc(spawnExpr[2])) if barrier == nil: - result.add callCodeGenProc("nimFlowVarCreateCondVar", fvField) + result.add callCodegenProc("nimFlowVarCreateCondVar", fvField) elif spawnKind == srByVar: var field = newSym(skField, getIdent"fv", owner, n.info) @@ -556,7 +556,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; let wrapper = createWrapperProc(fn, threadParam, argsParam, varSection, varInit, call, barrierAsExpr, fvAsExpr, spawnKind) - result.add callCodeGenProc("nimSpawn", wrapper.newSymNode, + result.add callCodegenProc("nimSpawn", wrapper.newSymNode, genAddrOf(scratchObj.newSymNode)) if spawnKind == srFlowVar: result.add fvField diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 475326161..6d4c65268 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -35,7 +35,7 @@ proc registerSysType(t: PType) = proc newSysType(kind: TTypeKind, size: int): PType = result = newType(kind, systemModule) result.size = size - result.align = size + result.align = size.int16 proc getSysSym(name: string): PSym = result = strTableGet(systemModule.tab, getIdent(name)) @@ -44,6 +44,7 @@ proc getSysSym(name: string): PSym = result = newSym(skError, getIdent(name), systemModule, systemModule.info) result.typ = newType(tyError, systemModule) if result.kind == skStub: loadStub(result) + if result.kind == skAlias: result = result.owner proc getSysMagic*(name: string, m: TMagic): PSym = var ti: TIdentIter @@ -165,13 +166,14 @@ proc setIntLitType*(result: PNode) = proc getCompilerProc(name: string): PSym = var ident = getIdent(name, hashIgnoreStyle(name)) result = strTableGet(compilerprocs, ident) - if result == nil: + if result == nil: result = strTableGet(rodCompilerprocs, ident) - if result != nil: + if result != nil: strTableAdd(compilerprocs, result) if result.kind == skStub: loadStub(result) - -proc registerCompilerProc(s: PSym) = + if result.kind == skAlias: result = result.owner + +proc registerCompilerProc(s: PSym) = strTableAdd(compilerprocs, s) proc finishSystem(tab: TStrTable) = discard diff --git a/compiler/main.nim b/compiler/main.nim index b4af49248..82e55058c 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -15,8 +15,7 @@ import wordrecg, sem, semdata, idents, passes, docgen, extccomp, cgen, jsgen, json, nversion, platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, - tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists, - pretty + tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists from magicsys import systemModule, resetSysTypes @@ -164,19 +163,6 @@ proc commandEval(exp: string) = var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" evalNim(echoExp.parseString, makeStdinModule()) -proc commandPrettyOld = - var projectFile = addFileExt(mainCommandArg(), NimExt) - var module = parseFile(projectFile.fileInfoIdx) - if module != nil: - renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt)) - -proc commandPretty = - msgs.gErrorMax = high(int) # do not stop after first error - semanticPasses() - registerPass(prettyPass) - compileProject() - pretty.overwriteFiles() - proc commandScan = var f = addFileExt(mainCommandArg(), NimExt) var stream = llStreamOpen(f, fmRead) @@ -217,25 +203,6 @@ proc commandSuggest = else: gProjectMainIdx compileProject(projFile) -proc wantMainModule = - if gProjectFull.len == 0: - if optMainModule.len == 0: - fatal(gCmdLineInfo, errCommandExpectsFilename) - else: - gProjectName = optMainModule - gProjectFull = gProjectPath / gProjectName - - gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx - -proc requireMainModuleOption = - if optMainModule.len == 0: - fatal(gCmdLineInfo, errMainModuleMustBeSpecified) - else: - gProjectName = optMainModule - gProjectFull = gProjectPath / gProjectName - - gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx - proc resetMemory = resetCompilationLists() ccgutils.resetCaches() @@ -299,30 +266,22 @@ proc mainCommand* = # current path is always looked first for modules prependStr(searchPaths, gProjectPath) setId(100) - passes.gIncludeFile = includeModule - passes.gImportModule = importModule case command.normalize of "c", "cc", "compile", "compiletoc": # compile means compileToC currently gCmd = cmdCompileToC - wantMainModule() commandCompileToC() of "cpp", "compiletocpp": - extccomp.cExt = ".cpp" gCmd = cmdCompileToCpp if cCompiler == ccGcc: setCC("gcc") - wantMainModule() defineSymbol("cpp") commandCompileToC() of "objc", "compiletooc": - extccomp.cExt = ".m" gCmd = cmdCompileToOC - wantMainModule() defineSymbol("objc") commandCompileToC() of "run": gCmd = cmdRun - wantMainModule() when hasTinyCBackend: extccomp.setCC("tcc") commandCompileToC() @@ -330,41 +289,33 @@ proc mainCommand* = rawMessage(errInvalidCommandX, command) of "js", "compiletojs": gCmd = cmdCompileToJS - wantMainModule() commandCompileToJS() of "compiletollvm": gCmd = cmdCompileToLLVM - wantMainModule() when hasLLVM_Backend: CommandCompileToLLVM() else: rawMessage(errInvalidCommandX, command) - of "pretty": - gCmd = cmdPretty - wantMainModule() - commandPretty() of "doc": + wantMainModule() gCmd = cmdDoc loadConfigs(DocConfig) - wantMainModule() commandDoc() of "doc2": gCmd = cmdDoc loadConfigs(DocConfig) - wantMainModule() defineSymbol("nimdoc") commandDoc2() of "rst2html": gCmd = cmdRst2html loadConfigs(DocConfig) - wantMainModule() commandRst2Html() of "rst2tex": gCmd = cmdRst2tex loadConfigs(DocTexConfig) - wantMainModule() commandRst2TeX() of "jsondoc": + wantMainModule() gCmd = cmdDoc loadConfigs(DocConfig) wantMainModule() @@ -376,12 +327,11 @@ proc mainCommand* = commandBuildIndex() of "gendepend": gCmd = cmdGenDepend - wantMainModule() commandGenDepend() of "dump": gCmd = cmdDump if getConfigVar("dump.format") == "json": - requireMainModuleOption() + wantMainModule() var definedSymbols = newJArray() for s in definedSymbolNames(): definedSymbols.elems.add(%s) @@ -405,7 +355,6 @@ proc mainCommand* = for it in iterSearchPath(searchPaths): msgWriteln(it) of "check": gCmd = cmdCheck - wantMainModule() commandCheck() of "parse": gCmd = cmdParse @@ -429,7 +378,6 @@ proc mainCommand* = if gEvalExpr != "": commandEval(gEvalExpr) else: - wantMainModule() commandSuggest() of "serve": isServing = true diff --git a/compiler/modules.nim b/compiler/modules.nim index b102224cd..05b795473 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -117,7 +117,7 @@ proc newModule(fileIdx: int32): PSym = result.kind = skModule let filename = fileIdx.toFullPath result.name = getIdent(splitFile(filename).name) - if not isNimrodIdentifier(result.name.s): + if not isNimIdentifier(result.name.s): rawMessage(errInvalidModuleName, result.name.s) result.info = newLineInfo(fileIdx, 1, 1) @@ -177,7 +177,7 @@ proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} = proc `==^`(a, b: string): bool = try: result = sameFile(a, b) - except EOS: + except OSError: result = false proc compileSystemModule* = @@ -185,8 +185,18 @@ proc compileSystemModule* = systemFileIdx = fileInfoIdx(options.libpath/"system.nim") discard compileModule(systemFileIdx, {sfSystemModule}) -proc compileProject*(projectFile = gProjectMainIdx) = +proc wantMainModule* = + if gProjectFull.len == 0: + fatal(gCmdLineInfo, errCommandExpectsFilename) + gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx + +passes.gIncludeFile = includeModule +passes.gImportModule = importModule + +proc compileProject*(projectFileIdx = -1'i32) = + wantMainModule() let systemFileIdx = fileInfoIdx(options.libpath / "system.nim") + let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx if projectFile == systemFileIdx: discard compileModule(projectFile, {sfMainModule, sfSystemModule}) else: diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 730cb9605..51d2836f8 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -119,12 +119,12 @@ type warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode, warnEachIdentIsTuple, warnShadowIdent, warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, - warnUninit, warnGcMem, warnUser, + warnUninit, warnGcMem, warnLockLevel, warnUser, hintSuccess, hintSuccessX, hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, - hintConditionAlwaysTrue, hintPattern, + hintConditionAlwaysTrue, hintName, hintPattern, hintUser const @@ -368,7 +368,7 @@ const warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]", warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]", warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]", - warnDeprecated: "\'$1\' is deprecated [Deprecated]", + warnDeprecated: "$1 is deprecated [Deprecated]", warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]", warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]", warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]", @@ -387,9 +387,10 @@ const warnProveField: "cannot prove that field '$1' is accessible [ProveField]", warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]", warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]", - warnGcUnsafe2: "cannot prove '$1' is GC-safe. This will become a compile time error in the future.", + warnGcUnsafe2: "cannot prove '$1' is GC-safe. Does not compile with --threads:on.", warnUninit: "'$1' might not have been initialized [Uninit]", warnGcMem: "'$1' uses GC'ed memory [GcMem]", + warnLockLevel: "$1 [LockLevel]", warnUser: "$1 [User]", hintSuccess: "operation successful [Success]", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]", @@ -405,11 +406,12 @@ const hintConf: "used config file \'$1\' [Conf]", hintPath: "added path: '$1' [Path]", hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]", + hintName: "name should be: '$1' [Name]", hintPattern: "$1 [Pattern]", hintUser: "$1 [User]"] const - WarningsToStr*: array[0..26, string] = ["CannotOpenFile", "OctalEscape", + WarningsToStr*: array[0..27, string] = ["CannotOpenFile", "OctalEscape", "XIsNeverRead", "XmightNotBeenInit", "Deprecated", "ConfigDeprecated", "SmallLshouldNotBeUsed", "UnknownMagic", @@ -418,12 +420,12 @@ const "AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap", "UnsafeCode", "EachIdentIsTuple", "ShadowIdent", "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit", - "GcMem", "User"] + "GcMem", "LockLevel", "User"] - HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong", + HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong", "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", - "Path", "CondTrue", "Pattern", + "Path", "CondTrue", "Name", "Pattern", "User"] const @@ -441,7 +443,7 @@ type TNoteKinds* = set[TNoteKind] TFileInfo*{.final.} = object - fullPath*: string # This is a canonical full filesystem path + fullPath: string # This is a canonical full filesystem path projPath*: string # This is relative to the project's root shortName*: string # short name of the module quotedName*: PRope # cached quoted short name for codegen @@ -468,8 +470,8 @@ type TErrorOutputs* = set[TErrorOutput] - ERecoverableError* = object of EInvalidValue - ESuggestDone* = object of E_Base + ERecoverableError* = object of ValueError + ESuggestDone* = object of Exception const InvalidFileIDX* = int32(-1) @@ -567,7 +569,7 @@ var gErrorMax*: int = 1 # stop after gErrorMax errors when useCaas: - var stdoutSocket*: TSocket + var stdoutSocket*: Socket proc unknownLineInfo*(): TLineInfo = result.line = int16(-1) @@ -858,7 +860,7 @@ proc sourceLine*(i: TLineInfo): PRope = try: for line in lines(i.toFullPath): addSourceLine i.fileIndex, line.string - except EIO: + except IOError: discard internalAssert i.fileIndex < fileInfos.len # can happen if the error points to EOF: diff --git a/compiler/nimrod.ini b/compiler/nim.ini index 7135b3490..576b6d2bb 100644 --- a/compiler/nimrod.ini +++ b/compiler/nim.ini @@ -2,7 +2,7 @@ ; and project. [Project] -Name: "Nimrod" +Name: "Nim" Version: "$version" Platforms: """ windows: i386;amd64 @@ -16,15 +16,15 @@ Platforms: """ """ Authors: "Andreas Rumpf" -Description: """This is the Nimrod Compiler. Nimrod is a new statically typed, +Description: """This is the Nim Compiler. Nim is a new statically typed, imperative programming language, that supports procedural, functional, object oriented and generic programming styles while remaining simple and efficient. -A special feature that Nimrod inherited from Lisp is that Nimrod's abstract +A special feature that Nim inherited from Lisp is that Nim's abstract syntax tree (AST) is part of the specification - this allows a powerful macro system which can be used to create domain specific languages. -Nimrod is a compiled, garbage-collected systems programming language -which has an excellent productivity/performance ratio. Nimrod's design +Nim is a compiled, garbage-collected systems programming language +which has an excellent productivity/performance ratio. Nim's design focuses on the 3E: efficiency, expressiveness, elegance (in the order of priority).""" @@ -32,7 +32,7 @@ App: Console License: "copying.txt" [Config] -Files: "config/nimrod.cfg" +Files: "config/nim.cfg" Files: "config/nimdoc.cfg" Files: "config/nimdoc.tex.cfg" @@ -61,8 +61,8 @@ Files: "icons/koch.res" Files: "icons/koch_icon.o" Files: "compiler/readme.txt" -Files: "compiler/nimrod.ini" -Files: "compiler/nimrod.cfg" +Files: "compiler/nim.ini" +Files: "compiler/nim.nimrod.cfg" Files: "compiler/*.nim" Files: "doc/*.txt" Files: "compiler/nimfix/*.nim" @@ -113,10 +113,9 @@ Files: "examples/*.tmpl" [Windows] -Files: "bin/nimrod.exe" -Files: "bin/nimrod_debug.exe" +Files: "bin/nim.exe" +Files: "bin/nim_debug.exe" Files: "bin/c2nim.exe" -Files: "bin/niminst.exe" Files: "bin/nimgrep.exe" Files: "dist/*.dll" @@ -132,7 +131,7 @@ Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia ; for now only NSIS supports optional downloads [UnixBin] -Files: "bin/nimrod" +Files: "bin/nim" [Unix] @@ -156,6 +155,5 @@ flags = "-w" [deb] buildDepends: "gcc (>= 4:4.3.2)" pkgDepends: "gcc (>= 4:4.3.2)" -shortDesc: "The Nimrod Compiler" -licenses: "bin/nimrod,MIT;lib/*,MIT;" - +shortDesc: "The Nim Compiler" +licenses: "bin/nim,MIT;lib/*,MIT;" diff --git a/compiler/nimrod.nim b/compiler/nim.nim index 618d98698..a87e0a1ac 100644 --- a/compiler/nimrod.nim +++ b/compiler/nim.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -40,7 +40,7 @@ proc handleCmdLine() = if gProjectName != "": try: gProjectFull = canonicalizePath(gProjectName) - except EOS: + except OSError: gProjectFull = gProjectName var p = splitFile(gProjectFull) gProjectPath = p.dir @@ -58,7 +58,7 @@ proc handleCmdLine() = if msgs.gErrorCounter == 0: when hasTinyCBackend: if gCmd == cmdRun: - tccgen.run(service.arguments) + tccgen.run(commands.arguments) if optRun in gGlobalOptions: if gCmd == cmdCompileToJS: var ex: string @@ -67,7 +67,7 @@ proc handleCmdLine() = else: ex = quoteShell( completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir)) - execExternalProgram("node " & ex & ' ' & service.arguments) + execExternalProgram("node " & ex & ' ' & commands.arguments) else: var binPath: string if options.outFile.len > 0: @@ -77,7 +77,7 @@ proc handleCmdLine() = # Figure out ourselves a valid binary name. binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir var ex = quoteShell(binPath) - execExternalProgram(ex & ' ' & service.arguments) + execExternalProgram(ex & ' ' & commands.arguments) when declared(GC_setMaxPause): GC_setMaxPause 2_000 diff --git a/compiler/nimrod.nimrod.cfg b/compiler/nim.nimrod.cfg index 2c6e6f249..ba7697c4c 100644 --- a/compiler/nimrod.nimrod.cfg +++ b/compiler/nim.nimrod.cfg @@ -1,6 +1,4 @@ -# Special configuration file for the Nimrod project - -mainModule:"nimrod.nim" +# Special configuration file for the Nim project # gc:markAndSweep @@ -21,3 +19,4 @@ define:useStdoutAsStdmsg cs:partial #define:useNodeIds +symbol:nimfix diff --git a/compiler/babelcmd.nim b/compiler/nimblecmd.nim index 7fa233732..049b94aa9 100644 --- a/compiler/babelcmd.nim +++ b/compiler/nimblecmd.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## Implements some helper procs for Babel (Nimrod's package manager) support. +## Implements some helper procs for Nimble (Nim's package manager) support. import parseutils, strutils, strtabs, os, options, msgs, lists @@ -43,7 +43,7 @@ proc `<.`(a, b: string): bool = if a[i] == '.': inc i if b[j] == '.': inc j -proc addPackage(packages: PStringTable, p: string) = +proc addPackage(packages: StringTableRef, p: string) = let x = versionSplitPos(p) let name = p.substr(0, x-1) if x < p.len: @@ -53,12 +53,12 @@ proc addPackage(packages: PStringTable, p: string) = else: packages[name] = latest -iterator chosen(packages: PStringTable): string = +iterator chosen(packages: StringTableRef): string = for key, val in pairs(packages): let res = if val == latest: key else: key & '-' & val yield res -proc addBabelPath(p: string, info: TLineInfo) = +proc addNimblePath(p: string, info: TLineInfo) = if not contains(options.searchPaths, p): if gVerbosity >= 1: message(info, hintPath, p) lists.prependStr(options.lazyPaths, p) @@ -70,10 +70,10 @@ proc addPathWithNimFiles(p: string, info: TLineInfo) = result = true break if hasNimFile(p): - addBabelPath(p, info) + addNimblePath(p, info) else: for kind, p2 in walkDir(p): - if hasNimFile(p2): addBabelPath(p2, info) + if hasNimFile(p2): addNimblePath(p2, info) proc addPathRec(dir: string, info: TLineInfo) = var packages = newStringTable(modeStyleInsensitive) @@ -83,8 +83,8 @@ proc addPathRec(dir: string, info: TLineInfo) = if k == pcDir and p[pos] != '.': addPackage(packages, p) for p in packages.chosen: - addBabelPath(p, info) + addNimblePath(p, info) -proc babelPath*(path: string, info: TLineInfo) = +proc nimblePath*(path: string, info: TLineInfo) = addPathRec(path, info) - addBabelPath(path, info) + addNimblePath(path, info) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 136a0d454..98fe831d3 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -14,7 +14,7 @@ import options, idents, wordrecg # ---------------- configuration file parser ----------------------------- -# we use Nimrod's scanner here to safe space and work +# we use Nim's scanner here to safe space and work proc ppGetTok(L: var TLexer, tok: var TToken) = # simple filter @@ -224,8 +224,8 @@ proc loadConfigs*(cfg: string) = if libpath == "": # choose default libpath: var prefix = getPrefixDir() - if prefix == "/usr": libpath = "/usr/lib/nimrod" - elif prefix == "/usr/local": libpath = "/usr/local/lib/nimrod" + if prefix == "/usr": libpath = "/usr/lib/nim" + elif prefix == "/usr/local": libpath = "/usr/local/lib/nim" else: libpath = joinPath(prefix, "lib") if optSkipConfigFile notin gGlobalOptions: @@ -244,5 +244,6 @@ proc loadConfigs*(cfg: string) = if gProjectName.len != 0: # new project wide config file: - readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg")) - + let projectConfig = changeFileExt(gProjectFull, "nim.cfg") + if fileExists(projectConfig): readConfigFile(projectConfig) + else: readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg")) diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index 0ee108d48..5693cbe91 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## exposes the Nimrod VM to clients. +## exposes the Nim VM to clients. import ast, modules, passes, passaux, condsyms, diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim index 8e0f5db6d..225b78479 100644 --- a/compiler/nimfix/prettybase.nim +++ b/compiler/nimfix/prettybase.nim @@ -34,7 +34,7 @@ proc loadFile*(info: TLineInfo) = for line in lines(path): gSourceFiles[i].lines.add(line) # extract line ending of the file: - var lex: TBaseLexer + var lex: BaseLexer open(lex, newFileStream(path, fmRead)) var pos = lex.bufpos while true: diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim index 038573c35..e18e1c22a 100644 --- a/compiler/nimlexbase.nim +++ b/compiler/nimlexbase.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -37,7 +37,7 @@ const NewLines* = {CR, LF} type - TBaseLexer* = object of TObject + TBaseLexer* = object of RootObj bufpos*: int buf*: cstring bufLen*: int # length of buffer in characters diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim index d65618e0a..aa7686d30 100644 --- a/compiler/nimsets.nim +++ b/compiler/nimsets.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# this unit handles Nimrod sets; it implements symbolic sets +# this unit handles Nim sets; it implements symbolic sets import ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer diff --git a/compiler/nversion.nim b/compiler/nversion.nim index bd1f79ac6..c29880fe2 100644 --- a/compiler/nversion.nim +++ b/compiler/nversion.nim @@ -1,20 +1,20 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# This module contains Nimrod's version. It is the only place where it needs +# This module contains Nim's version. It is the only place where it needs # to be changed. const MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets? VersionMajor* = 0 - VersionMinor* = 9 - VersionPatch* = 6 + VersionMinor* = 10 + VersionPatch* = 0 VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch RodFileVersion* = "1215" # modify this if the rod-format changes! diff --git a/compiler/options.nim b/compiler/options.nim index 02719cacc..838f99f8e 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -68,7 +68,7 @@ type # please make sure we have under 32 options # also: generate header file TGlobalOptions* = set[TGlobalOption] - TCommands* = enum # Nimrod's commands + TCommands* = enum # Nim's commands # **keep binary compatible** cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc, @@ -114,7 +114,7 @@ var gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of # the tracked source X, saved by the CAAS client. gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer. - gNoBabelPath* = false + gNoNimblePath* = false proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools} proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc @@ -139,7 +139,7 @@ const JsonExt* = "json" TexExt* = "tex" IniExt* = "ini" - DefaultConfig* = "nimrod.cfg" + DefaultConfig* = "nim.cfg" DocConfig* = "nimdoc.cfg" DocTexConfig* = "nimdoc.tex.cfg" @@ -152,7 +152,6 @@ var gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/ gProjectFull* = "" # projectPath/projectName gProjectMainIdx*: int32 # the canonical path id of the main module - optMainModule* = "" # the main module that should be used for idetools commands nimcacheDir* = "" command* = "" # the main command (e.g. cc, check, scan, etc) commandArgs*: seq[string] = @[] # any arguments after the main command @@ -189,8 +188,8 @@ proc getPrefixDir*(): string = result = splitPath(getAppDir()).head proc canonicalizePath*(path: string): string = - result = path.expandFilename - when not FileSystemCaseSensitive: result = result.toLower + when not FileSystemCaseSensitive: result = path.expandFilename.toLower + else: result = path.expandFilename proc shortenDir*(dir: string): string = ## returns the interesting part of a dir @@ -238,6 +237,9 @@ proc getPackageName*(path: string): string = #echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name return packageCache[d] inc parents + for file in walkFiles(d / "*.nimble"): + result = file.splitFile.name + break packageSearch for file in walkFiles(d / "*.babel"): result = file.splitFile.name break packageSearch @@ -295,7 +297,7 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = createDir(subdir) when noTimeMachine: excludeDirFromTimeMachine(subdir) - except EOS: + except OSError: writeln(stdout, "cannot create directory: " & subdir) quit(1) result = joinPath(subdir, tail) @@ -335,6 +337,16 @@ proc findFile*(f: string): string {.procvar.} = proc findModule*(modulename, currentModule: string): string = # returns path to module + when defined(nimfix): + # '.nimfix' modules are preferred over '.nim' modules so that specialized + # versions can be kept for 'nimfix'. + block: + let m = addFileExt(modulename, "nimfix") + let currentPath = currentModule.splitFile.dir + result = currentPath / m + if not existsFile(result): + result = findFile(m) + if existsFile(result): return result let m = addFileExt(modulename, NimExt) let currentPath = currentModule.splitFile.dir result = currentPath / m diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index bbdba8c22..300abea1e 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/parser.nim b/compiler/parser.nim index 6ff0c2dfc..20c037c00 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# This module implements the parser of the standard Nimrod syntax. +# This module implements the parser of the standard Nim syntax. # The parser strictly reflects the grammar ("doc/grammar.txt"); however # it uses several helper routines to keep the parser small. A special # efficient algorithm is used for the precedence levels. The parser here can @@ -84,7 +84,7 @@ proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream, proc openParser*(p: var TParser, filename: string, inputStream: PLLStream, strongSpaces=false) = - openParser(p, filename.fileInfoIdx, inputstream, strongSpaces) + openParser(p, filename.fileInfoIdx, inputStream, strongSpaces) proc closeParser(p: var TParser) = ## Close a parser, freeing up its resources. diff --git a/compiler/passaux.nim b/compiler/passaux.nim index 0ba9f22d0..f754c80e5 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/passes.nim b/compiler/passes.nim index 66a1a4954..a63e29b35 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -16,7 +16,7 @@ import nimsets, syntaxes, times, rodread, idgen type - TPassContext* = object of TObject # the pass's context + TPassContext* = object of RootObj # the pass's context fromCache*: bool # true if created by "openCached" PPassContext* = ref TPassContext diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 5e21289b5..3d71aa4d1 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/pbraces.nim b/compiler/pbraces.nim index ce6e0d9a9..cf4dbffc5 100644 --- a/compiler/pbraces.nim +++ b/compiler/pbraces.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index d73494c6e..52eb46bf4 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -130,6 +130,7 @@ proc processImportCpp(s: PSym, extname: string) = excl(s.flags, sfForward) let m = s.getModule() incl(m.flags, sfCompileToCpp) + extccomp.gMixedMode = true proc processImportObjC(s: PSym, extname: string) = setExternName(s, extname) @@ -447,6 +448,9 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = addSon(result, newSymNode(e)) else: addSon(result, newStrNode(nkStrLit, sub)) + else: + # an empty '``' produces a single '`' + addSon(result, newStrNode(nkStrLit, $marker)) if c < 0: break a = c + 1 else: illFormedAst(n) @@ -518,6 +522,28 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) = else: invalidPragma(n) +proc pragmaLockStmt(c: PContext; it: PNode) = + if it.kind != nkExprColonExpr: + invalidPragma(it) + else: + let n = it[1] + if n.kind != nkBracket: + localError(n.info, errGenerated, "locks pragma takes a list of expressions") + else: + for i in 0 .. <n.len: + n.sons[i] = c.semExpr(c, n.sons[i]) + +proc pragmaLocks(c: PContext, it: PNode): TLockLevel = + if it.kind != nkExprColonExpr: + invalidPragma(it) + else: + if it[1].kind != nkNilLit: + let x = expectIntLit(c, it) + if x < 0 or x > MaxLockLevel: + localError(it[1].info, "integer must be within 0.." & $MaxLockLevel) + else: + result = TLockLevel(x) + proc typeBorrow(sym: PSym, n: PNode) = if n.kind == nkExprColonExpr: let it = n.sons[1] @@ -807,6 +833,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, if sym == nil: invalidPragma(it) of wLine: pragmaLine(c, it) of wRaises, wTags: pragmaRaisesOrTags(c, it) + of wLocks: + if sym == nil: pragmaLockStmt(c, it) + elif sym.typ == nil: invalidPragma(it) + else: sym.typ.lockLevel = pragmaLocks(c, it) of wGuard: if sym == nil or sym.kind notin {skVar, skLet, skField}: invalidPragma(it) diff --git a/compiler/pretty.nim b/compiler/pretty.nim deleted file mode 100644 index 17311f9e6..000000000 --- a/compiler/pretty.nim +++ /dev/null @@ -1,281 +0,0 @@ -# -# -# The Nimrod Compiler -# (c) Copyright 2014 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements the code "prettifier". This is part of the toolchain -## to convert Nimrod code into a consistent style. - -import - strutils, os, options, ast, astalgo, msgs, ropes, idents, passes, - intsets, strtabs, semdata - -const - removeTP = false # when true, "nimrod pretty" converts TTyp to Typ. - -type - TGen = object of TPassContext - module*: PSym - PGen = ref TGen - - TSourceFile = object - lines: seq[string] - dirty: bool - fullpath: string - -var - gSourceFiles: seq[TSourceFile] = @[] - gCheckExtern: bool - rules: PStringTable - -proc loadFile(info: TLineInfo) = - let i = info.fileIndex - if i >= gSourceFiles.len: - gSourceFiles.setLen(i+1) - if gSourceFiles[i].lines.isNil: - gSourceFiles[i].lines = @[] - let path = info.toFullPath - gSourceFiles[i].fullpath = path - # we want to die here for EIO: - for line in lines(path): - gSourceFiles[i].lines.add(line) - -proc overwriteFiles*() = - let overWrite = options.getConfigVar("pretty.overwrite").normalize == "on" - let doStrip = options.getConfigVar("pretty.strip").normalize == "on" - for i in 0 .. high(gSourceFiles): - if not gSourceFiles[i].dirty: continue - let newFile = if overWrite: gSourceFiles[i].fullpath - else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim") - try: - var f = open(newFile, fmWrite) - for line in gSourceFiles[i].lines: - if doStrip: - f.write line.strip(leading = false, trailing = true) - else: - f.write line - f.write("\L") - f.close - except EIO: - rawMessage(errCannotOpenFile, newFile) - -proc `=~`(s: string, a: openArray[string]): bool = - for x in a: - if s.startsWith(x): return true - -proc beautifyName(s: string, k: TSymKind): string = - # minimal set of rules here for transition: - # GC_ is allowed - - let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'}) - if allUpper and k in {skConst, skEnumField, skType}: return s - result = newStringOfCap(s.len) - var i = 0 - case k - of skType, skGenericParam: - # Types should start with a capital unless builtins like 'int' etc.: - when removeTP: - if s[0] == 'T' and s[1] in {'A'..'Z'}: - i = 1 - if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string", - "char", "byte", "bool", "openArray", "seq", "array", "void", - "pointer", "float", "csize", "cdouble", "cchar", "cschar", - "cshort", "cu", "nil", "expr", "stmt", "typedesc", "auto", "any", - "range", "openarray", "varargs", "set", "cfloat" - ]: - result.add s[i] - else: - result.add toUpper(s[i]) - of skConst, skEnumField: - # for 'const' we keep how it's spelt; either upper case or lower case: - result.add s[0] - else: - # as a special rule, don't transform 'L' to 'l' - if s.len == 1 and s[0] == 'L': result.add 'L' - elif '_' in s: result.add(s[i]) - else: result.add toLower(s[0]) - inc i - while i < s.len: - if s[i] == '_': - if i > 0 and s[i-1] in {'A'..'Z'}: - # don't skip '_' as it's essential for e.g. 'GC_disable' - result.add('_') - inc i - result.add s[i] - else: - inc i - result.add toUpper(s[i]) - elif allUpper: - result.add toLower(s[i]) - else: - result.add s[i] - inc i - -proc checkStyle*(info: TLineInfo, s: string, k: TSymKind) = - let beau = beautifyName(s, k) - if s != beau: - message(info, errGenerated, "name should be: " & beau) - -const - Letters = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'} - -proc identLen(line: string, start: int): int = - while start+result < line.len and line[start+result] in Letters: - inc result - -proc differ(line: string, a, b: int, x: string): bool = - let y = line[a..b] - result = cmpIgnoreStyle(y, x) == 0 and y != x - when false: - var j = 0 - for i in a..b: - if line[i] != x[j]: return true - inc j - return false - -proc checkDef*(n: PNode; s: PSym) = - # operators stay as they are: - if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return - if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return - - if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern: - checkStyle(n.info, s.name.s, s.kind) - -proc checkDef(c: PGen; n: PNode) = - if n.kind != nkSym: return - checkDef(n, n.sym) - -proc checkUse*(info: TLineInfo; s: PSym) = - if info.fileIndex < 0: return - # we simply convert it to what it looks like in the definition - # for consistency - - # operators stay as they are: - if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return - if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return - let newName = s.name.s - - loadFile(info) - - let line = gSourceFiles[info.fileIndex].lines[info.line-1] - var first = min(info.col.int, line.len) - if first < 0: return - #inc first, skipIgnoreCase(line, "proc ", first) - while first > 0 and line[first-1] in Letters: dec first - if first < 0: return - if line[first] == '`': inc first - - let last = first+identLen(line, first)-1 - if differ(line, first, last, newName): - # last-first+1 != newName.len or - var x = line.substr(0, first-1) & newName & line.substr(last+1) - when removeTP: - # the WinAPI module is full of 'TX = X' which after the substitution - # becomes 'X = X'. We remove those lines: - if x.match(peg"\s* {\ident} \s* '=' \s* y$1 ('#' .*)?"): - x = "" - - system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x) - gSourceFiles[info.fileIndex].dirty = true - -when false: - var cannotRename = initIntSet() - - proc beautifyName(s: string, k: TSymKind): string = - let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'}) - result = newStringOfCap(s.len) - var i = 0 - case k - of skType, skGenericParam: - # skip leading 'T' - when removeTP: - if s[0] == 'T' and s[1] in {'A'..'Z'}: - i = 1 - if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string", - "char", "byte", "bool", "openArray", "seq", "array", "void", - "pointer", "float", "csize", "cdouble", "cchar", "cschar", - "cshort", "cu"]: - result.add s[i] - else: - result.add toUpper(s[i]) - of skConst, skEnumField: - # for 'const' we keep how it's spelt; either upper case or lower case: - result.add s[0] - else: - # as a special rule, don't transform 'L' to 'l' - if s.len == 1 and s[0] == 'L': result.add 'L' - else: result.add toLower(s[0]) - inc i - while i < s.len: - if s[i] == '_': - inc i - result.add toUpper(s[i]) - elif allUpper: - result.add toLower(s[i]) - else: - result.add s[i] - inc i - -proc check(c: PGen, n: PNode) = - case n.kind - of nkSym: checkUse(n.info, n.sym) - of nkBlockStmt, nkBlockExpr, nkBlockType: - checkDef(c, n[0]) - check(c, n.sons[1]) - of nkForStmt, nkParForStmt: - let L = n.len - for i in countup(0, L-3): - checkDef(c, n[i]) - check(c, n[L-2]) - check(c, n[L-1]) - of nkProcDef, nkLambdaKinds, nkMethodDef, nkIteratorDef, nkTemplateDef, - nkMacroDef, nkConverterDef: - checkDef(c, n[namePos]) - for i in namePos+1 .. <n.len: check(c, n.sons[i]) - of nkIdentDefs, nkVarTuple: - let a = n - checkMinSonsLen(a, 3) - let L = len(a) - for j in countup(0, L-3): checkDef(c, a.sons[j]) - check(c, a.sons[L-2]) - check(c, a.sons[L-1]) - of nkTypeSection, nkConstSection: - for i in countup(0, sonsLen(n) - 1): - let a = n.sons[i] - if a.kind == nkCommentStmt: continue - checkSonsLen(a, 3) - checkDef(c, a.sons[0]) - check(c, a.sons[1]) - check(c, a.sons[2]) - else: - for i in 0 .. <n.safeLen: check(c, n.sons[i]) - -proc processSym(c: PPassContext, n: PNode): PNode = - result = n - check(PGen(c), n) - -proc myOpen(module: PSym): PPassContext = - var g: PGen - new(g) - g.module = module - gCheckExtern = options.getConfigVar("pretty.checkextern").normalize == "on" - result = g - if rules.isNil: - rules = newStringTable(modeStyleInsensitive) - when removeTP: - # XXX activate when the T/P stuff is deprecated - let path = joinPath([getPrefixDir(), "config", "rename.rules.cfg"]) - for line in lines(path): - if line.len > 0: - let colon = line.find(':') - if colon > 0: - rules[line.substr(0, colon-1)] = line.substr(colon+1) - else: - rules[line] = line - -const prettyPass* = makePass(open = myOpen, process = processSym) - diff --git a/compiler/procfind.nim b/compiler/procfind.nim index 9f52cc117..473965a3d 100644 --- a/compiler/procfind.nim +++ b/compiler/procfind.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -11,7 +11,7 @@ # This is needed for proper handling of forward declarations. import - ast, astalgo, msgs, semdata, types, trees + ast, astalgo, msgs, semdata, types, trees, strutils proc equalGenericParams(procA, procB: PNode): bool = if sonsLen(procA) != sonsLen(procB): return @@ -68,11 +68,17 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym = ExactConstraints, IgnoreCC} var it: TIdentIter + result = initIdentIter(it, scope.symbols, fn.name) while result != nil: if result.kind in skProcKinds and sameType(result.typ, fn.typ, flags): case equalParams(result.typ.n, fn.typ.n) of paramsEqual: + if (sfExported notin result.flags) and (sfExported in fn.flags): + let message = ("public implementation '$1' has non-public " & + "forward declaration in $2") % + [getProcHeader(result), $result.info] + localError(fn.info, errGenerated, message) return of paramsIncompatible: localError(fn.info, errNotOverloadable, fn.name.s) diff --git a/compiler/readme.txt b/compiler/readme.txt index 3d3cf4b29..c4934e031 100644 --- a/compiler/readme.txt +++ b/compiler/readme.txt @@ -1,4 +1,4 @@ -This directory contains the Nimrod compiler written in Nimrod. Note that this +This directory contains the Nim compiler written in Nim. Note that this code has been translated from a bootstrapping version written in Pascal, so -the code is **not** a poster child of good Nimrod code. +the code is **not** a poster child of good Nim code. diff --git a/compiler/renderer.nim b/compiler/renderer.nim index c97b2f321..a4469acda 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# This module implements the renderer of the standard Nimrod representation. +# This module implements the renderer of the standard Nim representation. import lexer, options, idents, strutils, ast, msgs, lists @@ -1009,9 +1009,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkElse, " else") putWithSpace(g, tkColon, ":") gsub(g, n.sons[0]) - of nkTypeOfExpr: + of nkTypeOfExpr: putWithSpace(g, tkType, "type") - gsub(g, n.sons[0]) + if n.len > 0: gsub(g, n.sons[0]) of nkRefTy: if sonsLen(n) > 0: putWithSpace(g, tkRef, "ref") @@ -1306,7 +1306,7 @@ proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string = proc renderModule(n: PNode, filename: string, renderFlags: TRenderFlags = {}) = var - f: TFile + f: File g: TSrcGen initSrcGen(g, renderFlags) for i in countup(0, sonsLen(n) - 1): diff --git a/compiler/rodread.nim b/compiler/rodread.nim index 036e6cc3c..3b3538e5d 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -121,7 +121,7 @@ type r*: string # writers use this offset*: int # readers use this - TRodReader* = object of TObject + TRodReader* = object of RootObj pos: int # position; used for parsing s: cstring # mmap'ed file contents options: TOptions @@ -137,7 +137,7 @@ type line: int # only used for debugging, but is always in the code moduleID: int syms: TIdTable # already processed symbols - memfile: TMemFile # unfortunately there is no point in time where we + memfile: MemFile # unfortunately there is no point in time where we # can close this! XXX methods*: TSymSeq origFile: string @@ -280,11 +280,6 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) = loc.r = toRope(decodeStr(r.s, r.pos)) else: loc.r = nil - if r.s[r.pos] == '?': - inc(r.pos) - loc.a = decodeVInt(r.s, r.pos) - else: - loc.a = 0 if r.s[r.pos] == '>': inc(r.pos) else: internalError(info, "decodeLoc " & r.s[r.pos]) @@ -326,7 +321,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType = result.size = - 1 if r.s[r.pos] == '=': inc(r.pos) - result.align = decodeVInt(r.s, r.pos) + result.align = decodeVInt(r.s, r.pos).int16 else: result.align = 2 decodeLoc(r, result.loc, info) @@ -503,7 +498,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) = idTablePut(r.syms, s, s) strTableAdd(rodCompilerprocs, s) -proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) = +proc processIndex(r: PRodReader; idx: var TIndex; outf: File = nil) = var key, val, tmp: int inc(r.pos, 2) # skip "(\10" inc(r.line) @@ -659,7 +654,7 @@ proc newRodReader(modfilename: string, crc: TCrc32, new(result) try: result.memfile = memfiles.open(modfilename) - except EOS: + except OSError: return nil result.files = @[] result.modDeps = @[] @@ -916,7 +911,7 @@ initIdTable(gTypeTable) initStrTable(rodCompilerprocs) # viewer: -proc writeNode(f: TFile; n: PNode) = +proc writeNode(f: File; n: PNode) = f.write("(") if n != nil: f.write($n.kind) @@ -947,7 +942,7 @@ proc writeNode(f: TFile; n: PNode) = writeNode(f, n.sons[i]) f.write(")") -proc writeSym(f: TFile; s: PSym) = +proc writeSym(f: File; s: PSym) = if s == nil: f.write("{}\n") return @@ -985,7 +980,7 @@ proc writeSym(f: TFile; s: PSym) = f.writeNode(s.ast) f.write("}\n") -proc writeType(f: TFile; t: PType) = +proc writeType(f: File; t: PType) = if t == nil: f.write("[]\n") return diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 09b92cd8a..e0ef3c397 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 4231da2d0..9fed7ac52 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -187,9 +187,6 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = if loc.r != nil: add(result, '!') encodeStr(ropeToStr(loc.r), result) - if loc.a != 0: - add(result, '?') - encodeVInt(loc.a, result) if oldLen + 1 == result.len: # no data was necessary, so remove the '<' again: setLen(result, oldLen) @@ -297,7 +294,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) = # the last entry of a symbol: if s.ast != nil: # we used to attempt to save space here by only storing a dummy AST if - # it is not necessary, but Nimrod's heavy compile-time evaluation features + # it is not necessary, but Nim's heavy compile-time evaluation features # make that unfeasible nowadays: encodeNode(w, s.info, s.ast, result) when false: @@ -422,7 +419,7 @@ proc addStmt(w: PRodWriter, n: PNode) = proc writeRod(w: PRodWriter) = processStacks(w, true) - var f: TFile + var f: File if not open(f, completeGeneratedFilePath(changeFileExt( w.filename.withPackageName, RodExt)), fmWrite): diff --git a/compiler/ropes.nim b/compiler/ropes.nim index fcf5dd202..b14081694 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,7 +12,7 @@ # Ropes are a data structure that represents a very long string # efficiently; especially concatenation is done in O(1) instead of O(N). # Ropes make use a lazy evaluation: They are essentially concatenation -# trees that are only flattened when converting to a native Nimrod +# trees that are only flattened when converting to a native Nim # string or when written to disk. The empty string is represented by a # nil pointer. # A little picture makes everything clear: @@ -64,7 +64,7 @@ type # copy the format strings # though it is not necessary) PRope* = ref TRope - TRope*{.acyclic.} = object of TObject # the empty rope is represented + TRope*{.acyclic.} = object of RootObj # the empty rope is represented # by nil to safe space left*, right*: PRope length*: int @@ -216,7 +216,7 @@ proc app(a: var PRope, b: PRope) = a = con(a, b) proc app(a: var PRope, b: string) = a = con(a, b) proc prepend(a: var PRope, b: PRope) = a = con(b, a) -proc writeRope*(f: TFile, c: PRope) = +proc writeRope*(f: File, c: PRope) = var stack = @[c] while len(stack) > 0: var it = pop(stack) @@ -228,7 +228,7 @@ proc writeRope*(f: TFile, c: PRope) = write(f, it.data) proc writeRope*(head: PRope, filename: string, useWarning = false) = - var f: TFile + var f: File if open(f, filename, fmWrite): if head != nil: writeRope(f, head) close(f) @@ -299,7 +299,7 @@ proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) = const bufSize = 1024 # 1 KB is reasonable -proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool = +proc auxRopeEqualsFile(r: PRope, bin: var File, buf: pointer): bool = if r.data != nil: if r.length > bufSize: errorHandler(rTokenTooLong, r.data) @@ -312,7 +312,7 @@ proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool = if result: result = auxRopeEqualsFile(r.right, bin, buf) proc ropeEqualsFile(r: PRope, f: string): bool = - var bin: TFile + var bin: File result = open(bin, f) if not result: return # not equal if file does not exist diff --git a/compiler/saturate.nim b/compiler/saturate.nim index ed197bdd1..f4fe29a20 100644 --- a/compiler/saturate.nim +++ b/compiler/saturate.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/sem.nim b/compiler/sem.nim index 26a59334c..81846e1b4 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -15,9 +15,12 @@ import magicsys, parser, nversion, nimsets, semfold, importer, procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, - evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity, + evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity, semparallel, lowerings +when defined(nimfix): + import nimfix.prettybase + # implementation proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.} @@ -37,8 +40,7 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) proc addParams(c: PContext, n: PNode, kind: TSymKind) proc maybeAddResult(c: PContext, s: PSym, n: PNode) proc instGenericContainer(c: PContext, n: PNode, header: PType): PType -proc tryExpr(c: PContext, n: PNode, - flags: TExprFlags = {}, bufferErrors = false): PNode +proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc fixImmediateParams(n: PNode): PNode proc activate(c: PContext, n: PNode) proc semQuoteAst(c: PContext, n: PNode): PNode @@ -308,6 +310,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, pushInfoContext(nOrig.info) markUsed(n.info, sym) + styleCheckUse(n.info, sym) if sym == c.p.owner: globalError(n.info, errRecursiveDependencyX, sym.name.s) @@ -340,7 +343,7 @@ type TSemGenericFlags = set[TSemGenericFlag] proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var TIntSet): PNode + ctx: var IntSet): PNode include semtypes, semtempl, semgnrc, semstmts, semexprs @@ -367,6 +370,8 @@ proc myOpen(module: PSym): PPassContext = c.semInferredLambda = semInferredLambda c.semGenerateInstance = generateInstance c.semTypeNode = semTypeNode + c.instDeepCopy = sigmatch.instDeepCopy + pushProcCon(c, module) pushOwner(c.module) c.importTable = openScope(c) diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim new file mode 100644 index 000000000..483d36bf3 --- /dev/null +++ b/compiler/semasgn.nim @@ -0,0 +1,197 @@ +# +# +# The Nim Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements lifting for assignments and ``deepCopy``. + +# included from sem.nim + +type + TLiftCtx = object + c: PContext + info: TLineInfo # for construction + result: PNode + kind: TTypeAttachedOp + +type + TFieldInstCtx = object # either 'tup[i]' or 'field' is valid + tupleType: PType # if != nil we're traversing a tuple + tupleIndex: int + field: PSym + replaceByFieldName: bool + +proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = + case n.kind + of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n + of nkIdent: + result = n + var L = sonsLen(forLoop) + if c.replaceByFieldName: + if n.ident.id == forLoop[0].ident.id: + let fieldName = if c.tupleType.isNil: c.field.name.s + elif c.tupleType.n.isNil: "Field" & $c.tupleIndex + else: c.tupleType.n.sons[c.tupleIndex].sym.name.s + result = newStrNode(nkStrLit, fieldName) + return + # other fields: + for i in ord(c.replaceByFieldName)..L-3: + if n.ident.id == forLoop[i].ident.id: + var call = forLoop.sons[L-2] + var tupl = call.sons[i+1-ord(c.replaceByFieldName)] + if c.field.isNil: + result = newNodeI(nkBracketExpr, n.info) + result.add(tupl) + result.add(newIntNode(nkIntLit, c.tupleIndex)) + else: + result = newNodeI(nkDotExpr, n.info) + result.add(tupl) + result.add(newSymNode(c.field, n.info)) + break + else: + if n.kind == nkContinueStmt: + localError(n.info, errGenerated, + "'continue' not supported in a 'fields' loop") + result = copyNode(n) + newSons(result, sonsLen(n)) + for i in countup(0, sonsLen(n)-1): + result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop) + +proc liftBodyObj(c: TLiftCtx; typ, x, y: PNode) = + case typ.kind + of nkSym: + var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid + fc.field = typ.sym + fc.replaceByFieldName = c.m == mFieldPairs + openScope(c.c) + inc c.c.inUnrolledContext + let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop) + father.add(semStmt(c.c, body)) + dec c.c.inUnrolledContext + closeScope(c.c) + of nkNilLit: discard + of nkRecCase: + let L = forLoop.len + let call = forLoop.sons[L-2] + if call.len > 2: + localError(forLoop.info, errGenerated, + "parallel 'fields' iterator does not work for 'case' objects") + return + # iterate over the selector: + asgnForObjectFields(c, typ[0], forLoop, father) + # we need to generate a case statement: + var caseStmt = newNodeI(nkCaseStmt, c.info) + # generate selector: + var access = newNodeI(nkDotExpr, forLoop.info, 2) + access.sons[0] = call.sons[1] + access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info) + caseStmt.add(semExprWithType(c.c, access)) + # copy the branches over, but replace the fields with the for loop body: + for i in 1 .. <typ.len: + var branch = copyTree(typ[i]) + let L = branch.len + branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info) + semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1]) + caseStmt.add(branch) + father.add(caseStmt) + of nkRecList: + for t in items(typ): liftBodyObj(c, t, x, y) + else: + illFormedAst(typ) + +proc newAsgnCall(op: PSym; x, y: PNode): PNode = + result = newNodeI(nkCall, x.info) + result.add(newSymNode(op)) + result.add x + result.add y + +proc newAsgnStmt(le, ri: PNode): PNode = + result = newNodeI(nkAsgn, le.info, 2) + result.sons[0] = le + result.sons[1] = ri + +proc newDestructorCall(op: PSym; x: PNode): PNode = + result = newNodeIT(nkCall, x.info, op.typ.sons[0]) + result.add(newSymNode(op)) + result.add x + +proc newDeepCopyCall(op: PSym; x, y: PNode): PNode = + result = newAsgnStmt(x, newDestructorCall(op, y)) + +proc considerOverloadedOp(c: TLiftCtx; t: PType; x, y: PNode): bool = + let op = t.attachedOps[c.kind] + if op != nil: + markUsed(c.info, op) + styleCheckUse(c.info, op) + case c.kind + of attachedDestructor: + c.result.add newDestructorCall(op, x) + of attachedAsgn: + c.result.add newAsgnCall(op, x, y) + of attachedDeepCopy: + c.result.add newDeepCopyCall(op, x, y) + result = true + +proc defaultOp(c: TLiftCtx; t: PType; x, y: PNode) = + if c.kind != attachedDestructor: + c.result.add newAsgnStmt(x, y) + +proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) = + const hasAttachedOp: array[TTypeAttachedOp, TTypeIter] = [ + (proc (t: PType, closure: PObject): bool = + t.attachedOp[attachedDestructor] != nil), + (proc (t: PType, closure: PObject): bool = + t.attachedOp[attachedAsgn] != nil), + (proc (t: PType, closure: PObject): bool = + t.attachedOp[attachedDeepCopy] != nil)] + case t.kind + of tyNone, tyEmpty: discard + of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString: + defaultOp(c, t, x, y) + of tyPtr, tyString: + if not considerOverloadedOp(c, t, x, y): + defaultOp(c, t, x, y) + of tyArrayConstr, tyArray, tySequence: + if iterOverType(lastSon(t), hasAttachedOp[c.kind], nil): + # generate loop and call the attached Op: + + else: + defaultOp(c, t, x, y) + of tyObject: + liftBodyObj(c, t.n, x, y) + of tyTuple: + liftBodyTup(c, t, x, y) + of tyRef: + # we MUST not check for acyclic here as a DAG might still share nodes: + + of tyProc: + if t.callConv != ccClosure or c.kind != attachedDeepCopy: + defaultOp(c, t, x, y) + else: + # a big problem is that we don't know the enviroment's type here, so we + # have to go through some indirection; we delegate this to the codegen: + call = newNodeI(nkCall, n.info, 2) + call.typ = t + call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy)) + call.sons[1] = y + c.result.add newAsgnStmt(x, call) + of tyVarargs, tyOpenArray: + localError(c.info, errGenerated, "cannot copy openArray") + of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, + tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, + tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt, + tyTypeDesc, tyGenericInvokation, tyBigNum, tyConst, tyForward: + internalError(c.info, "assignment requested for type: " & typeToString(t)) + of tyDistinct, tyOrdinal, tyRange, + tyGenericInst, tyFieldAccessor, tyStatic, tyVar: + liftBodyAux(c, lastSon(t)) + +proc liftBody(c: PContext; typ: PType; info: TLineInfo): PNode = + var a: TLiftCtx + a.info = info + a.result = newNodeI(nkStmtList, info) + liftBodyAux(a, typ) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 927b23cf2..3971b8ff5 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -39,7 +39,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, initialBinding: PNode, filter: TSymKinds, best, alt: var TCandidate, - errors: var seq[string]) = + errors: var CandidateErrors) = var o: TOverloadIter var sym = initOverloadIter(o, c, headSymbol) var symScope = o.lastOverloadScope @@ -58,10 +58,10 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, z.calleeSym = sym matches(c, n, orig, z) if errors != nil: - errors.safeAdd(getProcHeader(sym)) + errors.safeAdd(sym) if z.errors != nil: for err in z.errors: - errors[errors.len - 1].add("\n " & err) + errors.add(err) if z.state == csMatch: # little hack so that iterators are preferred over everything else: if sym.kind in skIterators: inc(z.exactMatches, 200) @@ -74,7 +74,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, else: discard sym = nextOverloadIter(o, c, headSymbol) -proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) = +proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = # Gives a detailed error message; this is separated from semOverloadedCall, # as semOverlodedCall is already pretty slow (and we need this information # only in case of an error). @@ -83,18 +83,38 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) = globalError(n.info, errTypeMismatch, "") if errors.len == 0: localError(n.info, errExprXCannotBeCalled, n[0].renderTree) + + # to avoid confusing errors like: + # got (SslPtr, SocketHandle) + # but expected one of: + # openssl.SSL_set_fd(ssl: SslPtr, fd: SocketHandle): cint + # we do a pre-analysis. If all types produce the same string, we will add + # module information. + let proto = describeArgs(c, n, 1, preferName) + + var prefer = preferName + for err in errors: + var errProto = "" + let n = err.typ.n + for i in countup(1, n.len - 1): + var p = n.sons[i] + if p.kind == nkSym: + add(errProto, typeToString(p.sym.typ, preferName)) + if i != n.len-1: add(errProto, ", ") + # else: ignore internal error as we're already in error handling mode + if errProto == proto: + prefer = preferModuleInfo + break + # now use the information stored in 'prefer' to produce a nice error message: var result = msgKindToString(errTypeMismatch) - add(result, describeArgs(c, n, 1)) + add(result, describeArgs(c, n, 1, prefer)) add(result, ')') - var candidates = "" for err in errors: - add(candidates, err) + add(candidates, err.getProcHeader(prefer)) add(candidates, "\n") - if candidates != "": add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates) - localError(n.info, errGenerated, result) proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) = @@ -114,7 +134,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode, else: initialBinding = nil - var errors: seq[string] + var errors: CandidateErrors var usedSyms: seq[PNode] template pickBest(headSymbol: expr) = @@ -254,6 +274,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = assert x.state == csMatch var finalCallee = x.calleeSym markUsed(n.sons[0].info, finalCallee) + styleCheckUse(n.sons[0].info, finalCallee) if finalCallee.ast == nil: internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check! if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty: @@ -286,6 +307,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = initCandidate(c, m, s, n) var newInst = generateInstance(c, s, m.bindings, n.info) markUsed(n.info, s) + styleCheckUse(n.info, s) result = newSymNode(newInst, n.info) proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = @@ -305,7 +327,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = result = explicitGenericSym(c, n, s) elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}: # choose the generic proc with the proper number of type parameters. - # XXX I think this could be improved by reusing sigmatch.ParamTypesMatch. + # XXX I think this could be improved by reusing sigmatch.paramTypesMatch. # It's good enough for now. result = newNodeI(a.kind, n.info) for i in countup(0, len(a)-1): diff --git a/compiler/semdata.nim b/compiler/semdata.nim index abecc1b6d..921e87d30 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -57,7 +57,7 @@ type # can access private object fields instCounter*: int # to prevent endless instantiations - ambiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot + ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot # store this info in the syms themselves!) inTypeClass*: int # > 0 if we are in a user-defined type class inGenericContext*: int # > 0 if we are in a generic type @@ -72,8 +72,7 @@ type libs*: TLinkedList # all libs used by this module semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} - semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}, - bufferErrors = false): PNode {.nimcall.} + semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}): PNode {.nimcall.} semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet @@ -83,15 +82,18 @@ type semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable, info: TLineInfo): PSym - includedFiles*: TIntSet # used to detect recursive include files + includedFiles*: IntSet # used to detect recursive include files userPragmas*: TStrTable evalContext*: PEvalContext - unknownIdents*: TIntSet # ids of all unknown identifiers to prevent + unknownIdents*: IntSet # ids of all unknown identifiers to prevent # naming it multiple times generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile lastGenericIdx*: int # used for the generics stack hloLoopDetector*: int # used to prevent endless loops in the HLO inParallelStmt*: int + instDeepCopy*: proc (c: PContext; dc: PSym; t: PType; + info: TLineInfo): PSym {.nimcall.} + proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = result.genericSym = s diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim index 3c30dc1bd..4ce610bf9 100644 --- a/compiler/semdestruct.nim +++ b/compiler/semdestruct.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 58cef36f9..287a11b33 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -13,6 +13,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, flags: TExprFlags = {}): PNode = markUsed(n.info, s) + styleCheckUse(n.info, s) pushInfoContext(n.info) result = evalTemplate(n, s, getCurrOwner()) if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags) @@ -79,6 +80,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = case s.kind of skConst: markUsed(n.info, s) + styleCheckUse(n.info, s) case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, tyTuple, tySet, tyUInt..tyUInt64: @@ -103,6 +105,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of skTemplate: result = semTemplateExpr(c, n, s, flags) of skVar, skLet, skResult, skParam, skForVar: markUsed(n.info, s) + styleCheckUse(n.info, s) # if a proc accesses a global variable, it is not side effect free: if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect) @@ -115,6 +118,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = # var len = 0 # but won't be called # genericThatUsesLen(x) # marked as taking a closure? of skGenericParam: + styleCheckUse(n.info, s) if s.typ.kind == tyStatic: result = newSymNode(s, n.info) result.typ = s.typ @@ -125,12 +129,14 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = return n of skType: markUsed(n.info, s) + styleCheckUse(n.info, s) if s.typ.kind == tyStatic and s.typ.n != nil: return s.typ.n result = newSymNode(s, n.info) result.typ = makeTypeDesc(c, s.typ) else: markUsed(n.info, s) + styleCheckUse(n.info, s) result = newSymNode(s, n.info) type @@ -259,6 +265,7 @@ proc semConv(c: PContext, n: PNode): PNode = let status = checkConvertible(c, result.typ, it.typ) if status in {convOK, convNotNeedeed}: markUsed(n.info, it.sym) + styleCheckUse(n.info, it.sym) markIndirect(c, it.sym) return it localError(n.info, errUseQualifier, op.sons[0].sym.name.s) @@ -360,6 +367,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode = result = newIntNode(nkIntLit, ord(t.kind == tyProc and t.callConv == ccClosure and tfIterator notin t.flags)) + else: discard else: var t2 = n[2].typ.skipTypes({tyTypeDesc}) maybeLiftType(t2, c, n.info) @@ -981,6 +989,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) if s != nil: markUsed(n.sons[1].info, s) + styleCheckUse(n.sons[1].info, s) return semSym(c, n, s, flags) n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType}) @@ -1004,6 +1013,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result.info = n.info result.typ = ty markUsed(n.info, f) + styleCheckUse(n.info, f) return of tyTypeParamsHolders: return readTypeParameter(c, ty, i, n.info) @@ -1036,12 +1046,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = if fieldVisible(c, f): # is the access to a public field or in the same module or in a friend? markUsed(n.sons[1].info, f) + styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) # we now have the correct field n.typ = f.typ - if check == nil: + if check == nil: result = n - else: + else: check.sons[0] = n check.typ = n.typ result = check @@ -1049,6 +1060,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = f = getSymFromList(ty.n, i) if f != nil: markUsed(n.sons[1].info, f) + styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) n.typ = f.typ @@ -1465,6 +1477,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = macroCall.sons[0] = newSymNode(expandedSym, macroCall.info) markUsed(n.info, expandedSym) + styleCheckUse(n.info, expandedSym) for i in countup(1, macroCall.len-1): macroCall.sons[i] = semExprWithType(c, macroCall[i], {}) @@ -1538,8 +1551,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = newNode(nkCall, n.info, quotes)]) result = semExpandToAst(c, result) -proc tryExpr(c: PContext, n: PNode, - flags: TExprFlags = {}, bufferErrors = false): PNode = +proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # watch out, hacks ahead: let oldErrorCount = msgs.gErrorCounter let oldErrorMax = msgs.gErrorMax @@ -1553,7 +1565,7 @@ proc tryExpr(c: PContext, n: PNode, let oldOwnerLen = len(gOwners) let oldGenerics = c.generics let oldErrorOutputs = errorOutputs - errorOutputs = if bufferErrors: {eInMemory} else: {} + #errorOutputs = if bufferErrors: {eInMemory} else: {} let oldContextLen = msgs.getInfoContextLen() let oldInGenericContext = c.inGenericContext @@ -1821,7 +1833,7 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = addSonSkipIntLit(typ, n.sons[i].typ) result.typ = typ -proc checkInitialized(n: PNode, ids: TIntSet, info: TLineInfo) = +proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) = case n.kind of nkRecList: for i in countup(0, sonsLen(n) - 1): @@ -1902,6 +1914,7 @@ proc semBlock(c: PContext, n: PNode): PNode = addDecl(c, labl) n.sons[0] = newSymNode(labl, n.sons[0].info) suggestSym(n.sons[0].info, labl) + styleCheckDef(labl) n.sons[1] = semExpr(c, n.sons[1]) n.typ = n.sons[1].typ if isEmptyType(n.typ): n.kind = nkBlockStmt @@ -1932,11 +1945,22 @@ proc semExport(c: PContext, n: PNode): PNode = if s == nil: localError(a.info, errGenerated, "invalid expr for 'export': " & renderTree(a)) - while s != nil: - if s.kind in ExportableSymKinds+{skModule}: - x.add(newSymNode(s, a.info)) - strTableAdd(c.module.tab, s) - s = nextOverloadIter(o, c, a) + elif s.kind == skModule: + # forward everything from that module: + strTableAdd(c.module.tab, s) + x.add(newSymNode(s, a.info)) + var ti: TTabIter + var it = initTabIter(ti, s.tab) + while it != nil: + if it.kind in ExportableSymKinds+{skModule}: + strTableAdd(c.module.tab, it) + it = nextIter(ti, s.tab) + else: + while s != nil: + if s.kind in ExportableSymKinds+{skModule}: + x.add(newSymNode(s, a.info)) + strTableAdd(c.module.tab, s) + s = nextOverloadIter(o, c, a) when false: if c.module.ast.isNil: c.module.ast = newNodeI(nkStmtList, n.info) @@ -2021,9 +2045,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = checkMinSonsLen(n, 1) let mode = if nfDotField in n.flags: {} else: {checkUndeclared} var s = qualifiedLookUp(c, n.sons[0], mode) - if s != nil: - if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr: - pretty.checkUse(n.sons[0].sons[1].info, s) + if s != nil: + #if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr: + # pretty.checkUse(n.sons[0].sons[1].info, s) case s.kind of skMacro: if sfImmediate notin s.flags: diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 30e02dcc9..76ac23e0d 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -255,6 +255,7 @@ proc evalIs(n, a: PNode): PNode = result = newIntNode(nkIntLit, ord(t.kind == tyProc and t.callConv == ccClosure and tfIterator in t.flags)) + else: discard else: # XXX semexprs.isOpImpl is slightly different and requires a context. yay. let t2 = n[2].typ @@ -683,9 +684,9 @@ proc getConstExpr(m: PSym, n: PNode): PNode = result = evalIs(n, a) else: result = magicCall(m, n) - except EOverflow: + except OverflowError: localError(n.info, errOverOrUnderflow) - except EDivByZero: + except DivByZeroError: localError(n.info, errConstantDivisionByZero) of nkAddr: var a = getConstExpr(m, n.sons[0]) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index a004d1465..6c218fa0c 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -28,7 +28,7 @@ proc getIdentNode(n: PNode): PNode = proc semGenericStmtScope(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var TIntSet): PNode = + ctx: var IntSet): PNode = openScope(c) result = semGenericStmt(c, n, flags, ctx) closeScope(c) @@ -37,7 +37,7 @@ template macroToExpand(s: expr): expr = s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags) proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, - ctx: var TIntSet): PNode = + ctx: var IntSet): PNode = incl(s.flags, sfUsed) case s.kind of skUnknown: @@ -47,33 +47,40 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result = symChoice(c, n, s, scOpen) of skTemplate: if macroToExpand(s): + styleCheckUse(n.info, s) let n = fixImmediateParams(n) result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) else: result = symChoice(c, n, s, scOpen) - of skMacro: + of skMacro: if macroToExpand(s): + styleCheckUse(n.info, s) result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) else: result = symChoice(c, n, s, scOpen) of skGenericParam: result = newSymNodeTypeDesc(s, n.info) - of skParam: + styleCheckUse(n.info, s) + of skParam: result = n + styleCheckUse(n.info, s) of skType: if (s.typ != nil) and (s.typ.kind != tyGenericParam): result = newSymNodeTypeDesc(s, n.info) else: result = n - else: result = newSymNode(s, n.info) + styleCheckUse(n.info, s) + else: + result = newSymNode(s, n.info) + styleCheckUse(n.info, s) proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var TIntSet): PNode = + ctx: var IntSet): PNode = result = n let ident = considerQuotedIdent(n) - var s = searchInScopes(c, ident) + var s = searchInScopes(c, ident).skipAlias(n) if s == nil: if ident.id notin ctx and withinMixin notin flags: localError(n.info, errUndeclaredIdentifier, ident.s) @@ -92,7 +99,7 @@ proc newDot(n, b: PNode): PNode = result.add(b) proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var TIntSet): PNode = + ctx: var IntSet): PNode = assert n.kind == nkDotExpr let luf = if withinMixin notin flags: {checkUndeclared} else: {} @@ -104,7 +111,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, result = n let n = n[1] let ident = considerQuotedIdent(n) - var s = searchInScopes(c, ident) + var s = searchInScopes(c, ident).skipAlias(n) if s != nil and s.kind in routineKinds: if withinBind in flags: result = newDot(result, symChoice(c, n, s, scClosed)) @@ -117,8 +124,13 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, else: result = newDot(result, sym) +proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) = + let s = newSymS(skUnknown, getIdentNode(n), c) + addPrelimDecl(c, s) + styleCheckDef(n.info, s, kind) + proc semGenericStmt(c: PContext, n: PNode, - flags: TSemGenericFlags, ctx: var TIntSet): PNode = + flags: TSemGenericFlags, ctx: var IntSet): PNode = result = n if gCmd == cmdIdeTools: suggestStmt(c, n) case n.kind @@ -161,13 +173,15 @@ proc semGenericStmt(c: PContext, n: PNode, case s.kind of skMacro: if macroToExpand(s): + styleCheckUse(fn.info, s) result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) else: n.sons[0] = symChoice(c, n.sons[0], s, scOption) result = n - of skTemplate: + of skTemplate: if macroToExpand(s): + styleCheckUse(fn.info, s) let n = fixImmediateParams(n) result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) @@ -184,14 +198,17 @@ proc semGenericStmt(c: PContext, n: PNode, first = 1 of skGenericParam: result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info) + styleCheckUse(fn.info, s) first = 1 of skType: # bad hack for generics: if (s.typ != nil) and (s.typ.kind != tyGenericParam): result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info) + styleCheckUse(fn.info, s) first = 1 else: result.sons[0] = newSymNode(s, n.sons[0].info) + styleCheckUse(fn.info, s) first = 1 # Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)' # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which @@ -226,14 +243,14 @@ proc semGenericStmt(c: PContext, n: PNode, openScope(c) n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx) for i in countup(0, L - 3): - addPrelimDecl(c, newSymS(skUnknown, n.sons[i], c)) + addTempDecl(c, n.sons[i], skForVar) n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx) closeScope(c) of nkBlockStmt, nkBlockExpr, nkBlockType: checkSonsLen(n, 2) openScope(c) if n.sons[0].kind != nkEmpty: - addPrelimDecl(c, newSymS(skUnknown, n.sons[0], c)) + addTempDecl(c, n.sons[0], skLabel) n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx) closeScope(c) of nkTryStmt: @@ -256,7 +273,7 @@ proc semGenericStmt(c: PContext, n: PNode, a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) for j in countup(0, L-3): - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) + addTempDecl(c, getIdentNode(a.sons[j]), skVar) of nkGenericParams: for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] @@ -266,23 +283,23 @@ proc semGenericStmt(c: PContext, n: PNode, a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) # do not perform symbol lookup for default expressions for j in countup(0, L-3): - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) + addTempDecl(c, getIdentNode(a.sons[j]), skType) of nkConstSection: for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue if (a.kind != nkConstDef): illFormedAst(a) checkSonsLen(a, 3) - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c)) + addTempDecl(c, getIdentNode(a.sons[0]), skConst) a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx) a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx) - of nkTypeSection: + of nkTypeSection: for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue if (a.kind != nkTypeDef): illFormedAst(a) checkSonsLen(a, 3) - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c)) + addTempDecl(c, getIdentNode(a.sons[0]), skType) for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue @@ -306,9 +323,9 @@ proc semGenericStmt(c: PContext, n: PNode, of nkIdent: a = n.sons[i] else: illFormedAst(n) addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c)) - of nkObjectTy, nkTupleTy: + of nkObjectTy, nkTupleTy: discard - of nkFormalParams: + of nkFormalParams: checkMinSonsLen(n, 1) if n.sons[0].kind != nkEmpty: n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx) @@ -320,17 +337,17 @@ proc semGenericStmt(c: PContext, n: PNode, a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) for j in countup(0, L-3): - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) + addTempDecl(c, getIdentNode(a.sons[j]), skParam) of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef, nkLambdaKinds: checkSonsLen(n, bodyPos + 1) if n.kind notin nkLambdaKinds: - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c)) + addTempDecl(c, getIdentNode(n.sons[0]), skProc) openScope(c) n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], flags, ctx) if n.sons[paramsPos].kind != nkEmpty: - if n.sons[paramsPos].sons[0].kind != nkEmpty: + if n.sons[paramsPos].sons[0].kind != nkEmpty: addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info)) n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx) n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index b205eb09a..8ac3849b4 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index 1bece95c2..c685d602d 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -55,7 +55,7 @@ proc annotateType*(n: PNode, t: PType) = else: globalError(n.info, "() must have an object or tuple type") of nkBracket: - if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenarray}: + if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenArray}: n.typ = t for m in n: annotateType(m, x.elemType) else: diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index d4aeba32a..a72a6ab7d 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index 7c489c3b6..c4546f616 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -320,7 +320,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) = # since we already ensure sfAddrTaken is not in s.flags, we only need to # prevent direct assignments to the monotonic variable: let slot = c.getSlot(n[0].sym) - slot.blackListed = true + slot.blacklisted = true invalidateFacts(c.guards, n[0]) analyseSons(c, n) addAsgnFact(c.guards, n[0], n[1]) @@ -335,7 +335,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) = localError(n.info, "invalid control flow for 'parallel'") # 'break' that leaves the 'parallel' section is not valid either # or maybe we should generate a 'try' XXX - of nkVarSection: + of nkVarSection, nkLetSection: for it in n: let value = it.lastSon if value.kind != nkEmpty: @@ -396,7 +396,7 @@ proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode = proc transformSpawn(owner: PSym; n, barrier: PNode): PNode = case n.kind - of nkVarSection: + of nkVarSection, nkLetSection: result = nil for it in n: let b = it.lastSon @@ -464,6 +464,6 @@ proc liftParallel*(owner: PSym; n: PNode): PNode = result = newNodeI(nkStmtList, n.info) generateAliasChecks(a, result) result.add varSection - result.add callCodeGenProc("openBarrier", barrier) + result.add callCodegenProc("openBarrier", barrier) result.add transformSpawn(owner, body, barrier) - result.add callCodeGenProc("closeBarrier", barrier) + result.add callCodegenProc("closeBarrier", barrier) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index da4adcf49..0d8c7c479 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -57,26 +57,114 @@ discard """ c() --> we need a stack of scopes for this analysis -""" -const trackGlobals = false ## we don't need it for now + # XXX enhance the algorithm to care about 'dirty' expressions: + lock a[i].L: + inc i # mark 'i' dirty + lock a[j].L: + access a[i], a[j] # --> reject a[i] +""" type TEffects = object exc: PNode # stack of exceptions tags: PNode # list of tags - uses: PNode # list of used global variables bottom: int owner: PSym init: seq[int] # list of initialized variables guards: TModel # nested guards locked: seq[PNode] # locked locations - gcUnsafe, isRecursive: bool + gcUnsafe, isRecursive, isToplevel: bool + maxLockLevel, currLockLevel: TLockLevel PEffects = var TEffects +proc `<`(a, b: TLockLevel): bool {.borrow.} +proc `<=`(a, b: TLockLevel): bool {.borrow.} +proc `==`(a, b: TLockLevel): bool {.borrow.} +proc max(a, b: TLockLevel): TLockLevel {.borrow.} + proc isLocalVar(a: PEffects, s: PSym): bool = s.kind in {skVar, skResult} and sfGlobal notin s.flags and s.owner == a.owner +proc getLockLevel(t: PType): TLockLevel = + var t = t + # tyGenericInst(TLock {tyGenericBody}, tyStatic, tyObject): + if t.kind == tyGenericInst and t.len == 3: t = t.sons[1] + if t.kind == tyStatic and t.n != nil and t.n.kind in {nkCharLit..nkInt64Lit}: + result = t.n.intVal.TLockLevel + +proc lockLocations(a: PEffects; pragma: PNode) = + if pragma.kind != nkExprColonExpr: + localError(pragma.info, errGenerated, "locks pragma without argument") + return + var firstLL = TLockLevel(-1'i16) + for x in pragma[1]: + let thisLL = getLockLevel(x.typ) + if thisLL != 0.TLockLevel: + if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel: + localError(x.info, "invalid lock level: " & $thisLL) + elif firstLL < 0.TLockLevel: firstLL = thisLL + elif firstLL != thisLL: + localError(x.info, errGenerated, + "multi-lock requires the same static lock level for every operand") + a.maxLockLevel = max(a.maxLockLevel, firstLL) + a.locked.add x + if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel: + if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL: + localError(pragma.info, errGenerated, + "invalid nested locking") + a.currLockLevel = firstLL + +proc guardGlobal(a: PEffects; n: PNode; guard: PSym) = + # check whether the corresponding lock is held: + for L in a.locked: + if L.kind == nkSym and L.sym == guard: return + # we allow accesses nevertheless in top level statements for + # easier initialization: + #if a.isTopLevel: + # message(n.info, warnUnguardedAccess, renderTree(n)) + #else: + if not a.isTopLevel: + localError(n.info, errGenerated, "unguarded access: " & renderTree(n)) + +# 'guard*' are checks which are concerned with 'guard' annotations +# (var x{.guard: y.}: int) +proc guardDotAccess(a: PEffects; n: PNode) = + let ri = n.sons[1] + if ri.kind != nkSym or ri.sym.kind != skField: return + var g = ri.sym.guard + if g.isNil or a.isTopLevel: return + # fixup guard: + if g.kind == skUnknown: + var field: PSym = nil + var ty = n.sons[0].typ.skipTypes(abstractPtrs) + if ty.kind == tyTuple: + field = lookupInRecord(ty.n, g.name) + else: + while ty != nil and ty.kind == tyObject: + field = lookupInRecord(ty.n, g.name) + if field != nil: break + ty = ty.sons[0] + if ty == nil: break + ty = ty.skipTypes(abstractPtrs) + if field == nil: + localError(n.info, errGenerated, "invalid guard field: " & g.name.s) + return + g = field + #ri.sym.guard = field + # XXX unfortunately this is not correct for generic instantiations! + if g.kind == skField: + let dot = newNodeI(nkDotExpr, n.info, 2) + dot.sons[0] = n.sons[0] + dot.sons[1] = newSymNode(g) + dot.typ = g.typ + for L in a.locked: + #if a.guards.sameSubexprs(dot, L): return + if guards.sameTree(dot, L): return + localError(n.info, errGenerated, "unguarded access: " & renderTree(n)) + else: + guardGlobal(a, n, g) + proc initVar(a: PEffects, n: PNode) = if n.kind != nkSym: return let s = n.sym @@ -93,12 +181,9 @@ proc initVarViaNew(a: PEffects, n: PNode) = # are initialized: initVar(a, n) -when trackGlobals: - proc addUse(a: PEffects, e: PNode) = - var aa = a.uses - for i in 0 .. <aa.len: - if aa[i].sym.id == e.sym.id: return - a.uses.add(e) +proc warnAboutGcUnsafe(n: PNode) = + #assert false + message(n.info, warnGcUnsafe, renderTree(n)) proc useVar(a: PEffects, n: PNode) = let s = n.sym @@ -110,12 +195,11 @@ proc useVar(a: PEffects, n: PNode) = message(n.info, warnUninit, s.name.s) # prevent superfluous warnings about the same variable: a.init.add s.id - if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind == skVar: - when trackGlobals: - a.addUse(copyNode(n)) + if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}: + if s.guard != nil: guardGlobal(a, n, s.guard) if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and tfGcSafe notin s.typ.flags: - if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n)) + if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) a.gcUnsafe = true type @@ -130,20 +214,27 @@ proc addToIntersection(inter: var TIntersection, s: int) = proc throws(tracked, n: PNode) = if n.typ == nil or n.typ.kind != tyError: tracked.add n - + +proc getEbase(): PType = + result = if getCompilerProc("Exception") != nil: sysTypeFromName"Exception" + else: sysTypeFromName"E_Base" + proc excType(n: PNode): PType = # reraise is like raising E_Base: - let t = if n.kind == nkEmpty: sysTypeFromName"E_Base" else: n.typ + let t = if n.kind == nkEmpty: getEbase() else: n.typ result = skipTypes(t, skipPtrs) proc createRaise(n: PNode): PNode = result = newNode(nkType) - result.typ = sysTypeFromName"E_Base" + result.typ = getEbase() if not n.isNil: result.info = n.info proc createTag(n: PNode): PNode = result = newNode(nkType) - result.typ = sysTypeFromName"TEffect" + if getCompilerProc("RootEffect") != nil: + result.typ = sysTypeFromName"RootEffect" + else: + result.typ = sysTypeFromName"TEffect" if not n.isNil: result.info = n.info proc createAnyGlobal(n: PNode): PNode = @@ -179,17 +270,11 @@ proc mergeTags(a: PEffects, b, comesFrom: PNode) = else: for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil) -when trackGlobals: - proc mergeUses(a: PEffects, b, comesFrom: PNode) = - if b.isNil: - addUse(a, createAnyGlobal(comesFrom)) - else: - for effect in items(b): addUse(a, effect) - proc listEffects(a: PEffects) = for e in items(a.exc): message(e.info, hintUser, typeToString(e.typ)) for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ)) - for e in items(a.uses): message(e.info, hintUser, e.sym.name.s) + #if a.maxLockLevel != 0: + # message(e.info, hintUser, "lockLevel: " & a.maxLockLevel) proc catches(tracked: PEffects, e: PType) = let e = skipTypes(e, skipPtrs) @@ -322,6 +407,25 @@ proc importedFromC(n: PNode): bool = # when imported from C, we assume GC-safety. result = n.kind == nkSym and sfImportc in n.sym.flags +proc getLockLevel(s: PSym): TLockLevel = + result = s.typ.lockLevel + if result == UnspecifiedLockLevel: + if {sfImportc, sfNoSideEffect} * s.flags != {} or + tfNoSideEffect in s.typ.flags: + result = 0.TLockLevel + else: + result = UnknownLockLevel + #message(s.info, warnUser, "FOR THIS " & s.name.s) + +proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) = + if lockLevel >= tracked.currLockLevel: + # if in lock section: + if tracked.currLockLevel > 0.TLockLevel: + localError n.info, errGenerated, + "expected lock level < " & $tracked.currLockLevel & + " but got lock level " & $lockLevel + tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel) + proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = let pragma = s.ast.sons[pragmasPos] let spec = effectSpec(pragma, wRaises) @@ -331,8 +435,9 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = mergeTags(tracked, tagSpec, n) if notGcSafe(s.typ) and sfImportc notin s.flags: - if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n)) + if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) tracked.gcUnsafe = true + mergeLockLevels(tracked, n, s.getLockLevel) proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = let n = n.skipConv @@ -352,8 +457,22 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree) of impYes: discard +proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) = + addEffect(tracked, createRaise(n)) + addTag(tracked, createTag(n)) + let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel + else: op.lockLevel + #if lockLevel == UnknownLockLevel: + # message(n.info, warnUser, "had to assume the worst here") + mergeLockLevels(tracked, n, lockLevel) + +proc isOwnedProcVar(n: PNode; owner: PSym): bool = + # XXX prove the soundness of this effect system rule + result = n.kind == nkSym and n.sym.kind == skParam and owner == n.sym.owner + proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = - let op = skipConvAndClosure(n).typ + let a = skipConvAndClosure(n) + let op = a.typ if op != nil and op.kind == tyProc and n.kind != nkNilLit: internalAssert op.n.sons[0].kind == nkEffectList var effectList = op.n.sons[0] @@ -365,21 +484,18 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = # we have no explicit effects but it's a forward declaration and so it's # stated there are no additional effects, so simply propagate them: propagateEffects(tracked, n, n.sym) - else: + elif not isOwnedProcVar(a, tracked.owner): # we have no explicit effects so assume the worst: - addEffect(tracked, createRaise(n)) - addTag(tracked, createTag(n)) - when trackGlobals: addUse(tracked, createAnyGlobal(n)) + assumeTheWorst(tracked, n, op) # assume GcUnsafe unless in its type; 'forward' does not matter: - if notGcSafe(op): - if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n)) + if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner): + if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) tracked.gcUnsafe = true else: mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n) - when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n) if notGcSafe(op): - if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n)) + if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) tracked.gcUnsafe = true notNilCheck(tracked, n, paramType) @@ -506,8 +622,12 @@ proc track(tracked: PEffects, n: PNode) = # are indistinguishable from normal procs (both have tyProc type) and # we can detect them only by checking for attached nkEffectList. if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList: - if a.kind == nkSym and a.sym == tracked.owner: - tracked.isRecursive = true + if a.kind == nkSym: + if a.sym == tracked.owner: tracked.isRecursive = true + # even for recursive calls we need to check the lock levels (!): + mergeLockLevels(tracked, n, a.sym.getLockLevel) + else: + mergeLockLevels(tracked, n, op.lockLevel) var effectList = op.n.sons[0] if a.kind == nkSym and a.sym.kind == skMethod: propagateEffects(tracked, n, a.sym) @@ -515,18 +635,14 @@ proc track(tracked: PEffects, n: PNode) = if isForwardedProc(a): propagateEffects(tracked, n, a.sym) elif isIndirectCall(a, tracked.owner): - addEffect(tracked, createRaise(n)) - addTag(tracked, createTag(n)) - when trackGlobals: addUse(tracked, createAnyGlobal(n)) - # XXX handle 'gcsafe' properly for callbacks! + assumeTheWorst(tracked, n, op) else: mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n) - when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n) if notGcSafe(op) and not importedFromC(a): # and it's not a recursive call: if not (a.kind == nkSym and a.sym == tracked.owner): - message(n.info, warnGcUnsafe, renderTree(n)) + warnAboutGcUnsafe(n) tracked.gcUnsafe = true for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i)) if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}: @@ -534,6 +650,9 @@ proc track(tracked: PEffects, n: PNode) = initVarViaNew(tracked, n.sons[1]) for i in 0 .. <safeLen(n): track(tracked, n.sons[i]) + of nkDotExpr: + guardDotAccess(tracked, n) + for i in 0 .. <len(n): track(tracked, n.sons[i]) of nkCheckedFieldExpr: track(tracked, n.sons[0]) if warnProveField in gNotes: checkFieldAccess(tracked.guards, n) @@ -547,7 +666,7 @@ proc track(tracked: PEffects, n: PNode) = addAsgnFact(tracked.guards, n.sons[0], n.sons[1]) notNilCheck(tracked, n.sons[1], n.sons[0].typ) when false: cstringCheck(tracked, n) - of nkVarSection: + of nkVarSection, nkLetSection: for child in n: let last = lastSon(child) if child.kind == nkIdentDefs and last.kind != nkEmpty: @@ -589,6 +708,16 @@ proc track(tracked: PEffects, n: PNode) = if sfDiscriminant in x.sons[0].sym.flags: addDiscriminantFact(tracked.guards, x) setLen(tracked.guards, oldFacts) + of nkPragmaBlock: + let pragmaList = n.sons[0] + let oldLocked = tracked.locked.len + let oldLockLevel = tracked.currLockLevel + for i in 0 .. <pragmaList.len: + if whichPragma(pragmaList.sons[i]) == wLocks: + lockLocations(tracked, pragmaList.sons[i]) + track(tracked, n.lastSon) + setLen(tracked.locked, oldLocked) + tracked.currLockLevel = oldLockLevel of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef: discard @@ -639,6 +768,16 @@ proc checkMethodEffects*(disp, branch: PSym) = if sfThread in disp.flags and notGcSafe(branch.typ): localError(branch.info, "base method is GC-safe, but '$1' is not" % branch.name.s) + if branch.typ.lockLevel > disp.typ.lockLevel: + when true: + message(branch.info, warnLockLevel, + "base method has lock level $1, but dispatcher has $2" % + [$branch.typ.lockLevel, $disp.typ.lockLevel]) + else: + # XXX make this an error after bigbreak has been released: + localError(branch.info, + "base method has lock level $1, but dispatcher has $2" % + [$branch.typ.lockLevel, $disp.typ.lockLevel]) proc setEffectsForProcType*(t: PType, n: PNode) = var effects = t.n.sons[0] @@ -659,14 +798,13 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) = newSeq(effects.sons, effectListLen) effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info) effects.sons[tagEffects] = newNodeI(nkArgList, s.info) - effects.sons[usesEffects] = newNodeI(nkArgList, s.info) t.exc = effects.sons[exceptionEffects] t.tags = effects.sons[tagEffects] - t.uses = effects.sons[usesEffects] t.owner = s t.init = @[] t.guards = @[] + t.locked = @[] proc trackProc*(s: PSym, body: PNode) = var effects = s.typ.n.sons[0] @@ -700,9 +838,17 @@ proc trackProc*(s: PSym, body: PNode) = if optThreadAnalysis in gGlobalOptions: if sfThread in s.flags and t.gcUnsafe: - #localError(s.info, warnGcUnsafe2, s.name.s) - localError(s.info, "'$1' is not GC-safe" % s.name.s) + if optThreads in gGlobalOptions: + localError(s.info, "'$1' is not GC-safe" % s.name.s) + else: + localError(s.info, warnGcUnsafe2, s.name.s) if not t.gcUnsafe: s.typ.flags.incl tfGcSafe + if s.typ.lockLevel == UnspecifiedLockLevel: + s.typ.lockLevel = t.maxLockLevel + elif t.maxLockLevel > s.typ.lockLevel: + localError(s.info, + "declared lock level is $1, but real lock level is $2" % + [$s.typ.lockLevel, $t.maxLockLevel]) proc trackTopLevelStmt*(module: PSym; n: PNode) = if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, @@ -711,5 +857,5 @@ proc trackTopLevelStmt*(module: PSym; n: PNode) = var effects = newNode(nkEffectList, n.info) var t: TEffects initEffects(effects, module, t) - + t.isToplevel = true track(t, n) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d394a2ae5..255507548 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -29,17 +29,18 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = of nkIdent: s = lookUp(c, n.sons[0]) of nkSym: s = n.sons[0].sym else: illFormedAst(n) - if s.kind == skLabel and s.owner.id == c.p.owner.id: + if s.kind == skLabel and s.owner.id == c.p.owner.id: var x = newSymNode(s) x.info = n.info incl(s.flags, sfUsed) n.sons[0] = x suggestSym(x.info, s) + styleCheckUse(x.info, s) else: localError(n.info, errInvalidControlFlowX, s.name.s) else: localError(n.info, errGenerated, "'continue' cannot have a label") - elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0): + elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0): localError(n.info, errInvalidControlFlowX, renderTree(n, {renderNoComments})) @@ -198,11 +199,12 @@ proc semCase(c: PContext, n: PNode): PNode = var covered: BiggestInt = 0 var typ = commonTypeBegin var hasElse = false + var notOrdinal = false case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool: chckCovered = true of tyFloat..tyFloat128, tyString, tyError: - discard + notOrdinal = true else: localError(n.info, errSelectorMustBeOfCertainTypes) return @@ -232,6 +234,9 @@ proc semCase(c: PContext, n: PNode): PNode = hasElse = true else: illFormedAst(x) + if notOrdinal and not hasElse: + message(n.info, warnDeprecated, + "use 'else: discard'; non-ordinal case without 'else'") if chckCovered: if covered == toCover(n.sons[0].typ): hasElse = true @@ -263,7 +268,7 @@ proc semTry(c: PContext, n: PNode): PNode = checkMinSonsLen(a, 1) var length = sonsLen(a) if a.kind == nkExceptBranch: - # XXX what does this do? so that ``except [a, b, c]`` is supported? + # so that ``except [a, b, c]`` is supported: if length == 2 and a.sons[0].kind == nkBracket: a.sons[0..0] = a.sons[0].sons length = a.sonsLen @@ -323,6 +328,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = else: result = semIdentWithPragma(c, kind, n, {}) suggestSym(n.info, result) + styleCheckDef(result) proc checkNilable(v: PSym) = if sfGlobal in v.flags and {tfNotNil, tfNeedsInit} * v.typ.flags != {}: @@ -350,9 +356,14 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var def: PNode if a.sons[length-1].kind != nkEmpty: def = semExprWithType(c, a.sons[length-1], {efAllowDestructor}) - # BUGFIX: ``fitNode`` is needed here! - # check type compability between def.typ and typ: - if typ != nil: def = fitNode(c, typ, def) + if typ != nil: + if typ.isMetaType: + def = inferWithMetatype(c, typ, def) + typ = def.typ + else: + # BUGFIX: ``fitNode`` is needed here! + # check type compability between def.typ and typ + def = fitNode(c, typ, def) else: typ = skipIntLit(def.typ) if typ.kind in {tySequence, tyArray, tySet} and @@ -441,7 +452,7 @@ proc semConst(c: PContext, n: PNode): PNode = if typ == nil: localError(a.sons[2].info, errConstExprExpected) continue - if not typeAllowed(typ, skConst): + if not typeAllowed(typ, skConst) and def.kind != nkNilLit: localError(a.info, errXisNoType, typeToString(typ)) continue v.typ = typ @@ -614,6 +625,7 @@ proc addForVarDecl(c: PContext, v: PSym) = proc symForVar(c: PContext, n: PNode): PSym = let m = if n.kind == nkPragmaExpr: n.sons[0] else: n result = newSymG(skForVar, m, c) + styleCheckDef(result) proc semForVars(c: PContext, n: PNode): PNode = result = n @@ -1021,7 +1033,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = sameType(s.typ.sons[1], s.typ.sons[0]): # Note: we store the deepCopy in the base of the pointer to mitigate # the problem that pointers are structural types: - let t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst) + var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst) + while true: + if t.kind == tyGenericBody: t = t.lastSon + elif t.kind == tyGenericInvokation: t = t.sons[0] + else: break if t.kind in {tyObject, tyDistinct, tyEnum}: if t.deepCopy.isNil: t.deepCopy = s else: @@ -1036,6 +1052,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = of "=": discard else: localError(n.info, errGenerated, "'destroy' or 'deepCopy' expected for 'override'") + incl(s.flags, sfUsed) type TProcCompilationSteps = enum @@ -1292,9 +1309,14 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode = let pragmaList = n.sons[0] pragma(c, nil, pragmaList, exprPragmas) result = semExpr(c, n.sons[1]) + n.sons[1] = result for i in 0 .. <pragmaList.len: - if whichPragma(pragmaList.sons[i]) == wLine: - setLine(result, pragmaList.sons[i].info) + case whichPragma(pragmaList.sons[i]) + of wLine: setLine(result, pragmaList.sons[i].info) + of wLocks: + result = n + result.typ = n.sons[1].typ + else: discard proc semStaticStmt(c: PContext, n: PNode): PNode = let a = semStmt(c, n.sons[0]) @@ -1393,6 +1415,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = else: discard if result.len == 1: result = result.sons[0] + when defined(nimfix): + if result.kind == nkCommentStmt and not result.comment.isNil and + not (result.comment[0] == '#' and result.comment[1] == '#'): + # it is an old-style comment statement: we replace it with 'discard ""': + prettybase.replaceComment(result.info) when false: # a statement list (s; e) has the type 'e': if result.kind == nkStmtList and result.len > 0: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index ee8b1ccb8..0a647a65d 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -71,7 +71,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode = addSon(result, newSymNode(a, n.info)) a = nextOverloadIter(o, c, n) -proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode = +proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode = for i in 0 .. < n.len: var a = n.sons[i] # If 'a' is an overloaded symbol, we used to use the first symbol @@ -91,7 +91,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode = illFormedAst(a) result = newNodeI(nkEmpty, n.info) -proc semMixinStmt(c: PContext, n: PNode, toMixin: var TIntSet): PNode = +proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode = for i in 0 .. < n.len: toMixin.incl(considerQuotedIdent(n.sons[i]).id) result = newNodeI(nkEmpty, n.info) @@ -106,7 +106,7 @@ proc replaceIdentBySym(n: var PNode, s: PNode) = type TemplCtx {.pure, final.} = object c: PContext - toBind, toMixin, toInject: TIntSet + toBind, toMixin, toInject: IntSet owner: PSym proc getIdentNode(c: var TemplCtx, n: PNode): PNode = @@ -146,6 +146,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode = if s.owner == c.owner and s.kind == skParam: incl(s.flags, sfUsed) result = newSymNode(s, n.info) + styleCheckUse(n.info, s) else: for i in 0 .. <n.safeLen: result.sons[i] = onlyReplaceParams(c, n.sons[i]) @@ -183,12 +184,15 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = if not isTemplParam(c, ident): let local = newGenSym(k, ident, c) addPrelimDecl(c.c, local) + styleCheckDef(n.info, local) replaceIdentBySym(n, newSymNode(local, n.info)) else: replaceIdentBySym(n, ident) proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode = incl(s.flags, sfUsed) + # we do not call styleCheckUse here, as the identifier is not really + # resolved here. We will fixup the used identifiers later. case s.kind of skUnknown: # Introduced in this pass! Leave it as an identifier. @@ -204,7 +208,8 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode = result = newSymNodeTypeDesc(s, n.info) else: result = n - else: result = newSymNode(s, n.info) + else: + result = newSymNode(s, n.info) proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode = result = n @@ -214,6 +219,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode = if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags): incl(s.flags, sfUsed) result = newSymNode(s, n.info) + styleCheckUse(n.info, s) else: for i in countup(0, safeLen(n) - 1): result.sons[i] = semRoutineInTemplName(c, n.sons[i]) @@ -228,6 +234,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode = var s = newGenSym(k, ident, c) s.ast = n addPrelimDecl(c.c, s) + styleCheckDef(n.info, s) n.sons[namePos] = newSymNode(s, n.sons[namePos].info) else: n.sons[namePos] = ident @@ -261,6 +268,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = if s.owner == c.owner and s.kind == skParam: incl(s.flags, sfUsed) result = newSymNode(s, n.info) + styleCheckUse(n.info, s) elif contains(c.toBind, s.id): result = symChoice(c.c, n, s, scClosed) elif contains(c.toMixin, s.name.id): @@ -270,6 +278,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = # var yz: T incl(s.flags, sfUsed) result = newSymNode(s, n.info) + styleCheckUse(n.info, s) else: result = semTemplSymbol(c.c, n, s) of nkBind: @@ -322,6 +331,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = # labels are always 'gensym'ed: let s = newGenSym(skLabel, n.sons[0], c) addPrelimDecl(c.c, s) + styleCheckDef(s) n.sons[0] = newSymNode(s, n.sons[0].info) n.sons[1] = semTemplBody(c, n.sons[1]) closeScope(c) @@ -456,6 +466,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = incl(s.flags, sfGlobal) else: s = semIdentVis(c, skTemplate, n.sons[0], {}) + styleCheckDef(s) # check parameter list: s.scope = c.currentScope pushOwner(s) @@ -527,6 +538,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = # semtypes.addParamOrResult). Within the pattern we have to ensure # to use the param with the proper type though: incl(s.flags, sfUsed) + styleCheckUse(n.info, s) let x = c.owner.typ.n.sons[s.position+1].sym assert x.name == s.name result = newSymNode(x, n.info) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 53fe4e266..b3ff6c82a 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -82,6 +82,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = incl(e.flags, sfExported) if not isPure: strTableAdd(c.module.tab, e) addSon(result.n, newSymNode(e)) + styleCheckDef(e) if sfGenSym notin e.flags and not isPure: addDecl(c, e) inc(counter) if not hasNull: incl(result.flags, tfNeedsInit) @@ -92,7 +93,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType = var base = semTypeNode(c, n.sons[1], nil) addSonSkipIntLit(result, base) if base.kind == tyGenericInst: base = lastSon(base) - if base.kind != tyGenericParam: + if base.kind != tyGenericParam: if not isOrdinalType(base): localError(n.info, errOrdinalTypeExpected) elif lengthOrd(base) > MaxSetElements: @@ -279,9 +280,15 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = if n.kind == nkSym: result = n.sym else: - result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) + when defined(nimfix): + result = pickSym(c, n, skType) + if result.isNil: + result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) + else: + result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) if result != nil: markUsed(n.info, result) + styleCheckUse(n.info, result) if result.kind == skParam and result.typ.kind == tyTypeDesc: # This is a typedesc param. is it already bound? # it's not bound when it's used multiple times in the @@ -358,7 +365,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = else: addSon(result.n, newSymNode(field)) addSonSkipIntLit(result, typ) - if gCmd == cmdPretty: checkDef(a.sons[j], field) + if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field) proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym = @@ -394,7 +401,7 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, else: discard else: result = semIdentVis(c, kind, n, allowed) - if gCmd == cmdPretty: checkDef(n, result) + if gCmd == cmdPretty: styleCheckDef(n.info, result) proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) = let ex = t[branchIndex][currentEx].skipConv @@ -461,9 +468,9 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, swap(branch.sons[L-2], branch.sons[L-1]) checkForOverlap(c, t, i, branchIndex) -proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, +proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, father: PNode, rectype: PType) -proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int, +proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int, father: PNode, rectype: PType) = var a = copyNode(n) checkMinSonsLen(n, 2) @@ -498,7 +505,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int, localError(a.info, errNotAllCasesCovered) addSon(father, a) -proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, +proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, father: PNode, rectype: PType) = if n == nil: return case n.kind @@ -524,7 +531,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, else: illFormedAst(n) if c.inGenericContext > 0: # use a new check intset here for each branch: - var newCheck: TIntSet + var newCheck: IntSet assign(newCheck, check) var newPos = pos var newf = newNodeI(nkRecList, n.info) @@ -574,11 +581,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, localError(n.sons[i].info, errAttemptToRedefine, f.name.s) if a.kind == nkEmpty: addSon(father, newSymNode(f)) else: addSon(a, newSymNode(f)) + styleCheckDef(f) if a.kind != nkEmpty: addSon(father, a) of nkEmpty: discard else: illFormedAst(n) -proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int, +proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int, n: PNode) = case n.kind of nkRecCase: @@ -597,7 +605,7 @@ proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int, inc(pos) else: internalError(n.info, "addInheritedFieldsAux()") -proc addInheritedFields(c: PContext, check: var TIntSet, pos: var int, +proc addInheritedFields(c: PContext, check: var IntSet, pos: var int, obj: PType) = if (sonsLen(obj) > 0) and (obj.sons[0] != nil): addInheritedFields(c, check, pos, obj.sons[0]) @@ -814,10 +822,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, for i in 1 .. <paramType.sonsLen: let lifted = liftingWalk(paramType.sons[i]) if lifted != nil: paramType.sons[i] = lifted - - let expanded = instGenericContainer(c, info, paramType, - allowMetaTypes = true) - result = liftingWalk(expanded, true) + when false: + let expanded = instGenericContainer(c, info, paramType, + allowMetaTypes = true) + result = liftingWalk(expanded, true) of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true)) @@ -828,6 +836,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, of tyGenericParam: markUsed(info, paramType.sym) + styleCheckUse(info, paramType.sym) if tfWildcard in paramType.flags: paramType.flags.excl tfWildcard paramType.sym.kind = skType @@ -847,7 +856,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType, kind: TSymKind): PType = var res: PNode - cl: TIntSet + cl: IntSet checkMinSonsLen(n, 1) result = newOrPrevType(tyProc, prev, c) result.callConv = lastOptionEntry(c).defaultCC @@ -913,7 +922,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, addSon(result.n, newSymNode(arg)) rawAddSon(result, finalType) addParamOrResult(c, arg, kind) - if gCmd == cmdPretty: checkDef(a.sons[j], arg) + if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, arg) var r: PType if n.sons[0].kind != nkEmpty: @@ -1188,6 +1197,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = assignType(prev, t) result = prev markUsed(n.info, n.sym) + styleCheckUse(n.info, n.sym) else: if n.sym.kind != skError: localError(n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) @@ -1234,7 +1244,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = proc setMagicType(m: PSym, kind: TTypeKind, size: int) = m.typ.kind = kind - m.typ.align = size + m.typ.align = size.int16 m.typ.size = size proc processMagicType(c: PContext, m: PSym) = @@ -1332,6 +1342,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = if def.typ.kind != tyTypeDesc: typ = newTypeWithSons(c, tyStatic, @[def.typ]) else: + # the following line fixes ``TV2*[T:SomeNumber=TR] = array[0..1, T]`` + # from manyloc/named_argument_bug/triengine: + def.typ = def.typ.skipTypes({tyTypeDesc}) if not containsGenericType(def.typ): def = fitNode(c, typ, def) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 9f0a4100d..9c15be635 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -216,7 +216,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = result.typ = replaceTypeVarsT(cl, s.typ) result.ast = replaceTypeVarsN(cl, s.ast) -proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = +proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = result = PType(idTableGet(cl.typeMap, t)) if result == nil: if cl.allowMetaTypes or tfRetType in t.flags: return @@ -299,6 +299,11 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = if newbody.isGenericAlias: newbody = newbody.skipGenericAlias rawAddSon(result, newbody) checkPartialConstructedType(cl.info, newbody) + let dc = newbody.deepCopy + if dc != nil and sfFromGeneric notin newbody.deepCopy.flags: + # 'deepCopy' needs to be instantiated for + # generics *when the type is constructed*: + newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info) proc eraseVoidParams*(t: PType) = if t.sons[0] != nil and t.sons[0].kind == tyEmpty: diff --git a/compiler/service.nim b/compiler/service.nim index 22f5c6e33..4a1b296cd 100644 --- a/compiler/service.nim +++ b/compiler/service.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -25,39 +25,17 @@ var lastCaasCmd* = "" # in caas mode, the list of defines and options will be given at start-up? # it's enough to check that the previous compilation command is the same? - arguments* = "" - # the arguments to be passed to the program that - # should be run proc processCmdLine*(pass: TCmdLinePass, cmd: string) = var p = parseopt.initOptParser(cmd) var argsCount = 0 - while true: + while true: parseopt.next(p) case p.kind - of cmdEnd: break - of cmdLongoption, cmdShortOption: - # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") - # we fix this here - var bracketLe = strutils.find(p.key, '[') - if bracketLe >= 0: - var key = substr(p.key, 0, bracketLe - 1) - var val = substr(p.key, bracketLe + 1) & ':' & p.val - processSwitch(key, val, pass, gCmdLineInfo) - else: - processSwitch(p.key, p.val, pass, gCmdLineInfo) + of cmdEnd: break + of cmdLongoption, cmdShortOption: processSwitch(pass, p) of cmdArgument: - if argsCount == 0: - options.command = p.key - else: - if pass == passCmd1: options.commandArgs.add p.key - if argsCount == 1: - # support UNIX style filenames anywhere for portable build scripts: - options.gProjectName = unixToNativePath(p.key) - arguments = cmdLineRest(p) - break - inc argsCount - + if processArgument(pass, p, argsCount): break if pass == passCmd2: if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run": rawMessage(errArgsNeedRunOption, []) @@ -84,9 +62,9 @@ proc serve*(action: proc (){.nimcall.}) = of "tcp", "": when useCaas: var server = socket() - if server == invalidSocket: osError(osLastError()) + if server == invalidSocket: raiseOSError(osLastError()) let p = getConfigVar("server.port") - let port = if p.len > 0: parseInt(p).TPort else: 6000.TPort + let port = if p.len > 0: parseInt(p).Port else: 6000.Port server.bindAddr(port, getConfigVar("server.address")) var inp = "".TaintedString server.listen() diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index e5bf08097..4a3773ed8 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,7 +12,8 @@ import intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, - magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees + magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees, + nimfix.pretty when not defined(noDocgen): import docgen @@ -21,6 +22,7 @@ type TCandidateState* = enum csEmpty, csMatch, csNoMatch + CandidateErrors* = seq[PSym] TCandidate* {.final.} = object c*: PContext exactMatches*: int # also misused to prefer iters over procs @@ -44,7 +46,7 @@ type # a distrinct type typedescMatched: bool inheritancePenalty: int # to prefer closest father object type - errors*: seq[string] # additional clarifications to be displayed to the + errors*: CandidateErrors # additional clarifications to be displayed to the # user if overload resolution fails TTypeRelation* = enum # order is important! @@ -201,16 +203,17 @@ proc writeMatches*(c: TCandidate) = writeln(stdout, "intconv matches: " & $c.intConvMatches) writeln(stdout, "generic matches: " & $c.genericMatches) -proc argTypeToString(arg: PNode): string = +proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string = if arg.kind in nkSymChoices: - result = typeToString(arg[0].typ) + result = typeToString(arg[0].typ, prefer) for i in 1 .. <arg.len: result.add(" | ") - result.add typeToString(arg[i].typ) + result.add typeToString(arg[i].typ, prefer) else: - result = arg.typ.typeToString + result = arg.typ.typeToString(prefer) -proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string = +proc describeArgs*(c: PContext, n: PNode, startIdx = 1; + prefer: TPreferedDesc = preferName): string = result = "" for i in countup(startIdx, n.len - 1): var arg = n.sons[i] @@ -226,7 +229,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string = arg = c.semOperand(c, n.sons[i]) n.sons[i] = arg if arg.typ.kind == tyError: return - add(result, argTypeToString(arg)) + add(result, argTypeToString(arg, prefer)) if i != sonsLen(n) - 1: add(result, ", ") proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation @@ -479,8 +482,8 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, dummyParam.typ = dummyType addDecl(c, dummyParam) - var checkedBody = c.semTryExpr(c, body.n[3].copyTree, bufferErrors = false) - m.errors = bufferedMsgs + var checkedBody = c.semTryExpr(c, body.n[3].copyTree) + #m.errors = bufferedMsgs clearBufferedMsgs() if checkedBody == nil: return isNone @@ -1272,6 +1275,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, else: # only one valid interpretation found: markUsed(arg.info, arg.sons[best].sym) + styleCheckUse(arg.info, arg.sons[best].sym) result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best], argOrig) @@ -1319,7 +1323,7 @@ proc incrIndexType(t: PType) = inc t.sons[0].n.sons[1].intVal proc matchesAux(c: PContext, n, nOrig: PNode, - m: var TCandidate, marker: var TIntSet) = + m: var TCandidate, marker: var IntSet) = template checkConstraint(n: expr) {.immediate, dirty.} = if not formal.constraint.isNil: if matchNodeKinds(formal.constraint, n): @@ -1480,8 +1484,23 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool = # instantiate generic converters for that result = res != nil +proc instDeepCopy*(c: PContext; dc: PSym; t: PType; info: TLineInfo): PSym {. + procvar.} = + var m: TCandidate + initCandidate(c, m, dc.typ) + var f = dc.typ.sons[1] + if f.kind in {tyRef, tyPtr}: f = f.lastSon + if typeRel(m, f, t) == isNone: + localError(info, errGenerated, "cannot instantiate 'deepCopy'") + else: + result = c.semGenerateInstance(c, dc, m.bindings, info) + assert sfFromGeneric in result.flags + include suggest +when not declared(tests): + template tests(s: stmt) {.immediate.} = discard + tests: var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo()) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index c2bdfc5c3..c700db323 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -11,7 +11,7 @@ # included from sigmatch.nim -import algorithm, sequtils, pretty +import algorithm, sequtils const sep = '\t' @@ -331,7 +331,6 @@ proc markUsed(info: TLineInfo; s: PSym) = if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s) if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s) suggestSym(info, s) - if gCmd == cmdPretty: checkUse(info, s) proc useSym*(sym: PSym): PNode = result = newSymNode(sym) diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index d5062544f..61677a641 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -44,7 +44,7 @@ proc parseTopLevelStmt*(p: var TParsers): PNode proc parseFile(fileIdx: int32): PNode = var p: TParsers - f: TFile + f: File let filename = fileIdx.toFullPath if not open(f, filename): rawMessage(errCannotOpenFile, filename) diff --git a/compiler/tccgen.nim b/compiler/tccgen.nim index a571d416e..0082dfcbb 100644 --- a/compiler/tccgen.nim +++ b/compiler/tccgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/transf.nim b/compiler/transf.nim index 1ec31d605..6196512ba 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -785,8 +785,8 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode = # result = lambdalifting.liftIterator(prc, result) incl(result.flags, nfTransf) when useEffectSystem: trackProc(prc, result) - if prc.name.s == "testbody": - echo renderTree(result) + #if prc.name.s == "testbody": + # echo renderTree(result) proc transformStmt*(module: PSym, n: PNode): PNode = if nfTransf in n.flags: diff --git a/compiler/trees.nim b/compiler/trees.nim index 35e9334cc..b1edd21f3 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/treetab.nim b/compiler/treetab.nim index ecb8fb083..63f3fc6e2 100644 --- a/compiler/treetab.nim +++ b/compiler/treetab.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/types.nim b/compiler/types.nim index c04413857..87f2e1a59 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -16,21 +16,20 @@ proc firstOrd*(t: PType): BiggestInt proc lastOrd*(t: PType): BiggestInt proc lengthOrd*(t: PType): BiggestInt type - TPreferedDesc* = enum - preferName, preferDesc, preferExported + TPreferedDesc* = enum + preferName, preferDesc, preferExported, preferModuleInfo -proc typeToString*(typ: PType, prefer: TPreferedDesc = preferName): string -proc getProcHeader*(sym: PSym): string +proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string proc base*(t: PType): PType # ------------------- type iterator: ---------------------------------------- type - TTypeIter* = proc (t: PType, closure: PObject): bool {.nimcall.} # true if iteration should stop - TTypeMutator* = proc (t: PType, closure: PObject): PType {.nimcall.} # copy t and mutate it + TTypeIter* = proc (t: PType, closure: RootRef): bool {.nimcall.} # true if iteration should stop + TTypeMutator* = proc (t: PType, closure: RootRef): PType {.nimcall.} # copy t and mutate it TTypePredicate* = proc (t: PType): bool {.nimcall.} -proc iterOverType*(t: PType, iter: TTypeIter, closure: PObject): bool +proc iterOverType*(t: PType, iter: TTypeIter, closure: RootRef): bool # Returns result of `iter`. -proc mutateType*(t: PType, iter: TTypeMutator, closure: PObject): PType +proc mutateType*(t: PType, iter: TTypeMutator, closure: RootRef): PType # Returns result of `iter`. type @@ -121,7 +120,7 @@ proc isCompatibleToCString(a: PType): bool = (a.sons[1].kind == tyChar): result = true -proc getProcHeader(sym: PSym): string = +proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = result = sym.owner.name.s & '.' & sym.name.s & '(' var n = sym.typ.n for i in countup(1, sonsLen(n) - 1): @@ -129,13 +128,14 @@ proc getProcHeader(sym: PSym): string = if p.kind == nkSym: add(result, p.sym.name.s) add(result, ": ") - add(result, typeToString(p.sym.typ)) + add(result, typeToString(p.sym.typ, prefer)) if i != sonsLen(n)-1: add(result, ", ") else: internalError("getProcHeader") add(result, ')') - if n.sons[0].typ != nil: result.add(": " & typeToString(n.sons[0].typ)) - + if n.sons[0].typ != nil: + result.add(": " & typeToString(n.sons[0].typ, prefer)) + proc elemType*(t: PType): PType = assert(t != nil) case t.kind @@ -160,10 +160,10 @@ proc enumHasHoles(t: PType): bool = while b.kind in {tyConst, tyMutable, tyRange, tyGenericInst}: b = b.sons[0] result = b.kind == tyEnum and tfEnumHasHoles in b.flags -proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter, - closure: PObject): bool -proc iterOverNode(marker: var TIntSet, n: PNode, iter: TTypeIter, - closure: PObject): bool = +proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, + closure: RootRef): bool +proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter, + closure: RootRef): bool = if n != nil: case n.kind of nkNone..nkNilLit: @@ -174,8 +174,8 @@ proc iterOverNode(marker: var TIntSet, n: PNode, iter: TTypeIter, result = iterOverNode(marker, n.sons[i], iter, closure) if result: return -proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter, - closure: PObject): bool = +proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, + closure: RootRef): bool = result = false if t == nil: return result = iter(t, closure) @@ -190,15 +190,15 @@ proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter, if result: return if t.n != nil: result = iterOverNode(marker, t.n, iter, closure) -proc iterOverType(t: PType, iter: TTypeIter, closure: PObject): bool = +proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool = var marker = initIntSet() result = iterOverTypeAux(marker, t, iter, closure) proc searchTypeForAux(t: PType, predicate: TTypePredicate, - marker: var TIntSet): bool + marker: var IntSet): bool proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, - marker: var TIntSet): bool = + marker: var IntSet): bool = result = false case n.kind of nkRecList: @@ -220,7 +220,7 @@ proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, else: internalError(n.info, "searchTypeNodeForAux()") proc searchTypeForAux(t: PType, predicate: TTypePredicate, - marker: var TIntSet): bool = + marker: var IntSet): bool = # iterates over VALUE types! result = false if t == nil: return @@ -256,7 +256,7 @@ proc isObjectWithTypeFieldPredicate(t: PType): bool = tfFinal notin t.flags proc analyseObjectWithTypeFieldAux(t: PType, - marker: var TIntSet): TTypeFieldResult = + marker: var IntSet): TTypeFieldResult = var res: TTypeFieldResult result = frNone if t == nil: return @@ -310,8 +310,8 @@ proc containsHiddenPointer(typ: PType): bool = # that need to be copied deeply) result = searchTypeFor(typ, isHiddenPointer) -proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool -proc canFormAcycleNode(marker: var TIntSet, n: PNode, startId: int): bool = +proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool +proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = result = false if n != nil: result = canFormAcycleAux(marker, n.typ, startId) @@ -324,7 +324,7 @@ proc canFormAcycleNode(marker: var TIntSet, n: PNode, startId: int): bool = result = canFormAcycleNode(marker, n.sons[i], startId) if result: return -proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool = +proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = result = false if typ == nil: return if tfAcyclic in typ.flags: return @@ -353,10 +353,10 @@ proc canFormAcycle(typ: PType): bool = var marker = initIntSet() result = canFormAcycleAux(marker, typ, typ.id) -proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator, - closure: PObject): PType -proc mutateNode(marker: var TIntSet, n: PNode, iter: TTypeMutator, - closure: PObject): PNode = +proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, + closure: RootRef): PType +proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator, + closure: RootRef): PNode = result = nil if n != nil: result = copyNode(n) @@ -369,8 +369,8 @@ proc mutateNode(marker: var TIntSet, n: PNode, iter: TTypeMutator, for i in countup(0, sonsLen(n) - 1): addSon(result, mutateNode(marker, n.sons[i], iter, closure)) -proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator, - closure: PObject): PType = +proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, + closure: RootRef): PType = result = nil if t == nil: return result = iter(t, closure) @@ -380,7 +380,7 @@ proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator, if t.n != nil: result.n = mutateNode(marker, t.n, iter, closure) assert(result != nil) -proc mutateType(t: PType, iter: TTypeMutator, closure: PObject): PType = +proc mutateType(t: PType, iter: TTypeMutator, closure: RootRef): PType = var marker = initIntSet() result = mutateTypeAux(marker, t, iter, closure) @@ -415,10 +415,14 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = var t = typ result = "" if t == nil: return - if prefer == preferName and t.sym != nil and sfAnon notin t.sym.flags: + if prefer in {preferName, preferModuleInfo} and t.sym != nil and + sfAnon notin t.sym.flags: if t.kind == tyInt and isIntLit(t): return t.sym.name.s & " literal(" & $t.n.intVal & ")" - return t.sym.name.s + if prefer == preferName or t.sym.owner.isNil: + return t.sym.name.s + else: + return t.sym.owner.name.s & '.' & t.sym.name.s case t.kind of tyInt: if not isIntLit(t) or prefer == preferExported: @@ -492,8 +496,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = "set[" & typeToString(t.sons[0]) & ']' of tyOpenArray: result = "openarray[" & typeToString(t.sons[0]) & ']' - of tyDistinct: - result = "distinct " & typeToString(t.sons[0], preferName) + of tyDistinct: + result = "distinct " & typeToString(t.sons[0], + if prefer == preferModuleInfo: preferModuleInfo else: preferName) of tyTuple: # we iterate over t.sons here, because t.n may be nil result = "tuple[" @@ -530,15 +535,16 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if i < sonsLen(t) - 1: add(result, ", ") add(result, ')') if t.sons[0] != nil: add(result, ": " & typeToString(t.sons[0])) - var prag: string - if t.callConv != ccDefault: prag = CallingConvToStr[t.callConv] - else: prag = "" - if tfNoSideEffect in t.flags: + var prag = if t.callConv == ccDefault: "" else: CallingConvToStr[t.callConv] + if tfNoSideEffect in t.flags: addSep(prag) add(prag, "noSideEffect") if tfThread in t.flags: addSep(prag) add(prag, "gcsafe") + if t.lockLevel.ord != UnspecifiedLockLevel.ord: + addSep(prag) + add(prag, "locks: " & $t.lockLevel) if len(prag) != 0: add(result, "{." & prag & ".}") of tyVarargs, tyIter: result = typeToStr[t.kind] % typeToString(t.sons[0]) @@ -579,8 +585,7 @@ proc firstOrd(t: PType): BiggestInt = else: assert(t.n.sons[0].kind == nkSym) result = t.n.sons[0].sym.position - of tyGenericInst, tyDistinct, tyConst, tyMutable, - tyTypeDesc, tyFieldAccessor: + of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc, tyFieldAccessor: result = firstOrd(lastSon(t)) of tyOrdinal: if t.len > 0: result = firstOrd(lastSon(t)) @@ -969,6 +974,7 @@ proc inheritanceDiff*(a, b: PType): int = # | 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 a == b or a.kind == tyError or b.kind == tyError: return 0 assert a.kind == tyObject assert b.kind == tyObject var x = a @@ -1014,10 +1020,10 @@ type TTypeAllowedFlags = set[TTypeAllowedFlag] -proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, +proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, flags: TTypeAllowedFlags = {}): bool -proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind, +proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind, flags: TTypeAllowedFlags = {}): bool = result = true if n != nil: @@ -1041,7 +1047,7 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]], a = a.sons[i] result = a.kind == last -proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, +proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, flags: TTypeAllowedFlags = {}): bool = assert(kind in {skVar, skLet, skConst, skParam, skResult}) # if we have already checked the type, return true, because we stop the @@ -1207,8 +1213,11 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = else: result = ptrSize a = ptrSize of tyNil, tyCString, tyString, tySequence, tyPtr, tyRef, tyVar, tyOpenArray, - tyBigNum: - result = ptrSize + tyBigNum: + let base = typ.lastSon + if base == typ or (base.kind == tyTuple and base.size==szIllegalRecursion): + result = szIllegalRecursion + else: result = ptrSize a = result of tyArray, tyArrayConstr: let elemSize = computeSizeAux(typ.sons[1], a) @@ -1270,7 +1279,7 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = #internalError("computeSizeAux()") result = szUnknownSize typ.size = result - typ.align = int(a) + typ.align = int16(a) proc computeSize(typ: PType): BiggestInt = var a: BiggestInt = 1 @@ -1285,7 +1294,7 @@ proc getSize(typ: PType): BiggestInt = result = computeSize(typ) if result < 0: internalError("getSize: " & $typ.kind) -proc containsGenericTypeIter(t: PType, closure: PObject): bool = +proc containsGenericTypeIter(t: PType, closure: RootRef): bool = if t.kind == tyStatic: return t.n == nil @@ -1359,7 +1368,8 @@ proc compatibleEffects*(formal, actual: PType): bool = if real.len == 0: return false result = compatibleEffectsAux(st, real.sons[tagEffects]) if not result: return - result = true + result = formal.lockLevel.ord < 0 or + actual.lockLevel.ord <= formal.lockLevel.ord proc isCompileTimeOnly*(t: PType): bool {.inline.} = result = t.kind in {tyTypeDesc, tyStatic} diff --git a/compiler/vm.nim b/compiler/vm.nim index e40acca6c..e5b357a11 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -133,6 +133,8 @@ proc createStrKeepNode(x: var TFullReg) = # cause of bugs like these is that the VM does not properly distinguish # between variable defintions (var foo = e) and variable updates (foo = e). +include vmhooks + template createStr(x) = x.node = newNode(nkStrLit) @@ -256,8 +258,16 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame): c.currentExceptionB = c.currentExceptionA c.currentExceptionA = nil # execute the corresponding handler: + while c.code[pc2].opcode == opcExcept: inc pc2 return (pc2, f) inc pc2 + if c.code[pc2].opcode != opcExcept and nextExceptOrFinally >= 0: + # we're at the end of the *except list*, but maybe there is another + # *except branch*? + pc2 = nextExceptOrFinally+1 + if c.code[pc2].opcode == opcExcept: + nextExceptOrFinally = pc2 + c.code[pc2].regBx - wordExcess + if nextExceptOrFinally >= 0: pc2 = nextExceptOrFinally if c.code[pc2].opcode == opcFinally: @@ -801,7 +811,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let bb = regs[rb].node let isClosure = bb.kind == nkPar let prc = if not isClosure: bb.sym else: bb.sons[0].sym - if sfImportc in prc.flags: + if prc.offset < -1: + # it's a callback: + c.callbacks[-prc.offset-2].value( + VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[pointer](regs))) + elif sfImportc in prc.flags: if allowFFI notin c.features: globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI") # we pass 'tos.slots' instead of 'regs' so that the compiler can keep @@ -832,9 +846,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if isClosure: newFrame.slots[rc].kind = rkNode newFrame.slots[rc].node = regs[rb].node.sons[1] - # allocate the temporaries: - #for i in rc+ord(isClosure) .. <prc.offset: - # newFrame.slots[i] = newNode(nkEmpty) tos = newFrame move(regs, newFrame.slots) # -1 for the following 'inc pc' @@ -888,10 +899,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcTry: let rbx = instr.regBx - wordExcess tos.pushSafePoint(pc + rbx) + assert c.code[pc+rbx].opcode in {opcExcept, opcFinally} of opcExcept: # just skip it; it's followed by a jump; # we'll execute in the 'raise' handler - discard + let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc' + inc pc, rbx + assert c.code[pc+1].opcode in {opcExcept, opcFinally} of opcFinally: # just skip it; it's followed by the code we need to execute anyway tos.popSafePoint() @@ -1033,8 +1047,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = internalError(c.debug[pc], "too implement") of opcNarrowS: decodeB(rkInt) - let min = -(1 shl (rb-1)) - let max = (1 shl (rb-1))-1 + let min = -(1.BiggestInt shl (rb-1)) + let max = (1.BiggestInt shl (rb-1))-1 if regs[ra].intVal < min or regs[ra].intVal > max: stackTrace(c, tos, pc, errGenerated, msgKindToString(errUnhandledExceptionX) % "value out of range") @@ -1132,14 +1146,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcParseExprToAst: decodeB(rkNode) # c.debug[pc].line.int - countLines(regs[rb].strVal) ? - let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFilename, + let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFullPath, c.debug[pc].line.int) if sonsLen(ast) != 1: globalError(c.debug[pc], errExprExpected, "multiple statements") regs[ra].node = ast.sons[0] of opcParseStmtToAst: decodeB(rkNode) - let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFilename, + let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFullPath, c.debug[pc].line.int) regs[ra].node = ast of opcCallSite: @@ -1316,6 +1330,8 @@ proc evalExpr*(c: PCtx, n: PNode): PNode = assert c.code[start].opcode != opcEof result = execute(c, start) +include vmops + # for now we share the 'globals' environment. XXX Coming soon: An API for # storing&loading the 'globals' environment to get what a component system # requires. @@ -1325,6 +1341,7 @@ var proc setupGlobalCtx(module: PSym) = if globalCtx.isNil: globalCtx = newCtx(module) else: refresh(globalCtx, module) + registerAdditionalOps(globalCtx) proc myOpen(module: PSym): PPassContext = #var c = newEvalContext(module, emRepl) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index cad48abea..d7cdafb69 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -170,7 +170,12 @@ type sym*: PSym slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]] maxSlots*: int - + + VmArgs* = object + ra*, rb*, rc*: Natural + slots*: pointer + VmCallback* = proc (args: VmArgs) {.closure.} + PCtx* = ref TCtx TCtx* = object of passes.TPassContext # code gen context code*: seq[TInstr] @@ -189,6 +194,7 @@ type traceActive*: bool loopIterations*: int comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces + callbacks*: seq[tuple[key: string, value: VmCallback]] TPosition* = distinct int @@ -198,12 +204,15 @@ proc newCtx*(module: PSym): PCtx = PCtx(code: @[], debug: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations, - comesFromHeuristic: unknownLineInfo()) + comesFromHeuristic: unknownLineInfo(), callbacks: @[]) proc refresh*(c: PCtx, module: PSym) = c.module = module c.prc = PProc(blocks: @[]) +proc registerCallback*(c: PCtx; name: string; callback: VmCallback) = + c.callbacks.add((name, callback)) + const firstABxInstr* = opcTJmp largeInstrs* = { # instructions which use 2 int32s instead of 1: diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index fdd8276cc..6673d0bd2 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -9,7 +9,7 @@ import ast, types, msgs, osproc, streams, options -proc readOutput(p: PProcess): string = +proc readOutput(p: Process): string = result = "" var output = p.outputStream while not output.atEnd: @@ -33,6 +33,6 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = # the module dependencies are accurate: appendToModule(module, newNode(nkIncludeStmt, info, @[ newStrNode(nkStrLit, filename)])) - except EIO: + except IOError: localError(info, errCannotOpenFile, file) result = "" diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index a4ddc2e15..e0e34306c 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -46,7 +46,6 @@ proc debugInfo(info: TLineInfo): string = proc codeListing(c: PCtx, result: var string, start=0; last = -1) = # first iteration: compute all necessary labels: var jumpTargets = initIntSet() - let last = if last < 0: c.code.len-1 else: min(last, c.code.len-1) for i in start..last: let x = c.code[i] @@ -83,7 +82,7 @@ proc codeListing(c: PCtx, result: var string, start=0; last = -1) = result.add("\n") inc i -proc echoCode*(c: PCtx, start=0; last = -1) {.deprecated.} = +proc echoCode*(c: PCtx; start=0; last = -1) {.deprecated.} = var buf = "" codeListing(c, buf, start, last) echo buf @@ -1068,6 +1067,9 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; c.gABC(n, opcNodeToReg, dest, dest) elif c.prc.slots[tmp].kind >= slotTempUnknown: gABC(c, n, opcAddrNode, dest, tmp) + # XXX this can still be wrong sometimes; hopefully it's only generated + # in call contexts, where it is safe + #message(n.info, warnUser, "suspicious opcode used") else: gABC(c, n, opcAddrReg, dest, tmp) c.freeTemp(tmp) @@ -1124,6 +1126,7 @@ proc checkCanEval(c: PCtx; n: PNode) = # we need to ensure that we don't evaluate 'x' here: # proc foo() = var x ... let s = n.sym + if {sfCompileTime, sfGlobal} <= s.flags: return if s.kind in {skVar, skTemp, skLet, skParam, skResult} and not s.isOwnedBy(c.prc.sym) and s.owner != c.module: cannotEval(n) @@ -1134,6 +1137,9 @@ proc isTemp(c: PCtx; dest: TDest): bool = template needsAdditionalCopy(n): expr = not c.isTemp(dest) and not fitsRegister(n.typ) +proc skipDeref(n: PNode): PNode = + result = if n.kind in {nkDerefExpr, nkHiddenDeref}: n.sons[0] else: n + proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode; dest, idx, value: TRegister) = # opcLdObj et al really means "load address". We sometimes have to create a @@ -1497,6 +1503,26 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) = proc genProc*(c: PCtx; s: PSym): int +proc matches(s: PSym; x: string): bool = + let y = x.split('.') + var s = s + var L = y.len-1 + while L >= 0: + if s == nil or y[L].cmpIgnoreStyle(s.name.s) != 0: return false + s = s.owner + dec L + result = true + +proc procIsCallback(c: PCtx; s: PSym): bool = + if s.offset < -1: return true + var i = -2 + for key, value in items(c.callbacks): + if s.matches(key): + doAssert s.offset == -1 + s.offset = i + return true + dec i + proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = case n.kind of nkSym: @@ -1507,7 +1533,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = genRdVar(c, n, dest, flags) of skProc, skConverter, skMacro, skTemplate, skMethod, skIterators: # 'skTemplate' is only allowed for 'getAst' support: - if sfImportc in s.flags: c.importcSym(n.info, s) + if procIsCallback(c, s): discard + elif sfImportc in s.flags: c.importcSym(n.info, s) genLit(c, n, dest) of skConst: gen(c, s.ast, dest) @@ -1569,6 +1596,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = let L = n.len-1 for i in 0 .. <L: gen(c, n.sons[i]) gen(c, n.sons[L], dest, flags) + of nkPragmaBlock: + gen(c, n.lastSon, dest, flags) of nkDiscardStmt: unused(n, dest) gen(c, n.sons[0]) diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim new file mode 100644 index 000000000..cce87d433 --- /dev/null +++ b/compiler/vmhooks.nim @@ -0,0 +1,45 @@ +# +# +# The Nim Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +template setX(k, field) {.immediate, dirty.} = + var s: seq[TFullReg] + move(s, cast[seq[TFullReg]](a.slots)) + if s[a.ra].kind != k: + myreset(s[a.ra]) + s[a.ra].kind = k + s[a.ra].field = v + +proc setResult*(a: VmArgs; v: BiggestInt) = setX(rkInt, intVal) +proc setResult*(a: VmArgs; v: BiggestFloat) = setX(rkFloat, floatVal) +proc setResult*(a: VmArgs; v: bool) = + let v = v.ord + setX(rkInt, intVal) + +proc setResult*(a: VmArgs; v: string) = + var s: seq[TFullReg] + move(s, cast[seq[TFullReg]](a.slots)) + if s[a.ra].kind != rkNode: + myreset(s[a.ra]) + s[a.ra].kind = rkNode + s[a.ra].node = newNode(nkStrLit) + s[a.ra].node.strVal = v + +template getX(k, field) {.immediate, dirty.} = + doAssert i < a.rc-1 + let s = cast[seq[TFullReg]](a.slots) + doAssert s[i+a.rb+1].kind == k + result = s[i+a.rb+1].field + +proc getInt*(a: VmArgs; i: Natural): BiggestInt = getX(rkInt, intVal) +proc getFloat*(a: VmArgs; i: Natural): BiggestFloat = getX(rkFloat, floatVal) +proc getString*(a: VmArgs; i: Natural): string = + doAssert i < a.rc-1 + let s = cast[seq[TFullReg]](a.slots) + doAssert s[i+a.rb+1].kind == rkNode + result = s[i+a.rb+1].node.strVal diff --git a/compiler/vmops.nim b/compiler/vmops.nim new file mode 100644 index 000000000..aa25d208a --- /dev/null +++ b/compiler/vmops.nim @@ -0,0 +1,75 @@ +# +# +# The Nim Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# Unforunately this cannot be a module yet: +#import vmdeps, vm +from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, + arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, + floor, ceil, fmod + +from os import getEnv, existsEnv, dirExists, fileExists + +template mathop(op) {.immediate, dirty.} = + registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`) + +template osop(op) {.immediate, dirty.} = + registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`) + +template systemop(op) {.immediate, dirty.} = + registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`) + +template wrap1f(op) {.immediate, dirty.} = + proc `op Wrapper`(a: VmArgs) {.nimcall.} = + setResult(a, op(getFloat(a, 0))) + mathop op + +template wrap2f(op) {.immediate, dirty.} = + proc `op Wrapper`(a: VmArgs) {.nimcall.} = + setResult(a, op(getFloat(a, 0), getFloat(a, 1))) + mathop op + +template wrap1s(op) {.immediate, dirty.} = + proc `op Wrapper`(a: VmArgs) {.nimcall.} = + setResult(a, op(getString(a, 0))) + osop op + +template wrap2svoid(op) {.immediate, dirty.} = + proc `op Wrapper`(a: VmArgs) {.nimcall.} = + op(getString(a, 0), getString(a, 1)) + systemop op + +proc registerAdditionalOps*(c: PCtx) = + wrap1f(sqrt) + wrap1f(ln) + wrap1f(log10) + wrap1f(log2) + wrap1f(exp) + wrap1f(round) + wrap1f(arccos) + wrap1f(arcsin) + wrap1f(arctan) + wrap2f(arctan2) + wrap1f(cos) + wrap1f(cosh) + wrap2f(hypot) + wrap1f(sinh) + wrap1f(sin) + wrap1f(tan) + wrap1f(tanh) + wrap2f(pow) + wrap1f(trunc) + wrap1f(floor) + wrap1f(ceil) + wrap2f(fmod) + + wrap1s(getEnv) + wrap1s(existsEnv) + wrap1s(dirExists) + wrap1s(fileExists) + wrap2svoid(writeFile) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index d81031917..068f59c71 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this |